Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

286 rindas
9.2 KiB

  1. # High level events that make up HTTP/1.1 conversations. Loosely inspired by
  2. # the corresponding events in hyper-h2:
  3. #
  4. # http://python-hyper.org/h2/en/stable/api.html#events
  5. #
  6. # Don't subclass these. Stuff will break.
  7. from . import _headers
  8. from ._util import bytesify, LocalProtocolError
  9. # Everything in __all__ gets re-exported as part of the h11 public API.
  10. __all__ = [
  11. "Request",
  12. "InformationalResponse",
  13. "Response",
  14. "Data",
  15. "EndOfMessage",
  16. "ConnectionClosed",
  17. ]
  18. class _EventBundle(object):
  19. _fields = []
  20. _defaults = {}
  21. def __init__(self, **kwargs):
  22. _parsed = kwargs.pop("_parsed", False)
  23. allowed = set(self._fields)
  24. for kwarg in kwargs:
  25. if kwarg not in allowed:
  26. raise TypeError(
  27. "unrecognized kwarg {} for {}"
  28. .format(kwarg, self.__class__.__name__))
  29. required = allowed.difference(self._defaults)
  30. for field in required:
  31. if field not in kwargs:
  32. raise TypeError(
  33. "missing required kwarg {} for {}"
  34. .format(field, self.__class__.__name__))
  35. self.__dict__.update(self._defaults)
  36. self.__dict__.update(kwargs)
  37. # Special handling for some fields
  38. if "headers" in self.__dict__:
  39. self.headers = _headers.normalize_and_validate(
  40. self.headers, _parsed=_parsed)
  41. if not _parsed:
  42. for field in ["method", "target", "http_version", "reason"]:
  43. if field in self.__dict__:
  44. self.__dict__[field] = bytesify(self.__dict__[field])
  45. if "status_code" in self.__dict__:
  46. if not isinstance(self.status_code, int):
  47. raise LocalProtocolError("status code must be integer")
  48. self._validate()
  49. def _validate(self):
  50. pass
  51. def __repr__(self):
  52. name = self.__class__.__name__
  53. kwarg_strs = ["{}={}".format(field, self.__dict__[field])
  54. for field in self._fields]
  55. kwarg_str = ", ".join(kwarg_strs)
  56. return "{}({})".format(name, kwarg_str)
  57. # Useful for tests
  58. def __eq__(self, other):
  59. return (self.__class__ == other.__class__
  60. and self.__dict__ == other.__dict__)
  61. def __ne__(self, other):
  62. return not self.__eq__(other)
  63. # This is an unhashable type.
  64. __hash__ = None
  65. class Request(_EventBundle):
  66. """The beginning of an HTTP request.
  67. Fields:
  68. .. attribute:: method
  69. An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte
  70. string. :term:`Bytes-like objects <bytes-like object>` and native
  71. strings containing only ascii characters will be automatically
  72. converted to byte strings.
  73. .. attribute:: target
  74. The target of an HTTP request, e.g. ``b"/index.html"``, or one of the
  75. more exotic formats described in `RFC 7320, section 5.3
  76. <https://tools.ietf.org/html/rfc7230#section-5.3>`_. Always a byte
  77. string. :term:`Bytes-like objects <bytes-like object>` and native
  78. strings containing only ascii characters will be automatically
  79. converted to byte strings.
  80. .. attribute:: headers
  81. Request headers, represented as a list of (name, value) pairs. See
  82. :ref:`the header normalization rules <headers-format>` for details.
  83. .. attribute:: http_version
  84. The HTTP protocol version, represented as a byte string like
  85. ``b"1.1"``. See :ref:`the HTTP version normalization rules
  86. <http_version-format>` for details.
  87. """
  88. _fields = ["method", "target", "headers", "http_version"]
  89. _defaults = {"http_version": b"1.1"}
  90. def _validate(self):
  91. # "A server MUST respond with a 400 (Bad Request) status code to any
  92. # HTTP/1.1 request message that lacks a Host header field and to any
  93. # request message that contains more than one Host header field or a
  94. # Host header field with an invalid field-value."
  95. # -- https://tools.ietf.org/html/rfc7230#section-5.4
  96. host_count = 0
  97. for name, value in self.headers:
  98. if name == b"host":
  99. host_count += 1
  100. if self.http_version == b"1.1" and host_count == 0:
  101. raise LocalProtocolError("Missing mandatory Host: header")
  102. if host_count > 1:
  103. raise LocalProtocolError("Found multiple Host: headers")
  104. class _ResponseBase(_EventBundle):
  105. _fields = ["status_code", "headers", "http_version", "reason"]
  106. _defaults = {"http_version": b"1.1",
  107. "reason": b""}
  108. class InformationalResponse(_ResponseBase):
  109. """An HTTP informational response.
  110. Fields:
  111. .. attribute:: status_code
  112. The status code of this response, as an integer. For an
  113. :class:`InformationalResponse`, this is always in the range [100,
  114. 200).
  115. .. attribute:: headers
  116. Request headers, represented as a list of (name, value) pairs. See
  117. :ref:`the header normalization rules <headers-format>` for
  118. details.
  119. .. attribute:: http_version
  120. The HTTP protocol version, represented as a byte string like
  121. ``b"1.1"``. See :ref:`the HTTP version normalization rules
  122. <http_version-format>` for details.
  123. .. attribute:: reason
  124. The reason phrase of this response, as a byte string. For example:
  125. ``b"OK"``, or ``b"Not Found"``.
  126. """
  127. def _validate(self):
  128. if not (100 <= self.status_code < 200):
  129. raise LocalProtocolError(
  130. "InformationalResponse status_code should be in range "
  131. "[100, 200), not {}"
  132. .format(self.status_code))
  133. class Response(_ResponseBase):
  134. """The beginning of an HTTP response.
  135. Fields:
  136. .. attribute:: status_code
  137. The status code of this response, as an integer. For an
  138. :class:`Response`, this is always in the range [200,
  139. 600).
  140. .. attribute:: headers
  141. Request headers, represented as a list of (name, value) pairs. See
  142. :ref:`the header normalization rules <headers-format>` for details.
  143. .. attribute:: http_version
  144. The HTTP protocol version, represented as a byte string like
  145. ``b"1.1"``. See :ref:`the HTTP version normalization rules
  146. <http_version-format>` for details.
  147. .. attribute:: reason
  148. The reason phrase of this response, as a byte string. For example:
  149. ``b"OK"``, or ``b"Not Found"``.
  150. """
  151. def _validate(self):
  152. if not (200 <= self.status_code < 600):
  153. raise LocalProtocolError(
  154. "Response status_code should be in range [200, 600), not {}"
  155. .format(self.status_code))
  156. class Data(_EventBundle):
  157. """Part of an HTTP message body.
  158. Fields:
  159. .. attribute:: data
  160. A :term:`bytes-like object` containing part of a message body. Or, if
  161. using the ``combine=False`` argument to :meth:`Connection.send`, then
  162. any object that your socket writing code knows what to do with, and for
  163. which calling :func:`len` returns the number of bytes that will be
  164. written -- see :ref:`sendfile` for details.
  165. .. attribute:: chunk_start
  166. A marker that indicates whether this data object is from the start of a
  167. chunked transfer encoding chunk. This field is ignored when when a Data
  168. event is provided to :meth:`Connection.send`: it is only valid on
  169. events emitted from :meth:`Connection.next_event`. You probably
  170. shouldn't use this attribute at all; see
  171. :ref:`chunk-delimiters-are-bad` for details.
  172. .. attribute:: chunk_end
  173. A marker that indicates whether this data object is the last for a
  174. given chunked transfer encoding chunk. This field is ignored when when
  175. a Data event is provided to :meth:`Connection.send`: it is only valid
  176. on events emitted from :meth:`Connection.next_event`. You probably
  177. shouldn't use this attribute at all; see
  178. :ref:`chunk-delimiters-are-bad` for details.
  179. """
  180. _fields = ["data", "chunk_start", "chunk_end"]
  181. _defaults = {"chunk_start": False, "chunk_end": False}
  182. # XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that
  183. # are forbidden to be sent in a trailer, since processing them as if they were
  184. # present in the header section might bypass external security filters."
  185. # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part
  186. # Unfortunately, the list of forbidden fields is long and vague :-/
  187. class EndOfMessage(_EventBundle):
  188. """The end of an HTTP message.
  189. Fields:
  190. .. attribute:: headers
  191. Default value: ``[]``
  192. Any trailing headers attached to this message, represented as a list of
  193. (name, value) pairs. See :ref:`the header normalization rules
  194. <headers-format>` for details.
  195. Must be empty unless ``Transfer-Encoding: chunked`` is in use.
  196. """
  197. _fields = ["headers"]
  198. _defaults = {"headers": []}
  199. class ConnectionClosed(_EventBundle):
  200. """This event indicates that the sender has closed their outgoing
  201. connection.
  202. Note that this does not necessarily mean that they can't *receive* further
  203. data, because TCP connections are composed to two one-way channels which
  204. can be closed independently. See :ref:`closing` for details.
  205. No fields.
  206. """
  207. pass