Ejemplo n.º 1
0
    def test_request_correctly_sent_max_chunk(self, frame_buffer):
        """
        Test that request correctly sent when data length multiple
        max chunk. We check last chunk has a end flag and correct number
        of chunks.
        """
        def data_callback(chunk, **kwargs):
            frame_buffer.add_data(chunk)

        # one chunk
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'1'*1024, final=True)

        frames = list(frame_buffer)
        assert len(frames) == 2
        assert isinstance(frames[1], DataFrame)
        assert frames[1].flags == set(['END_STREAM'])

        # two chunks
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'1' * 2024, final=True)

        frames = list(frame_buffer)
        assert len(frames) == 3
        assert isinstance(frames[1], DataFrame)
        assert frames[2].flags == set(['END_STREAM'])

        # two chunks with last chunk < 1024
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'1' * 2000, final=True)

        frames = list(frame_buffer)
        assert len(frames) == 3
        assert isinstance(frames[1], DataFrame)
        assert frames[2].flags == set(['END_STREAM'])

        # no chunks
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'', final=True)

        frames = list(frame_buffer)
        assert len(frames) == 1
Ejemplo n.º 2
0
 def request(self):
     self.conn = HTTP20Connection('www.google.com', enable_push=True)
     self.conn._sock = DummySocket()
     self.conn._sock.buffer = BytesIO(
         b''.join([frame.serialize() for frame in self.frames])
     )
     self.conn.request('GET', '/')
Ejemplo n.º 3
0
    def test_closed_connections_are_reset(self):
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        wm = c.window_manager
        c.request('GET', '/')
        c.close()

        assert c._sock is None
        assert not c.streams
        assert c.recent_stream is None
        assert c.next_stream_id == 1
        assert c.window_manager is not wm
        with c._conn as conn:
            assert conn.state_machine.state == ConnectionState.IDLE
            origin_h2_conn = conn

        c.close()
        assert c._sock is None
        assert not c.streams
        assert c.recent_stream is None
        assert c.next_stream_id == 1
        assert c.window_manager is not wm
        with c._conn as conn:
            assert conn.state_machine.state == ConnectionState.IDLE
            assert conn != origin_h2_conn
Ejemplo n.º 4
0
    def test_stream_close_behavior(self):
        # Prepare a socket so we can open a stream.
        sock = DummySocket()
        c = HTTP20Connection('www.google.com')
        c._sock = sock

        # Open a few requests (which creates a stream)
        s1 = c.request('GET', '/')
        c.request('GET', '/')

        # simulate state of blocking on read while sock
        f = GoAwayFrame(0)
        # Set error code to PROTOCOL_ERROR
        f.error_code = 1
        c._sock.buffer = BytesIO(f.serialize())

        # 'Receive' the GOAWAY frame.
        # Validate that the spec error name and description are used to throw
        # the connection exception.
        with pytest.raises(ConnectionError):
            c.get_response(s1)

        # try to read again after close
        with pytest.raises(ConnectionError):
            c._single_read()
Ejemplo n.º 5
0
    def test_read_headers_out_of_order(self):
        # If header blocks aren't decoded in the same order they're received,
        # regardless of the stream they belong to, the decoder state will
        # become corrupted.
        e = Encoder()
        h1 = HeadersFrame(1)
        h1.data = e.encode([(':status', 200), ('content-type', 'foo/bar')])
        h1.flags |= set(['END_HEADERS', 'END_STREAM'])
        h3 = HeadersFrame(3)
        h3.data = e.encode([(':status', 200), ('content-type', 'baz/qux')])
        h3.flags |= set(['END_HEADERS', 'END_STREAM'])
        sock = DummySocket()
        sock.buffer = BytesIO(h1.serialize() + h3.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        r1 = c.request('GET', '/a')
        r3 = c.request('GET', '/b')

        assert c.get_response(r3).headers == HTTPHeaderMap(
            [('content-type', 'baz/qux')]
        )
        assert c.get_response(r1).headers == HTTPHeaderMap(
            [('content-type', 'foo/bar')]
        )
Ejemplo n.º 6
0
    def send_request_message(self, request_id, meta, body, message_expiry_in_seconds=None):
        connection = HTTP20Connection(
            host=self.http_host,
            port=self.http_port,
            secure=self.secure,
            ssl_context=self.ssl_context,
        )
        message = {'request_id': request_id, 'meta': meta, 'body': body}

        serializer = self.default_serializer
        non_default_serializer = False
        if 'serializer' in meta:
            # TODO: Breaking change: Assume a MIME type is always specified. This should not be done until all
            # TODO servers and clients have Step 2 code. This will be a Step 3 breaking change.
            serializer = meta.pop('serializer')
            non_default_serializer = True
        serialized_message = serializer.dict_to_blob(message)
        if non_default_serializer:
            # TODO: Breaking change: Make this happen always, not just when a specific MIME type was requested.
            # TODO This should not be done until all servers and clients have this Step 1 code. This will be a Step
            # TODO 2 breaking change.
            serialized_message = (
                'content-type:{};'.format(serializer.mime_type).encode('utf-8') + serialized_message
            )

        request = connection.request('POST', '/', body=serialized_message)
        self.requests.append((connection, request))
Ejemplo n.º 7
0
    def test_stream_window_increments_appropriately(self, frame_buffer):
        e = Encoder()
        h = HeadersFrame(1)
        h.data = e.encode([(':status', 200), ('content-type', 'foo/bar')])
        h.flags = set(['END_HEADERS'])
        d = DataFrame(1)
        d.data = b'hi there sir'
        d2 = DataFrame(1)
        d2.data = b'hi there sir again'
        sock = DummySocket()
        sock.buffer = BytesIO(h.serialize() + d.serialize() + d2.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.request('GET', '/')
        c.streams[1]._in_window_manager.window_size = 1000
        c.streams[1]._in_window_manager.initial_window_size = 1000
        resp = c.get_response()
        resp.read(len(b'hi there sir'))
        resp.read(len(b'hi there sir again'))

        frame_buffer.add_data(b''.join(sock.queue))
        queue = list(frame_buffer)
        assert len(queue) == 3  # one headers frame, two window update frames.
        assert isinstance(queue[1], WindowUpdateFrame)
        assert queue[1].window_increment == len(b'hi there sir')
        assert isinstance(queue[2], WindowUpdateFrame)
        assert queue[2].window_increment == len(b'hi there sir again')
Ejemplo n.º 8
0
    def test_window_increments_appropriately(self):
        e = Encoder()
        h = HeadersFrame(1)
        h.data = e.encode({':status': 200, 'content-type': 'foo/bar'})
        h.flags = set(['END_HEADERS'])
        d = DataFrame(1)
        d.data = b'hi there sir'
        d2 = DataFrame(1)
        d2.data = b'hi there sir again'
        d2.flags = set(['END_STREAM'])
        sock = DummySocket()
        sock.buffer = BytesIO(h.serialize() + d.serialize() + d2.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.window_manager.window_size = 1000
        c.window_manager.initial_window_size = 1000
        c.request('GET', '/')
        resp = c.get_response()
        resp.read()

        queue = list(map(decode_frame, map(memoryview, sock.queue)))
        assert len(queue) == 3  # one headers frame, two window update frames.
        assert isinstance(queue[1], WindowUpdateFrame)
        assert queue[1].window_increment == len(b'hi there sir')
        assert isinstance(queue[2], WindowUpdateFrame)
        assert queue[2].window_increment == len(b'hi there sir again')
Ejemplo n.º 9
0
    def test_different_request_headers(self):
        sock = DummySocket()

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.request('GET', '/', body='hello', headers={b'name': b'value'})
        s = c.recent_stream

        assert list(s.headers.items()) == [
            (b':method', b'GET'),
            (b':scheme', b'https'),
            (b':authority', b'www.google.com'),
            (b':path', b'/'),
            (b'name', b'value'),
        ]

        c.request('GET', '/', body='hello', headers={u'name2': u'value2'})
        s = c.recent_stream

        assert list(s.headers.items()) == [
            (b':method', b'GET'),
            (b':scheme', b'https'),
            (b':authority', b'www.google.com'),
            (b':path', b'/'),
            (b'name2', b'value2'),
        ]
Ejemplo n.º 10
0
 def test_connections_can_parse_proxy_hosts_and_ports(self):
     c = HTTP20Connection('www.google.com',
                          proxy_host='localhost',
                          proxy_port=8443)
     assert c.host == 'www.google.com'
     assert c.proxy_host == 'localhost'
     assert c.proxy_port == 8443
Ejemplo n.º 11
0
    def test_putrequest_establishes_new_stream(self):
        c = HTTP20Connection("www.google.com")

        stream_id = c.putrequest('GET', '/')
        stream = c.streams[stream_id]

        assert len(c.streams) == 1
        assert c.recent_stream is stream
Ejemplo n.º 12
0
    def test_connections_can_parse_ipv6_hosts_and_ports(self):
        c = HTTP20Connection('[abcd:dcba::1234]',
                             proxy_host='[ffff:aaaa::1]:8443')

        assert c.host == 'abcd:dcba::1234'
        assert c.port == 443
        assert c.proxy_host == 'ffff:aaaa::1'
        assert c.proxy_port == 8443
Ejemplo n.º 13
0
    def test_receive_unexpected_frame(self):
        # RST_STREAM frames are never defined on connections, so send one of
        # those.
        c = HTTP20Connection('www.google.com')
        f = RstStreamFrame(1)

        with pytest.raises(ValueError):
            c.receive_frame(f)
Ejemplo n.º 14
0
    def test_that_we_correctly_send_over_the_socket(self):
        sock = DummySocket()
        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'hello there', final=True)

        # Don't bother testing that the serialization was ok, that should be
        # fine.
        assert len(sock.queue) == 3
Ejemplo n.º 15
0
    def test_connections_increment_send_window_properly(self):
        f = WindowUpdateFrame(0)
        f.window_increment = 1000
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()

        # 'Receive' the WINDOWUPDATE frame.
        c.receive_frame(f)

        assert c._out_flow_control_window == 65535 + 1000
Ejemplo n.º 16
0
    def test_ping_with_ack_ignored(self):
        c = HTTP20Connection('www.google.com')
        f = PingFrame(0)
        f.flags = set(['ACK'])
        f.opaque_data = b'12345678'

        def data_cb(frame, tolerate_peer_gone=False):
            assert False, 'should not be called'

        c._send_cb = data_cb
        c.receive_frame(f)
Ejemplo n.º 17
0
    def test_closed_connections_are_reset(self):
        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        wm = c.window_manager
        c.request('GET', '/')
        c.close()

        assert c._sock is None
        assert not c.streams
        assert c.recent_stream is None
        assert c.next_stream_id == 1
        assert c.window_manager is not wm
Ejemplo n.º 18
0
    def test_incrementing_window_after_close(self):
        """
        Hyper does not attempt to increment the flow control window once the
        stream is closed.
        """
        # For this test, we want to send a response that has three frames at
        # the default max frame size (16,384 bytes). That will, on the third
        # frame, trigger the processing to increment the flow control window,
        # which should then not happen.
        f = SettingsFrame(0, settings={h2.settings.INITIAL_WINDOW_SIZE: 100})

        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._sock.buffer = BytesIO(f.serialize())

        # Open stream 1.
        c.request('GET', '/')

        # Check what data we've sent right now.
        originally_sent_data = c._sock.queue[:]

        # Swap out the buffer to get a GoAway frame.
        length = 16384
        total_length = (3 * 16384) + len(b'some more data')
        e = Encoder()
        h1 = HeadersFrame(1)
        h1.data = e.encode(
            [(':status', 200), ('content-length', '%d' % total_length)]
        )
        h1.flags |= set(['END_HEADERS'])

        d1 = DataFrame(1)
        d1.data = b'\x00' * length
        d2 = d1
        d3 = d1
        d4 = DataFrame(1)
        d4.data = b'some more data'
        d4.flags |= set(['END_STREAM'])

        buffer = BytesIO(
            b''.join(f.serialize() for f in [h1, d1, d2, d3, d4])
        )
        c._sock.buffer = buffer

        # Read the response
        resp = c.get_response(stream_id=1)
        assert resp.status == 200
        assert resp.read() == b''.join(
            [b'\x00' * (3 * length), b'some more data']
        )

        # We should have sent only one extra frame
        assert len(originally_sent_data) + 1 == len(c._sock.queue)
Ejemplo n.º 19
0
    def test_we_can_read_from_the_socket(self):
        sock = DummySocket()
        sock.buffer = BytesIO(b'\x00\x00\x08\x00\x01\x00\x00\x00\x01testdata')

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.putrequest('GET', '/')
        c.endheaders()
        c._recv_cb()

        s = c.recent_stream
        assert s.data == [b'testdata']
Ejemplo n.º 20
0
    def test_send_tolerate_peer_gone(self):
        class ErrorSocket(DummySocket):
            def sendall(self, data):
                raise socket.error(errno.EPIPE)

        c = HTTP20Connection('www.google.com')
        c._sock = ErrorSocket()
        f = SettingsFrame(0)
        with pytest.raises(socket.error):
            c._send_cb(f, False)
        c._sock = DummySocket()
        c._send_cb(f, True)  # shouldn't raise an error
Ejemplo n.º 21
0
    def test_goaway_frame_NO_ERROR(self):
        f = GoAwayFrame(0)
        # Set error code to NO_ERROR
        f.error_code = 0

        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()

        # 'Receive' the GOAWAY frame.
        # Test makes sure no exception is raised; error code 0 means we are
        # dealing with a standard and graceful shutdown.
        c.receive_frame(f)
Ejemplo n.º 22
0
    def test_putrequest_autosets_headers(self):
        c = HTTP20Connection("www.google.com")

        c.putrequest('GET', '/')
        s = c.recent_stream

        assert s.headers == [
            (':method', 'GET'),
            (':scheme', 'https'),
            (':authority', 'www.google.com'),
            (':path', '/'),
        ]
Ejemplo n.º 23
0
    def test_that_we_correctly_send_over_the_socket(self):
        sock = DummySocket()
        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.putrequest('GET', '/')
        c.endheaders(message_body=b'hello there', final=True)

        # Don't bother testing that the serialization was ok, that should be
        # fine.
        assert len(sock.queue) == 2
        # Confirm the window got shrunk.
        assert c._out_flow_control_window == 65535 - len(b'hello there')
Ejemplo n.º 24
0
    def test_putrequest_sends_data(self):
        sock = DummySocket()

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.request('GET',
                  '/',
                  body='hello',
                  headers={'Content-Type': 'application/json'})

        # The socket should have received one headers frame and one body frame.
        assert len(sock.queue) == 2
        assert c._out_flow_control_window == 65535 - len(b'hello')
Ejemplo n.º 25
0
    def test_putrequest_sends_data(self):
        sock = DummySocket()

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.request('GET',
                  '/',
                  body='hello',
                  headers={'Content-Type': 'application/json'})

        # The socket should have received one headers frame and two body
        # frames.
        assert len(sock.queue) == 3
Ejemplo n.º 26
0
    def test_we_can_read_from_the_socket(self):
        sock = DummySocket()
        sock.buffer = BytesIO(b'\x00\x08\x00\x01\x00\x00\x00\x01testdata')

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        c.putrequest('GET', '/')
        c.endheaders()
        c._recv_cb()

        s = c.recent_stream
        assert len(s._queued_frames) == 1
        assert isinstance(s._queued_frames[0], DataFrame)
        assert s._queued_frames[0].data == b'testdata'
Ejemplo n.º 27
0
    def test_putheader_puts_headers(self):
        c = HTTP20Connection("www.google.com")

        c.putrequest('GET', '/')
        c.putheader('name', 'value')
        s = c.recent_stream

        assert list(s.headers.items()) == [
            (b':method', b'GET'),
            (b':scheme', b'https'),
            (b':authority', b'www.google.com'),
            (b':path', b'/'),
            (b'name', b'value'),
        ]
Ejemplo n.º 28
0
    def test_endheaders_sends_data(self, frame_buffer):
        def data_callback(chunk, **kwargs):
            frame_buffer.add_data(chunk)

        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders()

        frames = list(frame_buffer)
        assert len(frames) == 1
        f = frames[0]
        assert isinstance(f, HeadersFrame)
Ejemplo n.º 29
0
    def test_endheaders_sends_data(self):
        frames = []

        def data_callback(frame):
            frames.append(frame)

        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        c.putrequest('GET', '/')
        c.endheaders()

        assert len(frames) == 1
        f = frames[0]
        assert isinstance(f, HeadersFrame)
Ejemplo n.º 30
0
    def test_ping(self, frame_buffer):
        def data_callback(chunk, **kwargs):
            frame_buffer.add_data(chunk)

        c = HTTP20Connection('www.google.com')
        c._sock = DummySocket()
        c._send_cb = data_callback
        opaque = '00000000'
        c.ping(opaque)

        frames = list(frame_buffer)
        assert len(frames) == 1
        f = frames[0]
        assert isinstance(f, PingFrame)
        assert f.opaque_data == to_bytestring(opaque)