Exemple #1
0
def _secure_headers(headers, hdr_validation_flags):
    """
    Certain headers are at risk of being attacked during the header compression
    phase, and so need to be kept out of header compression contexts. This
    function automatically transforms certain specific headers into HPACK
    never-indexed fields to ensure they don't get added to header compression
    contexts.

    This function currently implements two rules:

    - 'authorization' and 'proxy-authorization' fields are automatically made
      never-indexed.
    - Any 'cookie' header field shorter than 20 bytes long is made
      never-indexed.

    These fields are the most at-risk. These rules are inspired by Firefox
    and nghttp2.
    """
    for header in headers:
        if header[0] in _SECURE_HEADERS:
            yield NeverIndexedHeaderTuple(*header)
        elif header[0] in (b'cookie', u'cookie') and len(header[1]) < 20:
            yield NeverIndexedHeaderTuple(*header)
        else:
            yield header
Exemple #2
0
    async def send_request(
        self,
        method: str,
        path: str,
        additional_headers: Optional[Iterable] = None,
        end_stream: bool = False,
    ) -> int:
        if self.closed:
            raise ConnectionClosedError

        scheme = 'https' if self.secure else 'http'
        headers = [
            HeaderTuple(':method', method),
            HeaderTuple(':scheme', scheme),
            HeaderTuple(':authority', self.host),
            NeverIndexedHeaderTuple(':path', path),
        ]
        if additional_headers is not None:
            headers.extend(additional_headers)

        await asyncio.gather(
            self._writable.wait(),
            self._stream_creatable.wait(),
        )

        stream_id = self._h2.get_next_available_stream_id()
        logger.debug(f'[{stream_id}] Sending request: {method} '
                     f'{scheme}://{self.host}{path}')
        self._h2.send_headers(stream_id, headers, end_stream=end_stream)
        self._flush()

        stream = self._create_stream(stream_id)
        return stream.id
Exemple #3
0
    def test_authorization_headers_never_indexed_push(self, headers,
                                                      auth_header,
                                                      frame_factory):
        """
        Authorization and Proxy-Authorization headers are always forced to be
        never-indexed, regardless of their form, when pushed by a server.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [auth_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(auth_header[0].lower(), auth_header[1])
        ]

        c = h2.connection.H2Connection(client_side=False)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(self.example_request_headers)
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=expected_headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(stream_id=1,
                      promised_stream_id=2,
                      request_headers=send_headers)

        assert c.data_to_send() == expected_frame.serialize()
Exemple #4
0
    def test_short_cookie_headers_never_indexed_push(self, headers,
                                                     cookie_header,
                                                     frame_factory):
        """
        Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
        are never indexed when pushed by servers.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection(client_side=False)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(self.example_request_headers)
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=expected_headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(stream_id=1,
                      promised_stream_id=2,
                      request_headers=send_headers)

        assert c.data_to_send() == expected_frame.serialize()
Exemple #5
0
 def test_sensitive_headers_with_header_tuples(self):
     """
     A header field stored in a NeverIndexedHeaderTuple emits a
     representation that forbids indexing.
     """
     e = Encoder()
     result = (b'\x82\x14\x88\x63\xa1\xa9' +
               b'\x32\x08\x73\xd0\xc7\x10' +
               b'\x87\x25\xa8\x49\xe9\xea' +
               b'\x5f\x5f\x89\x41\x6a\x41' +
               b'\x92\x6e\xe5\x35\x52\x9f')
     header_set = [
         NeverIndexedHeaderTuple(':method', 'GET'),
         NeverIndexedHeaderTuple(':path', '/jimiscool/'),
         NeverIndexedHeaderTuple('customkey', 'sensitiveinfo'),
     ]
     assert e.encode(header_set, huffman=True) == result
Exemple #6
0
    def test_equal_for_different_indexes(self):
        """
        HeaderTuples compare equal to equivalent NeverIndexedHeaderTuples.
        """
        t1 = HeaderTuple('name', 'value')
        t2 = NeverIndexedHeaderTuple('name', 'value')

        assert t1 == t2
        assert t1 is not t2
Exemple #7
0
def _combine_cookie_fields(headers, hdr_validation_flags):
    """
    RFC 7540 § 8.1.2.5 allows HTTP/2 clients to split the Cookie header field,
    which must normally appear only once, into multiple fields for better
    compression. However, they MUST be joined back up again when received.
    This normalization step applies that transform. The side-effect is that
    all cookie fields now appear *last* in the header block.
    """
    # There is a problem here about header indexing. Specifically, it's
    # possible that all these cookies are sent with different header indexing
    # values. At this point it shouldn't matter too much, so we apply our own
    # logic and make them never-indexed.
    cookies = []
    for header in headers:
        if header[0] == b'cookie':
            cookies.append(header[1])
        else:
            yield header
    if cookies:
        cookie_val = b'; '.join(cookies)
        yield NeverIndexedHeaderTuple(b'cookie', cookie_val)
Exemple #8
0
    def test_short_cookie_headers_never_indexed(self, headers, cookie_header,
                                                frame_factory):
        """
        Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
        are never indexed.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, send_headers)

        f = frame_factory.build_headers_frame(headers=expected_headers)
        assert c.data_to_send() == f.serialize()
Exemple #9
0
    def test_authorization_headers_never_indexed(self, headers, auth_header,
                                                 frame_factory):
        """
        Authorization and Proxy-Authorization headers are always forced to be
        never-indexed, regardless of their form.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [auth_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(auth_header[0].lower(), auth_header[1])
        ]

        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, send_headers)

        f = frame_factory.build_headers_frame(headers=expected_headers)
        assert c.data_to_send() == f.serialize()
class TestSecureHeaders(object):
    """
    Certain headers should always be transformed to their never-indexed form.
    """
    example_request_headers = [
        (u':authority', u'example.com'),
        (u':path', u'/'),
        (u':scheme', u'https'),
        (u':method', u'GET'),
    ]
    bytes_example_request_headers = [
        (b':authority', b'example.com'),
        (b':path', b'/'),
        (b':scheme', b'https'),
        (b':method', b'GET'),
    ]
    possible_auth_headers = [
        (u'authorization', u'test'),
        (u'Authorization', u'test'),
        (u'authorization', u'really long test'),
        HeaderTuple(u'authorization', u'test'),
        HeaderTuple(u'Authorization', u'test'),
        HeaderTuple(u'authorization', u'really long test'),
        NeverIndexedHeaderTuple(u'authorization', u'test'),
        NeverIndexedHeaderTuple(u'Authorization', u'test'),
        NeverIndexedHeaderTuple(u'authorization', u'really long test'),
        (b'authorization', b'test'),
        (b'Authorization', b'test'),
        (b'authorization', b'really long test'),
        HeaderTuple(b'authorization', b'test'),
        HeaderTuple(b'Authorization', b'test'),
        HeaderTuple(b'authorization', b'really long test'),
        NeverIndexedHeaderTuple(b'authorization', b'test'),
        NeverIndexedHeaderTuple(b'Authorization', b'test'),
        NeverIndexedHeaderTuple(b'authorization', b'really long test'),
        (u'proxy-authorization', u'test'),
        (u'Proxy-Authorization', u'test'),
        (u'proxy-authorization', u'really long test'),
        HeaderTuple(u'proxy-authorization', u'test'),
        HeaderTuple(u'Proxy-Authorization', u'test'),
        HeaderTuple(u'proxy-authorization', u'really long test'),
        NeverIndexedHeaderTuple(u'proxy-authorization', u'test'),
        NeverIndexedHeaderTuple(u'Proxy-Authorization', u'test'),
        NeverIndexedHeaderTuple(u'proxy-authorization', u'really long test'),
        (b'proxy-authorization', b'test'),
        (b'Proxy-Authorization', b'test'),
        (b'proxy-authorization', b'really long test'),
        HeaderTuple(b'proxy-authorization', b'test'),
        HeaderTuple(b'Proxy-Authorization', b'test'),
        HeaderTuple(b'proxy-authorization', b'really long test'),
        NeverIndexedHeaderTuple(b'proxy-authorization', b'test'),
        NeverIndexedHeaderTuple(b'Proxy-Authorization', b'test'),
        NeverIndexedHeaderTuple(b'proxy-authorization', b'really long test'),
    ]
    secured_cookie_headers = [
        (u'cookie', u'short'),
        (u'Cookie', u'short'),
        (u'cookie', u'nineteen byte cooki'),
        HeaderTuple(u'cookie', u'short'),
        HeaderTuple(u'Cookie', u'short'),
        HeaderTuple(u'cookie', u'nineteen byte cooki'),
        NeverIndexedHeaderTuple(u'cookie', u'short'),
        NeverIndexedHeaderTuple(u'Cookie', u'short'),
        NeverIndexedHeaderTuple(u'cookie', u'nineteen byte cooki'),
        NeverIndexedHeaderTuple(u'cookie', u'longer manually secured cookie'),
        (b'cookie', b'short'),
        (b'Cookie', b'short'),
        (b'cookie', b'nineteen byte cooki'),
        HeaderTuple(b'cookie', b'short'),
        HeaderTuple(b'Cookie', b'short'),
        HeaderTuple(b'cookie', b'nineteen byte cooki'),
        NeverIndexedHeaderTuple(b'cookie', b'short'),
        NeverIndexedHeaderTuple(b'Cookie', b'short'),
        NeverIndexedHeaderTuple(b'cookie', b'nineteen byte cooki'),
        NeverIndexedHeaderTuple(b'cookie', b'longer manually secured cookie'),
    ]
    unsecured_cookie_headers = [
        (u'cookie', u'twenty byte cookie!!'),
        (u'Cookie', u'twenty byte cookie!!'),
        (u'cookie', u'substantially longer than 20 byte cookie'),
        HeaderTuple(u'cookie', u'twenty byte cookie!!'),
        HeaderTuple(u'cookie', u'twenty byte cookie!!'),
        HeaderTuple(u'Cookie', u'twenty byte cookie!!'),
        (b'cookie', b'twenty byte cookie!!'),
        (b'Cookie', b'twenty byte cookie!!'),
        (b'cookie', b'substantially longer than 20 byte cookie'),
        HeaderTuple(b'cookie', b'twenty byte cookie!!'),
        HeaderTuple(b'cookie', b'twenty byte cookie!!'),
        HeaderTuple(b'Cookie', b'twenty byte cookie!!'),
    ]

    server_config = h2.config.H2Configuration(client_side=False)

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('auth_header', possible_auth_headers)
    def test_authorization_headers_never_indexed(self,
                                                 headers,
                                                 auth_header,
                                                 frame_factory):
        """
        Authorization and Proxy-Authorization headers are always forced to be
        never-indexed, regardless of their form.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [auth_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(auth_header[0].lower(), auth_header[1])
        ]

        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, send_headers)

        f = frame_factory.build_headers_frame(headers=expected_headers)
        assert c.data_to_send() == f.serialize()

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('auth_header', possible_auth_headers)
    def test_authorization_headers_never_indexed_push(self,
                                                      headers,
                                                      auth_header,
                                                      frame_factory):
        """
        Authorization and Proxy-Authorization headers are always forced to be
        never-indexed, regardless of their form, when pushed by a server.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [auth_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(auth_header[0].lower(), auth_header[1])
        ]

        c = h2.connection.H2Connection(config=self.server_config)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(
            self.example_request_headers
        )
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=expected_headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(
            stream_id=1,
            promised_stream_id=2,
            request_headers=send_headers
        )

        assert c.data_to_send() == expected_frame.serialize()

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('cookie_header', secured_cookie_headers)
    def test_short_cookie_headers_never_indexed(self,
                                                headers,
                                                cookie_header,
                                                frame_factory):
        """
        Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
        are never indexed.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, send_headers)

        f = frame_factory.build_headers_frame(headers=expected_headers)
        assert c.data_to_send() == f.serialize()

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('cookie_header', secured_cookie_headers)
    def test_short_cookie_headers_never_indexed_push(self,
                                                     headers,
                                                     cookie_header,
                                                     frame_factory):
        """
        Short cookie headers, and cookies provided as NeverIndexedHeaderTuple,
        are never indexed when pushed by servers.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            NeverIndexedHeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection(config=self.server_config)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(
            self.example_request_headers
        )
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=expected_headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(
            stream_id=1,
            promised_stream_id=2,
            request_headers=send_headers
        )

        assert c.data_to_send() == expected_frame.serialize()

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('cookie_header', unsecured_cookie_headers)
    def test_long_cookie_headers_can_be_indexed(self,
                                                headers,
                                                cookie_header,
                                                frame_factory):
        """
        Longer cookie headers can be indexed.
        """
        # Regardless of what we send, we expect it to be indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            HeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, send_headers)

        f = frame_factory.build_headers_frame(headers=expected_headers)
        assert c.data_to_send() == f.serialize()

    @pytest.mark.parametrize(
        'headers', (example_request_headers, bytes_example_request_headers)
    )
    @pytest.mark.parametrize('cookie_header', unsecured_cookie_headers)
    def test_long_cookie_headers_can_be_indexed_push(self,
                                                     headers,
                                                     cookie_header,
                                                     frame_factory):
        """
        Longer cookie headers can be indexed.
        """
        # Regardless of what we send, we expect it to be never indexed.
        send_headers = headers + [cookie_header]
        expected_headers = headers + [
            HeaderTuple(cookie_header[0].lower(), cookie_header[1])
        ]

        c = h2.connection.H2Connection(config=self.server_config)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(
            self.example_request_headers
        )
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=expected_headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(
            stream_id=1,
            promised_stream_id=2,
            request_headers=send_headers
        )

        assert c.data_to_send() == expected_frame.serialize()
class TestHeaderIndexing(object):
    """
    Test that Hyper-h2 can correctly handle never indexed header fields using
    the appropriate hpack data structures.
    """
    example_request_headers = [
        HeaderTuple(u':authority', u'example.com'),
        HeaderTuple(u':path', u'/'),
        HeaderTuple(u':scheme', u'https'),
        HeaderTuple(u':method', u'GET'),
    ]
    bytes_example_request_headers = [
        HeaderTuple(b':authority', b'example.com'),
        HeaderTuple(b':path', b'/'),
        HeaderTuple(b':scheme', b'https'),
        HeaderTuple(b':method', b'GET'),
    ]

    extended_request_headers = [
        HeaderTuple(u':authority', u'example.com'),
        HeaderTuple(u':path', u'/'),
        HeaderTuple(u':scheme', u'https'),
        HeaderTuple(u':method', u'GET'),
        NeverIndexedHeaderTuple(u'authorization', u'realpassword'),
    ]
    bytes_extended_request_headers = [
        HeaderTuple(b':authority', b'example.com'),
        HeaderTuple(b':path', b'/'),
        HeaderTuple(b':scheme', b'https'),
        HeaderTuple(b':method', b'GET'),
        NeverIndexedHeaderTuple(b'authorization', b'realpassword'),
    ]

    example_response_headers = [
        HeaderTuple(u':status', u'200'),
        HeaderTuple(u'server', u'fake-serv/0.1.0')
    ]
    bytes_example_response_headers = [
        HeaderTuple(b':status', b'200'),
        HeaderTuple(b'server', b'fake-serv/0.1.0')
    ]

    extended_response_headers = [
        HeaderTuple(u':status', u'200'),
        HeaderTuple(u'server', u'fake-serv/0.1.0'),
        NeverIndexedHeaderTuple(u'secure', u'you-bet'),
    ]
    bytes_extended_response_headers = [
        HeaderTuple(b':status', b'200'),
        HeaderTuple(b'server', b'fake-serv/0.1.0'),
        NeverIndexedHeaderTuple(b'secure', b'you-bet'),
    ]

    server_config = h2.config.H2Configuration(client_side=False)

    @pytest.mark.parametrize(
        'headers', (
            example_request_headers,
            bytes_example_request_headers,
            extended_request_headers,
            bytes_extended_request_headers,
        )
    )
    def test_sending_header_tuples(self, headers, frame_factory):
        """
        Providing HeaderTuple and HeaderTuple subclasses preserves the metadata
        about indexing.
        """
        c = h2.connection.H2Connection()
        c.initiate_connection()

        # Clear the data, then send headers.
        c.clear_outbound_data_buffer()
        c.send_headers(1, headers)

        f = frame_factory.build_headers_frame(headers=headers)
        assert c.data_to_send() == f.serialize()

    @pytest.mark.parametrize(
        'headers', (
            example_request_headers,
            bytes_example_request_headers,
            extended_request_headers,
            bytes_extended_request_headers,
        )
    )
    def test_header_tuples_in_pushes(self, headers, frame_factory):
        """
        Providing HeaderTuple and HeaderTuple subclasses to push promises
        preserves metadata about indexing.
        """
        c = h2.connection.H2Connection(config=self.server_config)
        c.receive_data(frame_factory.preamble())

        # We can use normal headers for the request.
        f = frame_factory.build_headers_frame(
            self.example_request_headers
        )
        c.receive_data(f.serialize())

        frame_factory.refresh_encoder()
        expected_frame = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=headers,
            flags=['END_HEADERS'],
        )

        c.clear_outbound_data_buffer()
        c.push_stream(
            stream_id=1,
            promised_stream_id=2,
            request_headers=headers
        )

        assert c.data_to_send() == expected_frame.serialize()

    @pytest.mark.parametrize(
        'headers,encoding', (
            (example_request_headers, 'utf-8'),
            (bytes_example_request_headers, None),
            (extended_request_headers, 'utf-8'),
            (bytes_extended_request_headers, None),
        )
    )
    def test_header_tuples_are_decoded_request(self,
                                               headers,
                                               encoding,
                                               frame_factory):
        """
        The indexing status of the header is preserved when emitting
        RequestReceived events.
        """
        config = h2.config.H2Configuration(
            client_side=False, header_encoding=encoding
        )
        c = h2.connection.H2Connection(config=config)
        c.receive_data(frame_factory.preamble())

        f = frame_factory.build_headers_frame(headers)
        data = f.serialize()
        events = c.receive_data(data)

        assert len(events) == 1
        event = events[0]

        assert isinstance(event, h2.events.RequestReceived)
        assert_header_blocks_actually_equal(headers, event.headers)

    @pytest.mark.parametrize(
        'headers,encoding', (
            (example_response_headers, 'utf-8'),
            (bytes_example_response_headers, None),
            (extended_response_headers, 'utf-8'),
            (bytes_extended_response_headers, None),
        )
    )
    def test_header_tuples_are_decoded_response(self,
                                                headers,
                                                encoding,
                                                frame_factory):
        """
        The indexing status of the header is preserved when emitting
        ResponseReceived events.
        """
        config = h2.config.H2Configuration(
            header_encoding=encoding
        )
        c = h2.connection.H2Connection(config=config)
        c.initiate_connection()
        c.send_headers(stream_id=1, headers=self.example_request_headers)

        f = frame_factory.build_headers_frame(headers)
        data = f.serialize()
        events = c.receive_data(data)

        assert len(events) == 1
        event = events[0]

        assert isinstance(event, h2.events.ResponseReceived)
        assert_header_blocks_actually_equal(headers, event.headers)

    @pytest.mark.parametrize(
        'headers,encoding', (
            (example_response_headers, 'utf-8'),
            (bytes_example_response_headers, None),
            (extended_response_headers, 'utf-8'),
            (bytes_extended_response_headers, None),
        )
    )
    def test_header_tuples_are_decoded_info_response(self,
                                                     headers,
                                                     encoding,
                                                     frame_factory):
        """
        The indexing status of the header is preserved when emitting
        InformationalResponseReceived events.
        """
        # Manipulate the headers to send 100 Continue. We need to copy the list
        # to avoid breaking the example headers.
        headers = headers[:]
        if encoding:
            headers[0] = HeaderTuple(u':status', u'100')
        else:
            headers[0] = HeaderTuple(b':status', b'100')

        config = h2.config.H2Configuration(
            header_encoding=encoding
        )
        c = h2.connection.H2Connection(config=config)
        c.initiate_connection()
        c.send_headers(stream_id=1, headers=self.example_request_headers)

        f = frame_factory.build_headers_frame(headers)
        data = f.serialize()
        events = c.receive_data(data)

        assert len(events) == 1
        event = events[0]

        assert isinstance(event, h2.events.InformationalResponseReceived)
        assert_header_blocks_actually_equal(headers, event.headers)

    @pytest.mark.parametrize(
        'headers,encoding', (
            (example_response_headers, 'utf-8'),
            (bytes_example_response_headers, None),
            (extended_response_headers, 'utf-8'),
            (bytes_extended_response_headers, None),
        )
    )
    def test_header_tuples_are_decoded_trailers(self,
                                                headers,
                                                encoding,
                                                frame_factory):
        """
        The indexing status of the header is preserved when emitting
        TrailersReceived events.
        """
        # Manipulate the headers to remove the status, which shouldn't be in
        # the trailers. We need to copy the list to avoid breaking the example
        # headers.
        headers = headers[1:]

        config = h2.config.H2Configuration(
            header_encoding=encoding
        )
        c = h2.connection.H2Connection(config=config)
        c.initiate_connection()
        c.send_headers(stream_id=1, headers=self.example_request_headers)
        f = frame_factory.build_headers_frame(self.example_response_headers)
        data = f.serialize()
        c.receive_data(data)

        f = frame_factory.build_headers_frame(headers, flags=['END_STREAM'])
        data = f.serialize()
        events = c.receive_data(data)

        assert len(events) == 2
        event = events[0]

        assert isinstance(event, h2.events.TrailersReceived)
        assert_header_blocks_actually_equal(headers, event.headers)

    @pytest.mark.parametrize(
        'headers,encoding', (
            (example_request_headers, 'utf-8'),
            (bytes_example_request_headers, None),
            (extended_request_headers, 'utf-8'),
            (bytes_extended_request_headers, None),
        )
    )
    def test_header_tuples_are_decoded_push_promise(self,
                                                    headers,
                                                    encoding,
                                                    frame_factory):
        """
        The indexing status of the header is preserved when emitting
        PushedStreamReceived events.
        """
        config = h2.config.H2Configuration(
            header_encoding=encoding
        )
        c = h2.connection.H2Connection(config=config)
        c.initiate_connection()
        c.send_headers(stream_id=1, headers=self.example_request_headers)

        f = frame_factory.build_push_promise_frame(
            stream_id=1,
            promised_stream_id=2,
            headers=headers,
            flags=['END_HEADERS'],
        )
        data = f.serialize()
        events = c.receive_data(data)

        assert len(events) == 1
        event = events[0]

        assert isinstance(event, h2.events.PushedStreamReceived)
        assert_header_blocks_actually_equal(headers, event.headers)
Exemple #12
0
 def test_never_indexed_tuples_are_not_indexable(self):
     """
     NeverIndexedHeaderTuple objects cannot be indexed.
     """
     h = NeverIndexedHeaderTuple('name', 'value')
     assert not h.indexable