tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_rfc7838.py (15036B)


      1 # -*- coding: utf-8 -*-
      2 """
      3 test_rfc7838
      4 ~~~~~~~~~~~~
      5 
      6 Test the RFC 7838 ALTSVC support.
      7 """
      8 import pytest
      9 
     10 import h2.config
     11 import h2.connection
     12 import h2.events
     13 import h2.exceptions
     14 
     15 
     16 class TestRFC7838Client(object):
     17    """
     18    Tests that the client supports receiving the RFC 7838 AltSvc frame.
     19    """
     20    example_request_headers = [
     21        (':authority', 'example.com'),
     22        (':path', '/'),
     23        (':scheme', 'https'),
     24        (':method', 'GET'),
     25    ]
     26    example_response_headers = [
     27        (u':status', u'200'),
     28        (u'server', u'fake-serv/0.1.0')
     29    ]
     30 
     31    def test_receiving_altsvc_stream_zero(self, frame_factory):
     32        """
     33        An ALTSVC frame received on stream zero correctly transposes all the
     34        fields from the frames.
     35        """
     36        c = h2.connection.H2Connection()
     37        c.initiate_connection()
     38        c.clear_outbound_data_buffer()
     39 
     40        f = frame_factory.build_alt_svc_frame(
     41            stream_id=0, origin=b"example.com", field=b'h2=":8000"; ma=60'
     42        )
     43        events = c.receive_data(f.serialize())
     44 
     45        assert len(events) == 1
     46        event = events[0]
     47 
     48        assert isinstance(event, h2.events.AlternativeServiceAvailable)
     49        assert event.origin == b"example.com"
     50        assert event.field_value == b'h2=":8000"; ma=60'
     51 
     52        # No data gets sent.
     53        assert not c.data_to_send()
     54 
     55    def test_receiving_altsvc_stream_zero_no_origin(self, frame_factory):
     56        """
     57        An ALTSVC frame received on stream zero without an origin field is
     58        ignored.
     59        """
     60        c = h2.connection.H2Connection()
     61        c.initiate_connection()
     62        c.clear_outbound_data_buffer()
     63 
     64        f = frame_factory.build_alt_svc_frame(
     65            stream_id=0, origin=b"", field=b'h2=":8000"; ma=60'
     66        )
     67        events = c.receive_data(f.serialize())
     68 
     69        assert not events
     70        assert not c.data_to_send()
     71 
     72    def test_receiving_altsvc_on_stream(self, frame_factory):
     73        """
     74        An ALTSVC frame received on a stream correctly transposes all the
     75        fields from the frame and attaches the expected origin.
     76        """
     77        c = h2.connection.H2Connection()
     78        c.initiate_connection()
     79        c.send_headers(stream_id=1, headers=self.example_request_headers)
     80        c.clear_outbound_data_buffer()
     81 
     82        f = frame_factory.build_alt_svc_frame(
     83            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
     84        )
     85        events = c.receive_data(f.serialize())
     86 
     87        assert len(events) == 1
     88        event = events[0]
     89 
     90        assert isinstance(event, h2.events.AlternativeServiceAvailable)
     91        assert event.origin == b"example.com"
     92        assert event.field_value == b'h2=":8000"; ma=60'
     93 
     94        # No data gets sent.
     95        assert not c.data_to_send()
     96 
     97    def test_receiving_altsvc_on_stream_with_origin(self, frame_factory):
     98        """
     99        An ALTSVC frame received on a stream with an origin field present gets
    100        ignored.
    101        """
    102        c = h2.connection.H2Connection()
    103        c.initiate_connection()
    104        c.send_headers(stream_id=1, headers=self.example_request_headers)
    105        c.clear_outbound_data_buffer()
    106 
    107        f = frame_factory.build_alt_svc_frame(
    108            stream_id=1, origin=b"example.com", field=b'h2=":8000"; ma=60'
    109        )
    110        events = c.receive_data(f.serialize())
    111 
    112        assert len(events) == 0
    113        assert not c.data_to_send()
    114 
    115    def test_receiving_altsvc_on_stream_not_yet_opened(self, frame_factory):
    116        """
    117        When an ALTSVC frame is received on a stream the client hasn't yet
    118        opened, the frame is ignored.
    119        """
    120        c = h2.connection.H2Connection()
    121        c.initiate_connection()
    122        c.clear_outbound_data_buffer()
    123 
    124        # We'll test this twice, once on a client-initiated stream ID and once
    125        # on a server initiated one.
    126        f1 = frame_factory.build_alt_svc_frame(
    127            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    128        )
    129        f2 = frame_factory.build_alt_svc_frame(
    130            stream_id=2, origin=b"", field=b'h2=":8000"; ma=60'
    131        )
    132        events = c.receive_data(f1.serialize() + f2.serialize())
    133 
    134        assert len(events) == 0
    135        assert not c.data_to_send()
    136 
    137    def test_receiving_altsvc_before_sending_headers(self, frame_factory):
    138        """
    139        When an ALTSVC frame is received but the client hasn't sent headers yet
    140        it gets ignored.
    141        """
    142        c = h2.connection.H2Connection()
    143        c.initiate_connection()
    144 
    145        # We need to create the idle stream. We have to do it by calling
    146        # a private API. While this can't naturally happen in hyper-h2 (we
    147        # don't currently have a mechanism by which this could occur), it could
    148        # happen in the future and we defend against it.
    149        c._begin_new_stream(
    150            stream_id=1, allowed_ids=h2.connection.AllowedStreamIDs.ODD
    151        )
    152        c.clear_outbound_data_buffer()
    153 
    154        f = frame_factory.build_alt_svc_frame(
    155            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    156        )
    157        events = c.receive_data(f.serialize())
    158 
    159        assert len(events) == 0
    160        assert not c.data_to_send()
    161 
    162    def test_receiving_altsvc_after_receiving_headers(self, frame_factory):
    163        """
    164        When an ALTSVC frame is received but the server has already sent
    165        headers it gets ignored.
    166        """
    167        c = h2.connection.H2Connection()
    168        c.initiate_connection()
    169        c.send_headers(stream_id=1, headers=self.example_request_headers)
    170 
    171        f = frame_factory.build_headers_frame(
    172            headers=self.example_response_headers
    173        )
    174        c.receive_data(f.serialize())
    175        c.clear_outbound_data_buffer()
    176 
    177        f = frame_factory.build_alt_svc_frame(
    178            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    179        )
    180        events = c.receive_data(f.serialize())
    181 
    182        assert len(events) == 0
    183        assert not c.data_to_send()
    184 
    185    def test_receiving_altsvc_on_closed_stream(self, frame_factory):
    186        """
    187        When an ALTSVC frame is received on a closed stream, we ignore it.
    188        """
    189        c = h2.connection.H2Connection()
    190        c.initiate_connection()
    191        c.send_headers(
    192            stream_id=1, headers=self.example_request_headers, end_stream=True
    193        )
    194 
    195        f = frame_factory.build_headers_frame(
    196            headers=self.example_response_headers,
    197            flags=['END_STREAM'],
    198        )
    199        c.receive_data(f.serialize())
    200        c.clear_outbound_data_buffer()
    201 
    202        f = frame_factory.build_alt_svc_frame(
    203            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    204        )
    205        events = c.receive_data(f.serialize())
    206 
    207        assert len(events) == 0
    208        assert not c.data_to_send()
    209 
    210    def test_receiving_altsvc_on_pushed_stream(self, frame_factory):
    211        """
    212        When an ALTSVC frame is received on a stream that the server pushed,
    213        the frame is accepted.
    214        """
    215        c = h2.connection.H2Connection()
    216        c.initiate_connection()
    217        c.send_headers(stream_id=1, headers=self.example_request_headers)
    218 
    219        f = frame_factory.build_push_promise_frame(
    220            stream_id=1,
    221            promised_stream_id=2,
    222            headers=self.example_request_headers
    223        )
    224        c.receive_data(f.serialize())
    225        c.clear_outbound_data_buffer()
    226 
    227        f = frame_factory.build_alt_svc_frame(
    228            stream_id=2, origin=b"", field=b'h2=":8000"; ma=60'
    229        )
    230        events = c.receive_data(f.serialize())
    231 
    232        assert len(events) == 1
    233        event = events[0]
    234 
    235        assert isinstance(event, h2.events.AlternativeServiceAvailable)
    236        assert event.origin == b"example.com"
    237        assert event.field_value == b'h2=":8000"; ma=60'
    238 
    239        # No data gets sent.
    240        assert not c.data_to_send()
    241 
    242    def test_cannot_send_explicit_alternative_service(self, frame_factory):
    243        """
    244        A client cannot send an explicit alternative service.
    245        """
    246        c = h2.connection.H2Connection()
    247        c.initiate_connection()
    248        c.send_headers(stream_id=1, headers=self.example_request_headers)
    249        c.clear_outbound_data_buffer()
    250 
    251        with pytest.raises(h2.exceptions.ProtocolError):
    252            c.advertise_alternative_service(
    253                field_value=b'h2=":8000"; ma=60',
    254                origin=b"example.com",
    255            )
    256 
    257    def test_cannot_send_implicit_alternative_service(self, frame_factory):
    258        """
    259        A client cannot send an implicit alternative service.
    260        """
    261        c = h2.connection.H2Connection()
    262        c.initiate_connection()
    263        c.send_headers(stream_id=1, headers=self.example_request_headers)
    264        c.clear_outbound_data_buffer()
    265 
    266        with pytest.raises(h2.exceptions.ProtocolError):
    267            c.advertise_alternative_service(
    268                field_value=b'h2=":8000"; ma=60',
    269                stream_id=1,
    270            )
    271 
    272 
    273 class TestRFC7838Server(object):
    274    """
    275    Tests that the server supports sending the RFC 7838 AltSvc frame.
    276    """
    277    example_request_headers = [
    278        (':authority', 'example.com'),
    279        (':path', '/'),
    280        (':scheme', 'https'),
    281        (':method', 'GET'),
    282    ]
    283    example_response_headers = [
    284        (u':status', u'200'),
    285        (u'server', u'fake-serv/0.1.0')
    286    ]
    287 
    288    server_config = h2.config.H2Configuration(client_side=False)
    289 
    290    def test_receiving_altsvc_as_server_stream_zero(self, frame_factory):
    291        """
    292        When an ALTSVC frame is received on stream zero and we are a server,
    293        we ignore it.
    294        """
    295        c = h2.connection.H2Connection(config=self.server_config)
    296        c.initiate_connection()
    297        c.receive_data(frame_factory.preamble())
    298        c.clear_outbound_data_buffer()
    299 
    300        f = frame_factory.build_alt_svc_frame(
    301            stream_id=0, origin=b"example.com", field=b'h2=":8000"; ma=60'
    302        )
    303        events = c.receive_data(f.serialize())
    304 
    305        assert len(events) == 0
    306        assert not c.data_to_send()
    307 
    308    def test_receiving_altsvc_as_server_on_stream(self, frame_factory):
    309        """
    310        When an ALTSVC frame is received on a stream and we are a server, we
    311        ignore it.
    312        """
    313        c = h2.connection.H2Connection(config=self.server_config)
    314        c.initiate_connection()
    315        c.receive_data(frame_factory.preamble())
    316 
    317        f = frame_factory.build_headers_frame(
    318            headers=self.example_request_headers
    319        )
    320        c.receive_data(f.serialize())
    321        c.clear_outbound_data_buffer()
    322 
    323        f = frame_factory.build_alt_svc_frame(
    324            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    325        )
    326        events = c.receive_data(f.serialize())
    327 
    328        assert len(events) == 0
    329        assert not c.data_to_send()
    330 
    331    def test_sending_explicit_alternative_service(self, frame_factory):
    332        """
    333        A server can send an explicit alternative service.
    334        """
    335        c = h2.connection.H2Connection(config=self.server_config)
    336        c.initiate_connection()
    337        c.receive_data(frame_factory.preamble())
    338        c.clear_outbound_data_buffer()
    339 
    340        c.advertise_alternative_service(
    341            field_value=b'h2=":8000"; ma=60',
    342            origin=b"example.com",
    343        )
    344 
    345        f = frame_factory.build_alt_svc_frame(
    346            stream_id=0, origin=b"example.com", field=b'h2=":8000"; ma=60'
    347        )
    348        assert c.data_to_send() == f.serialize()
    349 
    350    def test_sending_implicit_alternative_service(self, frame_factory):
    351        """
    352        A server can send an implicit alternative service.
    353        """
    354        c = h2.connection.H2Connection(config=self.server_config)
    355        c.initiate_connection()
    356        c.receive_data(frame_factory.preamble())
    357 
    358        f = frame_factory.build_headers_frame(
    359            headers=self.example_request_headers
    360        )
    361        c.receive_data(f.serialize())
    362        c.clear_outbound_data_buffer()
    363 
    364        c.advertise_alternative_service(
    365            field_value=b'h2=":8000"; ma=60',
    366            stream_id=1,
    367        )
    368 
    369        f = frame_factory.build_alt_svc_frame(
    370            stream_id=1, origin=b"", field=b'h2=":8000"; ma=60'
    371        )
    372        assert c.data_to_send() == f.serialize()
    373 
    374    def test_no_implicit_alternative_service_before_headers(self,
    375                                                            frame_factory):
    376        """
    377        If headers haven't been received yet, the server forbids sending an
    378        implicit alternative service.
    379        """
    380        c = h2.connection.H2Connection(config=self.server_config)
    381        c.initiate_connection()
    382        c.receive_data(frame_factory.preamble())
    383        c.clear_outbound_data_buffer()
    384 
    385        with pytest.raises(h2.exceptions.ProtocolError):
    386            c.advertise_alternative_service(
    387                field_value=b'h2=":8000"; ma=60',
    388                stream_id=1,
    389            )
    390 
    391    def test_no_implicit_alternative_service_after_response(self,
    392                                                            frame_factory):
    393        """
    394        If the server has sent response headers, hyper-h2 forbids sending an
    395        implicit alternative service.
    396        """
    397        c = h2.connection.H2Connection(config=self.server_config)
    398        c.initiate_connection()
    399        c.receive_data(frame_factory.preamble())
    400 
    401        f = frame_factory.build_headers_frame(
    402            headers=self.example_request_headers
    403        )
    404        c.receive_data(f.serialize())
    405        c.send_headers(stream_id=1, headers=self.example_response_headers)
    406        c.clear_outbound_data_buffer()
    407 
    408        with pytest.raises(h2.exceptions.ProtocolError):
    409            c.advertise_alternative_service(
    410                field_value=b'h2=":8000"; ma=60',
    411                stream_id=1,
    412            )
    413 
    414    def test_cannot_provide_origin_and_stream_id(self, frame_factory):
    415        """
    416        The user cannot provide both the origin and stream_id arguments when
    417        advertising alternative services.
    418        """
    419        c = h2.connection.H2Connection(config=self.server_config)
    420        c.initiate_connection()
    421        c.receive_data(frame_factory.preamble())
    422        f = frame_factory.build_headers_frame(
    423            headers=self.example_request_headers
    424        )
    425        c.receive_data(f.serialize())
    426 
    427        with pytest.raises(ValueError):
    428            c.advertise_alternative_service(
    429                field_value=b'h2=":8000"; ma=60',
    430                origin=b"example.com",
    431                stream_id=1,
    432            )
    433 
    434    def test_cannot_provide_unicode_altsvc_field(self, frame_factory):
    435        """
    436        The user cannot provide the field value for alternative services as a
    437        unicode string.
    438        """
    439        c = h2.connection.H2Connection(config=self.server_config)
    440        c.initiate_connection()
    441        c.receive_data(frame_factory.preamble())
    442 
    443        with pytest.raises(ValueError):
    444            c.advertise_alternative_service(
    445                field_value=u'h2=":8000"; ma=60',
    446                origin=b"example.com",
    447            )