await Request(scope, receive).post_vars() method, closes #700

Needed for #698
pull/652/head^2
Simon Willison 2020-03-16 19:47:37 -07:00
rodzic 7e357abbc3
commit a000c80d50
2 zmienionych plików z 37 dodań i 4 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
import json
from datasette.utils import RequestParameters
from mimetypes import guess_type
from urllib.parse import parse_qs, urlunparse
from urllib.parse import parse_qs, urlunparse, parse_qsl
from pathlib import Path
from html import escape
import re
@ -13,8 +13,9 @@ class NotFound(Exception):
class Request:
def __init__(self, scope):
def __init__(self, scope, receive):
self.scope = scope
self.receive = receive
@property
def method(self):
@ -66,6 +67,18 @@ class Request:
def raw_args(self):
return {key: value[0] for key, value in self.args.items()}
async def post_vars(self):
body = []
body = b""
more_body = True
while more_body:
message = await self.receive()
assert message["type"] == "http.request", message
body += message.get("body", b"")
more_body = message.get("more_body", False)
return dict(parse_qsl(body.decode("utf-8")))
@classmethod
def fake(cls, path_with_query_string, method="GET", scheme="http"):
"Useful for constructing Request objects for tests"
@ -79,7 +92,7 @@ class Request:
"scheme": scheme,
"type": "http",
}
return cls(scope)
return cls(scope, None)
class AsgiRouter:
@ -171,7 +184,7 @@ class AsgiView:
# that were already tucked into scope["url_route"]["kwargs"] by
# the router, similar to how Django Channels works:
# https://channels.readthedocs.io/en/latest/topics/routing.html#urlrouter
request = Request(scope)
request = Request(scope, receive)
self = view.view_class(*class_args, **class_kwargs)
response = await self.dispatch_request(
request, **scope["url_route"]["kwargs"]

Wyświetl plik

@ -423,3 +423,23 @@ def test_check_connection_spatialite_raises():
def test_check_connection_passes():
conn = sqlite3.connect(":memory:")
utils.check_connection(conn)
@pytest.mark.asyncio
async def test_request_post_vars():
scope = {
"http_version": "1.1",
"method": "POST",
"path": "/",
"raw_path": b"/",
"query_string": b"",
"scheme": "http",
"type": "http",
"headers": [[b"content-type", b"application/x-www-form-urlencoded"]],
}
async def receive():
return {"type": "http.request", "body": b"foo=bar&baz=1", "more_body": False}
request = Request(scope, receive)
assert {"foo": "bar", "baz": "1"} == await request.post_vars()