async def test_http2_connection_post_request(): origin = Origin(b"https", b"example.com", 443) stream = AsyncMockStream([ 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(), ]) async with AsyncHTTP2Connection(origin=origin, stream=stream) as conn: response = await 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!"
async 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 = AsyncMockStream([ 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(), ]) async with AsyncHTTP2Connection(origin=origin, stream=stream) as conn: async with conn.stream("GET", "https://example.com/") as response: await response.aread() assert response.status == 200 assert response.content == b"Hello, world!" await conn.aclose() with pytest.raises(ConnectionNotAvailable): await conn.request("GET", "https://example.com/")
async 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 = AsyncMockStream([ 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!", ]) async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn: with pytest.raises(LocalProtocolError) as exc_info: await 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) == "<AsyncHTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
async def test_http2_connection(): origin = Origin(b"https", b"example.com", 443) stream = AsyncMockStream([ 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(), ]) async with AsyncHTTP2Connection(origin=origin, stream=stream, keepalive_expiry=5.0) as conn: response = await 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) == "<AsyncHTTP2Connection ['https://example.com:443', IDLE, Request Count: 1]>" )
async 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 = AsyncMockStream([ 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!", ]) async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn: async 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) == "<AsyncHTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
async 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 = AsyncMockStream([]) async with AsyncHTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RuntimeError): await conn.request("GET", "https://other.com/")
async 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 = AsyncMockStream([b"Wait, this isn't valid HTTP!", b""]) async with AsyncHTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): await conn.request("GET", "https://example.com/")
async 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 = AsyncMockStream([ 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!", ]) async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn: async with conn.stream("GET", "https://example.com/") as response: await response.aread() assert response.status == 200 assert response.content == b"Hello, world!"
async 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 = AsyncMockStream([ 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!", ]) async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn: async with conn.stream("GET", "https://example.com/"): with pytest.raises(ConnectionNotAvailable): await conn.request("GET", "https://example.com/")
async 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 = AsyncMockStream([b"Wait, this isn't valid HTTP!", b""]) async with AsyncHTTP11Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): await 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) == "<AsyncHTTP11Connection ['https://example.com:443', CLOSED, Request Count: 1]>" )
async def test_http2_connection_with_rst_stream(): """ 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 = AsyncMockStream([ 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(), # Stream is closed midway through the first response... hyperframe.frame.RstStreamFrame(stream_id=1, error_code=8).serialize(), # ...Which doesn't prevent the 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"", ]) async with AsyncHTTP2Connection(origin=origin, stream=stream) as conn: with pytest.raises(RemoteProtocolError): await conn.request("GET", "https://example.com/") response = await conn.request("GET", "https://example.com/") assert response.status == 200
async def test_http11_connection(): origin = Origin(b"https", b"example.com", 443) stream = AsyncMockStream([ 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!", ]) async with AsyncHTTP11Connection(origin=origin, stream=stream, keepalive_expiry=5.0) as conn: response = await 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) == "<AsyncHTTP11Connection ['https://example.com:443', IDLE, Request Count: 1]>" )