def test_http11_connection_with_local_protocol_error(): """ If a local protocol error occurs, then no response will be returned, and the connection will not be reusable. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) with HTTP11Connection(origin=origin, stream=stream) as conn: with pytest.raises(LocalProtocolError) as exc_info: conn.request("GET", "https://example.com/", headers={"Host": "\0"}) assert str(exc_info.value) == "Illegal header value b'\\x00'" assert not conn.is_idle() assert conn.is_closed() assert not conn.is_available() assert not conn.has_expired() assert ( repr(conn) == "<HTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
def test_http2_connection_post_request(): origin = Origin(b"https", b"example.com", 443) stream = MockStream( [ hyperframe.frame.SettingsFrame().serialize(), hyperframe.frame.HeadersFrame( stream_id=1, data=hpack.Encoder().encode( [ (b":status", b"200"), (b"content-type", b"plain/text"), ] ), flags=["END_HEADERS"], ).serialize(), hyperframe.frame.DataFrame( stream_id=1, data=b"Hello, world!", flags=["END_STREAM"] ).serialize(), ] ) with HTTP2Connection(origin=origin, stream=stream) as conn: response = conn.request( "POST", "https://example.com/", headers={b"content-length": b"17"}, content=b'{"data": "upload"}', ) assert response.status == 200 assert response.content == b"Hello, world!"
def test_http2_connection_attempt_close(): """ A connection can only be closed when it is idle. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream( [ hyperframe.frame.SettingsFrame().serialize(), hyperframe.frame.HeadersFrame( stream_id=1, data=hpack.Encoder().encode( [ (b":status", b"200"), (b"content-type", b"plain/text"), ] ), flags=["END_HEADERS"], ).serialize(), hyperframe.frame.DataFrame( stream_id=1, data=b"Hello, world!", flags=["END_STREAM"] ).serialize(), ] ) with HTTP2Connection(origin=origin, stream=stream) as conn: with conn.stream("GET", "https://example.com/") as response: response.read() assert response.status == 200 assert response.content == b"Hello, world!" conn.close() with pytest.raises(ConnectionNotAvailable): conn.request("GET", "https://example.com/")
def test_http11_connection_unread_response(): """ If the client releases the response without reading it to termination, then the connection will not be reusable. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) with HTTP11Connection(origin=origin, stream=stream) as conn: with conn.stream("GET", "https://example.com/") as response: assert response.status == 200 assert not conn.is_idle() assert conn.is_closed() assert not conn.is_available() assert not conn.has_expired() assert ( repr(conn) == "<HTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
def test_http2_request_to_incorrect_origin(): """ A connection can only send requests to whichever origin it is connected to. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([]) with HTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RuntimeError): conn.request("GET", "https://other.com/")
def test_http2_connection_with_remote_protocol_error(): """ If a remote protocol error occurs, then no response will be returned, and the connection will not be reusable. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([b"Wait, this isn't valid HTTP!", b""]) with HTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): conn.request("GET", "https://example.com/")
def test_http11_connection_attempt_close(): """ A connection can only be closed when it is idle. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) with HTTP11Connection(origin=origin, stream=stream) as conn: with conn.stream("GET", "https://example.com/") as response: response.read() assert response.status == 200 assert response.content == b"Hello, world!"
def test_http11_connection_handles_one_active_request(): """ Attempting to send a request while one is already in-flight will raise a ConnectionNotAvailable exception. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) with HTTP11Connection(origin=origin, stream=stream) as conn: with conn.stream("GET", "https://example.com/"): with pytest.raises(ConnectionNotAvailable): conn.request("GET", "https://example.com/")
def test_http2_connection_with_goaway(): """ If a stream reset occurs, then no response will be returned, but the connection will remain reusable for other requests. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream( [ hyperframe.frame.SettingsFrame().serialize(), hyperframe.frame.HeadersFrame( stream_id=1, data=hpack.Encoder().encode( [ (b":status", b"200"), (b"content-type", b"plain/text"), ] ), flags=["END_HEADERS"], ).serialize(), # Connection is closed midway through the first response... hyperframe.frame.GoAwayFrame(stream_id=0, error_code=0).serialize(), # ...We'll never get to this second response. hyperframe.frame.HeadersFrame( stream_id=3, data=hpack.Encoder().encode( [ (b":status", b"200"), (b"content-type", b"plain/text"), ] ), flags=["END_HEADERS"], ).serialize(), hyperframe.frame.DataFrame( stream_id=3, data=b"Hello, world!", flags=["END_STREAM"] ).serialize(), b"", ] ) with HTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): conn.request("GET", "https://example.com/") with pytest.raises(RemoteProtocolError): conn.request("GET", "https://example.com/")
def test_http11_connection_with_remote_protocol_error(): """ If a remote protocol error occurs, then no response will be returned, and the connection will not be reusable. """ origin = Origin(b"https", b"example.com", 443) stream = MockStream([b"Wait, this isn't valid HTTP!", b""]) with HTTP11Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): conn.request("GET", "https://example.com/") assert not conn.is_idle() assert conn.is_closed() assert not conn.is_available() assert not conn.has_expired() assert ( repr(conn) == "<HTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
def test_http2_connection(): origin = Origin(b"https", b"example.com", 443) stream = MockStream( [ hyperframe.frame.SettingsFrame().serialize(), hyperframe.frame.HeadersFrame( stream_id=1, data=hpack.Encoder().encode( [ (b":status", b"200"), (b"content-type", b"plain/text"), ] ), flags=["END_HEADERS"], ).serialize(), hyperframe.frame.DataFrame( stream_id=1, data=b"Hello, world!", flags=["END_STREAM"] ).serialize(), ] ) with HTTP2Connection( origin=origin, stream=stream, keepalive_expiry=5.0 ) as conn: response = conn.request("GET", "https://example.com/") assert response.status == 200 assert response.content == b"Hello, world!" assert conn.is_idle() assert conn.is_available() assert not conn.is_closed() assert not conn.has_expired() assert ( conn.info() == "'https://example.com:443', HTTP/2, IDLE, Request Count: 1" ) assert ( repr(conn) == "<HTTP2Connection ['https://example.com:443', IDLE, Request Count: 1]>" )
def test_http11_connection(): origin = Origin(b"https", b"example.com", 443) stream = MockStream([ b"HTTP/1.1 200 OK\r\n", b"Content-Type: plain/text\r\n", b"Content-Length: 13\r\n", b"\r\n", b"Hello, world!", ]) with HTTP11Connection(origin=origin, stream=stream, keepalive_expiry=5.0) as conn: response = conn.request("GET", "https://example.com/") assert response.status == 200 assert response.content == b"Hello, world!" assert conn.is_idle() assert not conn.is_closed() assert conn.is_available() assert not conn.has_expired() assert ( repr(conn) == "<HTTP11Connection ['https://example.com:443', IDLE, Request Count: 1]>" )