Ejemplo n.º 1
0
async def test_start_stop():
    async def server_handler(reader: asyncio.StreamReader,
                             writer: asyncio.StreamWriter):
        assert await reader.readuntil(b"\r\n\r\n"
                                      ) == b"GET /hello HTTP/1.1\r\n\r\n"
        writer.write(b"HTTP/1.1 204 No Content\r\n\r\n")
        await writer.drain()
        writer.close()

    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        state = HelperAddon()
        tctx.master.addons.add(state)
        async with tcp_server(server_handler) as addr:
            tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
            assert not ps.server
            ps.running()
            await tctx.master.await_log("Proxy server listening", level="info")
            assert ps.server

            proxy_addr = ps.server.sockets[0].getsockname()[:2]
            reader, writer = await asyncio.open_connection(*proxy_addr)
            req = f"GET http://{addr[0]}:{addr[1]}/hello HTTP/1.1\r\n\r\n"
            writer.write(req.encode())
            assert await reader.readuntil(
                b"\r\n\r\n") == b"HTTP/1.1 204 No Content\r\n\r\n"

            tctx.configure(ps, server=False)
            await tctx.master.await_log("Stopping server", level="info")
            assert not ps.server
            assert state.flows
            assert state.flows[0].request.path == "/hello"
            assert state.flows[0].response.status_code == 204
Ejemplo n.º 2
0
async def test_inject_fail() -> None:
    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        ps.inject_websocket(
            tflow.tflow(),
            True,
            b"test"
        )
        await tctx.master.await_log("Cannot inject WebSocket messages into non-WebSocket flows.", level="warn")
        ps.inject_tcp(
            tflow.tflow(),
            True,
            b"test"
        )
        await tctx.master.await_log("Cannot inject TCP messages into non-TCP flows.", level="warn")

        ps.inject_websocket(
            tflow.twebsocketflow(),
            True,
            b"test"
        )
        await tctx.master.await_log("Flow is not from a live connection.", level="warn")
        ps.inject_websocket(
            tflow.ttcpflow(),
            True,
            b"test"
        )
        await tctx.master.await_log("Flow is not from a live connection.", level="warn")
Ejemplo n.º 3
0
def test_self_connect():
    server = tserver_conn()
    client = tclient_conn()
    server.address = ("localhost", 8080)
    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        # not calling .running() here to avoid unnecessary socket
        ps.options = tctx.options
        ps.server_connect(server_hooks.ServerConnectionHookData(
            server, client))
        assert server.error == "Stopped mitmproxy from recursively connecting to itself."
Ejemplo n.º 4
0
async def test_asgi_full():
    ps = Proxyserver()
    addons = [
        asgiapp.WSGIApp(tapp, "testapp", 80),
        asgiapp.ASGIApp(errapp, "errapp", 80),
        asgiapp.ASGIApp(noresponseapp, "noresponseapp", 80),
    ]
    with taddons.context(ps, *addons) as tctx:
        tctx.master.addons.add(next_layer.NextLayer())
        tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
        ps.running()
        await tctx.master.await_log("Proxy server listening", level="info")
        proxy_addr = ps.server.sockets[0].getsockname()[:2]

        reader, writer = await asyncio.open_connection(*proxy_addr)
        req = f"GET http://testapp:80/ HTTP/1.1\r\n\r\n"
        writer.write(req.encode())
        header = await reader.readuntil(b"\r\n\r\n")
        assert header.startswith(b"HTTP/1.1 200 OK")
        body = await reader.readuntil(b"testapp")
        assert body == b"testapp"

        reader, writer = await asyncio.open_connection(*proxy_addr)
        req = f"GET http://testapp:80/parameters?param1=1&param2=2 HTTP/1.1\r\n\r\n"
        writer.write(req.encode())
        header = await reader.readuntil(b"\r\n\r\n")
        assert header.startswith(b"HTTP/1.1 200 OK")
        body = await reader.readuntil(b"}")
        assert body == b'{"param1": "1", "param2": "2"}'

        reader, writer = await asyncio.open_connection(*proxy_addr)
        req = f"POST http://testapp:80/requestbody HTTP/1.1\r\nContent-Length: 6\r\n\r\nHello!"
        writer.write(req.encode())
        header = await reader.readuntil(b"\r\n\r\n")
        assert header.startswith(b"HTTP/1.1 200 OK")
        body = await reader.readuntil(b"}")
        assert body == b'{"body": "Hello!"}'

        reader, writer = await asyncio.open_connection(*proxy_addr)
        req = f"GET http://errapp:80/?foo=bar HTTP/1.1\r\n\r\n"
        writer.write(req.encode())
        header = await reader.readuntil(b"\r\n\r\n")
        assert header.startswith(b"HTTP/1.1 500")
        body = await reader.readuntil(b"ASGI Error")
        assert body == b"ASGI Error"

        reader, writer = await asyncio.open_connection(*proxy_addr)
        req = f"GET http://noresponseapp:80/ HTTP/1.1\r\n\r\n"
        writer.write(req.encode())
        header = await reader.readuntil(b"\r\n\r\n")
        assert header.startswith(b"HTTP/1.1 500")
        body = await reader.readuntil(b"ASGI Error")
        assert body == b"ASGI Error"
Ejemplo n.º 5
0
async def test_warn_no_nextlayer():
    """
    Test that we log an error if the proxy server is started without NextLayer addon.
    That is a mean trap to fall into when writing end-to-end tests.
    """
    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
        ps.running()
        assert await tctx.master.await_log("Proxy server listening at", level="info")
        assert tctx.master.has_log("Warning: Running proxyserver without nextlayer addon!", level="warn")
        await ps.shutdown_server()
Ejemplo n.º 6
0
def test_self_connect():
    server = tserver_conn()
    client = tclient_conn()
    server.address = ("localhost", 8080)
    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        # not calling .running() here to avoid unnecessary socket
        ps.options = tctx.options
        ps.server_connect(
            server_hooks.ServerConnectionHookData(server, client)
        )
        assert "Request destination unknown" in server.error
Ejemplo n.º 7
0
async def test_start_stop():
    async def server_handler(reader: asyncio.StreamReader,
                             writer: asyncio.StreamWriter):
        assert await reader.readuntil(b"\r\n\r\n"
                                      ) == b"GET /hello HTTP/1.1\r\n\r\n"
        writer.write(b"HTTP/1.1 204 No Content\r\n\r\n")
        await writer.drain()
        writer.close()

    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        state = HelperAddon()
        tctx.master.addons.add(state)
        async with tcp_server(server_handler) as addr:
            tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
            assert not ps.server
            ps.running()
            await tctx.master.await_log("Proxy server listening", level="info")
            assert ps.server

            proxy_addr = ps.server.sockets[0].getsockname()[:2]
            reader, writer = await asyncio.open_connection(*proxy_addr)
            req = f"GET http://{addr[0]}:{addr[1]}/hello HTTP/1.1\r\n\r\n"
            writer.write(req.encode())
            assert await reader.readuntil(
                b"\r\n\r\n") == b"HTTP/1.1 204 No Content\r\n\r\n"
            assert repr(ps) == "ProxyServer(running, 1 active conns)"

            tctx.configure(ps, server=False)
            await tctx.master.await_log("Stopping server", level="info")
            assert not ps.server
            assert state.flows
            assert state.flows[0].request.path == "/hello"
            assert state.flows[0].response.status_code == 204

            # Waiting here until everything is really torn down... takes some effort.
            conn_handler = list(ps._connections.values())[0]
            client_handler = conn_handler.transports[
                conn_handler.client].handler
            writer.close()
            await writer.wait_closed()
            try:
                await client_handler
            except asyncio.CancelledError:
                pass
            for _ in range(5):
                # Get all other scheduled coroutines to run.
                await asyncio.sleep(0)
            assert repr(ps) == "ProxyServer(stopped, 0 active conns)"
Ejemplo n.º 8
0
def tctx() -> context.Context:
    opts = options.Options()
    Proxyserver().load(opts)
    TermLog().load(opts)
    return context.Context(
        connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329),
        opts)
Ejemplo n.º 9
0
async def test_playback_https_upstream():
    handler_ok = asyncio.Event()

    async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        conn_req = await reader.readuntil(b"\r\n\r\n")
        assert conn_req == b'CONNECT address:22 HTTP/1.1\r\n\r\n'
        writer.write(b"HTTP/1.1 502 Bad Gateway\r\n\r\n")
        await writer.drain()
        assert not await reader.read()
        handler_ok.set()

    cp = ClientPlayback()
    ps = Proxyserver()
    with taddons.context(cp, ps) as tctx:
        tctx.configure(cp)
        async with tcp_server(handler) as addr:
            cp.running()
            flow = tflow.tflow(live=False)
            flow.request.scheme = b"https"
            flow.request.content = b"data"
            tctx.options.mode = f"upstream:http://{addr[0]}:{addr[1]}"
            cp.start_replay([flow])
            assert cp.count() == 1
            await asyncio.wait_for(cp.queue.join(), 5)
            await asyncio.wait_for(handler_ok.wait(), 5)
            cp.done()
            assert flow.response is None
            assert str(flow.error) == f'Upstream proxy {addr[0]}:{addr[1]} refused HTTP CONNECT request: 502 Bad Gateway'
Ejemplo n.º 10
0
def test_options():
    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        with pytest.raises(exceptions.OptionsError):
            tctx.configure(ps, body_size_limit="invalid")
        tctx.configure(ps, body_size_limit="1m")

        with pytest.raises(exceptions.OptionsError):
            tctx.configure(ps, stream_large_bodies="invalid")
        tctx.configure(ps, stream_large_bodies="1m")
Ejemplo n.º 11
0
async def test_startup_err(monkeypatch) -> None:
    async def _raise(*_):
        raise OSError("cannot bind")

    monkeypatch.setattr(asyncio, "start_server", _raise)

    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        await ps.running()
        await tctx.master.await_log("cannot bind", level="error")
Ejemplo n.º 12
0
async def test_playback(mode, concurrency):
    handler_ok = asyncio.Event()

    async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        if mode == "err":
            writer.close()
            handler_ok.set()
            return
        req = await reader.readline()
        if mode == "upstream":
            assert req == b'GET http://address:22/path HTTP/1.1\r\n'
        else:
            assert req == b'GET /path HTTP/1.1\r\n'
        req = await reader.readuntil(b"data")
        assert req == (
            b'header: qvalue\r\n'
            b'content-length: 4\r\n'
            b'\r\n'
            b'data'
        )
        writer.write(b"HTTP/1.1 204 No Content\r\n\r\n")
        await writer.drain()
        assert not await reader.read()
        handler_ok.set()

    cp = ClientPlayback()
    ps = Proxyserver()
    with taddons.context(cp, ps) as tctx:
        tctx.configure(cp, client_replay_concurrency=concurrency)
        async with tcp_server(handler) as addr:

            cp.running()
            flow = tflow.tflow(live=False)
            flow.request.content = b"data"
            if mode == "upstream":
                tctx.options.mode = f"upstream:http://{addr[0]}:{addr[1]}"
                flow.request.authority = f"{addr[0]}:{addr[1]}"
                flow.request.host, flow.request.port = 'address', 22
            else:
                flow.request.host, flow.request.port = addr
            cp.start_replay([flow])
            assert cp.count() == 1
            await asyncio.wait_for(cp.queue.join(), 5)
            await asyncio.wait_for(handler_ok.wait(), 5)
            cp.done()
            if mode != "err":
                assert flow.response.status_code == 204
Ejemplo n.º 13
0
async def test_playback(mode):
    handler_ok = asyncio.Event()

    async def handler(reader: asyncio.StreamReader,
                      writer: asyncio.StreamWriter):
        if mode == "err":
            writer.close()
            handler_ok.set()
            return
        if mode == "upstream":
            conn_req = await reader.readuntil(b"\r\n\r\n")
            assert conn_req == b'CONNECT address:22 HTTP/1.1\r\n\r\n'
            writer.write(b"HTTP/1.1 200 Connection Established\r\n\r\n")
        req = await reader.readuntil(b"data")
        assert req == (b'GET /path HTTP/1.1\r\n'
                       b'header: qvalue\r\n'
                       b'content-length: 4\r\n'
                       b'\r\n'
                       b'data')
        writer.write(b"HTTP/1.1 204 No Content\r\n\r\n")
        await writer.drain()
        assert not await reader.read()
        handler_ok.set()

    cp = ClientPlayback()
    ps = Proxyserver()
    with taddons.context(cp, ps) as tctx:
        async with tcp_server(handler) as addr:

            cp.running()
            flow = tflow.tflow()
            flow.request.content = b"data"
            if mode == "upstream":
                tctx.options.mode = f"upstream:http://{addr[0]}:{addr[1]}"
            else:
                flow.request.host, flow.request.port = addr
            cp.start_replay([flow])
            assert cp.count() == 1
            await asyncio.wait_for(cp.queue.join(), 5)
            await asyncio.wait_for(handler_ok.wait(), 5)
            cp.done()
            if mode != "err":
                assert flow.response.status_code == 204
Ejemplo n.º 14
0
from mitmproxy import options, connection
from mitmproxy.addons.proxyserver import Proxyserver
from mitmproxy.connection import Server
from mitmproxy.http import HTTPFlow
from mitmproxy.proxy.layers.http import HTTPMode
from mitmproxy.proxy import context, events
from mitmproxy.proxy.commands import OpenConnection, SendData
from mitmproxy.proxy.events import DataReceived, Start, ConnectionClosed
from mitmproxy.proxy.layers import http
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
from test.mitmproxy.proxy.layers.http.test_http2 import make_h2, example_response_headers, example_request_headers, \
    start_h2_client
from test.mitmproxy.proxy.tutils import Placeholder, Playbook, reply, _TracebackInPlaybook, _eq

opts = options.Options()
Proxyserver().load(opts)

request_lines = sampled_from([
    b"GET / HTTP/1.1",
    b"GET http://example.com/ HTTP/1.1",
    b"CONNECT example.com:443 HTTP/1.1",
    b"HEAD /foo HTTP/0.9",
])
response_lines = sampled_from([
    b"HTTP/1.1 200 OK",
    b"HTTP/1.1 100 Continue",
    b"HTTP/0.9 204 No Content",
    b"HEAD /foo HTTP/0.9",
])
headers = lists(sampled_from([
    b"Host: example.com",
Ejemplo n.º 15
0
            except asyncio.CancelledError:
                pass
            for _ in range(5):
                # Get all other scheduled coroutines to run.
                await asyncio.sleep(0)
            assert repr(ps) == "ProxyServer(stopped, 0 active conns)"


@pytest.mark.asyncio
async def test_inject():
    async def server_handler(reader: asyncio.StreamReader,
                             writer: asyncio.StreamWriter):
        while s := await reader.read(1):
            writer.write(s.upper())

    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        state = HelperAddon()
        tctx.master.addons.add(state)
        async with tcp_server(server_handler) as addr:
            tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
            ps.running()
            await tctx.master.await_log("Proxy server listening", level="info")
            proxy_addr = ps.server.sockets[0].getsockname()[:2]
            reader, writer = await asyncio.open_connection(*proxy_addr)

            req = f"CONNECT {addr[0]}:{addr[1]} HTTP/1.1\r\n\r\n"
            writer.write(req.encode())
            assert await reader.readuntil(
                b"\r\n\r\n") == b"HTTP/1.1 200 Connection established\r\n\r\n"
Ejemplo n.º 16
0
            try:
                await client_handler
            except asyncio.CancelledError:
                pass
            for _ in range(5):
                # Get all other scheduled coroutines to run.
                await asyncio.sleep(0)
            assert repr(ps) == "ProxyServer(stopped, 0 active conns)"


async def test_inject() -> None:
    async def server_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
        while s := await reader.read(1):
            writer.write(s.upper())

    ps = Proxyserver()
    with taddons.context(ps) as tctx:
        state = HelperAddon()
        tctx.master.addons.add(state)
        async with tcp_server(server_handler) as addr:
            tctx.configure(ps, listen_host="127.0.0.1", listen_port=0)
            await ps.running()
            await tctx.master.await_log("Proxy server listening", level="info")
            proxy_addr = ps.server.sockets[0].getsockname()[:2]
            reader, writer = await asyncio.open_connection(*proxy_addr)

            req = f"CONNECT {addr[0]}:{addr[1]} HTTP/1.1\r\n\r\n"
            writer.write(req.encode())
            assert await reader.readuntil(b"\r\n\r\n") == b"HTTP/1.1 200 Connection established\r\n\r\n"

            writer.write(b"a")