diff --git a/rolo/proxy.py b/rolo/proxy.py index c5d125c..b704951 100644 --- a/rolo/proxy.py +++ b/rolo/proxy.py @@ -75,6 +75,9 @@ def forward( else: headers["X-Forwarded-For"] = f"{client_ip}" + if "X-Forwarded-Proto" not in request.headers and "X-Forwarded-Proto" not in headers: + headers["X-Forwarded-Proto"] = f"{request.scheme}" + if forward_path is None: forward_path = get_raw_path(request) if forward_path: diff --git a/tests/test_proxy.py b/tests/test_proxy.py index 62a09e0..89e83f2 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -111,7 +111,7 @@ def test_get_with_different_base_url_plain_rule(self, router_server, httpserver: assert response.ok assert response.text == "ok/bar/" # it's calling /bar/ because it's part of the root URL - def test_xff_header(self, router_server, httpserver: HTTPServer): + def test_x_forwarded_for_header(self, router_server, httpserver: HTTPServer): router, proxy = router_server backend = httpserver @@ -133,6 +133,28 @@ def _echo_headers(request): headers = response.json() assert headers["X-Forwarded-For"] == "127.0.0.2, 127.0.0.1" + def test_x_forwarded_proto_header(self, router_server, httpserver: HTTPServer): + router, proxy = router_server + backend = httpserver + + def _echo_headers(request): + return Response(json.dumps(dict(request.headers)), mimetype="application/json") + + backend.expect_request("/echo").respond_with_handler(_echo_headers) + + router.add("/", ProxyHandler(backend.url_for("/"))) + + response = requests.get(proxy.url + "/echo") + assert response.ok + headers = response.json() + assert headers["X-Forwarded-Proto"] == "http" + + # Any existing X-Forwarded-Proto header should not be overwritten + response = requests.get(proxy.url + "/echo", headers={"X-Forwarded-Proto": "https"}) + assert response.ok + headers = response.json() + assert headers["X-Forwarded-Proto"] == "https" + def test_post_form_data_with_query_args(self, router_server, httpserver: HTTPServer): router, proxy = router_server backend = httpserver