示例#1
0
    def test_on_priority_updates(self):
        client_conn = Connection(
            self.client_stream, client_side=True, on_unhandled=mock.Mock())
        client_conn.initiate_connection()
        stream_id = client_conn.get_next_available_stream_id()
        client_conn.send_request(
            stream_id,
            HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        client_conn.send_priority_updates(
            stream_id, 0, 10, False)

        server_conn = Connection(
            self.server_stream, client_side=False,
            on_priority_updates=self.on_priority_updates,
            on_unhandled=mock.Mock())
        server_conn.initiate_connection()
        yield server_conn.read_bytes()
        self.assertIsNotNone(self.priority_updates)
        self.assertEqual(
            self.priority_updates,
            dict(stream_id=stream_id, depends_on=0, weight=10, exclusive=False))
示例#2
0
class TestHttp2Layer(ProxyAsyncTestCase):
    def setUp(self):
        super(TestHttp2Layer, self).setUp()
        self.asyncSetUp()
        self.src_events = []
        self.dest_events = []

    @gen_test
    def asyncSetUp(self):
        self.client_stream, src_stream = yield self.create_iostream_pair()
        dest_stream, self.server_stream = yield self.create_iostream_pair()

        server_state = ServerContext(config={},
                                     interceptor=mock.Mock(
                                         **{
                                             "publish.return_value": None,
                                             "request.return_value": None,
                                             "response.return_value": None,
                                         }))

        self.http_layer = Http2Layer(
            server_state,
            LayerContext(mode="socks",
                         src_stream=src_stream,
                         dest_stream=dest_stream))

    def record_src_event(self, *args):
        self.src_events.append(args)

    def record_dest_event(self, *args):
        self.dest_events.append(args)

    def ignore_event(self, *args):
        pass

    @coroutine
    def read_until_new_event(self, conn, events):
        curr_count = len(events)
        while curr_count == len(events):
            yield conn.read_bytes()

    @gen_test
    def test_req_and_resp(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_response=self.record_src_event,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_response(
            1,
            HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                         body=b"ccc"))

        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        result = yield result_future
        self.assertIsNotNone(result)
        self.assertIsInstance(result, LayerContext)

        self.assertEqual(len(self.src_events), 1)
        stream_id, response = self.src_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(response.code, "200")
        self.assertEqual(response.version, "HTTP/2")
        self.assertEqual(response.headers,
                         HttpHeaders([(":status", "200"), ("aaa", "bbb")]))
        self.assertEqual(response.body, b"ccc")

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, _ = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"), (":path", "/"), ("aaa", "bbb")]))

    @gen_test
    def test_req_with_priority_updated(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]),
            priority_weight=10,
            priority_depends_on=0,
            priority_exclusive=False)

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, priority_updated = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"), (":path", "/"), ("aaa", "bbb")]))
        self.assertIsNotNone(priority_updated)
        self.assertEqual(priority_updated.weight, 10)
        self.assertEqual(priority_updated.exclusive, False)
        self.assertEqual(priority_updated.depends_on, 0)

    @gen_test
    def test_push(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_response=self.record_src_event,
                                      on_push=self.record_src_event,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_pushed_stream(
            1, 2,
            HttpRequest(headers=[(":method", "GET"), (":path", "/resource")]))
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.server_conn.send_response(
            2,
            HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                         body=b"ccc"))
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future

        self.assertEqual(len(self.src_events), 2)
        stream_id, parent_stream_id, request = self.src_events[0]
        self.assertEqual(stream_id, 2)
        self.assertEqual(parent_stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/resource")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"), (":path", "/resource")]))

        stream_id, response = self.src_events[1]
        self.assertEqual(stream_id, 2)
        self.assertEqual(response.code, "200")
        self.assertEqual(response.version, "HTTP/2")
        self.assertEqual(response.headers,
                         HttpHeaders([(":status", "200"), ("aaa", "bbb")]))

    @gen_test
    def test_window_updates(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_window_updates=self.record_src_event,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_window_updates=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_window_updates(0, 100)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))
        self.client_conn.send_window_updates(1, 200)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_window_updates(1, 300)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        print self.src_events
        self.assertEqual(len(self.src_events), 1)
        self.assertEqual(self.src_events[0], (1, 300))
        self.assertEqual(len(self.dest_events), 2)
        self.assertEqual(self.dest_events[0], (0, 100))
        self.assertEqual(self.dest_events[1], (1, 200))

    @gen_test
    def test_priority_updated(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream,
            client_side=False,
            on_priority_updates=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))
        self.client_conn.send_priority_updates(1, 0, 10, False)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.dest_events), 1)
        self.assertEqual(self.dest_events[0], (1, 0, 10, False))

    @gen_test
    def test_reset(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_reset=self.record_src_event,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_reset=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_reset(1, 0)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_request(
            3,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_reset(3, 0)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.src_events), 1)
        self.assertEqual(self.src_events[0], (3, 0))
        self.assertEqual(len(self.dest_events), 3)  # NOTE: req, reset, req
        self.assertEqual(self.dest_events[1], (1, 0))

    @gen_test
    def test_src_send_terminate(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_terminate=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_terminate()
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.dest_events), 1)
        self.assertEqual(self.dest_events[0], (None, 0, 0))

    @gen_test
    def test_dest_send_terminate(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_terminate=self.record_src_event,
                                      on_settings=self.record_src_event,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        # NOTE: because hyper-h2 will always send SettingsChanged when init
        # Than client will receive two setting frame from destination and server
        yield self.read_until_new_event(self.client_conn, self.src_events)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.server_conn.send_terminate()
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.src_events), 3)
        self.assertEqual(self.src_events[2], (None, 0, 0))

    @gen_test
    def test_safe_mapping_id(self):
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.assertEqual(
            self.http_layer.safe_mapping_id(self.http_layer.src_to_dest_ids,
                                            1), 0)

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.assertEqual(
            self.http_layer.safe_mapping_id(self.http_layer.src_to_dest_ids,
                                            1), 1)

        self.client_stream.close()
        self.server_stream.close()
        yield result_future

    @gen_test
    def test_replay(self):
        self.http_layer.context.mode = "replay"
        self.client_conn = Connection(self.client_stream,
                                      client_side=True,
                                      on_unhandled=self.ignore_event)
        self.server_conn = Connection(self.server_stream,
                                      client_side=False,
                                      on_request=self.record_dest_event,
                                      on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1,
            HttpRequest(headers=[(":method", "GET"), (":path",
                                                      "/"), ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_response(
            1,
            HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                         body=b"ccc"))

        result = yield result_future

        self.assertIsNotNone(result)
        self.assertIsInstance(result, LayerContext)

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, _ = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"), (":path", "/"), ("aaa", "bbb")]))

    def tearDown(self):
        self.client_stream.close()
        self.server_stream.close()
        self.http_layer.src_stream.close()
        self.http_layer.dest_stream.close()
示例#3
0
class Http2Layer(ApplicationLayer):
    '''
    Http2Layer: Responsible for handling the http2 request and response.
    '''
    def __init__(self, server_state, context):
        super(Http2Layer, self).__init__(server_state, context)
        self.src_conn = Connection(
            self.src_stream, client_side=False,
            conn_type="source",
            on_request=self.on_request,
            on_settings=self.on_src_settings,
            on_window_updates=self.on_src_window_updates,
            on_priority_updates=self.on_src_priority_updates,
            on_reset=self.on_src_reset,
            on_terminate=self.on_src_terminate,
            readonly=(context.mode == "replay"))
        self.dest_conn = Connection(
            self.dest_stream, client_side=True,
            conn_type="destination",
            on_response=self.on_response,
            on_push=self.on_push,
            on_settings=self.on_dest_settings,
            on_window_updates=self.on_dest_window_updates,
            on_terminate=self.on_dest_terminate,
            on_reset=self.on_dest_reset)
        self.streams = dict()
        self.src_to_dest_ids = dict([(0, 0)])
        self.dest_to_src_ids = dict([(0, 0)])
        self._future = concurrent.Future()

    @gen.coroutine
    def process_and_return_context(self):
        yield self._init_h2_connection()
        self.src_stream.read_until_close(
            streaming_callback=self.src_conn.receive)
        self.src_stream.set_close_callback(self.on_src_close)

        self.dest_stream.read_until_close(
            streaming_callback=self.dest_conn.receive)
        self.dest_stream.set_close_callback(self.on_dest_close)
        result = yield self._future
        raise gen.Return(result)

    @gen.coroutine
    def _init_h2_connection(self):
        self.dest_conn.initiate_connection()
        yield self.dest_conn.flush()
        self.src_conn.initiate_connection()
        yield self.src_conn.flush()

    def on_src_close(self):
        logger.debug("{0}: src stream closed".format(self))
        self.dest_stream.close()
        self.layer_finish()

    def on_dest_close(self):
        logger.debug("{0}: dest stream closed".format(self))
        self.src_stream.close()
        self.layer_finish()

    def layer_finish(self):
        if self._future.running():
            self._future.set_result(self.context)

    def update_ids(self, src_stream_id, dest_stream_id):
        self.src_to_dest_ids[src_stream_id] = dest_stream_id
        self.dest_to_src_ids[dest_stream_id] = src_stream_id

    def on_request(self, stream_id, request, priority_updated):
        dest_stream_id = self.dest_conn.get_next_available_stream_id()
        self.update_ids(stream_id, dest_stream_id)

        if priority_updated:
            priority_weight = priority_updated.weight
            priority_exclusive = priority_updated.exclusive
            priority_depends_on = self.safe_mapping_id(
                self.src_to_dest_ids, priority_updated.depends_on)
        else:
            priority_weight = None
            priority_exclusive = None
            priority_depends_on = None

        stream = Stream(self, self.context, stream_id, dest_stream_id)
        stream.on_request(
            request,
            priority_weight=priority_weight,
            priority_exclusive=priority_exclusive,
            priority_depends_on=priority_depends_on)
        self.streams[stream_id] = stream

    def on_push(self, pushed_stream_id, parent_stream_id, request):
        self.update_ids(pushed_stream_id, pushed_stream_id)
        target_parent_stream_id = self.dest_to_src_ids[parent_stream_id]

        stream = Stream(self, self.context, pushed_stream_id, pushed_stream_id)
        stream.on_push(request, target_parent_stream_id)
        self.streams[pushed_stream_id] = stream

    def on_response(self, stream_id, response):
        src_stream_id = self.dest_to_src_ids[stream_id]
        self.streams[src_stream_id].on_response(response)

        self.on_finish(src_stream_id)

    def on_finish(self, src_stream_id):
        stream = self.streams[src_stream_id]

        self.interceptor.publish(
            layer_context=self.context, request=stream.request,
            response=stream.response)
        del self.streams[src_stream_id]

        if self.context.mode == "replay":
            self.src_stream.close()
            self.dest_stream.close()

    def on_src_settings(self, changed_settings):
        new_settings = {
            id: cs.new_value for (id, cs) in changed_settings.iteritems()
        }
        self.dest_conn.send_update_settings(new_settings)

    def on_dest_settings(self, changed_settings):
        new_settings = {
            id: cs.new_value for (id, cs) in changed_settings.iteritems()
        }
        self.src_conn.send_update_settings(new_settings)

    def on_src_window_updates(self, stream_id, delta):
        target_stream_id = self.safe_mapping_id(self.src_to_dest_ids, stream_id)
        self.dest_conn.send_window_updates(target_stream_id, delta)

    def on_dest_window_updates(self, stream_id, delta):
        target_stream_id = self.safe_mapping_id(self.dest_to_src_ids, stream_id)
        self.src_conn.send_window_updates(target_stream_id, delta)

    def on_src_priority_updates(self, stream_id, depends_on,
                                weight, exclusive):
        target_stream_id = self.safe_mapping_id(
            self.src_to_dest_ids, stream_id)
        target_depends_on = self.safe_mapping_id(
            self.src_to_dest_ids, depends_on)
        if target_stream_id:
            self.dest_conn.send_priority_updates(
                target_stream_id, target_depends_on, weight, exclusive)

    def safe_mapping_id(self, ids, stream_id):
        if stream_id in ids:
            return ids[stream_id]
        return 0

    def on_src_reset(self, stream_id, error_code):
        target_stream_id = self.src_to_dest_ids[stream_id]
        self.dest_conn.send_reset(target_stream_id, error_code)

    def on_dest_reset(self, stream_id, error_code):
        target_stream_id = self.dest_to_src_ids[stream_id]
        self.src_conn.send_reset(target_stream_id, error_code)

    def on_src_terminate(self, additional_data, error_code, last_stream_id):
        self.dest_conn.send_terminate(
            error_code=error_code,
            additional_data=additional_data,
            last_stream_id=last_stream_id)

    def on_dest_terminate(self, additional_data, error_code, last_stream_id):
        self.src_conn.send_terminate(
            error_code=error_code,
            additional_data=additional_data,
            last_stream_id=last_stream_id)
示例#4
0
class TestHttp2Layer(ProxyAsyncTestCase):
    def setUp(self):
        super(TestHttp2Layer, self).setUp()
        self.asyncSetUp()
        self.src_events = []
        self.dest_events = []

    @gen_test
    def asyncSetUp(self):
        self.client_stream, src_stream = yield self.create_iostream_pair()
        dest_stream, self.server_stream = yield self.create_iostream_pair()

        server_state = ServerContext(
            config={},
            interceptor=mock.Mock(**{
                "publish.return_value": None,
                "request.return_value": None,
                "response.return_value": None,
            })
        )

        self.http_layer = Http2Layer(
            server_state,
            LayerContext(mode="socks",
                         src_stream=src_stream,
                         dest_stream=dest_stream))

    def record_src_event(self, *args):
        self.src_events.append(args)

    def record_dest_event(self, *args):
        self.dest_events.append(args)

    def ignore_event(self, *args):
        pass

    @coroutine
    def read_until_new_event(self, conn, events):
        curr_count = len(events)
        while curr_count == len(events):
            yield conn.read_bytes()

    @gen_test
    def test_req_and_resp(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_response=self.record_src_event,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_response(
            1, HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                            body=b"ccc"))

        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        result = yield result_future
        self.assertIsNotNone(result)
        self.assertIsInstance(result, LayerContext)

        self.assertEqual(len(self.src_events), 1)
        stream_id, response = self.src_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(response.code, "200")
        self.assertEqual(response.version, "HTTP/2")
        self.assertEqual(
            response.headers,
            HttpHeaders([(":status", "200"),
                         ("aaa", "bbb")]))
        self.assertEqual(response.body, b"ccc")

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, _ = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"),
                         (":path", "/"),
                         ("aaa", "bbb")]))

    @gen_test
    def test_req_with_priority_updated(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]),
            priority_weight=10,
            priority_depends_on=0,
            priority_exclusive=False)

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, priority_updated = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"),
                         (":path", "/"),
                         ("aaa", "bbb")]))
        self.assertIsNotNone(priority_updated)
        self.assertEqual(priority_updated.weight, 10)
        self.assertEqual(priority_updated.exclusive, False)
        self.assertEqual(priority_updated.depends_on, 0)

    @gen_test
    def test_push(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_response=self.record_src_event,
            on_push=self.record_src_event,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_pushed_stream(1, 2, HttpRequest(
            headers=[(":method", "GET"), (":path", "/resource")]))
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.server_conn.send_response(
            2, HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                            body=b"ccc"))
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future

        self.assertEqual(len(self.src_events), 2)
        stream_id, parent_stream_id, request = self.src_events[0]
        self.assertEqual(stream_id, 2)
        self.assertEqual(parent_stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/resource")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"),
                         (":path", "/resource")]))

        stream_id, response = self.src_events[1]
        self.assertEqual(stream_id, 2)
        self.assertEqual(response.code, "200")
        self.assertEqual(response.version, "HTTP/2")
        self.assertEqual(
            response.headers,
            HttpHeaders([(":status", "200"),
                         ("aaa", "bbb")]))

    @gen_test
    def test_window_updates(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_window_updates=self.record_src_event,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_window_updates=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_window_updates(0, 100)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        self.client_conn.send_window_updates(1, 200)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_window_updates(1, 300)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        print self.src_events
        self.assertEqual(len(self.src_events), 1)
        self.assertEqual(self.src_events[0], (1, 300))
        self.assertEqual(len(self.dest_events), 2)
        self.assertEqual(self.dest_events[0], (0, 100))
        self.assertEqual(self.dest_events[1], (1, 200))

    @gen_test
    def test_priority_updated(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_priority_updates=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        self.client_conn.send_priority_updates(1, 0, 10, False)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.dest_events), 1)
        self.assertEqual(self.dest_events[0], (1, 0, 10, False))

    @gen_test
    def test_reset(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_reset=self.record_src_event,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_reset=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_reset(1, 0)
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_conn.send_request(
            3, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_reset(3, 0)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.src_events), 1)
        self.assertEqual(self.src_events[0], (3, 0))
        self.assertEqual(len(self.dest_events), 3)  # NOTE: req, reset, req
        self.assertEqual(self.dest_events[1], (1, 0))

    @gen_test
    def test_src_send_terminate(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_terminate=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_terminate()
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.dest_events), 1)
        self.assertEqual(self.dest_events[0], (None, 0, 0))

    @gen_test
    def test_dest_send_terminate(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_terminate=self.record_src_event,
            on_settings=self.record_src_event,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        # NOTE: because hyper-h2 will always send SettingsChanged when init
        # Than client will receive two setting frame from destination and server
        yield self.read_until_new_event(self.client_conn, self.src_events)
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.server_conn.send_terminate()
        yield self.read_until_new_event(self.client_conn, self.src_events)

        self.client_stream.close()
        self.server_stream.close()

        yield result_future
        self.assertEqual(len(self.src_events), 3)
        self.assertEqual(self.src_events[2], (None, 0, 0))

    @gen_test
    def test_safe_mapping_id(self):
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.assertEqual(
            self.http_layer.safe_mapping_id(self.http_layer.src_to_dest_ids, 1), 0)

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))
        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.assertEqual(
            self.http_layer.safe_mapping_id(self.http_layer.src_to_dest_ids, 1), 1)

        self.client_stream.close()
        self.server_stream.close()
        yield result_future

    @gen_test
    def test_replay(self):
        self.http_layer.context.mode = "replay"
        self.client_conn = Connection(
            self.client_stream, client_side=True,
            on_unhandled=self.ignore_event)
        self.server_conn = Connection(
            self.server_stream, client_side=False,
            on_request=self.record_dest_event,
            on_unhandled=self.ignore_event)

        result_future = self.http_layer.process_and_return_context()
        self.client_conn.initiate_connection()
        self.server_conn.initiate_connection()

        self.client_conn.send_request(
            1, HttpRequest(headers=[
                (":method", "GET"),
                (":path", "/"),
                ("aaa", "bbb")]))

        yield self.read_until_new_event(self.server_conn, self.dest_events)

        self.server_conn.send_response(
            1, HttpResponse(headers=[(":status", "200"), ("aaa", "bbb")],
                            body=b"ccc"))

        result = yield result_future

        self.assertIsNotNone(result)
        self.assertIsInstance(result, LayerContext)

        self.assertEqual(len(self.dest_events), 1)
        stream_id, request, _ = self.dest_events[0]
        self.assertEqual(stream_id, 1)
        self.assertEqual(request.method, "GET")
        self.assertEqual(request.path, "/")
        self.assertEqual(request.version, "HTTP/2")
        self.assertEqual(
            request.headers,
            HttpHeaders([(":method", "GET"),
                         (":path", "/"),
                         ("aaa", "bbb")]))

    def tearDown(self):
        self.client_stream.close()
        self.server_stream.close()
        self.http_layer.src_stream.close()
        self.http_layer.dest_stream.close()