Sanic can now parse args and json

This commit is contained in:
Channel Cat 2016-10-02 18:45:44 -07:00
parent 0489526ac9
commit e0b9260644
3 changed files with 73 additions and 14 deletions

View File

@ -5,6 +5,8 @@ import signal
import functools import functools
import httptools import httptools
import logging import logging
from ujson import loads as json_loads
from urllib.parse import parse_qs
import httptools import httptools
try: try:
@ -21,7 +23,7 @@ from .response import HTTPResponse
PRINT = 0 PRINT = 0
class Request: class Request:
__slots__ = ('protocol', 'url', 'headers', 'version', 'method') __slots__ = ('protocol', 'url', 'headers', 'version', 'method', 'query_string', 'body', 'parsed_json', 'parsed_args')
def __init__(self, protocol, url, headers, version, method): def __init__(self, protocol, url, headers, version, method):
self.protocol = protocol self.protocol = protocol
@ -30,6 +32,35 @@ class Request:
self.version = version self.version = version
self.method = method self.method = method
# Capture query string
query_string_position = self.url.find(b"?")
if query_string_position != -1:
self.query_string = self.url[query_string_position+1:]
self.url = self.url[:query_string_position]
else:
self.query_string = None
# Init but do not inhale
self.body = None
self.parsed_json = None
self.parsed_args = None
@property
def json(self):
if not self.parsed_json:
if not self.body:
raise ValueError("No body to parse")
self.parsed_json = json_loads(self.body)
return self.parsed_json
@property
def args(self):
if not self.parsed_args and self.query_string:
self.parsed_args = {k:v if len(v)>1 else v[0] for k,v in parse_qs(self.query_string).items()}
return self.parsed_args
class HttpProtocol(asyncio.Protocol): class HttpProtocol(asyncio.Protocol):
__slots__ = ('loop', __slots__ = ('loop',
@ -79,8 +110,8 @@ class HttpProtocol(asyncio.Protocol):
try: try:
#print(data) #print(data)
self.parser.feed_data(data) self.parser.feed_data(data)
except httptools.parser.errors.HttpParserError: except httptools.parser.errors.HttpParserError as e:
#log.error("Invalid request data, connection closed") log.error("Invalid request data, connection closed ({})".format(e))
self.transport.close() self.transport.close()
def on_url(self, url): def on_url(self, url):
@ -98,21 +129,27 @@ class HttpProtocol(asyncio.Protocol):
method=self.parser.get_method() method=self.parser.get_method()
) )
#print("res {} - {}".format(n, self.request)) #print("res {} - {}".format(n, self.request))
self.loop.call_soon(self.handle, self.request)
def on_body(self, body):
self.request.body = body
def on_message_complete(self):
self.loop.create_task(self.get_response(self.request))
# -------------------------------------------- # # -------------------------------------------- #
# Responding # Responding
# -------------------------------------------- # # -------------------------------------------- #
def handle(self, request): async def get_response(self, request):
handler = self.router.get(request.url) handler = self.router.get(request.url)
if handler.is_async: try:
future = asyncio.Future() if handler.is_async:
self.loop.create_task(self.handle_response(future, handler, request)) response = await handler(request)
future.add_done_callback(self.handle_result) else:
else: response = handler(request)
response = handler(request) except Exception as e:
self.write_response(request, response) response = HTTPResponse("Error: {}".format(e))
self.write_response(request, response)
def write_response(self, request, response): def write_response(self, request, response):
#print("response - {} - {}".format(self.n, self.request)) #print("response - {} - {}".format(self.n, self.request))
@ -122,8 +159,8 @@ class HttpProtocol(asyncio.Protocol):
#print("KA - {}".format(self.parser.should_keep_alive())) #print("KA - {}".format(self.parser.should_keep_alive()))
if not keep_alive: if not keep_alive:
self.transport.close() self.transport.close()
except: except Exception as e:
log.error("Writing request failed, connection closed") log.error("Writing request failed, connection closed {}".format(e))
self.transport.close() self.transport.close()
self.parser = None self.parser = None

13
test.aiohttp.py Normal file
View File

@ -0,0 +1,13 @@
from aiohttp import web
async def handle(request):
name = request.match_info.get('name', "Anonymous")
text = "Hello, " + name
return web.Response(text=text)
app = web.Application()
app.router.add_get('/', handle)
app.router.add_get('/{name}', handle)
web.run_app(app)

View File

@ -6,8 +6,17 @@ app = Sanic("test")
@app.route("/") @app.route("/")
async def test(request): async def test(request):
return json({ "test": True }) return json({ "test": True })
@app.route("/text") @app.route("/text")
def test(request): def test(request):
return text('hi') return text('hi')
@app.route("/post_json")
def test(request):
return json({ "received": True, "message": request.json })
@app.route("/query_string")
def test(request):
return json({ "parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string })
app.run(host="0.0.0.0") app.run(host="0.0.0.0")