From d3e99c9a357031d8f01ccc626aa307ba02f0154d Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Sun, 25 Dec 2016 09:49:54 -0800 Subject: [PATCH] Add performant smart response handling --- sanic/server.py | 27 +++++++++++++++++++---- tests/test_response.py | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/sanic/server.py b/sanic/server.py index 11756005..b5e27f5a 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -6,7 +6,9 @@ from signal import SIGINT, SIGTERM from time import time from httptools import HttpRequestParser from httptools.parser.errors import HttpParserError + from .exceptions import ServerError +from .response import json, text try: import uvloop as async_loop @@ -147,12 +149,29 @@ class HttpProtocol(asyncio.Protocol): # -------------------------------------------- # def write_response(self, response): - try: - keep_alive = self.parser.should_keep_alive() \ - and not self.signal.stopped + + def attempt_write(_response): self.transport.write( - response.output( + _response.output( 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: self.transport.close() else: diff --git a/tests/test_response.py b/tests/test_response.py index f35f10e9..6dd504f4 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,4 +1,7 @@ from random import choice +from json import loads as json_loads, JSONDecodeError + +import pytest from sanic import Sanic from sanic.response import HTTPResponse @@ -16,3 +19,49 @@ def test_response_body_not_a_string(): request, response = sanic_endpoint_test(app, uri='/hello') 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)