Exemple #1
0
def test_response_trailers(tctx: Context, open_h2_server_conn: Server, stream):
    playbook, cff = start_h2_client(tctx)
    tctx.server = open_h2_server_conn
    sff = FrameFactory()

    def enable_streaming(flow: HTTPFlow):
        flow.response.stream = bool(stream)

    flow = Placeholder(HTTPFlow)
    (playbook >> DataReceived(
        tctx.client,
        cff.build_headers_frame(example_request_headers,
                                flags=["END_STREAM"]).serialize()) <<
     http.HttpRequestHeadersHook(flow) >> reply() << http.HttpRequestHook(flow)
     >> reply() << SendData(tctx.server, Placeholder(bytes))
     # a conforming h2 server would send settings first, we disregard this for now.
     >> DataReceived(
         tctx.server,
         sff.build_headers_frame(example_response_headers).serialize() +
         sff.build_data_frame(b"Hello, World!").serialize()) <<
     http.HttpResponseHeadersHook(flow) >> reply(side_effect=enable_streaming))
    if stream:
        playbook << SendData(
            tctx.client,
            cff.build_headers_frame(example_response_headers).serialize() +
            cff.build_data_frame(b"Hello, World!").serialize())
    assert (playbook >> DataReceived(
        tctx.server,
        sff.build_headers_frame(example_response_trailers,
                                flags=["END_STREAM"]).serialize()) <<
            http.HttpResponseHook(flow))
    assert flow().response.trailers
    del flow().response.trailers["resp-trailer-a"]
    if stream:
        assert (playbook >> reply() << SendData(
            tctx.client,
            cff.build_headers_frame(example_response_trailers[1:],
                                    flags=["END_STREAM"]).serialize()))
    else:
        assert (playbook >> reply() << SendData(
            tctx.client,
            cff.build_headers_frame(example_response_headers).serialize() +
            cff.build_data_frame(b"Hello, World!").serialize() +
            cff.build_headers_frame(example_response_trailers[1:],
                                    flags=["END_STREAM"]).serialize()))
Exemple #2
0
def test_close_during_connect_hook(tctx):
    flow = Placeholder(HTTPFlow)
    assert (Playbook(http.HttpLayer(tctx, HTTPMode.regular)) >> DataReceived(
        tctx.client, b'CONNECT hi.ls:443 HTTP/1.1\r\n'
        b'Proxy-Connection: keep-alive\r\n'
        b'Connection: keep-alive\r\n'
        b'Host: hi.ls:443\r\n\r\n') << http.HttpConnectHook(flow) >>
            ConnectionClosed(tctx.client) << CloseConnection(
                tctx.client) >> reply(to=-3))
Exemple #3
0
def test_protocol_error(ws_testdata):
    tctx, playbook = ws_testdata
    flow = Placeholder(WebSocketFlow)
    assert (
            playbook
            << websocket.WebsocketStartHook(flow)
            >> reply()
            >> DataReceived(tctx.server, b"\x01\x03foo")
            >> DataReceived(tctx.server, b"\x02\x03bar")
            << SendData(tctx.server, masked(b"\x88/\x03\xeaexpected CONTINUATION, got <Opcode.BINARY: 2>"))
            << CloseConnection(tctx.server)
            << SendData(tctx.client, b"\x88/\x03\xeaexpected CONTINUATION, got <Opcode.BINARY: 2>")
            << CloseConnection(tctx.client)
            << websocket.WebsocketErrorHook(flow)
            >> reply()

    )
    assert not flow().messages
def test_unfragmented(ws_testdata):
    tctx, playbook, flow = ws_testdata
    assert (
            playbook
            << websocket.WebsocketStartHook(flow)
            >> reply()
            >> DataReceived(tctx.server, b"\x81\x06foo")
    )
    # This already triggers wsproto to emit a wsproto.events.Message, see
    # https://github.com/mitmproxy/mitmproxy/issues/4701
    assert(
            playbook
            >> DataReceived(tctx.server, b"bar")
            << websocket.WebsocketMessageHook(flow)
            >> reply()
            << SendData(tctx.client, b"\x81\x06foobar")
    )
    assert flow.websocket.messages[-1].content == b"foobar"
def test_unknown_ext(ws_testdata):
    tctx, playbook, flow = ws_testdata
    flow.response.headers["Sec-WebSocket-Extensions"] = "funky-bits; param=42"
    assert (
            playbook
            << Log("Ignoring unknown WebSocket extension 'funky-bits'.")
            << websocket.WebsocketStartHook(flow)
            >> reply()
    )
Exemple #6
0
def test_request_stream_modify(tctx):
    """Test HTTP response streaming"""
    server = Placeholder(Server)

    def enable_streaming(flow: HTTPFlow):
        flow.request.stream = lambda x: x.upper()

    assert (Playbook(http.HttpLayer(tctx, HTTPMode.regular)) >> DataReceived(
        tctx.client, b"POST http://example.com/ HTTP/1.1\r\n"
        b"Host: example.com\r\n"
        b"Content-Length: 6\r\n\r\n"
        b"abc") << http.HttpRequestHeadersHook(
            Placeholder(HTTPFlow)) >> reply(side_effect=enable_streaming) <<
            OpenConnection(server) >> reply(None) << SendData(
                server, b"POST / HTTP/1.1\r\n"
                b"Host: example.com\r\n"
                b"Content-Length: 6\r\n\r\n"
                b"ABC"))
Exemple #7
0
def test_server_aborts(tctx, data):
    """Test the scenario where the server doesn't serve a response"""
    server = Placeholder(Server)
    flow = Placeholder(HTTPFlow)
    err = Placeholder(bytes)
    playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
    assert (playbook >> DataReceived(
        tctx.client,
        b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n") <<
            OpenConnection(server) >> reply(None) << SendData(
                server, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"))
    if data:
        playbook >> DataReceived(server, data)
    assert (playbook >> ConnectionClosed(server) << CloseConnection(server)
            << http.HttpErrorHook(flow) >> reply() << SendData(
                tctx.client, err) << CloseConnection(tctx.client))
    assert flow().error
    assert b"502 Bad Gateway" in err()
Exemple #8
0
def test_http_proxy(tctx):
    """Test a simple HTTP GET / request"""
    server = Placeholder(Server)
    flow = Placeholder(HTTPFlow)
    assert (Playbook(http.HttpLayer(tctx, HTTPMode.regular)) >> DataReceived(
        tctx.client,
        b"GET http://example.com/foo?hello=1 HTTP/1.1\r\nHost: example.com\r\n\r\n"
    ) << http.HttpRequestHeadersHook(flow) >> reply() << http.HttpRequestHook(
        flow) >> reply() << OpenConnection(server) >> reply(None) << SendData(
            server, b"GET /foo?hello=1 HTTP/1.1\r\nHost: example.com\r\n\r\n")
            >> DataReceived(
                server,
                b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World") <<
            http.HttpResponseHeadersHook(flow) >> reply() >> DataReceived(
                server, b"!") << http.HttpResponseHook(flow) >> reply() <<
            SendData(
                tctx.client,
                b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!"))
    assert server().address == ("example.com", 80)
def test_unknown_ext(ws_testdata):
    tctx, playbook = ws_testdata
    flow = Placeholder(WebSocketFlow)
    # noinspection PyUnresolvedReferences
    http_flow: HTTPFlow = playbook.layer.flow.handshake_flow
    http_flow.response.headers[
        "Sec-WebSocket-Extensions"] = "funky-bits; param=42"
    assert (
        playbook << Log("Ignoring unknown WebSocket extension 'funky-bits'.")
        << websocket.WebsocketStartHook(flow) >> reply())
def test_upgrade_streamed(tctx):
    """If the HTTP response is streamed, we may get early data from the client."""
    tctx.server.address = ("example.com", 80)
    tctx.server.state = ConnectionState.OPEN
    flow = Placeholder(HTTPFlow)

    def enable_streaming(flow: HTTPFlow):
        flow.response.stream = True

    assert (
            Playbook(http.HttpLayer(tctx, HTTPMode.transparent))
            >> DataReceived(tctx.client,
                            b"GET / HTTP/1.1\r\n"
                            b"Connection: upgrade\r\n"
                            b"Upgrade: websocket\r\n"
                            b"Sec-WebSocket-Version: 13\r\n"
                            b"\r\n")
            << http.HttpRequestHeadersHook(flow)
            >> reply()
            << http.HttpRequestHook(flow)
            >> reply()
            << SendData(tctx.server, b"GET / HTTP/1.1\r\n"
                                     b"Connection: upgrade\r\n"
                                     b"Upgrade: websocket\r\n"
                                     b"Sec-WebSocket-Version: 13\r\n"
                                     b"\r\n")
            >> DataReceived(tctx.server, b"HTTP/1.1 101 Switching Protocols\r\n"
                                         b"Upgrade: websocket\r\n"
                                         b"Connection: Upgrade\r\n"
                                         b"\r\n")
            << http.HttpResponseHeadersHook(flow)
            >> reply(side_effect=enable_streaming)
            << SendData(tctx.client, b"HTTP/1.1 101 Switching Protocols\r\n"
                                     b"Upgrade: websocket\r\n"
                                     b"Connection: Upgrade\r\n"
                                     b"\r\n")
            << http.HttpResponseHook(flow)
            >> DataReceived(tctx.client, masked_bytes(b"\x81\x0bhello world"))  # early !!
            >> reply(to=-2)
            << websocket.WebsocketStartHook(flow)
            >> reply()
            << websocket.WebsocketMessageHook(flow)
            >> reply()
            << SendData(tctx.server, masked(b"\x81\x0bhello world"))
            >> DataReceived(tctx.server, b"\x82\nhello back")
            << websocket.WebsocketMessageHook(flow)
            >> reply()
            << SendData(tctx.client, b"\x82\nhello back")
            >> DataReceived(tctx.client, masked_bytes(b"\x81\x0bhello again"))
            << websocket.WebsocketMessageHook(flow)
            >> reply()
            << SendData(tctx.server, masked(b"\x81\x0bhello again"))
    )
Exemple #11
0
def test_socks5_eager_err(tctx: Context):
    tctx.options.connection_strategy = "eager"
    server = Placeholder(Server)
    assert (Playbook(modes.Socks5Proxy(tctx)) >> DataReceived(
        tctx.client, CLIENT_HELLO) << SendData(
            tctx.client, SERVER_HELLO) >> DataReceived(
                tctx.client, b"\x05\x01\x00\x01\x7f\x00\x00\x01\x12\x34") <<
            OpenConnection(server) >> reply("out of socks") << SendData(
                tctx.client, b"\x05\x04\x00\x01\x00\x00\x00\x00\x00\x00") <<
            CloseConnection(tctx.client))
Exemple #12
0
def test_stream_concurrency(tctx):
    """Test that we can send an intercepted request with a lower stream id than one that has already been sent."""
    playbook, cff = start_h2_client(tctx)
    flow1 = Placeholder(HTTPFlow)
    flow2 = Placeholder(HTTPFlow)

    reqheadershook1 = http.HttpRequestHeadersHook(flow1)
    reqheadershook2 = http.HttpRequestHeadersHook(flow2)
    reqhook1 = http.HttpRequestHook(flow1)
    reqhook2 = http.HttpRequestHook(flow2)

    server = Placeholder(Server)
    data_req1 = Placeholder(bytes)
    data_req2 = Placeholder(bytes)

    assert (playbook
            >> DataReceived(
                tctx.client,
                cff.build_headers_frame(example_request_headers, flags=["END_STREAM"], stream_id=1).serialize() +
                cff.build_headers_frame(example_request_headers, flags=["END_STREAM"], stream_id=3).serialize())
            << reqheadershook1
            << reqheadershook2
            >> reply(to=reqheadershook1)
            << reqhook1
            >> reply(to=reqheadershook2)
            << reqhook2
            # req 2 overtakes 1 and we already have a reply:
            >> reply(to=reqhook2)
            << OpenConnection(server)
            >> reply(None, side_effect=make_h2)
            << SendData(server, data_req2)
            >> reply(to=reqhook1)
            << SendData(server, data_req1)
            )
    frames = decode_frames(data_req2())
    assert [type(x) for x in frames] == [
        hyperframe.frame.SettingsFrame,
        hyperframe.frame.HeadersFrame,
    ]
    frames = decode_frames(data_req1())
    assert [type(x) for x in frames] == [
        hyperframe.frame.HeadersFrame,
    ]
Exemple #13
0
def test_http_proxy_relative_request(tctx):
    """Test handling of a relative-form "GET /" in regular proxy mode."""
    server = Placeholder(Server)
    assert (Playbook(http.HttpLayer(
        tctx, HTTPMode.regular), hooks=False) >> DataReceived(
            tctx.client, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") <<
            OpenConnection(server) >> reply(None) << SendData(
                server, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") >>
            DataReceived(server, b"HTTP/1.1 204 No Content\r\n\r\n") <<
            SendData(tctx.client, b"HTTP/1.1 204 No Content\r\n\r\n"))
    assert server().address == ("example.com", 80)
Exemple #14
0
def test_transparent_failure(tctx: Context, monkeypatch):
    """Test that we recover from a transparent mode resolve error."""
    def raise_err(sock):
        raise RuntimeError("platform-specific error")

    monkeypatch.setattr(platform, "original_addr", raise_err)
    assert (Playbook(modes.TransparentProxy(tctx), logs=True) << GetSocket(
        tctx.client
    ) >> reply(object()) << Log(
        "Transparent mode failure: RuntimeError('platform-specific error')",
        "info"))
Exemple #15
0
def test_no_headers(tctx):
    """Test that we can correctly reassemble requests/responses with no headers."""
    server = Placeholder(Server)
    assert (
        Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False) >>
        DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\n\r\n")
        << OpenConnection(server) >> reply(None) << SendData(
            server, b"GET / HTTP/1.1\r\n\r\n") >> DataReceived(
                server, b"HTTP/1.1 204 No Content\r\n\r\n") << SendData(
                    tctx.client, b"HTTP/1.1 204 No Content\r\n\r\n"))
    assert server().address == ("example.com", 80)
Exemple #16
0
    def test_immediate_disconnect(self, tctx: context.Context, close_at):
        """Test the scenario where the client is disconnecting during the handshake.
        This may happen because they are not interested in the connection anymore, or because they do not like
        the proxy certificate."""
        playbook, client_layer, tssl_client = make_client_tls_layer(
            tctx, sni=b"wrong.host.mitmproxy.org")
        playbook.logs = True
        tls_hook_data = tutils.Placeholder(TlsData)

        playbook >> events.DataReceived(tctx.client, tssl_client.bio_read())
        playbook << tls.TlsClienthelloHook(tutils.Placeholder())

        if close_at == "tls_clienthello":
            assert (playbook >> events.ConnectionClosed(
                tctx.client) >> tutils.reply(to=-2) << tls.TlsStartClientHook(
                    tutils.Placeholder()) >> reply_tls_start_client() <<
                    tls.TlsFailedClientHook(tls_hook_data) >> tutils.reply() <<
                    commands.CloseConnection(tctx.client))
            assert tls_hook_data().conn.error
            return

        playbook >> tutils.reply()
        playbook << tls.TlsStartClientHook(tutils.Placeholder())

        if close_at == "tls_start_client":
            assert (playbook >> events.ConnectionClosed(
                tctx.client) >> reply_tls_start_client(to=-2) <<
                    tls.TlsFailedClientHook(tls_hook_data) >> tutils.reply() <<
                    commands.CloseConnection(tctx.client))
            assert tls_hook_data().conn.error
            return

        assert (playbook >> reply_tls_start_client() << commands.SendData(
            tctx.client, tutils.Placeholder()
        ) >> events.ConnectionClosed(tctx.client) << commands.Log(
            "Client TLS handshake failed. The client disconnected during the handshake. "
            "If this happens consistently for wrong.host.mitmproxy.org, this may indicate that the "
            "client does not trust the proxy's certificate.",
            "info") << tls.TlsFailedClientHook(tls_hook_data) >>
                tutils.reply() << commands.CloseConnection(tctx.client))
        assert tls_hook_data().conn.error
Exemple #17
0
def test_reverse_eager_connect_failure(tctx: Context):
    """
    Test
        client --TCP-- mitmproxy --TCP over TLS-- server
    reverse proxying.
    """

    tctx.options.mode = "reverse:https://localhost:8000"
    tctx.options.connection_strategy = "eager"
    playbook = Playbook(modes.ReverseProxy(tctx))
    assert (playbook << OpenConnection(tctx.server) >> reply("IPoAC unstable")
            << CloseConnection(tctx.client) >> ConnectionClosed(tctx.client))
Exemple #18
0
    def test_func_references(self, tctx: Context):
        nl = layer.NextLayer(tctx)
        playbook = tutils.Playbook(nl)

        assert (playbook >> events.DataReceived(tctx.client, b"foo") <<
                layer.NextLayerHook(nl))
        nl.layer = tutils.EchoLayer(tctx)
        handle = nl.handle_event
        assert (playbook >> tutils.reply() << commands.SendData(
            tctx.client, b"foo"))
        sd, = handle(events.DataReceived(tctx.client, b"bar"))
        assert isinstance(sd, commands.SendData)
Exemple #19
0
def test_socks5_auth_success(client_greeting: bytes, server_choice: bytes,
                             client_auth: bytes, server_resp: bytes,
                             address: bytes, packed: bytes, tctx: Context):
    ProxyAuth().load(tctx.options)
    tctx.options.proxyauth = "user:password"
    server = Placeholder(Server)
    nextlayer = Placeholder(NextLayer)
    playbook = (Playbook(modes.Socks5Proxy(tctx), logs=True) >> DataReceived(
        tctx.client, client_greeting) << SendData(tctx.client, server_choice)
                >> DataReceived(tctx.client, client_auth) <<
                modes.Socks5AuthHook(Placeholder(modes.Socks5AuthData)) >>
                reply(side_effect=_valid_socks_auth) << SendData(
                    tctx.client, server_resp) >> DataReceived(
                        tctx.client,
                        b"\x05\x01\x00" + packed + b"\x12\x34applicationdata")
                << OpenConnection(server) >> reply(None) << SendData(
                    tctx.client, b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00")
                << NextLayerHook(nextlayer))
    assert playbook
    assert server().address == (address, 0x1234)
    assert nextlayer().data_client() == b"applicationdata"
Exemple #20
0
def test_no_normalization(tctx):
    """Test that we don't normalize headers when we just pass them through."""

    server = Placeholder(Server)
    flow = Placeholder(HTTPFlow)
    playbook, cff = start_h2_client(tctx)

    request_headers = example_request_headers + (
        (b"Should-Not-Be-Capitalized! ", b" :) "), )
    response_headers = example_response_headers + ((b"Same", b"Here"), )

    initial = Placeholder(bytes)
    assert (playbook >> DataReceived(
        tctx.client,
        cff.build_headers_frame(request_headers, flags=[
            "END_STREAM"
        ]).serialize()) << http.HttpRequestHeadersHook(flow) >> reply() <<
            http.HttpRequestHook(flow) >> reply() << OpenConnection(server) >>
            reply(None, side_effect=make_h2) << SendData(server, initial))
    frames = decode_frames(initial())
    assert [type(x) for x in frames] == [
        hyperframe.frame.SettingsFrame,
        hyperframe.frame.HeadersFrame,
    ]
    assert hpack.hpack.Decoder().decode(frames[1].data,
                                        True) == list(request_headers)

    sff = FrameFactory()
    assert (playbook >> DataReceived(
        server,
        sff.build_headers_frame(response_headers, flags=[
            "END_STREAM"
        ]).serialize()) << http.HttpResponseHeadersHook(flow) >> reply() <<
            http.HttpResponseHook(flow) >> reply() << SendData(
                tctx.client,
                cff.build_headers_frame(response_headers).serialize() +
                cff.build_data_frame(b"", flags=["END_STREAM"]).serialize()))
    assert flow().request.headers.fields == ((b"Should-Not-Be-Capitalized! ",
                                              b" :) "), )
    assert flow().response.headers.fields == ((b"Same", b"Here"), )
Exemple #21
0
def test_upgrade(tctx, proto):
    """Test a HTTP -> WebSocket upgrade with different protocols enabled"""
    if proto != "websocket":
        tctx.options.websocket = False
    if proto != "tcp":
        tctx.options.rawtcp = False

    tctx.server.address = ("example.com", 80)
    tctx.server.state = ConnectionState.OPEN
    http_flow = Placeholder(HTTPFlow)
    playbook = Playbook(http.HttpLayer(tctx, HTTPMode.transparent))
    (playbook >> DataReceived(
        tctx.client, b"GET / HTTP/1.1\r\n"
        b"Connection: upgrade\r\n"
        b"Upgrade: websocket\r\n"
        b"Sec-WebSocket-Version: 13\r\n"
        b"\r\n") << http.HttpRequestHeadersHook(http_flow) >> reply() <<
     http.HttpRequestHook(http_flow) >> reply() << SendData(
         tctx.server, b"GET / HTTP/1.1\r\n"
         b"Connection: upgrade\r\n"
         b"Upgrade: websocket\r\n"
         b"Sec-WebSocket-Version: 13\r\n"
         b"\r\n") >> DataReceived(
             tctx.server, b"HTTP/1.1 101 Switching Protocols\r\n"
             b"Upgrade: websocket\r\n"
             b"Connection: Upgrade\r\n"
             b"\r\n") << http.HttpResponseHeadersHook(http_flow) >> reply() <<
     http.HttpResponseHook(http_flow) >> reply() << SendData(
         tctx.client, b"HTTP/1.1 101 Switching Protocols\r\n"
         b"Upgrade: websocket\r\n"
         b"Connection: Upgrade\r\n"
         b"\r\n"))
    if proto == "websocket":
        assert playbook << WebsocketStartHook(http_flow)
    elif proto == "tcp":
        assert playbook << TcpStartHook(Placeholder(TCPFlow))
    else:
        assert (playbook << Log(
            "Sent HTTP 101 response, but no protocol is enabled to upgrade to.",
            "warn") << CloseConnection(tctx.client))
Exemple #22
0
def test_redirect(strategy, https_server, https_client, tctx, monkeypatch):
    """Test redirects between http:// and https:// in regular proxy mode."""
    server = Placeholder(Server)
    flow = Placeholder(HTTPFlow)
    tctx.options.connection_strategy = strategy
    p = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)

    if https_server:
        monkeypatch.setattr(tls, "ServerTLSLayer", tls.MockTLSLayer)

    def redirect(flow: HTTPFlow):
        if https_server:
            flow.request.url = "https://redirected.site/"
        else:
            flow.request.url = "http://redirected.site/"

    if https_client:
        p >> DataReceived(tctx.client, b"CONNECT example.com:80 HTTP/1.1\r\n\r\n")
        if strategy == "eager":
            p << OpenConnection(Placeholder())
            p >> reply(None)
        p << SendData(tctx.client, b'HTTP/1.1 200 Connection established\r\n\r\n')
        p >> DataReceived(tctx.client, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
        p << layer.NextLayerHook(Placeholder())
        p >> reply_next_layer(lambda ctx: http.HttpLayer(ctx, HTTPMode.transparent))
    else:
        p >> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
    p << http.HttpRequestHook(flow)
    p >> reply(side_effect=redirect)
    p << OpenConnection(server)
    p >> reply(None)
    p << SendData(server, b"GET / HTTP/1.1\r\nHost: redirected.site\r\n\r\n")
    p >> DataReceived(server, b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!")
    p << SendData(tctx.client, b"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!")

    assert p
    if https_server:
        assert server().address == ("redirected.site", 443)
    else:
        assert server().address == ("redirected.site", 80)
Exemple #23
0
def test_simple(tctx):
    playbook, cff = start_h2_client(tctx)
    flow = Placeholder(HTTPFlow)
    server = Placeholder(Server)
    initial = Placeholder(bytes)
    assert (
            playbook
            >> DataReceived(tctx.client,
                            cff.build_headers_frame(example_request_headers, flags=["END_STREAM"]).serialize())
            << http.HttpRequestHeadersHook(flow)
            >> reply()
            << http.HttpRequestHook(flow)
            >> reply()
            << OpenConnection(server)
            >> reply(None, side_effect=make_h2)
            << SendData(server, initial)
    )
    frames = decode_frames(initial())
    assert [type(x) for x in frames] == [
        hyperframe.frame.SettingsFrame,
        hyperframe.frame.HeadersFrame,
    ]
    sff = FrameFactory()
    assert (
            playbook
            # a conforming h2 server would send settings first, we disregard this for now.
            >> DataReceived(server, sff.build_headers_frame(example_response_headers).serialize())
            << http.HttpResponseHeadersHook(flow)
            >> reply()
            >> DataReceived(server, sff.build_data_frame(b"Hello, World!", flags=["END_STREAM"]).serialize())
            << http.HttpResponseHook(flow)
            >> reply()
            << SendData(tctx.client,
                        cff.build_headers_frame(example_response_headers).serialize() +
                        cff.build_data_frame(b"Hello, World!").serialize() +
                        cff.build_data_frame(b"", flags=["END_STREAM"]).serialize())
    )
    assert flow().request.url == "http://example.com/"
    assert flow().response.text == "Hello, World!"
Exemple #24
0
def test_dont_reuse_closed(tctx):
    """Test that a closed connection is not reused."""
    server = Placeholder(Server)
    server2 = Placeholder(Server)
    assert (
        Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False) >>
        DataReceived(
            tctx.client,
            b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
        << OpenConnection(server) >> reply(None) << SendData(
            server,
            b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") >> DataReceived(
                server, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") <<
        SendData(tctx.client, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")
        >> ConnectionClosed(server) << CloseConnection(server) >> DataReceived(
            tctx.client,
            b"GET http://example.com/two HTTP/1.1\r\nHost: example.com\r\n\r\n"
        ) << OpenConnection(server2) >> reply(None) << SendData(
            server2,
            b"GET /two HTTP/1.1\r\nHost: example.com\r\n\r\n") >> DataReceived(
                server2, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") <<
        SendData(tctx.client, b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"))
Exemple #25
0
def test_response_streaming(tctx):
    """Test HTTP response streaming"""
    server = Placeholder(Server)
    flow = Placeholder(HTTPFlow)

    def enable_streaming(flow: HTTPFlow):
        flow.response.stream = lambda x: x.upper()

    assert (Playbook(http.HttpLayer(tctx, HTTPMode.regular)) >> DataReceived(
        tctx.client,
        b"GET http://example.com/largefile HTTP/1.1\r\nHost: example.com\r\n\r\n"
    ) << http.HttpRequestHeadersHook(flow) >> reply() << http.HttpRequestHook(
        flow) >> reply() << OpenConnection(server) >> reply(None) << SendData(
            server, b"GET /largefile HTTP/1.1\r\nHost: example.com\r\n\r\n")
            >> DataReceived(
                server, b"HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nabc") <<
            http.HttpResponseHeadersHook(flow) >>
            reply(side_effect=enable_streaming) << SendData(
                tctx.client,
                b"HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nABC") >>
            DataReceived(server, b"def") << SendData(
                tctx.client, b"DEF") << http.HttpResponseHook(flow) >> reply())
Exemple #26
0
def test_response_until_eof(tctx):
    """Test scenario where the server response body is terminated by EOF."""
    server = Placeholder(Server)
    assert (Playbook(http.HttpLayer(
        tctx, HTTPMode.regular), hooks=False) >> DataReceived(
            tctx.client,
            b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
            << OpenConnection(server) >> reply(None) << SendData(
                server, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") >>
            DataReceived(server, b"HTTP/1.1 200 OK\r\n\r\nfoo") >>
            ConnectionClosed(server) << CloseConnection(server) << SendData(
                tctx.client, b"HTTP/1.1 200 OK\r\n\r\nfoo") << CloseConnection(
                    tctx.client))
Exemple #27
0
def test_socks5_success(address: str, packed: bytes, tctx: Context):
    tctx.options.connection_strategy = "eager"
    playbook = Playbook(modes.Socks5Proxy(tctx))
    server = Placeholder(Server)
    nextlayer = Placeholder(NextLayer)
    assert (playbook >> DataReceived(tctx.client, CLIENT_HELLO) << SendData(
        tctx.client, SERVER_HELLO) >> DataReceived(
            tctx.client, b"\x05\x01\x00" + packed + b"\x12\x34applicationdata")
            << OpenConnection(server) >> reply(None) << SendData(
                tctx.client, b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00") <<
            NextLayerHook(nextlayer))
    assert server().address == (address, 0x1234)
    assert nextlayer().data_client() == b"applicationdata"
def test_close_normal(ws_testdata):
    tctx, playbook, flow = ws_testdata
    masked_close = Placeholder(bytes)
    close = Placeholder(bytes)
    assert (
            playbook
            << websocket.WebsocketStartHook(flow)
            >> reply()
            >> DataReceived(tctx.client, masked_bytes(b"\x88\x00"))
            << SendData(tctx.server, masked_close)
            << CloseConnection(tctx.server)
            << SendData(tctx.client, close)
            << CloseConnection(tctx.client)
            << websocket.WebsocketEndHook(flow)
            >> reply()
    )
    # wsproto currently handles this inconsistently, see
    # https://github.com/python-hyper/wsproto/pull/153/files
    assert masked_close() == masked(b"\x88\x02\x03\xe8") or masked_close() == masked(b"\x88\x00")
    assert close() == b"\x88\x02\x03\xe8" or close() == b"\x88\x00"

    assert flow.websocket.close_code == 1005
Exemple #29
0
def test_http_reply_from_proxy(tctx):
    """Test a response served by mitmproxy itself."""

    def reply_from_proxy(flow: HTTPFlow):
        flow.response = Response.make(418)

    assert (
            Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
            >> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
            << http.HttpRequestHook(Placeholder())
            >> reply(side_effect=reply_from_proxy)
            << SendData(tctx.client, b"HTTP/1.1 418 I'm a teapot\r\ncontent-length: 0\r\n\r\n")
    )
Exemple #30
0
def test_transparent_tcp(tctx: Context, monkeypatch, connection_strategy):
    monkeypatch.setattr(platform, "original_addr", lambda sock:
                        ("address", 22))

    flow = Placeholder(TCPFlow)
    tctx.options.connection_strategy = connection_strategy

    sock = object()
    playbook = Playbook(modes.TransparentProxy(tctx))
    (playbook << GetSocket(tctx.client) >> reply(sock))
    if connection_strategy == "lazy":
        assert playbook
    else:
        assert (playbook << OpenConnection(tctx.server) >> reply(None) >>
                DataReceived(tctx.server, b"hello") << NextLayerHook(
                    Placeholder(NextLayer)) >> reply_next_layer(tcp.TCPLayer)
                << TcpStartHook(flow) >> reply() << TcpMessageHook(flow) >>
                reply() << SendData(tctx.client, b"hello"))
        assert flow().messages[0].content == b"hello"
        assert not flow().messages[0].from_client

    assert tctx.server.address == ("address", 22)