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
						
					
					
				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",
 | 
						|
        )
 | 
						|
    )
 |