async def test_http1_websocket(nursery: trio._core._run.Nursery) -> None:
    client_stream, server_stream = trio.testing.memory_stream_pair()
    server_stream.socket = MockSocket()
    server = TCPServer(sanity_framework, Config(), server_stream)
    nursery.start_soon(server.run)
    client = wsproto.WSConnection(wsproto.ConnectionType.CLIENT)
    await client_stream.send_all(
        client.send(wsproto.events.Request(host="hypercorn", target="/")))
    client.receive_data(await client_stream.receive_some(1024))
    assert list(client.events()) == [
        wsproto.events.AcceptConnection(extra_headers=[
            (b"date", b"Thu, 01 Jan 1970 01:23:20 GMT"),
            (b"server", b"hypercorn-h11"),
        ])
    ]
    await client_stream.send_all(
        client.send(wsproto.events.BytesMessage(data=SANITY_BODY)))
    client.receive_data(await client_stream.receive_some(1024))
    assert list(client.events()) == [
        wsproto.events.TextMessage(data="Hello & Goodbye")
    ]
    await client_stream.send_all(
        client.send(wsproto.events.CloseConnection(code=1000)))
    client.receive_data(await client_stream.receive_some(1024))
    assert list(client.events()) == [
        wsproto.events.CloseConnection(code=1000, reason="")
    ]
Exemple #2
0
async def test_startup_timeout_error(nursery: trio._core._run.Nursery) -> None:
    config = Config()
    config.startup_timeout = 0.01
    lifespan = Lifespan(SlowLifespanFramework(0.02, trio.sleep), config)  # type: ignore
    nursery.start_soon(lifespan.handle_lifespan)
    with pytest.raises(LifespanTimeout) as exc_info:
        await lifespan.wait_for_startup()
    assert str(exc_info.value).startswith("Timeout whilst awaiting startup")
Exemple #3
0
async def test_http2_request(nursery: trio._core._run.Nursery) -> None:
    client_stream, server_stream = trio.testing.memory_stream_pair()
    server_stream.transport_stream = Mock(return_value=PropertyMock(
        return_value=MockSocket()))
    server_stream.do_handshake = AsyncMock()
    server_stream.selected_alpn_protocol = Mock(return_value="h2")
    server = TCPServer(sanity_framework, Config(), WorkerContext(),
                       server_stream)
    nursery.start_soon(server.run)
    client = h2.connection.H2Connection()
    client.initiate_connection()
    await client_stream.send_all(client.data_to_send())
    stream_id = client.get_next_available_stream_id()
    client.send_headers(
        stream_id,
        [
            (":method", "GET"),
            (":path", "/"),
            (":authority", "hypercorn"),
            (":scheme", "https"),
            ("content-length", "%d" % len(SANITY_BODY)),
        ],
    )
    client.send_data(stream_id, SANITY_BODY)
    client.end_stream(stream_id)
    await client_stream.send_all(client.data_to_send())
    events = []
    open_ = True
    while open_:
        # bytes cast is key otherwise b"" is lost
        data = bytes(await client_stream.receive_some(1024))
        if data == b"":
            open_ = False

        h2_events = client.receive_data(data)
        for event in h2_events:
            if isinstance(event, h2.events.DataReceived):
                client.acknowledge_received_data(event.flow_controlled_length,
                                                 event.stream_id)
            elif isinstance(
                    event,
                (h2.events.ConnectionTerminated, h2.events.StreamEnded,
                 h2.events.StreamReset),
            ):
                open_ = False
                break
            else:
                events.append(event)
        await client_stream.send_all(client.data_to_send())
    assert isinstance(events[2], h2.events.ResponseReceived)
    assert events[2].headers == [
        (b":status", b"200"),
        (b"content-length", b"15"),
        (b"date", b"Thu, 01 Jan 1970 01:23:20 GMT"),
        (b"server", b"hypercorn-h2"),
    ]
Exemple #4
0
def _client_stream(
    nursery: trio._core._run.Nursery,
) -> Generator[trio.testing._memory_streams.MemorySendStream, None, None]:
    config = Config()
    config.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
    client_stream, server_stream = trio.testing.memory_stream_pair()
    server_stream.socket = MockSocket()
    server = TCPServer(slow_framework, config, WorkerContext(), server_stream)
    nursery.start_soon(server.run)
    yield client_stream
Exemple #5
0
async def spawn_app(
    nursery: trio._core._run.Nursery,
    app: ASGIFramework,
    config: Config,
    scope: dict,
    send: Callable[[dict], Awaitable[None]],
) -> Callable[[dict], Awaitable[None]]:
    app_send_channel, app_receive_channel = trio.open_memory_channel(config.max_app_queue_size)
    nursery.start_soon(_handle, app, config, scope, app_receive_channel.receive, send)
    return app_send_channel.send
Exemple #6
0
async def test_http2_websocket(nursery: trio._core._run.Nursery) -> None:
    client_stream, server_stream = trio.testing.memory_stream_pair()
    server_stream.transport_stream = Mock(return_value=PropertyMock(
        return_value=MockSocket()))
    server_stream.do_handshake = AsyncMock()
    server_stream.selected_alpn_protocol = Mock(return_value="h2")
    server = TCPServer(sanity_framework, Config(), WorkerContext(),
                       server_stream)
    nursery.start_soon(server.run)
    h2_client = h2.connection.H2Connection()
    h2_client.initiate_connection()
    await client_stream.send_all(h2_client.data_to_send())
    stream_id = h2_client.get_next_available_stream_id()
    h2_client.send_headers(
        stream_id,
        [
            (":method", "CONNECT"),
            (":path", "/"),
            (":authority", "hypercorn"),
            (":scheme", "https"),
            ("sec-websocket-version", "13"),
        ],
    )
    await client_stream.send_all(h2_client.data_to_send())
    events = h2_client.receive_data(await client_stream.receive_some(1024))
    await client_stream.send_all(h2_client.data_to_send())
    events = h2_client.receive_data(await client_stream.receive_some(1024))
    if not isinstance(events[-1], h2.events.ResponseReceived):
        events = h2_client.receive_data(await client_stream.receive_some(1024))
    assert events[-1].headers == [
        (b":status", b"200"),
        (b"date", b"Thu, 01 Jan 1970 01:23:20 GMT"),
        (b"server", b"hypercorn-h2"),
    ]
    client = wsproto.connection.Connection(wsproto.ConnectionType.CLIENT)
    h2_client.send_data(
        stream_id, client.send(wsproto.events.BytesMessage(data=SANITY_BODY)))
    await client_stream.send_all(h2_client.data_to_send())
    events = h2_client.receive_data(await client_stream.receive_some(1024))
    client.receive_data(events[0].data)
    assert list(client.events()) == [
        wsproto.events.TextMessage(data="Hello & Goodbye")
    ]
    h2_client.send_data(stream_id,
                        client.send(wsproto.events.CloseConnection(code=1000)))
    await client_stream.send_all(h2_client.data_to_send())
    events = h2_client.receive_data(await client_stream.receive_some(1024))
    client.receive_data(events[0].data)
    assert list(client.events()) == [
        wsproto.events.CloseConnection(code=1000, reason="")
    ]
    await client_stream.send_all(b"")
Exemple #7
0
async def test_h2_flow_control(nursery: trio._core._run.Nursery) -> None:
    connection = MockConnection()
    nursery.start_soon(connection.server.handle_connection)
    stream_id = await connection.send_request(
        BASIC_HEADERS + [(":method", "GET"), (":path", "/")],
        {h2.settings.SettingCodes.INITIAL_WINDOW_SIZE: FLOW_WINDOW_SIZE},
    )
    await connection.end_stream(stream_id)
    async for event in connection.get_events():
        if isinstance(event, h2.events.DataReceived):
            assert len(event.data) <= FLOW_WINDOW_SIZE
        elif isinstance(event, h2.events.StreamEnded):
            await connection.close()
Exemple #8
0
async def test_server_sends_chunked(nursery: trio._core._run.Nursery) -> None:
    connection = MockConnection(framework=chunked_response_framework)
    nursery.start_soon(connection.server.handle_connection)
    stream_id = await connection.send_request(
        BASIC_HEADERS + [(":method", "GET"), (":path", "/")], {})
    await connection.end_stream(stream_id)
    response_data = b""
    async for event in connection.get_events():
        if isinstance(event, h2.events.DataReceived):
            response_data += event.data
        elif isinstance(event, h2.events.StreamEnded):
            await connection.close()
    assert response_data == b"chunked data"
Exemple #9
0
async def test_h2server_upgrade(nursery: trio._core._run.Nursery) -> None:
    upgrade_request = h11.Request(method="GET",
                                  target="/",
                                  headers=[("Host", "hypercorn")])
    connection = MockConnection(upgrade_request=upgrade_request)
    nursery.start_soon(connection.server.handle_connection)
    response_data = b""
    async for event in connection.get_events():
        if isinstance(event, h2.events.ResponseReceived):
            assert (b":status", b"200") in event.headers
            assert (b"server", b"hypercorn-h2") in event.headers
            assert b"date" in (header[0] for header in event.headers)
        elif isinstance(event, h2.events.DataReceived):
            response_data += event.data
        elif isinstance(event, h2.events.StreamEnded):
            await connection.close()
Exemple #10
0
async def test_post_response_keep_alive_timeout(
        nursery: trio._core._run.Nursery) -> None:
    config = Config()
    config.keep_alive_timeout = 0.01
    connection = MockConnection(config=config)
    nursery.start_soon(connection.server.handle_connection)
    stream_id = await connection.send_request(
        BASIC_HEADERS + [(":method", "GET"), (":path", "/1")], {})
    await connection.end_stream(stream_id)
    async for event in connection.get_events():
        if isinstance(event, h2.events.StreamEnded):
            break  # Request ended
    with trio.move_on_after(2 * config.keep_alive_timeout):
        pass
    events = [event async for event in connection.get_events()]
    assert isinstance(events[-1], h2.events.ConnectionTerminated)
Exemple #11
0
async def test_http1_request(nursery: trio._core._run.Nursery) -> None:
    client_stream, server_stream = trio.testing.memory_stream_pair()
    server_stream.socket = MockSocket()
    server = TCPServer(sanity_framework, Config(), WorkerContext(),
                       server_stream)
    nursery.start_soon(server.run)
    client = h11.Connection(h11.CLIENT)
    await client_stream.send_all(
        client.send(
            h11.Request(
                method="POST",
                target="/",
                headers=[
                    (b"host", b"hypercorn"),
                    (b"connection", b"close"),
                    (b"content-length", b"%d" % len(SANITY_BODY)),
                ],
            )))
    await client_stream.send_all(client.send(h11.Data(data=SANITY_BODY)))
    await client_stream.send_all(client.send(h11.EndOfMessage()))
    events = []
    while True:
        event = client.next_event()
        if event == h11.NEED_DATA:
            # bytes cast is key otherwise b"" is lost
            data = bytes(await client_stream.receive_some(1024))
            client.receive_data(data)
        elif isinstance(event, h11.ConnectionClosed):
            break
        else:
            events.append(event)

    assert events == [
        h11.Response(
            status_code=200,
            headers=[
                (b"content-length", b"15"),
                (b"date", b"Thu, 01 Jan 1970 01:23:20 GMT"),
                (b"server", b"hypercorn-h11"),
                (b"connection", b"close"),
            ],
            http_version=b"1.1",
            reason=b"",
        ),
        h11.Data(data=b"Hello & Goodbye"),
        h11.EndOfMessage(headers=[]),  # type: ignore
    ]
Exemple #12
0
async def test_pipelining(nursery: trio._core._run.Nursery) -> None:
    connection = MockConnection()
    nursery.start_soon(connection.server.handle_connection)
    streams = [
        await connection.send_request(
            BASIC_HEADERS + [(":method", "GET"), (":path", "/1")], {}),
        await connection.send_request(
            BASIC_HEADERS + [(":method", "GET"), (":path", "/1")], {}),
    ]
    for stream_id in streams:
        await connection.end_stream(stream_id)
    responses = 0
    async for event in connection.get_events():
        if isinstance(event, h2.events.ResponseReceived):
            responses += 1
        elif isinstance(event, h2.events.StreamEnded) and responses == 2:
            await connection.close()
    assert responses == len(streams)
Exemple #13
0
async def test_h2_push(nursery: trio._core._run.Nursery) -> None:
    connection = MockConnection(framework=push_framework)
    nursery.start_soon(connection.server.handle_connection)
    stream_id = await connection.send_request(
        BASIC_HEADERS + [(":method", "GET"), (":path", "/")], {})
    await connection.end_stream(stream_id)
    push_received = False
    streams_received = 0
    async for event in connection.get_events():
        if isinstance(event, h2.events.PushedStreamReceived):
            assert (b":path", b"/") in event.headers
            assert (b":method", b"GET") in event.headers
            assert (b":scheme", b"http") in event.headers
            assert (b":authority", b"hypercorn") in event.headers
            push_received = True
        elif isinstance(event, h2.events.StreamEnded):
            streams_received += 1
            if streams_received == 2:
                await connection.close()
    assert push_received
Exemple #14
0
async def test_request(headers: list, body: str,
                       nursery: trio._core._run.Nursery) -> None:
    connection = MockConnection()
    nursery.start_soon(connection.server.handle_connection)
    stream_id = await connection.send_request(headers, {})
    if body != "":
        await connection.send_data(stream_id, body.encode())
    await connection.end_stream(stream_id)
    response_data = b""
    async for event in connection.get_events():
        if isinstance(event, h2.events.ResponseReceived):
            assert (b":status", b"200") in event.headers
            assert (b"server", b"hypercorn-h2") in event.headers
            assert b"date" in (header[0] for header in event.headers)
        elif isinstance(event, h2.events.DataReceived):
            response_data += event.data
        elif isinstance(event, h2.events.StreamEnded):
            await connection.close()
    data = json.loads(response_data.decode())
    assert data["request_body"] == body  # type: ignore