You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http.py 2.0KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. from urllib.parse import unquote, urlparse
  2. from asgiref.testing import ApplicationCommunicator
  3. class HttpCommunicator(ApplicationCommunicator):
  4. """
  5. ApplicationCommunicator subclass that has HTTP shortcut methods.
  6. It will construct the scope for you, so you need to pass the application
  7. (uninstantiated) along with HTTP parameters.
  8. This does not support full chunking - for that, just use ApplicationCommunicator
  9. directly.
  10. """
  11. def __init__(self, application, method, path, body=b"", headers=None):
  12. parsed = urlparse(path)
  13. self.scope = {
  14. "type": "http",
  15. "http_version": "1.1",
  16. "method": method.upper(),
  17. "path": unquote(parsed.path),
  18. "query_string": parsed.query.encode("utf-8"),
  19. "headers": headers or [],
  20. }
  21. assert isinstance(body, bytes)
  22. self.body = body
  23. self.sent_request = False
  24. super().__init__(application, self.scope)
  25. async def get_response(self, timeout=1):
  26. """
  27. Get the application's response. Returns a dict with keys of
  28. "body", "headers" and "status".
  29. """
  30. # If we've not sent the request yet, do so
  31. if not self.sent_request:
  32. self.sent_request = True
  33. await self.send_input({"type": "http.request", "body": self.body})
  34. # Get the response start
  35. response_start = await self.receive_output(timeout)
  36. assert response_start["type"] == "http.response.start"
  37. # Get all body parts
  38. response_start["body"] = b""
  39. while True:
  40. chunk = await self.receive_output(timeout)
  41. assert chunk["type"] == "http.response.body"
  42. assert isinstance(chunk["body"], bytes)
  43. response_start["body"] += chunk["body"]
  44. if not chunk.get("more_body", False):
  45. break
  46. # Return structured info
  47. del response_start["type"]
  48. response_start.setdefault("headers", [])
  49. return response_start