Example #1
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')
Example #2
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')]
        )
Example #3
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)
Example #4
0
    def create_socket(status_code, data, headers):
        # test helper method
        encoder = Encoder()
        h1 = HeadersFrame(1)
        h1.data = encoder.encode([(':status', status_code),
                                  ('content-length', len(data))] + headers)
        h1.flags |= set(['END_HEADERS'])

        d1 = DataFrame(1)
        d1.data = data

        d2 = DataFrame(1)
        d2.flags |= set(['END_STREAM'])

        content = b''.join(f.serialize() for f in [h1, d1, d2])
        buffer = BytesIO(content)

        return DummySocket(buffer)
Example #5
0
    def test_headers_with_continuation(self):
        e = Encoder()
        header_data = e.encode([(':status', 200), ('content-type', 'foo/bar'),
                                ('content-length', '0')])
        h = HeadersFrame(1)
        h.data = header_data[0:int(len(header_data) / 2)]
        h.flags.add('END_STREAM')
        c = ContinuationFrame(1)
        c.data = header_data[int(len(header_data) / 2):]
        c.flags.add('END_HEADERS')
        sock = DummySocket()
        sock.buffer = BytesIO(h.serialize() + c.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        r = c.request('GET', '/')

        assert set(c.get_response(r).headers.iter_raw()) == set([
            (b'content-type', b'foo/bar'), (b'content-length', b'0')
        ])
Example #6
0
    def test_headers_with_continuation(self):
        e = Encoder()
        header_data = e.encode([
            (':status', 200), ('content-type', 'foo/bar'),
            ('content-length', '0')
        ])
        h = HeadersFrame(1)
        h.data = header_data[0:int(len(header_data)/2)]
        h.flags.add('END_STREAM')
        c = ContinuationFrame(1)
        c.data = header_data[int(len(header_data)/2):]
        c.flags.add('END_HEADERS')
        sock = DummySocket()
        sock.buffer = BytesIO(h.serialize() + c.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        r = c.request('GET', '/')

        assert set(c.get_response(r).headers.iter_raw()) == set(
            [(b'content-type', b'foo/bar'), (b'content-length', b'0')]
        )
Example #7
0
    def test_streams_removed_on_close(self):
        # Create content for read from socket
        e = Encoder()
        h1 = HeadersFrame(1)
        h1.data = e.encode([(':status', 200), ('content-type', 'foo/bar')])
        h1.flags |= set(['END_HEADERS', 'END_STREAM'])
        sock = DummySocket()
        sock.buffer = BytesIO(h1.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        stream_id = c.request('GET', '/')

        # Create reference to current recent_recv_streams set
        recent_recv_streams = c.recent_recv_streams
        streams = c.streams

        resp = c.get_response(stream_id=stream_id)
        assert stream_id in recent_recv_streams
        assert stream_id in streams
        resp.read()
        assert stream_id not in recent_recv_streams
        assert stream_id not in streams
Example #8
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')])
Example #9
0
    def test_streams_removed_on_close(self):
        # Create content for read from socket
        e = Encoder()
        h1 = HeadersFrame(1)
        h1.data = e.encode([(':status', 200), ('content-type', 'foo/bar')])
        h1.flags |= set(['END_HEADERS', 'END_STREAM'])
        sock = DummySocket()
        sock.buffer = BytesIO(h1.serialize())

        c = HTTP20Connection('www.google.com')
        c._sock = sock
        stream_id = c.request('GET', '/')

        # Create reference to current recent_recv_streams set
        recent_recv_streams = c.recent_recv_streams
        streams = c.streams

        resp = c.get_response(stream_id=stream_id)
        assert stream_id in recent_recv_streams
        assert stream_id in streams
        resp.read()
        assert stream_id not in recent_recv_streams
        assert stream_id not in streams
Example #10
0
 def setup_method(self, method):
     self.frames = []
     self.encoder = Encoder()
     self.conn = None
Example #11
0
class TestServerPush(object):
    def setup_method(self, method):
        self.frames = []
        self.encoder = Encoder()
        self.conn = None

    def add_push_frame(self, stream_id, promised_stream_id, headers,
                       end_block=True):
        frame = PushPromiseFrame(stream_id)
        frame.promised_stream_id = promised_stream_id
        frame.data = self.encoder.encode(headers)
        if end_block:
            frame.flags.add('END_HEADERS')
        self.frames.append(frame)

    def add_headers_frame(self, stream_id, headers, end_block=True,
                          end_stream=False):
        frame = HeadersFrame(stream_id)
        frame.data = self.encoder.encode(headers)
        if end_block:
            frame.flags.add('END_HEADERS')
        if end_stream:
            frame.flags.add('END_STREAM')
        self.frames.append(frame)

    def add_data_frame(self, stream_id, data, end_stream=False):
        frame = DataFrame(stream_id)
        frame.data = data
        if end_stream:
            frame.flags.add('END_STREAM')
        self.frames.append(frame)

    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', '/')

    def assert_response(self):
        self.response = self.conn.get_response()
        assert self.response.status == 200
        assert dict(self.response.headers) == {b'content-type': [b'text/html']}

    def assert_pushes(self):
        self.pushes = list(self.conn.get_pushes())
        assert len(self.pushes) == 1
        assert self.pushes[0].method == b'GET'
        assert self.pushes[0].scheme == b'https'
        assert self.pushes[0].authority == b'www.google.com'
        assert self.pushes[0].path == b'/'
        expected_headers = {b'accept-encoding': [b'gzip']}
        assert dict(self.pushes[0].request_headers) == expected_headers

    def assert_push_response(self):
        push_response = self.pushes[0].get_response()
        assert push_response.status == 200
        assert dict(push_response.headers) == {
            b'content-type': [b'application/javascript']
        }
        assert push_response.read() == b'bar'

    def test_promise_before_headers(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        self.assert_pushes()
        assert self.response.read() == b'foo'
        self.assert_push_response()

    def test_promise_after_headers(self):
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        assert self.response.read() == b'foo'
        self.assert_pushes()
        self.assert_push_response()

    def test_promise_after_data(self):
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_data_frame(1, b'fo')
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'o', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        assert self.response.read() == b'foo'
        self.assert_pushes()
        self.assert_push_response()

    def test_capture_all_promises(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/one'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_push_frame(
            1,
            4,
            [
                (':method', 'GET'),
                (':path', '/two'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            4, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(4, b'two', end_stream=True)
        self.add_data_frame(2, b'one', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        pushes = list(self.conn.get_pushes(capture_all=True))
        assert len(pushes) == 2
        assert pushes[0].path == b'/one'
        assert pushes[1].path == b'/two'
        assert pushes[0].get_response().read() == b'one'
        assert pushes[1].get_response().read() == b'two'
        self.assert_response()
        assert self.response.read() == b'foo'

    def test_cancel_push(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )

        self.request()
        self.conn.get_response()
        list(self.conn.get_pushes())[0].cancel()

        f = RstStreamFrame(2)
        f.error_code = 8
        assert self.conn._sock.queue[-1] == f.serialize()

    def test_reset_pushed_streams_when_push_disabled(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )

        self.request()
        self.conn._enable_push = False
        self.conn.get_response()

        f = RstStreamFrame(2)
        f.error_code = 7
        assert self.conn._sock.queue[-1] == f.serialize()

    def test_pushed_requests_ignore_unexpected_headers(self):
        headers = HTTPHeaderMap([
            (':scheme', 'http'),
            (':method', 'get'),
            (':authority', 'google.com'),
            (':path', '/'),
            (':reserved', 'no'),
            ('no', 'no'),
        ])
        p = HTTP20Push(headers, DummyStream(b''))

        assert p.request_headers == HTTPHeaderMap([('no', 'no')])
Example #12
0
 def setup_method(self, method):
     self.frames = []
     self.encoder = Encoder()
     self.conn = None
Example #13
0
class TestServerPush(object):
    def setup_method(self, method):
        self.frames = []
        self.encoder = Encoder()
        self.conn = None

    def add_push_frame(self, stream_id, promised_stream_id, headers,
                       end_block=True):
        frame = PushPromiseFrame(stream_id)
        frame.promised_stream_id = promised_stream_id
        frame.data = self.encoder.encode(headers)
        if end_block:
            frame.flags.add('END_HEADERS')
        self.frames.append(frame)

    def add_headers_frame(self, stream_id, headers, end_block=True,
                          end_stream=False):
        frame = HeadersFrame(stream_id)
        frame.data = self.encoder.encode(headers)
        if end_block:
            frame.flags.add('END_HEADERS')
        if end_stream:
            frame.flags.add('END_STREAM')
        self.frames.append(frame)

    def add_data_frame(self, stream_id, data, end_stream=False):
        frame = DataFrame(stream_id)
        frame.data = data
        if end_stream:
            frame.flags.add('END_STREAM')
        self.frames.append(frame)

    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', '/')

    def assert_response(self):
        self.response = self.conn.get_response()
        assert self.response.status == 200
        assert dict(self.response.headers) == {b'content-type': [b'text/html']}

    def assert_pushes(self):
        self.pushes = list(self.conn.get_pushes())
        assert len(self.pushes) == 1
        assert self.pushes[0].method == b'GET'
        assert self.pushes[0].scheme == b'https'
        assert self.pushes[0].authority == b'www.google.com'
        assert self.pushes[0].path == b'/'
        expected_headers = {b'accept-encoding': [b'gzip']}
        assert dict(self.pushes[0].request_headers) == expected_headers

    def assert_push_response(self):
        push_response = self.pushes[0].get_response()
        assert push_response.status == 200
        assert dict(push_response.headers) == {
            b'content-type': [b'application/javascript']
        }
        assert push_response.read() == b'bar'

    def test_promise_before_headers(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        self.assert_pushes()
        assert self.response.read() == b'foo'
        self.assert_push_response()

    def test_promise_after_headers(self):
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        assert self.response.read() == b'foo'
        self.assert_pushes()
        self.assert_push_response()

    def test_promise_after_data(self):
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_data_frame(1, b'fo')
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'o', end_stream=True)
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(2, b'bar', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        self.assert_response()
        assert self.response.read() == b'foo'
        self.assert_pushes()
        self.assert_push_response()

    def test_capture_all_promises(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/one'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )
        self.add_push_frame(
            1,
            4,
            [
                (':method', 'GET'),
                (':path', '/two'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_data_frame(1, b'foo', end_stream=True)
        self.add_headers_frame(
            4, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_headers_frame(
            2, [(':status', '200'), ('content-type', 'application/javascript')]
        )
        self.add_data_frame(4, b'two', end_stream=True)
        self.add_data_frame(2, b'one', end_stream=True)

        self.request()
        assert len(list(self.conn.get_pushes())) == 0
        pushes = list(self.conn.get_pushes(capture_all=True))
        assert len(pushes) == 2
        assert pushes[0].path == b'/one'
        assert pushes[1].path == b'/two'
        assert pushes[0].get_response().read() == b'one'
        assert pushes[1].get_response().read() == b'two'
        self.assert_response()
        assert self.response.read() == b'foo'

    def test_cancel_push(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )

        self.request()
        self.conn.get_response()
        list(self.conn.get_pushes())[0].cancel()

        f = RstStreamFrame(2)
        f.error_code = 8
        assert self.conn._sock.queue[-1] == f.serialize()

    def test_reset_pushed_streams_when_push_disabled(self):
        self.add_push_frame(
            1,
            2,
            [
                (':method', 'GET'),
                (':path', '/'),
                (':authority', 'www.google.com'),
                (':scheme', 'https'),
                ('accept-encoding', 'gzip')
            ]
        )
        self.add_headers_frame(
            1, [(':status', '200'), ('content-type', 'text/html')]
        )

        self.request()
        self.conn._enable_push = False
        self.conn.get_response()

        f = RstStreamFrame(2)
        f.error_code = 7
        assert self.conn._sock.queue[-1] == f.serialize()

    def test_pushed_requests_ignore_unexpected_headers(self):
        headers = HTTPHeaderMap([
            (':scheme', 'http'),
            (':method', 'get'),
            (':authority', 'google.com'),
            (':path', '/'),
            (':reserved', 'no'),
            ('no', 'no'),
        ])
        p = HTTP20Push(headers, DummyStream(b''))

        assert p.request_headers == HTTPHeaderMap([('no', 'no')])