Пример #1
0
class ServerConn:
    def __init__(self):
        client_h2_config = H2Configuration(
            client_side=True,
            header_encoding='ascii',
        )
        self.client_h2c = H2Connection(client_h2_config)

        self.to_client_transport = TransportStub(self.client_h2c)
        self.client_h2c.initiate_connection()

        server_config = H2Configuration(
            client_side=False,
            header_encoding='ascii',
        )
        self.server_proto = H2Protocol(
            DummyHandler(),
            Configuration().__for_test__(),
            server_config,
        )
        self.server_proto.connection_made(self.to_client_transport)

        # complete settings exchange and clear events buffer
        self.client_flush()
        self.to_client_transport.events()

    def client_flush(self):
        self.server_proto.data_received(self.client_h2c.data_to_send())
Пример #2
0
async def test_send_trailing_metadata_on_closed_stream(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(create_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream,
                       ProtoCodec(),
                       request,
                       DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    send_trailing_metadata_done = False
    async with mk_stream(server_h2_stream, request_metadata) as server_stream:
        await server_stream.send_trailing_metadata(status=Status.UNKNOWN)
        send_trailing_metadata_done = True

    assert send_trailing_metadata_done
Пример #3
0
    def __init__(self, protocol):
        self.connection = H2Connection(
            H2Configuration(client_side=False, header_encoding='utf-8'))
        self._transport = TransportStub(self.connection)

        self._protocol = protocol
        self._protocol.connection_made(self._transport)
Пример #4
0
async def test_send_headers_into_closed_stream(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_processor = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    server_processor = EventsProcessor(DummyHandler(), server_conn)

    request = Request(method='POST',
                      scheme='http',
                      path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    await client_stream.send_request(request.to_headers(),
                                     _processor=client_processor)

    to_server_transport.process(server_processor)

    server_stream, = server_processor.streams.values()
    server_stream._h2_connection.streams.pop(server_stream.id)
    with pytest.raises(StreamClosedError):
        await server_stream.send_headers([(':status', '200')])
Пример #5
0
async def test_send_trailing_metadata_on_closed_stream(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    request = Request(method='POST', scheme='http', path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(request.to_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    send_trailing_metadata_done = False
    async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, ProtoCodec(),
                      DummyRequest, DummyReply,
                      metadata=request_metadata) as server_stream:
        await server_stream.send_trailing_metadata(status=Status.UNKNOWN)
        send_trailing_metadata_done = True

    assert send_trailing_metadata_done
Пример #6
0
async def test_recv_data_larger_than_window_size(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_processor = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    request = Request(method='POST',
                      scheme='http',
                      path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    await client_stream.send_request(request.to_headers(),
                                     _processor=client_processor)

    initial_window = server_h2c.local_settings.initial_window_size
    assert (client_h2c.local_flow_control_window(
        client_stream.id) == initial_window)

    # data should be bigger than window size
    data = b'0' * (initial_window + 1)
    size = len(data)

    # sending less than a full message
    await client_stream.send_data(data[:initial_window - 1])

    # let server process it's events
    server_processor = EventsProcessor(DummyHandler(), server_conn)
    for event in to_server_transport.events():
        server_processor.process(event)

    # checking window size was decreased
    assert client_h2c.local_flow_control_window(client_stream.id) == 1

    # simulate that server is waiting for the size of a message and should
    # acknowledge that size as soon as it will be received
    server_stream, = server_processor.streams.values()
    recv_task = loop.create_task(server_stream.recv_data(size))
    await asyncio.wait([recv_task], timeout=.01, loop=loop)
    assert server_stream.__buffer__._read_size == size
    assert server_stream.__buffer__._size == initial_window - 1

    # check that server acknowledged received partial data
    assert client_h2c.local_flow_control_window(client_stream.id) > 1

    # sending remaining data and recv_task should finish
    await client_stream.send_data(data[initial_window - 1:])
    for event in to_server_transport.events():
        server_processor.process(event)
    await asyncio.wait_for(recv_task, 0.01, loop=loop)
    assert server_stream.__buffer__._size == 0
Пример #7
0
async def test_exit_and_connection_was_broken(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    request = Request('POST', 'http', '/', authority='test.com')
    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(request.to_headers(),
                                        _processor=client_proc)

    request = SavoysRequest(kyler='cloth')
    await send_message(client_h2_stream, request, SavoysRequest, end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = Metadata.from_headers(server_proc.handler.headers)

    with pytest.raises(WriteError):
        async with Stream(server_h2_stream,
                          Cardinality.UNARY_UNARY,
                          SavoysRequest,
                          SavoysReply,
                          metadata=request_metadata) as server_stream:
            await server_stream.recv_message()

            # simulate broken connection
            to_client_transport.__raise_on_write__(WriteError)
Пример #8
0
async def test_unread_data_ack(loop):
    client_h2c, server_h2c = create_connections()
    initial_window = client_h2c.outbound_flow_control_window
    # should be large enough to trigger WINDOW_UPDATE frame
    data_size = initial_window - 1

    to_client_transport = TransportStub(client_h2c)
    server_handler = DummyHandler()
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)
    server_proc = EventsProcessor(server_handler, server_conn)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    await client_stream.send_request(create_headers(), _processor=client_proc)
    await client_stream.send_data(b'x' * data_size)
    assert client_h2c.outbound_flow_control_window == initial_window - data_size
    to_server_transport.process(server_proc)

    # server_handler.stream.recv_data(data_size) intentionally not called
    await server_handler.stream.send_headers(
        [  # trailers-only error
            (':status', '200'),
            ('content-type', 'application/grpc+proto'),
            ('grpc-status', str(Status.UNKNOWN.value)),
        ],
        end_stream=True)
    to_client_transport.process(client_proc)

    assert client_h2c.outbound_flow_control_window == initial_window - data_size
    server_handler.release_stream()  # should ack received data
    assert client_h2c.outbound_flow_control_window == initial_window
Пример #9
0
async def test_exit_and_connection_was_broken(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    request = Request(method='POST', scheme='http', path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(request.to_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    with pytest.raises(WriteError):
        async with Stream(server_h2_stream, Cardinality.UNARY_UNARY,
                          ProtoCodec(), DummyRequest, DummyReply,
                          metadata=request_metadata) as server_stream:
            await server_stream.recv_message()

            # simulate broken connection
            to_client_transport.__raise_on_write__(WriteError)
Пример #10
0
async def test_exit_and_connection_was_broken(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(create_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream,
                       ProtoCodec(),
                       request,
                       DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    with pytest.raises(WriteError):
        async with mk_stream(server_h2_stream,
                             request_metadata) as server_stream:
            server_stream.metadata = request_metadata
            await server_stream.recv_message()
            # simulate broken connection
            to_client_transport.__raise_on_write__(WriteError)
Пример #11
0
    def __init__(self, *, loop):
        client_config = H2Configuration(client_side=True,
                                        header_encoding='utf-8')
        self.client_h2c = H2Connection(client_config)

        self.to_client_transport = TransportStub(self.client_h2c)
        self.client_h2c.initiate_connection()

        server_config = H2Configuration(client_side=False,
                                        header_encoding='utf-8')
        self.server_proto = H2Protocol(DummyHandler(), server_config,
                                       loop=loop)
        self.server_proto.connection_made(self.to_client_transport)

        # complete settings exchange and clear events buffer
        self.client_flush()
        self.to_client_transport.events()
Пример #12
0
async def test_exit_and_connection_was_closed(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(create_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream,
                       ProtoCodec(),
                       request,
                       DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    async with mk_stream(server_h2_stream, request_metadata) as server_stream:
        await server_stream.recv_message()
        client_h2c.close_connection()
        to_server_transport.process(server_proc)

        raise ServerError()  # should be suppressed
Пример #13
0
async def test_exit_and_connection_was_closed(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    request = Request('POST', 'http', '/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(request.to_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = Metadata.from_headers(server_proc.handler.headers)

    async with Stream(server_h2_stream, Cardinality.UNARY_UNARY, ProtoCodec(),
                      DummyRequest, DummyReply,
                      metadata=request_metadata) as server_stream:
        await server_stream.recv_message()
        client_h2c.close_connection()
        to_server_transport.process(server_proc)

        raise ServerError()  # should be suppressed
Пример #14
0
async def test_exit_and_stream_was_closed(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, loop=loop)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(create_headers(),
                                        _processor=client_proc)

    request = DummyRequest(value='ping')
    await send_message(client_h2_stream, ProtoCodec(), request, DummyRequest,
                       end=True)
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream
    request_metadata = decode_metadata(server_proc.handler.headers)

    async with mk_stream(server_h2_stream, request_metadata) as server_stream:
        await server_stream.recv_message()

        # simulating client closing stream
        await client_h2_stream.reset()
        to_server_transport.process(server_proc)

        # we should fail here on this attempt to send something
        await server_stream.send_message(DummyReply(value='pong'))
Пример #15
0
async def test_initial_window_size_update(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_processor = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    request = Request(method='POST',
                      scheme='http',
                      path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    await client_stream.send_request(request.to_headers(),
                                     _processor=client_processor)

    # data should be bigger than window size
    initial_window = server_h2c.local_settings.initial_window_size
    data = b'0' * (initial_window + 1)

    assert (client_h2c.local_flow_control_window(
        client_stream.id) == initial_window)

    # send_data should wait until settings/window updated
    send_task = loop.create_task(client_stream.send_data(data))
    await asyncio.wait([send_task], timeout=0.01)

    assert client_h2c.local_flow_control_window(client_stream.id) == 0

    # updating settings and window, this should increase stream window size
    server_h2c.update_settings(
        {SettingCodes.INITIAL_WINDOW_SIZE: initial_window + 1})
    server_h2c.increment_flow_control_window(1, stream_id=None)
    server_conn.flush()
    to_client_transport.process(client_processor)

    assert client_h2c.local_flow_control_window(client_stream.id) == 1
    await asyncio.wait([send_task], timeout=0.01)

    assert send_task.done()
Пример #16
0
def test_max_window_size(config):
    server_h2c = H2Connection(
        H2Configuration(client_side=False, header_encoding='ascii'))
    proto = H2Protocol(Mock(), config.__for_test__(),
                       H2Configuration(client_side=True))
    proto.connection_made(TransportStub(server_h2c))
    assert server_h2c.outbound_flow_control_window \
        == config.http2_connection_window_size
    assert server_h2c.remote_settings.initial_window_size \
        == config.http2_stream_window_size
Пример #17
0
async def test_send_data_larger_than_frame_size(loop):
    client_h2c, server_h2c = create_connections()

    transport = TransportStub(server_h2c)
    conn = Connection(client_h2c, transport, loop=loop)
    stream = conn.create_stream()

    processor = EventsProcessor(DummyHandler(), conn)

    await stream.send_request(create_headers(), _processor=processor)
    await stream.send_data(b'0' * (client_h2c.max_outbound_frame_size + 1))
Пример #18
0
    def __init__(self, *, loop):
        server_config = H2Configuration(client_side=False,
                                        header_encoding='utf-8')
        self.server_h2c = H2Connection(server_config)

        self.to_server_transport = TransportStub(self.server_h2c)

        client_config = H2Configuration(client_side=True,
                                        header_encoding='utf-8')
        self.client_proto = H2Protocol(client.Handler(), client_config,
                                       loop=loop)
        self.client_proto.connection_made(self.to_server_transport)
Пример #19
0
async def test_receive_goaway(config):
    wrapper = Wrapper()
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, config=config)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, config=config)
    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream(wrapper=wrapper)

    await client_stream.send_request(create_headers(), _processor=client_proc)

    server_h2c.close_connection()
    server_conn.flush()
    to_client_transport.process(client_proc)

    with pytest.raises(StreamTerminatedError, match='Received GOAWAY frame'):
        with wrapper:
            pass
Пример #20
0
async def test_client_reset(
    loop,
    caplog,
    handler,
    level,
    msg,
    exc_type,
    exc_text,
    config,
):
    caplog.set_level(logging.INFO)
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    to_server_transport = TransportStub(server_h2c)

    client_conn = Connection(client_h2c, to_server_transport, config=config)
    server_conn = Connection(server_h2c, to_client_transport, config=config)

    server_proc = EventsProcessor(DummyHandler(), server_conn)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_h2_stream = client_conn.create_stream()
    await client_h2_stream.send_request(
        create_headers(path='/package.Service/Method'),
        _processor=client_proc,
    )
    to_server_transport.process(server_proc)

    server_h2_stream = server_proc.handler.stream

    methods = {
        '/package.Service/Method':
        Handler(
            handler,
            Cardinality.UNARY_UNARY,
            DummyRequest,
            DummyReply,
        )
    }
    task = loop.create_task(
        call_handler(methods, server_h2_stream, server_proc.handler.headers))
    await asyncio.wait([task], timeout=0.001)
    await client_h2_stream.reset()
    to_server_transport.process(server_proc)
    await asyncio.wait_for(task, 0.1)

    record, = caplog.records
    assert record.name == 'grpclib.server'
    assert record.levelname == level
    assert msg in record.getMessage()
    if exc_type is not None:
        assert record.exc_info[0] is exc_type
    if exc_text is not None:
        assert exc_text in record.exc_text
Пример #21
0
async def test_stream_release(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_processor = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    server_processor = EventsProcessor(DummyHandler(), server_conn)

    request = Request(method='POST',
                      scheme='http',
                      path='/',
                      content_type='application/grpc+proto',
                      authority='test.com')

    assert not client_processor.streams
    client_release_stream = await client_stream.send_request(
        request.to_headers(),
        _processor=client_processor,
    )
    assert client_release_stream and client_processor.streams

    # sending data and closing stream on the client-side
    msg = b'message'
    await client_stream.send_data(msg, end_stream=True)
    events1 = to_server_transport.process(server_processor)
    assert any(isinstance(e, StreamEnded) for e in events1), events1

    # intentionally sending some stream-specific frame after stream was
    # half-closed
    client_h2c.increment_flow_control_window(10, stream_id=client_stream.id)
    client_conn.flush()
    events2 = to_server_transport.process(server_processor)
    assert any(isinstance(e, WindowUpdated) for e in events2), events2

    server_stream, = server_processor.streams.values()
    await server_stream.recv_data(len(msg))
    await server_stream.end()

    events3 = to_client_transport.process(client_processor)
    assert any(isinstance(e, StreamEnded) for e in events3), events3

    # simulating request handler exit by releasing server-side stream
    server_processor.handler.release_stream()
    assert not server_processor.streams

    # simulating call exit by releasing client-side stream
    assert client_processor.streams
    client_release_stream()
    assert not client_processor.streams
Пример #22
0
async def test_send_headers_into_closed_stream(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    server_processor = EventsProcessor(DummyHandler(), server_conn)

    await client_stream.send_request(create_headers(), _processor=client_proc)

    to_server_transport.process(server_processor)

    server_stream, = server_processor.streams.values()
    server_stream._h2_connection.streams.pop(server_stream.id)
    with pytest.raises(StreamClosedError):
        await server_stream.send_headers([(':status', '200')])
Пример #23
0
async def test_initial_window_size_update(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    await client_stream.send_request(create_headers(), _processor=client_proc)

    # data should be bigger than window size
    initial_window = server_h2c.local_settings.initial_window_size
    data = b'0' * (initial_window + 1)

    assert (client_h2c.local_flow_control_window(
        client_stream.id) == initial_window)

    # send_data should wait until settings/window updated
    send_task = loop.create_task(client_stream.send_data(data))
    await asyncio.wait([send_task], timeout=0.01)

    assert client_h2c.local_flow_control_window(client_stream.id) == 0

    # updating settings and window, this should increase stream window size
    server_h2c.update_settings(
        {SettingCodes.INITIAL_WINDOW_SIZE: initial_window + 1})
    server_h2c.increment_flow_control_window(1, stream_id=None)
    server_conn.flush()
    to_client_transport.process(client_proc)

    assert client_h2c.local_flow_control_window(client_stream.id) == 1
    await asyncio.wait([send_task], timeout=0.01)

    assert send_task.result() is None
Пример #24
0
async def test_send_data_larger_than_frame_size(loop):
    client_h2c, server_h2c = create_connections()

    transport = TransportStub(server_h2c)
    conn = Connection(client_h2c, transport, loop=loop)
    stream = conn.create_stream()

    request = Request('POST', 'http', '/',
                      content_type='application/grpc+proto',
                      authority='test.com')
    processor = EventsProcessor(DummyHandler(), conn)

    await stream.send_request(request.to_headers(), _processor=processor)
    await stream.send_data(b'0' * (client_h2c.max_outbound_frame_size + 1))
Пример #25
0
class ServerStub:
    def __init__(self, protocol):
        self.connection = H2Connection(
            H2Configuration(client_side=False, header_encoding='utf-8'))
        self._transport = TransportStub(self.connection)

        self._protocol = protocol
        self._protocol.connection_made(self._transport)

    def events(self):
        return self._transport.events()

    def flush(self):
        self._protocol.data_received(self.connection.data_to_send())
Пример #26
0
async def test_stream_release(config):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, config=config)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, config=config)

    client_processor = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    server_processor = EventsProcessor(DummyHandler(), server_conn)

    assert not client_processor.streams
    client_release_stream = await client_stream.send_request(
        create_headers(),
        _processor=client_processor,
    )
    assert client_release_stream and client_processor.streams

    # sending data and closing stream on the client-side
    msg = b'message'
    await client_stream.send_data(msg, end_stream=True)
    events1 = to_server_transport.process(server_processor)
    assert any(isinstance(e, StreamEnded) for e in events1), events1

    # intentionally sending some stream-specific frame after stream was
    # half-closed
    client_h2c.increment_flow_control_window(10, stream_id=client_stream.id)
    client_conn.flush()
    events2 = to_server_transport.process(server_processor)
    assert any(isinstance(e, WindowUpdated) for e in events2), events2

    server_stream, = server_processor.streams.values()
    await server_stream.recv_data(len(msg))
    await server_stream.send_headers([(':status', '200')], end_stream=True)

    events3 = to_client_transport.process(client_processor)
    assert any(isinstance(e, StreamEnded) for e in events3), events3

    # simulating request handler exit by releasing server-side stream
    server_processor.handler.release_stream()
    assert not server_processor.streams

    # simulating call exit by releasing client-side stream
    assert client_processor.streams
    client_release_stream()
    assert not client_processor.streams
Пример #27
0
async def test_negative_window_size(loop):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, loop=loop)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, loop=loop)

    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    await client_stream.send_request(create_headers(), _processor=client_proc)

    # data should be bigger than window size
    initial_window = server_h2c.local_settings.initial_window_size
    data = b'0' * (initial_window + 1)

    assert (client_h2c.local_flow_control_window(
        client_stream.id) == initial_window)

    # send_data should wait until settings/window updated
    send_task = loop.create_task(client_stream.send_data(data))
    await asyncio.wait([send_task], timeout=0.01)

    assert client_h2c.local_flow_control_window(client_stream.id) == 0

    # updating settings, this should decrease connection window size
    server_h2c.update_settings(
        {SettingCodes.INITIAL_WINDOW_SIZE: initial_window - 1})
    server_conn.flush()
    to_client_transport.process(client_proc)

    # window is negative and client should wait
    assert client_h2c.local_flow_control_window(client_stream.id) == -1
    await asyncio.wait([send_task], timeout=0.01)
    assert not send_task.done()

    # now `send_data` should succeed
    server_h2c.increment_flow_control_window(2, stream_id=client_stream.id)
    # INITIAL_WINDOW_SIZE not changes connection's window size, so it should be
    # incremented only by 1
    server_h2c.increment_flow_control_window(1, stream_id=None)
    server_conn.flush()
    to_client_transport.process(client_proc)
    assert client_h2c.local_flow_control_window(client_stream.id) == 1
    await asyncio.wait([send_task], timeout=0.01)
    assert send_task.result() is None
Пример #28
0
async def test_recv_data_larger_than_window_size(loop, config):
    client_h2c, server_h2c = create_connections()

    to_client_transport = TransportStub(client_h2c)
    server_conn = Connection(server_h2c, to_client_transport, config=config)

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, config=config)

    client_proc = EventsProcessor(DummyHandler(), client_conn)
    client_stream = client_conn.create_stream()

    await client_stream.send_request(create_headers(), _processor=client_proc)

    initial_window = server_h2c.local_settings.initial_window_size
    assert (client_h2c.local_flow_control_window(
        client_stream.id) == initial_window)

    # data should be bigger than window size
    data = b'0' * (initial_window + 1)
    size = len(data)

    # sending less than a full message
    await client_stream.send_data(data[:initial_window - 1])

    # let server process it's events
    server_processor = EventsProcessor(DummyHandler(), server_conn)
    to_server_transport.process(server_processor)

    # checking window size was decreased
    assert client_h2c.local_flow_control_window(client_stream.id) == 1

    # simulate that server is waiting for the size of a message and should
    # acknowledge that size as soon as it will be received
    server_stream, = server_processor.streams.values()
    recv_task = loop.create_task(server_stream.recv_data(size))
    await asyncio.wait([recv_task], timeout=.01)
    assert server_stream.buffer._acked_size == initial_window - 1

    # check that server acknowledged received partial data
    assert client_h2c.local_flow_control_window(client_stream.id) > 1

    # sending remaining data and recv_task should finish
    await client_stream.send_data(data[initial_window - 1:])
    to_server_transport.process(server_processor)
    await asyncio.wait_for(recv_task, 0.01)
    assert server_stream.buffer._acked_size == 0
Пример #29
0
    def __init__(self):
        server_h2_config = H2Configuration(
            client_side=False,
            header_encoding='ascii',
        )
        self.server_h2c = H2Connection(server_h2_config)

        self.to_server_transport = TransportStub(self.server_h2c)

        client_h2_config = H2Configuration(
            client_side=True,
            header_encoding='ascii',
        )
        self.client_proto = H2Protocol(
            client.Handler(),
            Configuration().__for_test__(),
            client_h2_config,
        )
        self.client_proto.connection_made(self.to_server_transport)
Пример #30
0
async def test_release_stream_after_close(config):
    client_h2c, server_h2c = create_connections()

    to_server_transport = TransportStub(server_h2c)
    client_conn = Connection(client_h2c, to_server_transport, config=config)
    client_proc = EventsProcessor(DummyHandler(), client_conn)

    client_stream = client_conn.create_stream()
    release_stream = await client_stream.send_request(create_headers(),
                                                      _processor=client_proc)

    # to trigger connection.ack
    client_stream.buffer.add(b'test', 4)

    # to trigger data send
    client_h2c.ping(b'00000000')

    client_proc.close('test')
    release_stream()