This commit is contained in:
2024-12-17 14:36:15 -08:00
parent b2dbf46d28
commit 06d106de53
17731 changed files with 3037186 additions and 144 deletions

View File

@@ -0,0 +1,56 @@
from urllib.parse import unquote, urlparse
from asgiref.testing import ApplicationCommunicator
class HttpCommunicator(ApplicationCommunicator):
"""
ApplicationCommunicator subclass that has HTTP shortcut methods.
It will construct the scope for you, so you need to pass the application
(uninstantiated) along with HTTP parameters.
This does not support full chunking - for that, just use ApplicationCommunicator
directly.
"""
def __init__(self, application, method, path, body=b"", headers=None):
parsed = urlparse(path)
self.scope = {
"type": "http",
"http_version": "1.1",
"method": method.upper(),
"path": unquote(parsed.path),
"query_string": parsed.query.encode("utf-8"),
"headers": headers or [],
}
assert isinstance(body, bytes)
self.body = body
self.sent_request = False
super().__init__(application, self.scope)
async def get_response(self, timeout=1):
"""
Get the application's response. Returns a dict with keys of
"body", "headers" and "status".
"""
# If we've not sent the request yet, do so
if not self.sent_request:
self.sent_request = True
await self.send_input({"type": "http.request", "body": self.body})
# Get the response start
response_start = await self.receive_output(timeout)
assert response_start["type"] == "http.response.start"
# Get all body parts
response_start["body"] = b""
while True:
chunk = await self.receive_output(timeout)
assert chunk["type"] == "http.response.body"
assert isinstance(chunk["body"], bytes)
response_start["body"] += chunk["body"]
if not chunk.get("more_body", False):
break
# Return structured info
del response_start["type"]
response_start.setdefault("headers", [])
return response_start