Ejemplo n.º 1
0
    def test_response_ignores_unknown_headers(self):
        headers = HTTPHeaderMap([(':status', '200'), (':reserved', 'yes'),
                                 ('no', 'no')])
        stream = DummyStream(b'')
        resp = HTTP20Response(headers, stream)

        assert resp.headers == HTTPHeaderMap([('no', 'no')])
Ejemplo n.º 2
0
    def test_can_receive_trailers(self):
        headers = [('a', 'b'), ('c', 'd'), (':status', '200')]
        trailers = [('e', 'f'), ('g', 'h')]

        s = Stream(1, None, None, None, None, FixedDecoder(headers), None)
        s.state = STATE_HALF_CLOSED_LOCAL

        # Provide the first HEADERS frame.
        f = HeadersFrame(1)
        f.data = b'hi there!'
        f.flags.add('END_HEADERS')
        s.receive_frame(f)

        assert s.response_headers == HTTPHeaderMap(headers)

        # Now, replace the dummy decoder to ensure we get a new header block.
        s._decoder = FixedDecoder(trailers)

        # Provide the trailers.
        f = HeadersFrame(1)
        f.data = b'hi there again!'
        f.flags.add('END_STREAM')
        f.flags.add('END_HEADERS')
        s.receive_frame(f)

        # Now, check the trailers.
        assert s.response_trailers == HTTPHeaderMap(trailers)

        # Confirm we closed the stream.
        assert s.state == STATE_CLOSED
Ejemplo n.º 3
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.º 4
0
    def test_trailers_are_read(self):
        headers = HTTPHeaderMap([(':status', '200')])
        trailers = HTTPHeaderMap([('a', 'b'), ('c', 'd')])
        stream = DummyStream(b'', trailers=trailers)
        resp = HTTP20Response(headers, stream)

        assert resp.trailers == trailers
        assert resp.trailers['a'] == [b'b']
        assert resp.trailers['c'] == [b'd']
Ejemplo n.º 5
0
    def test_headers_must_be_strings(self):
        with pytest.raises(ValueError):
            HTTPHeaderMap(key=1)

        h = HTTPHeaderMap()
        with pytest.raises(ValueError):
            h['k'] = 1

        with pytest.raises(ValueError):
            h[1] = 'v'
Ejemplo n.º 6
0
    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')])
Ejemplo n.º 7
0
    def test_equality(self):
        h1 = HTTPHeaderMap()
        h1['k1'] = 'v1, v2'
        h1['k2'] = 'v3'
        h1['k1'] = 'v4'

        h2 = HTTPHeaderMap()
        h2['k1'] = 'v1, v2'
        h2['k2'] = 'v3'
        h2['k1'] = 'v4'

        assert h1 == h2
Ejemplo n.º 8
0
    def test_inequality_of_raw_ordering(self):
        h1 = HTTPHeaderMap()
        h1['k1'] = 'v1, v2'
        h1['k2'] = 'v3'
        h1['k1'] = 'v4'

        h2 = HTTPHeaderMap()
        h2['k1'] = 'v1'
        h2['k1'] = 'v2'
        h2['k2'] = 'v3'
        h2['k1'] = 'v4'

        assert h1 != h2
Ejemplo n.º 9
0
    def test_merge_headermaps_preserves_raw(self):
        h1 = HTTPHeaderMap([
            (b'hi', b'there')
        ])
        h2 = HTTPHeaderMap([
            (b'Hi', b'there, sir, maam')
        ])

        h1.merge(h2)

        assert list(h1.iter_raw()) == [
            (b'hi', b'there'),
            (b'Hi', b'there, sir, maam'),
        ]
Ejemplo n.º 10
0
    def test_response_calls_stream_close(self):
        headers = HTTPHeaderMap([(':status', '200')])
        stream = DummyStream('')
        resp = HTTP20Response(headers, stream)
        resp.close()

        assert stream.closed
Ejemplo n.º 11
0
    def test_getheader(self):
        headers = HTTPHeaderMap([(':status', '200'),
                                 ('content-type', 'application/json')])
        stream = DummyStream(b'')
        resp = HTTP20Response(headers, stream)

        assert resp.headers[b'content-type'] == [b'application/json']
Ejemplo n.º 12
0
    def _handle_header_block(self, headers):
        """
        Handles the logic for receiving a completed headers block.

        A headers block is an uninterrupted sequence of one HEADERS frame
        followed by zero or more CONTINUATION frames, and is terminated by a
        frame bearing the END_HEADERS flag.

        HTTP/2 allows receipt of up to three such blocks on a stream. The first
        is optional, and contains a 1XX response. The second is mandatory, and
        must contain a final response (200 or higher). The third is optional,
        and may contain 'trailers', headers that are sent after a chunk-encoded
        body is sent.

        Here we only process the simple state: no push, one header frame.
        """

        if self.response_headers is None:
            self.response_headers = HTTPHeaderMap(headers)
        else:
            # Received too many headers blocks.
            raise ProtocolError("Too many header blocks.")

        status = int(self.response_headers[b':status'][0])
        if status in [400, 403]:
            # xlog.warn("status:%d host:%s", status, self.host)
            self.connection.close("get 40x")

        return
Ejemplo n.º 13
0
    def test_length_counts_lines_separately(self):
        h = HTTPHeaderMap()
        h['k1'] = 'v1, v2'
        h['k2'] = 'v3'
        h['k1'] = 'v4'

        assert len(h) == 4
Ejemplo n.º 14
0
    def test_header_map_can_delete_value(self):
        h = HTTPHeaderMap()
        h['key'] = b'v1'
        del h[b'key']

        with pytest.raises(KeyError):
            h[b'key']
Ejemplo n.º 15
0
    def test_actual_get(self):
        h = HTTPHeaderMap()
        h['k1'] = 'v1, v2'
        h['k2'] = 'v3'
        h['k1'] = 'v4'

        assert h.get('k1') == [b'v1', b'v2', b'v4']
Ejemplo n.º 16
0
    def test_containment(self):
        h = HTTPHeaderMap()
        h['key'] = 'val'

        assert 'key' in h
        assert b'key' in h
        assert 'nonkey' not in h
Ejemplo n.º 17
0
    def test_header_map_deletes_all_values(self):
        h = HTTPHeaderMap()
        h['key'] = 'v1'
        h['key'] = 'v2'
        del h['key']

        with pytest.raises(KeyError):
            h['key']
Ejemplo n.º 18
0
    def test_keys(self):
        h = HTTPHeaderMap()
        h['k1'] = 'v1, v2'
        h['k2'] = 'v3'
        h['k1'] = 'v4'

        assert len(list(h.keys())) == 4
        assert list(h.keys()) == [b'k1', b'k1', b'k2', b'k1']
Ejemplo n.º 19
0
    def test_responses_are_context_managers(self):
        headers = HTTPHeaderMap([(':status', '200')])
        stream = DummyStream('')

        with HTTP20Response(headers, stream):
            pass

        assert stream.closed
Ejemplo n.º 20
0
    def test_values(self):
        h = HTTPHeaderMap()
        h['k1'] = 'v1, v2'
        h['k2'] = 'v3'
        h['k1'] = 'v4'

        assert len(list(h.values())) == 4
        assert list(h.values()) == [b'v1', b'v2', b'v3', b'v4']
Ejemplo n.º 21
0
    def test_response_transparently_decrypts_wrong_deflate(self):
        headers = HTTPHeaderMap([(':status', '200'),
                                 ('content-encoding', 'deflate')])
        c = zlib_compressobj(wbits=-zlib.MAX_WBITS)
        body = c.compress(b'this is test data')
        body += c.flush()
        resp = HTTP20Response(headers, DummyStream(body))

        assert resp.read() == b'this is test data'
Ejemplo n.º 22
0
    def test_raw_iteration(self):
        items = [
            (b'k1', b'v2'),
            (b'k2', b'v2, v3, v4'),
            (b'k2', b'v3'),
        ]
        h = HTTPHeaderMap(items)

        assert list(h.iter_raw()) == items
Ejemplo n.º 23
0
    def test_can_create_from_multiple_iterables(self):
        items = [
            (b'k1', b'v2'),
            (b'k2', b'v2'),
            (b'k2', b'v3'),
        ]
        h = HTTPHeaderMap(items, items, items)

        assert list(h) == items + items + items
Ejemplo n.º 24
0
    def test_request_with_unicodestring_body(self):
        c = HTTP11Connection('httpbin.org')
        c._sock = DummySocket()

        with pytest.raises(ValueError):
            c.request('POST',
                      '/post',
                      headers=HTTPHeaderMap([('User-Agent', 'hyper')]),
                      body=u'hi')
Ejemplo n.º 25
0
    def test_read_frames(self):
        headers = HTTPHeaderMap([(':status', '200')])
        stream = DummyStream(None)
        chunks = [b'12', b'3456', b'78', b'9']
        stream.data_frames = chunks
        resp = HTTP20Response(headers, stream)

        for recv, expected in zip(resp.read_chunked(), chunks[:]):
            assert recv == expected
Ejemplo n.º 26
0
 def __init__(self, attrs):
     self.body = {}
     self.headers = HTTPHeaderMap()
     self.items = []
     self.method = None
     self._url = ''
     self.url = DummyUrlInfo()
     for key, value in attrs.items():
         setattr(self, key, value)
Ejemplo n.º 27
0
    def test_merge_header_map_dict(self):
        h = HTTPHeaderMap([(b'hi', b'there')])
        d = {'cat': 'dog'}

        h.merge(d)

        assert list(h.items()) == [
            (b'hi', b'there'),
            (b'cat', b'dog'),
        ]
Ejemplo n.º 28
0
    def test_reading_trailers_early_reads_all_data(self):
        in_frames = []
        headers = [('a', 'b'), ('c', 'd'), (':status', '200')]
        trailers = [('e', 'f'), ('g', 'h')]

        def recv_cb(s):
            def inner():
                s.receive_frame(in_frames.pop(0))

            return inner

        s = Stream(1, None, None, None, None, FixedDecoder(headers),
                   FlowControlManager(65535))
        s._recv_cb = recv_cb(s)
        s.state = STATE_HALF_CLOSED_LOCAL

        # Provide the first HEADERS frame.
        f = HeadersFrame(1)
        f.data = b'hi there!'
        f.flags.add('END_HEADERS')
        in_frames.append(f)

        # Provide some data.
        f = DataFrame(1)
        f.data = b'testdata'
        in_frames.append(f)

        # Provide the trailers.
        f = HeadersFrame(1)
        f.data = b'hi there again!'
        f.flags.add('END_STREAM')
        f.flags.add('END_HEADERS')
        in_frames.append(f)

        # Begin by reading the first headers.
        assert s.getheaders() == HTTPHeaderMap(headers)

        # Now, replace the dummy decoder to ensure we get a new header block.
        s._decoder = FixedDecoder(trailers)

        # Ask for the trailers. This should also read the data frames.
        assert s.gettrailers() == HTTPHeaderMap(trailers)
        assert s.data == [b'testdata']
Ejemplo n.º 29
0
    def test_read_small_chunks(self):
        headers = HTTPHeaderMap([(':status', '200')])
        stream = DummyStream(b'1234567890')
        chunks = [b'12', b'34', b'56', b'78', b'90']
        resp = HTTP20Response(headers, stream)

        for chunk in chunks:
            assert resp.read(2) == chunk

        assert resp.read() == b''
Ejemplo n.º 30
0
    def __init__(self, connection, ip, stream_id, host, task, send_cb,
                 close_cb, header_encoder, header_decoder,
                 receive_window_manager, remote_window_size, max_frame_size):

        self.connection = connection
        self.ip = ip
        self.stream_id = stream_id
        self.host = host
        self.task = task
        self.state = STATE_IDLE
        self.get_head_time = None

        # There are two flow control windows: one for data we're sending,
        # one for data being sent to us.
        self.receive_window_manager = receive_window_manager
        self.remote_window_size = remote_window_size
        self.max_frame_size = max_frame_size

        # This is the callback handed to the stream by its parent connection.
        # It is called when the stream wants to send data. It expects to
        # receive a list of frames that will be automatically serialized.
        self._send_cb = send_cb

        # This is the callback to be called when the stream is closed.
        self._close_cb = close_cb

        # A reference to the header encoder and decoder objects belonging to
        # the parent connection.
        self._encoder = header_encoder
        self._decoder = header_decoder

        self.request_headers = HTTPHeaderMap()

        # Convert the body to bytes if needed.
        self.request_body = to_bytestring(self.task.body)

        # request body not send blocked by send window
        # the left body will send when send window opened.
        self.request_body_left = len(self.request_body)
        self.request_body_sended = False

        # data list before decode
        self.response_header_datas = []

        # Set to a key-value set of the response headers once their
        # HEADERS..CONTINUATION frame sequence finishes.
        self.response_headers = None

        # Unconsumed response data chunks
        self.response_body = []
        self.response_body_len = 0

        threading.Thread(target=self.timeout_response).start()
        self.start_request()