示例#1
0
    def test_http2_relay_traffic(self):
        """Tests if HTTP2 traffic can correctly be forwarded (including url-encoded characters)."""

        # Create a simple HTTP echo server
        class MyListener(ProxyListener):
            def forward_request(self, method, path, data, headers):
                return {"method": method, "path": path, "data": data}

        listener = MyListener()
        port_http_server = get_free_tcp_port()
        http_server = start_proxy_server(port_http_server, update_listener=listener, use_ssl=True)

        # Create a relay proxy which forwards request to the HTTP echo server
        port_relay_proxy = get_free_tcp_port()
        forward_url = f"https://localhost:{port_http_server}"
        relay_proxy = start_proxy_server(port_relay_proxy, forward_url=forward_url, use_ssl=True)

        # Contact the relay proxy
        query = "%2B=%3B%2C%2F%3F%3A%40%26%3D%2B%24%21%2A%27%28%29%23"
        path = f"/foo/bar%3B%2C%2F%3F%3A%40%26%3D%2B%24%21%2A%27%28%29%23baz?{query}"
        url = f"https://localhost:{port_relay_proxy}{path}"
        response = requests.post(url, verify=False)

        # Expect the response from the HTTP echo server
        expected = {
            "method": "POST",
            "path": path,
            "data": "",
        }
        assert json.loads(to_str(response.content)) == expected

        http_server.stop()
        relay_proxy.stop()
示例#2
0
def test_ssl_proxy_server():
    class MyListener(ProxyListener):
        def forward_request(self, *args, **kwargs):
            invocations.append((args, kwargs))
            return 200

    invocations = []

    # start SSL proxy
    listener = MyListener()
    port = get_free_tcp_port()
    server = start_proxy_server(port, update_listener=listener, use_ssl=True)
    wait_for_port_open(port)

    # start SSL proxy
    proxy_port = get_free_tcp_port()
    proxy = start_ssl_proxy(proxy_port, port, asynchronous=True)
    wait_for_port_open(proxy_port)

    # invoke SSL proxy server
    url = f"https://{LOCALHOST_HOSTNAME}:{proxy_port}"
    num_requests = 3
    for i in range(num_requests):
        response = requests.get(url, verify=False)
        assert response.status_code == 200

    # assert backend server has been invoked
    assert len(invocations) == num_requests

    # clean up
    proxy.stop()
    server.stop()
示例#3
0
def start_server(port, asynchronous=False):

    if is_port_open(port):
        LOG.debug("API Multiserver appears to be already running.")
        return

    class ConfigListener(ProxyListener):
        def forward_request(self, method, path, data, **kwargs):
            response = Response()
            response.status_code = 200
            response._content = "{}"
            try:
                if path == API_PATH_SERVERS:
                    if method == "POST":
                        start_api_server_locally(json.loads(to_str(data)))
                    elif method == "GET":
                        response._content = json.dumps(json_safe(API_SERVERS))
            except Exception as e:
                LOG.error("Unable to process request: %s" % e)
                response.status_code = 500
                response._content = str(e)
            return response

    proxy = start_proxy_server(port, update_listener=ConfigListener())
    if asynchronous:
        return proxy
    proxy.join()
示例#4
0
def run_parallel_download():

    file_length = 10000000

    class DownloadListener(ProxyListener):
        def forward_request(self, method, path, data, headers):
            sleep_time = int(path.replace("/", ""))
            time.sleep(sleep_time)
            response = Response()
            response.status_code = 200
            response._content = ("%s" % sleep_time) * file_length
            return response

    test_port = 12124
    tmp_file_pattern = "/tmp/test.%s"

    proxy = start_proxy_server(test_port, update_listener=DownloadListener())

    def do_download(param):
        tmp_file = tmp_file_pattern % param
        TMP_FILES.append(tmp_file)
        download("http://localhost:%s/%s" % (test_port, param), tmp_file)

    values = [1, 2, 3]
    parallelize(do_download, values)
    proxy.stop()

    for val in values:
        tmp_file = tmp_file_pattern % val
        assert len(load_file(tmp_file)) == file_length
示例#5
0
def _do_start_ssl_proxy_with_listener(port: int,
                                      target: PortOrUrl,
                                      requests_kwargs: Dict[str, Any] = None):
    target = f"http://localhost:{target}" if isinstance(target,
                                                        int) else target
    base_url = f"{'https://' if '://' not in target else ''}{target.rstrip('/')}"
    requests_kwargs = requests_kwargs or {}

    # define forwarding listener
    class Listener(ProxyListener):
        def forward_request(self, method, path, data, headers):
            # send request to target
            url = f"{base_url}{path}"
            response = requests.request(method=method,
                                        url=url,
                                        data=data,
                                        headers=headers,
                                        verify=False,
                                        **requests_kwargs)
            # fix encoding of response, based on Accept-Encoding header
            if "gzip" in headers.get(HEADER_ACCEPT_ENCODING, "").lower():
                response._content = gzip.compress(to_bytes(response._content))
                response.headers["Content-Length"] = str(len(
                    response._content))
                response.headers["Content-Encoding"] = "gzip"
            return response

    proxy_thread = start_proxy_server(port,
                                      update_listener=Listener(),
                                      use_ssl=True)
    return proxy_thread
示例#6
0
def do_start_edge(bind_address, port, use_ssl, asynchronous=False):
    from localstack.http.adapters import RouterListener
    from localstack.services.internal import LocalstackResourceHandler

    start_dns_server(asynchronous=True)

    listeners = [
        LocalstackResourceHandler(),  # handle internal resources first
        RouterListener(ROUTER),  # then custom routes
        PROXY_LISTENER_EDGE,  # then call the edge proxy listener
    ]

    # get port and start Edge
    print("Starting edge router (http%s port %s)..." % ("s" if use_ssl else "", port))
    # use use_ssl=True here because our proxy allows both, HTTP and HTTPS traffic
    proxy = start_proxy_server(
        port,
        bind_address=bind_address,
        use_ssl=True,
        update_listener=listeners,
        check_port=False,
    )
    if not asynchronous:
        proxy.join()
    return proxy
示例#7
0
def _do_start_ssl_proxy_with_client_auth(port: int, target: str,
                                         client_cert_key: Tuple[str, str]):
    base_url = f"{'https://' if '://' not in target else ''}{target.rstrip('/')}"

    # prepare cert files (TODO: check whether/how we can pass cert strings to requests.request(..) directly)
    cert_file = client_cert_key[0]
    if not os.path.exists(cert_file):
        cert_file = new_tmp_file()
        save_file(cert_file, client_cert_key[0])
    key_file = client_cert_key[1]
    if not os.path.exists(key_file):
        key_file = new_tmp_file()
        save_file(key_file, client_cert_key[1])
    cert_params = (cert_file, key_file)

    # define forwarding listener
    class Listener(ProxyListener):
        def forward_request(self, method, path, data, headers):
            url = f"{base_url}{path}"
            result = requests.request(method=method,
                                      url=url,
                                      data=data,
                                      headers=headers,
                                      cert=cert_params,
                                      verify=False)
            return result

    proxy_thread = start_proxy_server(port,
                                      update_listener=Listener(),
                                      use_ssl=True)
    return proxy_thread
示例#8
0
def start_proxy(port, backend_url=None, update_listener=None, quiet=False, params={}, use_ssl=None):
    use_ssl = config.USE_SSL if use_ssl is None else use_ssl
    proxy_thread = start_proxy_server(
        port=port,
        forward_url=backend_url,
        use_ssl=use_ssl,
        update_listener=update_listener,
        quiet=quiet,
        params=params,
    )
    return proxy_thread
示例#9
0
    def test_basic_https_invocation(self):
        class MyListener(ProxyListener):
            def forward_request(self, method, path, data, headers):
                return {"method": method, "path": path, "data": data}

        port = get_free_tcp_port()
        url = f"https://localhost:{port}/foo/bar"

        listener = MyListener()
        proxy = start_proxy_server(port, update_listener=listener, use_ssl=True)
        response = requests.post(url, verify=False)
        expected = {"method": "POST", "path": "/foo/bar", "data": ""}
        assert json.loads(to_str(response.content)) == expected
        proxy.stop()
示例#10
0
def do_start_edge(port, use_ssl, asynchronous=False):
    try:
        # start local DNS server, if present
        from localstack_ext.services import dns_server
        dns_server.start_servers()
    except Exception:
        pass

    # get port and start Edge
    print('Starting edge router (http%s port %s)...' % ('s' if use_ssl else '', port))
    # use use=True here because our proxy allows both, HTTP and HTTPS traffic
    proxy = start_proxy_server(port, use_ssl=True, update_listener=ProxyListenerEdge())
    if not asynchronous:
        proxy.join()
    return proxy
示例#11
0
def do_start_edge(bind_address, port, use_ssl, asynchronous=False):
    start_dns_server(asynchronous=True)

    # get port and start Edge
    print("Starting edge router (http%s port %s)..." % ("s" if use_ssl else "", port))
    # use use=True here because our proxy allows both, HTTP and HTTPS traffic
    proxy = start_proxy_server(
        port,
        bind_address=bind_address,
        use_ssl=True,
        update_listener=PROXY_LISTENER_EDGE,
    )
    if not asynchronous:
        proxy.join()
    return proxy
示例#12
0
    def test_ssl_proxy_server(self):
        class MyListener(ProxyListener):
            def forward_request(self, *args, **kwargs):
                invocations.append((args, kwargs))
                return {"foo": "bar"}

        invocations = []

        # start SSL proxy
        listener = MyListener()
        port = get_free_tcp_port()
        server = start_proxy_server(port,
                                    update_listener=listener,
                                    use_ssl=True)
        wait_for_port_open(port)

        # start SSL proxy
        proxy_port = get_free_tcp_port()
        proxy = start_ssl_proxy(proxy_port,
                                port,
                                asynchronous=True,
                                fix_encoding=True)
        wait_for_port_open(proxy_port)

        # invoke SSL proxy server
        url = f"https://{LOCALHOST_HOSTNAME}:{proxy_port}"
        num_requests = 3
        for i in range(num_requests):
            response = requests.get(url, verify=False)
            assert response.status_code == 200

        # assert backend server has been invoked
        assert len(invocations) == num_requests

        # invoke SSL proxy server with gzip response
        for encoding in ["gzip", "gzip, deflate"]:
            headers = {HEADER_ACCEPT_ENCODING: encoding}
            response = requests.get(url,
                                    headers=headers,
                                    verify=False,
                                    stream=True)
            result = response.raw.read()
            assert to_str(gzip.decompress(result)) == json.dumps(
                {"foo": "bar"})

        # clean up
        proxy.stop()
        server.stop()
示例#13
0
def proxy_server(proxy_listener, host="127.0.0.1", port=None) -> str:
    """
    Create a temporary proxy server on a random port (or the specified port) with the given proxy listener
    for the duration of the context manager.
    """
    from localstack.services.generic_proxy import start_proxy_server

    host = host
    port = port or get_free_tcp_port()
    thread = start_proxy_server(port, bind_address=host, update_listener=proxy_listener)
    url = f"http://{host}:{port}"
    assert poll_condition(
        lambda: is_port_open(port), timeout=5
    ), f"server on port {port} did not start"
    yield url
    thread.stop()
示例#14
0
def start_proxy(
    port: int,
    backend_url: str = None,
    update_listener=None,
    quiet: bool = False,
    use_ssl: bool = None,
):
    use_ssl = config.USE_SSL if use_ssl is None else use_ssl
    proxy_thread = start_proxy_server(
        port=port,
        forward_url=backend_url,
        use_ssl=use_ssl,
        update_listener=update_listener,
        quiet=quiet,
        check_port=False,
    )
    return proxy_thread
示例#15
0
    def test_http2_traffic(self):
        port = get_free_tcp_port()

        class MyListener(ProxyListener):
            def forward_request(self, method, path, data, headers):
                return {
                    'method': method, 'path': path, 'data': data
                }

        url = 'https://localhost:%s/foo/bar' % port

        listener = MyListener()
        proxy = start_proxy_server(port, update_listener=listener, use_ssl=True)
        time.sleep(1)
        response = requests.post(url, verify=False)
        self.assertEqual({'method': 'POST', 'path': '/foo/bar', 'data': ''}, json.loads(to_str(response.content)))
        proxy.stop()
示例#16
0
    def test_http2_traffic(self):
        port = get_free_tcp_port()

        class MyListener(ProxyListener):
            def forward_request(self, method, path, data, headers):
                return {"method": method, "path": path, "data": data}

        url = "https://localhost:%s/foo/bar" % port

        listener = MyListener()
        proxy = start_proxy_server(port,
                                   update_listener=listener,
                                   use_ssl=True)
        time.sleep(1)
        response = requests.post(url, verify=False)
        expected = {"method": "POST", "path": "/foo/bar", "data": ""}
        assert json.loads(to_str(response.content)) == expected
        proxy.stop()
示例#17
0
def test_download_with_timeout():
    class DownloadListener(ProxyListener):
        def forward_request(self, method, path, data, headers):
            if path == "/sleep":
                time.sleep(2)
            return {}

    port = get_free_tcp_port()
    proxy = start_proxy_server(port, update_listener=DownloadListener())

    tmp_file = new_tmp_file()
    download(f"http://localhost:{port}/", tmp_file)
    assert load_file(tmp_file) == "{}"
    with pytest.raises(TimeoutError):
        download(f"http://localhost:{port}/sleep", tmp_file, timeout=1)

    # clean up
    proxy.stop()
    rm_rf(tmp_file)
示例#18
0
def do_start_edge(bind_address, port, use_ssl, asynchronous=False):
    from localstack.services.internal import LocalstackResourceHandler

    # add internal routes as default listener
    ProxyListener.DEFAULT_LISTENERS.append(LocalstackResourceHandler())

    start_dns_server(asynchronous=True)

    # get port and start Edge
    print("Starting edge router (http%s port %s)..." % ("s" if use_ssl else "", port))
    # use use=True here because our proxy allows both, HTTP and HTTPS traffic
    proxy = start_proxy_server(
        port,
        bind_address=bind_address,
        use_ssl=True,
        update_listener=PROXY_LISTENER_EDGE,
    )
    if not asynchronous:
        proxy.join()
    return proxy
示例#19
0
    def test_forward_raw_path(self, monkeypatch):
        class MyListener(ProxyListener):
            def forward_request(self, method, path, data, headers):
                _path = get_full_raw_path(quart_request)
                return {"method": method, "path": _path}

        # start listener and configure EDGE_FORWARD_URL
        port = get_free_tcp_port()
        forward_url = f"http://localhost:{port}"
        listener = MyListener()
        proxy = start_proxy_server(port, update_listener=listener, use_ssl=True)
        monkeypatch.setattr(config, "EDGE_FORWARD_URL", forward_url)

        # run test request, assert that raw request path is forwarded
        test_arn = "arn:aws:test:resource/test"
        raw_path = f"/test/{urllib.parse.quote(test_arn)}/bar?q1=foo&q2=bar"
        url = f"{config.get_edge_url()}{raw_path}"
        response = requests.get(url)
        expected = {"method": "GET", "path": raw_path}
        assert json.loads(to_str(response.content)) == expected
        proxy.stop()
示例#20
0
    def test_static_route(self):
        class MyListener(ProxyListener):
            def forward_request(self, method, path, *args, **kwargs):
                return {"method": method, "path": path}

        # start proxy server
        listener = MyListener()
        port = get_free_tcp_port()
        server = start_proxy_server(port, update_listener=listener)
        wait_for_port_open(port)

        # request a /static/... path from the server and assert result
        url = f"http://{LOCALHOST_HOSTNAME}:{port}/static/index.html"
        response = requests.get(url, verify=False)
        assert response.ok
        assert json.loads(to_str(response.content)) == {
            "method": "GET",
            "path": "/static/index.html",
        }

        # clean up
        server.stop()