Format: text/x-python
⬇ Download File (5.5 KB)
   1  import pytest
   2  
   3  from .._events import Request
   4  from .._headers import (
   5      get_comma_header,
   6      has_expect_100_continue,
   7      Headers,
   8      normalize_and_validate,
   9      set_comma_header,
  10  )
  11  from .._util import LocalProtocolError
  12  
  13  
  14  def test_normalize_and_validate() -> None:
  15      assert normalize_and_validate([("foo", "bar")]) == [(b"foo", b"bar")]
  16      assert normalize_and_validate([(b"foo", b"bar")]) == [(b"foo", b"bar")]
  17  
  18      # no leading/trailing whitespace in names
  19      with pytest.raises(LocalProtocolError):
  20          normalize_and_validate([(b"foo ", "bar")])
  21      with pytest.raises(LocalProtocolError):
  22          normalize_and_validate([(b" foo", "bar")])
  23  
  24      # no weird characters in names
  25      with pytest.raises(LocalProtocolError) as excinfo:
  26          normalize_and_validate([(b"foo bar", b"baz")])
  27      assert "foo bar" in str(excinfo.value)
  28      with pytest.raises(LocalProtocolError):
  29          normalize_and_validate([(b"foo\x00bar", b"baz")])
  30      # Not even 8-bit characters:
  31      with pytest.raises(LocalProtocolError):
  32          normalize_and_validate([(b"foo\xffbar", b"baz")])
  33      # And not even the control characters we allow in values:
  34      with pytest.raises(LocalProtocolError):
  35          normalize_and_validate([(b"foo\x01bar", b"baz")])
  36  
  37      # no return or NUL characters in values
  38      with pytest.raises(LocalProtocolError) as excinfo:
  39          normalize_and_validate([("foo", "bar\rbaz")])
  40      assert "bar\\rbaz" in str(excinfo.value)
  41      with pytest.raises(LocalProtocolError):
  42          normalize_and_validate([("foo", "bar\nbaz")])
  43      with pytest.raises(LocalProtocolError):
  44          normalize_and_validate([("foo", "bar\x00baz")])
  45      # no leading/trailing whitespace
  46      with pytest.raises(LocalProtocolError):
  47          normalize_and_validate([("foo", "barbaz  ")])
  48      with pytest.raises(LocalProtocolError):
  49          normalize_and_validate([("foo", "  barbaz")])
  50      with pytest.raises(LocalProtocolError):
  51          normalize_and_validate([("foo", "barbaz\t")])
  52      with pytest.raises(LocalProtocolError):
  53          normalize_and_validate([("foo", "\tbarbaz")])
  54  
  55      # content-length
  56      assert normalize_and_validate([("Content-Length", "1")]) == [
  57          (b"content-length", b"1")
  58      ]
  59      with pytest.raises(LocalProtocolError):
  60          normalize_and_validate([("Content-Length", "asdf")])
  61      with pytest.raises(LocalProtocolError):
  62          normalize_and_validate([("Content-Length", "1x")])
  63      with pytest.raises(LocalProtocolError):
  64          normalize_and_validate([("Content-Length", "1"), ("Content-Length", "2")])
  65      assert normalize_and_validate(
  66          [("Content-Length", "0"), ("Content-Length", "0")]
  67      ) == [(b"content-length", b"0")]
  68      assert normalize_and_validate([("Content-Length", "0 , 0")]) == [
  69          (b"content-length", b"0")
  70      ]
  71      with pytest.raises(LocalProtocolError):
  72          normalize_and_validate(
  73              [("Content-Length", "1"), ("Content-Length", "1"), ("Content-Length", "2")]
  74          )
  75      with pytest.raises(LocalProtocolError):
  76          normalize_and_validate([("Content-Length", "1 , 1,2")])
  77  
  78      # transfer-encoding
  79      assert normalize_and_validate([("Transfer-Encoding", "chunked")]) == [
  80          (b"transfer-encoding", b"chunked")
  81      ]
  82      assert normalize_and_validate([("Transfer-Encoding", "cHuNkEd")]) == [
  83          (b"transfer-encoding", b"chunked")
  84      ]
  85      with pytest.raises(LocalProtocolError) as excinfo:
  86          normalize_and_validate([("Transfer-Encoding", "gzip")])
  87      assert excinfo.value.error_status_hint == 501  # Not Implemented
  88      with pytest.raises(LocalProtocolError) as excinfo:
  89          normalize_and_validate(
  90              [("Transfer-Encoding", "chunked"), ("Transfer-Encoding", "gzip")]
  91          )
  92      assert excinfo.value.error_status_hint == 501  # Not Implemented
  93  
  94  
  95  def test_get_set_comma_header() -> None:
  96      headers = normalize_and_validate(
  97          [
  98              ("Connection", "close"),
  99              ("whatever", "something"),
 100              ("connectiON", "fOo,, , BAR"),
 101          ]
 102      )
 103  
 104      assert get_comma_header(headers, b"connection") == [b"close", b"foo", b"bar"]
 105  
 106      headers = set_comma_header(headers, b"newthing", ["a", "b"])  # type: ignore
 107  
 108      with pytest.raises(LocalProtocolError):
 109          set_comma_header(headers, b"newthing", ["  a", "b"])  # type: ignore
 110  
 111      assert headers == [
 112          (b"connection", b"close"),
 113          (b"whatever", b"something"),
 114          (b"connection", b"fOo,, , BAR"),
 115          (b"newthing", b"a"),
 116          (b"newthing", b"b"),
 117      ]
 118  
 119      headers = set_comma_header(headers, b"whatever", ["different thing"])  # type: ignore
 120  
 121      assert headers == [
 122          (b"connection", b"close"),
 123          (b"connection", b"fOo,, , BAR"),
 124          (b"newthing", b"a"),
 125          (b"newthing", b"b"),
 126          (b"whatever", b"different thing"),
 127      ]
 128  
 129  
 130  def test_has_100_continue() -> None:
 131      assert has_expect_100_continue(
 132          Request(
 133              method="GET",
 134              target="/",
 135              headers=[("Host", "example.com"), ("Expect", "100-continue")],
 136          )
 137      )
 138      assert not has_expect_100_continue(
 139          Request(method="GET", target="/", headers=[("Host", "example.com")])
 140      )
 141      # Case insensitive
 142      assert has_expect_100_continue(
 143          Request(
 144              method="GET",
 145              target="/",
 146              headers=[("Host", "example.com"), ("Expect", "100-Continue")],
 147          )
 148      )
 149      # Doesn't work in HTTP/1.0
 150      assert not has_expect_100_continue(
 151          Request(
 152              method="GET",
 153              target="/",
 154              headers=[("Host", "example.com"), ("Expect", "100-continue")],
 155              http_version="1.0",
 156          )
 157      )
 158