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.
		
		
		
		
		
			
		
			
				
					158 lines
				
				5.5 KiB
			
		
		
			
		
	
	
					158 lines
				
				5.5 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								import pytest
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from .._events import Request
							 | 
						||
| 
								 | 
							
								from .._headers import (
							 | 
						||
| 
								 | 
							
								    get_comma_header,
							 | 
						||
| 
								 | 
							
								    has_expect_100_continue,
							 | 
						||
| 
								 | 
							
								    Headers,
							 | 
						||
| 
								 | 
							
								    normalize_and_validate,
							 | 
						||
| 
								 | 
							
								    set_comma_header,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								from .._util import LocalProtocolError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def test_normalize_and_validate() -> None:
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([("foo", "bar")]) == [(b"foo", b"bar")]
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([(b"foo", b"bar")]) == [(b"foo", b"bar")]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # no leading/trailing whitespace in names
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b"foo ", "bar")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b" foo", "bar")])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # no weird characters in names
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError) as excinfo:
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b"foo bar", b"baz")])
							 | 
						||
| 
								 | 
							
								    assert "foo bar" in str(excinfo.value)
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b"foo\x00bar", b"baz")])
							 | 
						||
| 
								 | 
							
								    # Not even 8-bit characters:
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b"foo\xffbar", b"baz")])
							 | 
						||
| 
								 | 
							
								    # And not even the control characters we allow in values:
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([(b"foo\x01bar", b"baz")])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # no return or NUL characters in values
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError) as excinfo:
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "bar\rbaz")])
							 | 
						||
| 
								 | 
							
								    assert "bar\\rbaz" in str(excinfo.value)
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "bar\nbaz")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "bar\x00baz")])
							 | 
						||
| 
								 | 
							
								    # no leading/trailing whitespace
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "barbaz  ")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "  barbaz")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "barbaz\t")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("foo", "\tbarbaz")])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # content-length
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([("Content-Length", "1")]) == [
							 | 
						||
| 
								 | 
							
								        (b"content-length", b"1")
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("Content-Length", "asdf")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("Content-Length", "1x")])
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("Content-Length", "1"), ("Content-Length", "2")])
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate(
							 | 
						||
| 
								 | 
							
								        [("Content-Length", "0"), ("Content-Length", "0")]
							 | 
						||
| 
								 | 
							
								    ) == [(b"content-length", b"0")]
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([("Content-Length", "0 , 0")]) == [
							 | 
						||
| 
								 | 
							
								        (b"content-length", b"0")
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate(
							 | 
						||
| 
								 | 
							
								            [("Content-Length", "1"), ("Content-Length", "1"), ("Content-Length", "2")]
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("Content-Length", "1 , 1,2")])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # transfer-encoding
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([("Transfer-Encoding", "chunked")]) == [
							 | 
						||
| 
								 | 
							
								        (b"transfer-encoding", b"chunked")
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								    assert normalize_and_validate([("Transfer-Encoding", "cHuNkEd")]) == [
							 | 
						||
| 
								 | 
							
								        (b"transfer-encoding", b"chunked")
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError) as excinfo:
							 | 
						||
| 
								 | 
							
								        normalize_and_validate([("Transfer-Encoding", "gzip")])
							 | 
						||
| 
								 | 
							
								    assert excinfo.value.error_status_hint == 501  # Not Implemented
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError) as excinfo:
							 | 
						||
| 
								 | 
							
								        normalize_and_validate(
							 | 
						||
| 
								 | 
							
								            [("Transfer-Encoding", "chunked"), ("Transfer-Encoding", "gzip")]
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    assert excinfo.value.error_status_hint == 501  # Not Implemented
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def test_get_set_comma_header() -> None:
							 | 
						||
| 
								 | 
							
								    headers = normalize_and_validate(
							 | 
						||
| 
								 | 
							
								        [
							 | 
						||
| 
								 | 
							
								            ("Connection", "close"),
							 | 
						||
| 
								 | 
							
								            ("whatever", "something"),
							 | 
						||
| 
								 | 
							
								            ("connectiON", "fOo,, , BAR"),
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert get_comma_header(headers, b"connection") == [b"close", b"foo", b"bar"]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    headers = set_comma_header(headers, b"newthing", ["a", "b"])  # type: ignore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    with pytest.raises(LocalProtocolError):
							 | 
						||
| 
								 | 
							
								        set_comma_header(headers, b"newthing", ["  a", "b"])  # type: ignore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert headers == [
							 | 
						||
| 
								 | 
							
								        (b"connection", b"close"),
							 | 
						||
| 
								 | 
							
								        (b"whatever", b"something"),
							 | 
						||
| 
								 | 
							
								        (b"connection", b"fOo,, , BAR"),
							 | 
						||
| 
								 | 
							
								        (b"newthing", b"a"),
							 | 
						||
| 
								 | 
							
								        (b"newthing", b"b"),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    headers = set_comma_header(headers, b"whatever", ["different thing"])  # type: ignore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assert headers == [
							 | 
						||
| 
								 | 
							
								        (b"connection", b"close"),
							 | 
						||
| 
								 | 
							
								        (b"connection", b"fOo,, , BAR"),
							 | 
						||
| 
								 | 
							
								        (b"newthing", b"a"),
							 | 
						||
| 
								 | 
							
								        (b"newthing", b"b"),
							 | 
						||
| 
								 | 
							
								        (b"whatever", b"different thing"),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def test_has_100_continue() -> None:
							 | 
						||
| 
								 | 
							
								    assert has_expect_100_continue(
							 | 
						||
| 
								 | 
							
								        Request(
							 | 
						||
| 
								 | 
							
								            method="GET",
							 | 
						||
| 
								 | 
							
								            target="/",
							 | 
						||
| 
								 | 
							
								            headers=[("Host", "example.com"), ("Expect", "100-continue")],
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    assert not has_expect_100_continue(
							 | 
						||
| 
								 | 
							
								        Request(method="GET", target="/", headers=[("Host", "example.com")])
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    # Case insensitive
							 | 
						||
| 
								 | 
							
								    assert has_expect_100_continue(
							 | 
						||
| 
								 | 
							
								        Request(
							 | 
						||
| 
								 | 
							
								            method="GET",
							 | 
						||
| 
								 | 
							
								            target="/",
							 | 
						||
| 
								 | 
							
								            headers=[("Host", "example.com"), ("Expect", "100-Continue")],
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    # Doesn't work in HTTP/1.0
							 | 
						||
| 
								 | 
							
								    assert not has_expect_100_continue(
							 | 
						||
| 
								 | 
							
								        Request(
							 | 
						||
| 
								 | 
							
								            method="GET",
							 | 
						||
| 
								 | 
							
								            target="/",
							 | 
						||
| 
								 | 
							
								            headers=[("Host", "example.com"), ("Expect", "100-continue")],
							 | 
						||
| 
								 | 
							
								            http_version="1.0",
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								    )
							 |