Format: text/x-python
⬇ Download File (4.5 KB)
   1  from http import HTTPStatus
   2  
   3  import pytest
   4  
   5  from .. import _events
   6  from .._events import (
   7      ConnectionClosed,
   8      Data,
   9      EndOfMessage,
  10      Event,
  11      InformationalResponse,
  12      Request,
  13      Response,
  14  )
  15  from .._util import LocalProtocolError
  16  
  17  
  18  def test_events() -> None:
  19      with pytest.raises(LocalProtocolError):
  20          # Missing Host:
  21          req = Request(
  22              method="GET", target="/", headers=[("a", "b")], http_version="1.1"
  23          )
  24      # But this is okay (HTTP/1.0)
  25      req = Request(method="GET", target="/", headers=[("a", "b")], http_version="1.0")
  26      # fields are normalized
  27      assert req.method == b"GET"
  28      assert req.target == b"/"
  29      assert req.headers == [(b"a", b"b")]
  30      assert req.http_version == b"1.0"
  31  
  32      # This is also okay -- has a Host (with weird capitalization, which is ok)
  33      req = Request(
  34          method="GET",
  35          target="/",
  36          headers=[("a", "b"), ("hOSt", "example.com")],
  37          http_version="1.1",
  38      )
  39      # we normalize header capitalization
  40      assert req.headers == [(b"a", b"b"), (b"host", b"example.com")]
  41  
  42      # Multiple host is bad too
  43      with pytest.raises(LocalProtocolError):
  44          req = Request(
  45              method="GET",
  46              target="/",
  47              headers=[("Host", "a"), ("Host", "a")],
  48              http_version="1.1",
  49          )
  50      # Even for HTTP/1.0
  51      with pytest.raises(LocalProtocolError):
  52          req = Request(
  53              method="GET",
  54              target="/",
  55              headers=[("Host", "a"), ("Host", "a")],
  56              http_version="1.0",
  57          )
  58  
  59      # Header values are validated
  60      for bad_char in "\x00\r\n\f\v":
  61          with pytest.raises(LocalProtocolError):
  62              req = Request(
  63                  method="GET",
  64                  target="/",
  65                  headers=[("Host", "a"), ("Foo", "asd" + bad_char)],
  66                  http_version="1.0",
  67              )
  68  
  69      # But for compatibility we allow non-whitespace control characters, even
  70      # though they're forbidden by the spec.
  71      Request(
  72          method="GET",
  73          target="/",
  74          headers=[("Host", "a"), ("Foo", "asd\x01\x02\x7f")],
  75          http_version="1.0",
  76      )
  77  
  78      # Request target is validated
  79      for bad_byte in b"\x00\x20\x7f\xee":
  80          target = bytearray(b"/")
  81          target.append(bad_byte)
  82          with pytest.raises(LocalProtocolError):
  83              Request(
  84                  method="GET", target=target, headers=[("Host", "a")], http_version="1.1"
  85              )
  86  
  87      # Request method is validated
  88      with pytest.raises(LocalProtocolError):
  89          Request(
  90              method="GET / HTTP/1.1",
  91              target=target,
  92              headers=[("Host", "a")],
  93              http_version="1.1",
  94          )
  95  
  96      ir = InformationalResponse(status_code=100, headers=[("Host", "a")])
  97      assert ir.status_code == 100
  98      assert ir.headers == [(b"host", b"a")]
  99      assert ir.http_version == b"1.1"
 100  
 101      with pytest.raises(LocalProtocolError):
 102          InformationalResponse(status_code=200, headers=[("Host", "a")])
 103  
 104      resp = Response(status_code=204, headers=[], http_version="1.0")  # type: ignore[arg-type]
 105      assert resp.status_code == 204
 106      assert resp.headers == []
 107      assert resp.http_version == b"1.0"
 108  
 109      with pytest.raises(LocalProtocolError):
 110          resp = Response(status_code=100, headers=[], http_version="1.0")  # type: ignore[arg-type]
 111  
 112      with pytest.raises(LocalProtocolError):
 113          Response(status_code="100", headers=[], http_version="1.0")  # type: ignore[arg-type]
 114  
 115      with pytest.raises(LocalProtocolError):
 116          InformationalResponse(status_code=b"100", headers=[], http_version="1.0")  # type: ignore[arg-type]
 117  
 118      d = Data(data=b"asdf")
 119      assert d.data == b"asdf"
 120  
 121      eom = EndOfMessage()
 122      assert eom.headers == []
 123  
 124      cc = ConnectionClosed()
 125      assert repr(cc) == "ConnectionClosed()"
 126  
 127  
 128  def test_intenum_status_code() -> None:
 129      # https://github.com/python-hyper/h11/issues/72
 130  
 131      r = Response(status_code=HTTPStatus.OK, headers=[], http_version="1.0")  # type: ignore[arg-type]
 132      assert r.status_code == HTTPStatus.OK
 133      assert type(r.status_code) is not type(HTTPStatus.OK)
 134      assert type(r.status_code) is int
 135  
 136  
 137  def test_header_casing() -> None:
 138      r = Request(
 139          method="GET",
 140          target="/",
 141          headers=[("Host", "example.org"), ("Connection", "keep-alive")],
 142          http_version="1.1",
 143      )
 144      assert len(r.headers) == 2
 145      assert r.headers[0] == (b"host", b"example.org")
 146      assert r.headers == [(b"host", b"example.org"), (b"connection", b"keep-alive")]
 147      assert r.headers.raw_items() == [
 148          (b"Host", b"example.org"),
 149          (b"Connection", b"keep-alive"),
 150      ]
 151