Beispiel #1
0
    def test_on_connection_closed(self):
        client_conn = Connection(h11.CLIENT,
                                 self.client_stream,
                                 on_response=self.on_response)
        client_conn.send_request(
            HttpRequest(method="GET",
                        path="/",
                        headers=[("Host", "localhost"),
                                 ("Connection", "close")]))

        server_conn = Connection(h11.SERVER,
                                 self.server_stream,
                                 on_request=self.on_request)
        yield server_conn.read_bytes()
        server_conn.send_response(
            HttpResponse(version="HTTP/1.1",
                         code="200",
                         reason="OK",
                         headers=[("Host", "localhost"),
                                  ("Content-Length", "4")],
                         body=b"Yaya"))

        yield client_conn.read_bytes()
        self.assertTrue(self.client_stream.closed())
        self.assertTrue(self.server_stream.closed())
Beispiel #2
0
    def test_on_info_response(self):
        client_conn = Connection(h11.CLIENT,
                                 self.client_stream,
                                 on_info_response=self.on_response)
        client_conn.send_request(
            HttpRequest(method="GET",
                        path="/chat",
                        version="HTTP/1.1",
                        headers=[("Host", "localhost"),
                                 ("Upgrade", "websocket")]))

        server_conn = Connection(h11.SERVER,
                                 self.server_stream,
                                 on_request=self.on_request)
        yield server_conn.read_bytes()
        server_conn.send_info_response(
            HttpResponse(version="HTTP/1.1",
                         code="101",
                         reason="Protocol Upgrade",
                         headers=[("Host", "localhost"),
                                  ("Upgrade", "websocket")]))

        yield client_conn.read_bytes()

        self.assertIsNotNone(self.response)
        self.assertEqual(
            self.response.headers,
            HttpHeaders([("host", "localhost"), ("upgrade", "websocket")]))
        self.assertEqual(self.response.code, "101")
        self.assertEqual(self.response.reason, "Protocol Upgrade")
        self.assertEqual(self.response.version, "HTTP/1.1")
Beispiel #3
0
    def test_parse_version(self):
        self.assertEqual(
            Connection(h11.CLIENT, None)._parse_version(None), "HTTP/1.1")

        http_content = mock.Mock()
        http_content.http_version = "1.1"
        self.assertEqual(
            Connection(h11.CLIENT, None)._parse_version(http_content),
            "HTTP/1.1")
Beispiel #4
0
    def test_on_request(self):
        client_conn = Connection(h11.CLIENT, self.client_stream)
        client_conn.send_request(HttpRequest(
            method="GET", path="/", headers=[("Host", "localhost")]))

        server_conn = Connection(
            h11.SERVER, self.server_stream, on_request=self.on_request)
        yield server_conn.read_bytes()

        self.assertIsNotNone(self.request)
        self.assertEqual(self.request.headers,
                         HttpHeaders([("host", "localhost")]))
        self.assertEqual(self.request.method, "GET")
        self.assertEqual(self.request.path, "/")
        self.assertEqual(self.request.version, "HTTP/1.1")
Beispiel #5
0
 def __init__(self, server_state, context):
     super(Http1Layer, self).__init__(server_state, context)
     self.src_conn = Connection(h11.SERVER,
                                self.src_stream,
                                conn_type="src",
                                readonly=(context.mode == "replay"),
                                on_request=self.on_request)
     self.dest_conn = Connection(h11.CLIENT,
                                 self.dest_stream,
                                 conn_type="dest",
                                 on_response=self.on_response,
                                 on_info_response=self.on_info_response)
     self.req = None
     self.resp = None
     self.switch_protocol = False
Beispiel #6
0
 def __init__(self, server_state, context):
     super(Http1Layer, self).__init__(server_state, context)
     self.src_conn = Connection(
         h11.SERVER,
         self.src_stream,
         conn_type="src",
         readonly=(context.mode == "replay"),
         on_request=self.on_request)
     self.dest_conn = Connection(
         h11.CLIENT,
         self.dest_stream,
         conn_type="dest",
         on_response=self.on_response,
         on_info_response=self.on_info_response)
     self.req = None
     self.resp = None
     self.switch_protocol = False
Beispiel #7
0
    def test_on_response(self):
        server_conn = Connection(h11.SERVER, self.server_stream)
        server_conn.send_response(HttpResponse(
            version="HTTP/1.1", code="200", reason="OK",
            headers=[("Host", "localhost"),
                     ("Content-Length", "1")],
            body=b"A"))

        client_conn = Connection(
            h11.CLIENT, self.client_stream, on_response=self.on_response)
        yield client_conn.read_bytes()

        self.assertIsNotNone(self.response)
        self.assertEqual(self.response.headers,
                         HttpHeaders([("host", "localhost"),
                                      ("content-length", "1")]))
        self.assertEqual(self.response.code, "200")
        self.assertEqual(self.response.reason, "OK")
        self.assertEqual(self.response.version, "HTTP/1.1")
        self.assertEqual(self.response.body, b"A")
Beispiel #8
0
    def test_on_connection_closed(self):
        client_conn = Connection(
            h11.CLIENT, self.client_stream, on_response=self.on_response)
        client_conn.send_request(HttpRequest(
            method="GET", path="/",
            headers=[("Host", "localhost"), ("Connection", "close")]))

        server_conn = Connection(
            h11.SERVER, self.server_stream, on_request=self.on_request)
        yield server_conn.read_bytes()
        server_conn.send_response(HttpResponse(
            version="HTTP/1.1", code="200", reason="OK",
            headers=[("Host", "localhost"),
                     ("Content-Length", "4")],
            body=b"Yaya"))

        yield client_conn.read_bytes()
        self.assertTrue(self.client_stream.closed())
        self.assertTrue(self.server_stream.closed())
Beispiel #9
0
    def test_on_request(self):
        client_conn = Connection(h11.CLIENT, self.client_stream)
        client_conn.send_request(
            HttpRequest(method="GET",
                        path="/",
                        headers=[("Host", "localhost")]))

        server_conn = Connection(h11.SERVER,
                                 self.server_stream,
                                 on_request=self.on_request)
        yield server_conn.read_bytes()

        self.assertIsNotNone(self.request)
        self.assertEqual(self.request.headers,
                         HttpHeaders([("host", "localhost")]))
        self.assertEqual(self.request.method, "GET")
        self.assertEqual(self.request.path, "/")
        self.assertEqual(self.request.version, "HTTP/1.1")
Beispiel #10
0
    def test_on_info_response(self):
        client_conn = Connection(
            h11.CLIENT, self.client_stream, on_info_response=self.on_response)
        client_conn.send_request(HttpRequest(
            method="GET", path="/chat", version="HTTP/1.1",
            headers=[("Host", "localhost"), ("Upgrade", "websocket")]))

        server_conn = Connection(h11.SERVER, self.server_stream, on_request=self.on_request)
        yield server_conn.read_bytes()
        server_conn.send_info_response(HttpResponse(
            version="HTTP/1.1", code="101", reason="Protocol Upgrade",
            headers=[("Host", "localhost"),
                     ("Upgrade", "websocket")]))

        yield client_conn.read_bytes()

        self.assertIsNotNone(self.response)
        self.assertEqual(self.response.headers,
                         HttpHeaders([("host", "localhost"),
                                      ("upgrade", "websocket")]))
        self.assertEqual(self.response.code, "101")
        self.assertEqual(self.response.reason, "Protocol Upgrade")
        self.assertEqual(self.response.version, "HTTP/1.1")
Beispiel #11
0
    def test_on_response(self):
        server_conn = Connection(h11.SERVER, self.server_stream)
        server_conn.send_response(
            HttpResponse(version="HTTP/1.1",
                         code="200",
                         reason="OK",
                         headers=[("Host", "localhost"),
                                  ("Content-Length", "1")],
                         body=b"A"))

        client_conn = Connection(h11.CLIENT,
                                 self.client_stream,
                                 on_response=self.on_response)
        yield client_conn.read_bytes()

        self.assertIsNotNone(self.response)
        self.assertEqual(
            self.response.headers,
            HttpHeaders([("host", "localhost"), ("content-length", "1")]))
        self.assertEqual(self.response.code, "200")
        self.assertEqual(self.response.reason, "OK")
        self.assertEqual(self.response.version, "HTTP/1.1")
        self.assertEqual(self.response.body, b"A")
Beispiel #12
0
class Http1Layer(ApplicationLayer, DestStreamCreatorMixin):
    def __init__(self, server_state, context):
        super(Http1Layer, self).__init__(server_state, context)
        self.src_conn = Connection(
            h11.SERVER,
            self.src_stream,
            conn_type="src",
            readonly=(context.mode == "replay"),
            on_request=self.on_request)
        self.dest_conn = Connection(
            h11.CLIENT,
            self.dest_stream,
            conn_type="dest",
            on_response=self.on_response,
            on_info_response=self.on_info_response)
        self.req = None
        self.resp = None
        self.switch_protocol = False

    @gen.coroutine
    def process_and_return_context(self):
        while not self.finished():
            self.req = None
            self.resp = None
            try:
                yield self.read_request()
                yield self.handle_http_proxy()
                self.send_request()
                yield self.read_response()
                self.send_response()
            except SrcStreamClosedError:
                if self.dest_stream:
                    self.dest_stream.close()
                self.context.done = True
                if self.req:
                    raise
            except DestStreamClosedError:
                self.src_stream.close()
                raise
            except SwitchToTunnelHttpProxy:
                break

        if self.switch_protocol:
            self.context.scheme = self.req.headers["Upgrade"]
        raise gen.Return(self.context)

    @gen.coroutine
    def read_request(self):
        # NOTE: run first request to handle protocol change
        logger.debug("{0} wait for request".format(self))
        while not self.req:
            try:
                data = yield self.src_stream.read_bytes(
                    self.src_stream.max_buffer_size, partial=True)
            except StreamClosedError:
                raise SrcStreamClosedError(detail="read request failed")
            else:
                self.src_conn.receive(data, raise_exception=True)
        logger.debug("{0} received request: {1}".format(self, self.req))

    @gen.coroutine
    def read_response(self):
        logger.debug("{0} wait for response".format(self))
        while not self.resp:
            try:
                data = yield self.dest_stream.read_bytes(
                    self.dest_stream.max_buffer_size, partial=True)
            except StreamClosedError:
                # NOTE: for HTTP protocol, there is some condition that response finish when they didn't send data
                # It may happen when there is no "Content-Length" or "Content-Encoding: chunked" defined in there header
                self.dest_conn.receive(b"", raise_exception=False)
                break
            else:
                self.dest_conn.receive(data, raise_exception=True)
        logger.debug("{0} received response: {1}".format(self, self.resp))

    def on_request(self, request):
        plugin_result = self.interceptor.request(
            layer_context=self.context, request=request)

        self.req = plugin_result.request if plugin_result else request

    def send_request(self):
        try:
            self.dest_conn.send_request(self.req)
        except StreamClosedError:
            raise DestStreamClosedError(detail="send request failed with {0}".format(
                _wrap_req_path(self.context, self.req)))

    def on_response(self, response):
        plugin_result = self.interceptor.response(
            layer_context=self.context,
            request=self.req, response=response)

        self.resp = plugin_result.response if plugin_result else response

    def send_response(self):
        try:
            if int(self.resp.code) in range(200, 600):
                self.src_conn.send_response(self.resp)
                self.finish()
            else:
                self.src_conn.send_info_response(self.resp)
                self.finish(switch_protocol=True)
        except StreamClosedError:
            raise SrcStreamClosedError(detail="send response failed {0}".format(
                _wrap_req_path(self.context, self.req)))

    def on_info_response(self, response):
        plugin_result = self.interceptor.response(
            layer_context=self.context,
            request=self.req, response=response)
        self.resp = plugin_result.response if plugin_result else response

    def finished(self):
        return (self.switch_protocol or
                self.src_stream.closed() or
                (self.dest_stream and self.dest_stream.closed()))

    def finish(self, switch_protocol=False):
        self.interceptor.publish(
            layer_context=self.context,
            request=self.req, response=self.resp)
        if (self.context.mode == "replay" or
                self.src_conn.closed() or
                self.dest_conn.closed()):
            self.src_stream.close()
            self.dest_stream.close()
            self.context.done = True
        elif switch_protocol:
            self.switch_protocol = True
        else:
            self.src_conn.start_next_cycle()
            self.dest_conn.start_next_cycle()

    @gen.coroutine
    def handle_http_proxy(self):
        if self.is_tunnel_http_proxy():
            logger.debug("{0} proxy tunnel to {1}".format(self, self.req.path))
            scheme, host, port = parse_tunnel_proxy_path(self.req.path)
            yield self.connect_to_dest(scheme, (host, port))
            self.src_conn.send_response(HttpResponse(
                code="200",
                reason="OK", version="HTTP/1.1"))
            raise SwitchToTunnelHttpProxy
        elif self.is_normal_http_proxy():
            logger.debug("{0} proxy to {1}".format(self, self.req.path))
            scheme, host, port, path = parse_proxy_path(self.req.path)
            self.req.path = path
            yield self.connect_to_dest(scheme, (host, port))
            self.dest_conn.io_stream = self.dest_stream
        else:
            raise gen.Return(None)

    def is_tunnel_http_proxy(self):
        return self.req.method == "CONNECT"

    def is_normal_http_proxy(self):
        return (self.req.path.startswith("http://") or
                self.req.path.startswith("https://"))

    @gen.coroutine
    def connect_to_dest(self, scheme, addr):
        if addr != (self.context.host, self.context.port):
            logger.debug("{0} proxy to new connection {1}".format(self, addr))
            if self.dest_stream:
                self.dest_stream.close()

            dest_stream = yield self.create_dest_stream(addr)
            self.context.dest_stream = dest_stream
            self.context.scheme = scheme
            self.context.host = addr[0]
            self.context.port = addr[1]
            logger.debug("{0} proxy to new connection success".format(self))
        else:
            logger.debug("{0} proxy to same connection".format(self))
Beispiel #13
0
class Http1Layer(ApplicationLayer, DestStreamCreatorMixin):
    def __init__(self, server_state, context):
        super(Http1Layer, self).__init__(server_state, context)
        self.src_conn = Connection(h11.SERVER,
                                   self.src_stream,
                                   conn_type="src",
                                   readonly=(context.mode == "replay"),
                                   on_request=self.on_request)
        self.dest_conn = Connection(h11.CLIENT,
                                    self.dest_stream,
                                    conn_type="dest",
                                    on_response=self.on_response,
                                    on_info_response=self.on_info_response)
        self.req = None
        self.resp = None
        self.switch_protocol = False

    @gen.coroutine
    def process_and_return_context(self):
        while not self.finished():
            self.req = None
            self.resp = None
            try:
                yield self.read_request()
                yield self.handle_http_proxy()
                self.send_request()
                yield self.read_response()
                self.send_response()
            except SrcStreamClosedError:
                if self.dest_stream:
                    self.dest_stream.close()
                self.context.done = True
                if self.req:
                    raise
            except DestStreamClosedError:
                self.src_stream.close()
                raise
            except SwitchToTunnelHttpProxy:
                break

        if self.switch_protocol:
            self.context.scheme = self.req.headers["Upgrade"]
        raise gen.Return(self.context)

    @gen.coroutine
    def read_request(self):
        # NOTE: run first request to handle protocol change
        logger.debug("{0} wait for request".format(self))
        while not self.req:
            try:
                data = yield self.src_stream.read_bytes(
                    self.src_stream.max_buffer_size, partial=True)
            except StreamClosedError:
                raise SrcStreamClosedError(detail="read request failed")
            else:
                self.src_conn.receive(data, raise_exception=True)
        logger.debug("{0} received request: {1}".format(self, self.req))

    @gen.coroutine
    def read_response(self):
        logger.debug("{0} wait for response".format(self))
        while not self.resp:
            try:
                data = yield self.dest_stream.read_bytes(
                    self.dest_stream.max_buffer_size, partial=True)
            except StreamClosedError:
                # NOTE: for HTTP protocol, there is some condition that response finish when they didn't send data
                # It may happen when there is no "Content-Length" or "Content-Encoding: chunked" defined in there header
                self.dest_conn.receive(b"", raise_exception=False)
                break
            else:
                self.dest_conn.receive(data, raise_exception=True)
        logger.debug("{0} received response: {1}".format(self, self.resp))

    def on_request(self, request):
        plugin_result = self.interceptor.request(layer_context=self.context,
                                                 request=request)

        self.req = plugin_result.request if plugin_result else request

    def send_request(self):
        try:
            self.dest_conn.send_request(self.req)
        except StreamClosedError:
            raise DestStreamClosedError(
                detail="send request failed with {0}".format(
                    _wrap_req_path(self.context, self.req)))

    def on_response(self, response):
        plugin_result = self.interceptor.response(layer_context=self.context,
                                                  request=self.req,
                                                  response=response)

        self.resp = plugin_result.response if plugin_result else response

    def send_response(self):
        try:
            if int(self.resp.code) in range(200, 600):
                self.src_conn.send_response(self.resp)
                self.finish()
            else:
                self.src_conn.send_info_response(self.resp)
                self.finish(switch_protocol=True)
        except StreamClosedError:
            raise SrcStreamClosedError(
                detail="send response failed {0}".format(
                    _wrap_req_path(self.context, self.req)))

    def on_info_response(self, response):
        plugin_result = self.interceptor.response(layer_context=self.context,
                                                  request=self.req,
                                                  response=response)
        self.resp = plugin_result.response if plugin_result else response

    def finished(self):
        return (self.switch_protocol or self.src_stream.closed()
                or (self.dest_stream and self.dest_stream.closed()))

    def finish(self, switch_protocol=False):
        self.interceptor.publish(layer_context=self.context,
                                 request=self.req,
                                 response=self.resp)
        if (self.context.mode == "replay" or self.src_conn.closed()
                or self.dest_conn.closed()):
            self.src_stream.close()
            self.dest_stream.close()
            self.context.done = True
        elif switch_protocol:
            self.switch_protocol = True
        else:
            self.src_conn.start_next_cycle()
            self.dest_conn.start_next_cycle()

    @gen.coroutine
    def handle_http_proxy(self):
        if self.is_tunnel_http_proxy():
            logger.debug("{0} proxy tunnel to {1}".format(self, self.req.path))
            scheme, host, port = parse_tunnel_proxy_path(self.req.path)
            yield self.connect_to_dest(scheme, (host, port))
            self.src_conn.send_response(
                HttpResponse(code="200", reason="OK", version="HTTP/1.1"))
            raise SwitchToTunnelHttpProxy
        elif self.is_normal_http_proxy():
            logger.debug("{0} proxy to {1}".format(self, self.req.path))
            scheme, host, port, path = parse_proxy_path(self.req.path)
            self.req.path = path
            yield self.connect_to_dest(scheme, (host, port))
            self.dest_conn.io_stream = self.dest_stream
        else:
            raise gen.Return(None)

    def is_tunnel_http_proxy(self):
        return self.req.method == "CONNECT"

    def is_normal_http_proxy(self):
        return (self.req.path.startswith("http://")
                or self.req.path.startswith("https://"))

    @gen.coroutine
    def connect_to_dest(self, scheme, addr):
        if addr != (self.context.host, self.context.port):
            logger.debug("{0} proxy to new connection {1}".format(self, addr))
            if self.dest_stream:
                self.dest_stream.close()

            dest_stream = yield self.create_dest_stream(addr)
            self.context.dest_stream = dest_stream
            self.context.scheme = scheme
            self.context.host = addr[0]
            self.context.port = addr[1]
            logger.debug("{0} proxy to new connection success".format(self))
        else:
            logger.debug("{0} proxy to same connection".format(self))