Add performant smart response handling

This commit is contained in:
Eli Uriegas 2016-12-25 09:49:54 -08:00
parent 6cf3754051
commit d3e99c9a35
2 changed files with 72 additions and 4 deletions

View File

@ -6,7 +6,9 @@ from signal import SIGINT, SIGTERM
from time import time from time import time
from httptools import HttpRequestParser from httptools import HttpRequestParser
from httptools.parser.errors import HttpParserError from httptools.parser.errors import HttpParserError
from .exceptions import ServerError from .exceptions import ServerError
from .response import json, text
try: try:
import uvloop as async_loop import uvloop as async_loop
@ -147,12 +149,29 @@ class HttpProtocol(asyncio.Protocol):
# -------------------------------------------- # # -------------------------------------------- #
def write_response(self, response): def write_response(self, response):
try:
keep_alive = self.parser.should_keep_alive() \ def attempt_write(_response):
and not self.signal.stopped
self.transport.write( self.transport.write(
response.output( _response.output(
self.request.version, keep_alive, self.request_timeout)) self.request.version, keep_alive, self.request_timeout))
try:
keep_alive = (self.parser.should_keep_alive()
and not self.signal.stopped)
try:
# If we already have an HTTPResponse object this should be
# as fast as ever
attempt_write(response)
except AttributeError:
try:
# A performant way to check if we have a list or dict
# Both list and dict contain a `clear` function
response.clear
attempt_write(json(response))
except AttributeError:
attempt_write(text(str(response)))
if not keep_alive: if not keep_alive:
self.transport.close() self.transport.close()
else: else:

View File

@ -1,4 +1,7 @@
from random import choice from random import choice
from json import loads as json_loads, JSONDecodeError
import pytest
from sanic import Sanic from sanic import Sanic
from sanic.response import HTTPResponse from sanic.response import HTTPResponse
@ -16,3 +19,49 @@ def test_response_body_not_a_string():
request, response = sanic_endpoint_test(app, uri='/hello') request, response = sanic_endpoint_test(app, uri='/hello')
assert response.text == str(random_num) assert response.text == str(random_num)
def test_json():
"""Tests the smart handling of dicts for handlers"""
app = Sanic('test_json')
@app.route('/')
async def handler(request):
return {"test": True}
request, response = sanic_endpoint_test(app)
try:
results = json_loads(response.text)
except JSONDecodeError:
pytest.fail(
"Expected JSON response but got '{}'".format(response))
assert results.get('test') is True
def test_text():
"""Tests the smart handling of strings for handlers"""
app = Sanic('test_text')
@app.route('/')
async def handler(request):
return 'Hello'
request, response = sanic_endpoint_test(app)
assert response.text == 'Hello'
def test_int():
"""Tests the smart handling of ints for handlers"""
app = Sanic('test_int')
random_int = choice(range(0, 10000))
@app.route('/')
async def handler(request):
return random_int
request, response = sanic_endpoint_test(app)
assert response.text == str(random_int)