]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
*) mod_proxy_http2: use only the ':authority' header to forward 'Host'
authorStefan Eissing <icing@apache.org>
Tue, 20 Sep 2022 12:40:58 +0000 (12:40 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 20 Sep 2022 12:40:58 +0000 (12:40 +0000)
     information to a backend. Deduce ':authority' from what the client
     sent when 'ProxyPreserveHost' is on.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1904164 13f79535-47bb-0310-9956-ffa450edef68

changes-entries/h2_proxy_host.txt [new file with mode: 0644]
modules/http2/h2_proxy_session.c
test/modules/http2/htdocs/cgi/hello.py
test/modules/http2/htdocs/cgi/mnot164.py
test/modules/http2/test_100_conn_reuse.py
test/modules/http2/test_600_h2proxy.py

diff --git a/changes-entries/h2_proxy_host.txt b/changes-entries/h2_proxy_host.txt
new file mode 100644 (file)
index 0000000..bbf34d6
--- /dev/null
@@ -0,0 +1,4 @@
+  *) mod_proxy_http2: use only the ':authority' header to forward 'Host'
+     information to a backend. Deduce ':authority' from what the client
+     sent when 'ProxyPreserveHost' is on.
+     [Stefan Eissing]
\ No newline at end of file
index dfe3a2c245e21473269e25c6caeff3b4171d0368..36b177b76ab8c93deeb2460acab925a1d2c7d9c1 100644 (file)
@@ -838,7 +838,10 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url,
     
     dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
     if (dconf->preserve_host) {
-        authority = r->hostname;
+        authority = apr_table_get(r->headers_in, "Host");
+        if (authority == NULL) {
+            authority = r->hostname;
+        }
     }
     else {
         authority = puri.hostname;
@@ -847,6 +850,9 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url,
             /* port info missing and port is not default for scheme: append */
             authority = apr_psprintf(stream->pool, "%s:%d", authority, puri.port);
         }
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c,
+                      "authority=%s from uri.hostname=%s and uri.port=%d",
+                      authority, puri.hostname, puri.port);
     }
     
     /* we need this for mapping relative uris in headers ("Link") back
@@ -884,7 +890,8 @@ static apr_status_t open_stream(h2_proxy_session *session, const char *url,
                              r->server->server_hostname);
         }
     }
-    
+    apr_table_unset(r->headers_in, "Host");
+
     /* Tuck away all already existing cookies */
     stream->saves = apr_table_make(r->pool, 2);
     apr_table_do(add_header, stream->saves, r->headers_out, "Set-Cookie", NULL);
index 9fb2eb689d8f75c4a358035035ec731120a562d1..f9aed3f1a470851ec78ab02d9e7ba49673b78e4b 100644 (file)
@@ -6,6 +6,7 @@ print("Content-Type: application/json")
 print()
 print("{")
 print("  \"https\" : \"%s\"," % (os.getenv('HTTPS', '')))
+print("  \"x_host\" : \"%s\"," % (os.getenv('X_HOST', '')))
 print("  \"host\" : \"%s\"," % (os.getenv('SERVER_NAME', '')))
 print("  \"port\" : \"%s\"," % (os.getenv('SERVER_PORT', '')))
 print("  \"protocol\" : \"%s\"," % (os.getenv('SERVER_PROTOCOL', '')))
index 949b0f195b019c1a3c891ad202d7f0918af8a8fc..0e5d1072464008e5750ed39098bd0537702bc036 100644 (file)
@@ -12,10 +12,13 @@ try:
 except KeyError:
     text="a"
     count=77784
-    
-    
+
+count = int(count)
+
 print("Status: 200 OK")
 print("Content-Type: text/html")
 print()
-sys.stdout.write(text*int(count))
+sys.stdout.flush()
+for _ in range(count):
+    sys.stdout.write(text)
 
index e0b663190a33604643a2fa3003ad7304986fde66..3ebac24d60bf2cdd54de2f0bb9129c0077b1dc2f 100644 (file)
@@ -27,7 +27,7 @@ class TestConnReuse:
     def test_h2_100_02(self, env):
         url = env.mkurl("https", "cgi", "/hello.py")
         hostname = ("cgi-alias.%s" % env.http_tld)
-        r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
+        r = env.curl_get(url, 5, options=["-H", f"Host: {hostname}"])
         assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         assert hostname == r.response["json"]["host"]
index d27143d22c42a1f339db63eecaa26e35939391ad..0f368eda03ce8ff0d4fa1d6dd8a2c9c3b6c6f9cc 100644 (file)
@@ -6,16 +6,15 @@ from .env import H2Conf, H2TestEnv
 @pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here")
 class TestH2Proxy:
 
-    @pytest.fixture(autouse=True, scope='class')
-    def _class_scope(self, env):
-        conf = H2Conf(env)
+    def test_h2_600_01(self, env):
+        conf = H2Conf(env, extras={
+            f'cgi.{env.http_tld}': [
+                "SetEnvIf Host (.+) X_HOST=$1",
+            ]
+        })
         conf.add_vhost_cgi(h2proxy_self=True)
-        if env.verbosity > 1:
-            conf.add("LogLevel proxy:trace2 proxy_http2:trace2")
         conf.install()
         assert env.apache_restart() == 0
-
-    def test_h2_600_01(self, env):
         url = env.mkurl("https", "cgi", "/h2proxy/hello.py")
         r = env.curl_get(url, 5)
         assert r.response["status"] == 200
@@ -24,4 +23,42 @@ class TestH2Proxy:
         assert r.response["json"]["ssl_protocol"] != ""
         assert r.response["json"]["h2"] == "on"
         assert r.response["json"]["h2push"] == "off"
-        assert r.response["json"]["host"] == f"cgi.{env.http_tld}"
+        assert r.response["json"]["x_host"] == f"cgi.{env.http_tld}:{env.https_port}"
+
+    def test_h2_600_02(self, env):
+        conf = H2Conf(env, extras={
+            f'cgi.{env.http_tld}': [
+                "SetEnvIf Host (.+) X_HOST=$1",
+                f"ProxyPreserveHost on",
+                f"ProxyPass /h2c/ h2c://127.0.0.1:{env.http_port}/",
+            ]
+        })
+        conf.add_vhost_cgi()
+        conf.install()
+        assert env.apache_restart() == 0
+        url = env.mkurl("https", "cgi", "/h2c/hello.py")
+        r = env.curl_get(url, 5)
+        assert r.response["status"] == 200
+        assert r.response["json"]["protocol"] == "HTTP/2.0"
+        assert r.response["json"]["https"] == ""
+        # the proxied backend sees Host header as passed on front
+        assert r.response["json"]["x_host"] == f"cgi.{env.http_tld}:{env.https_port}"
+
+    def test_h2_600_03(self, env):
+        conf = H2Conf(env, extras={
+            f'cgi.{env.http_tld}': [
+                "SetEnvIf Host (.+) X_HOST=$1",
+                f"ProxyPreserveHost off",
+                f"ProxyPass /h2c/ h2c://127.0.0.1:{env.http_port}/",
+            ]
+        })
+        conf.add_vhost_cgi()
+        conf.install()
+        assert env.apache_restart() == 0
+        url = env.mkurl("https", "cgi", "/h2c/hello.py")
+        r = env.curl_get(url, 5)
+        assert r.response["status"] == 200
+        assert r.response["json"]["protocol"] == "HTTP/2.0"
+        assert r.response["json"]["https"] == ""
+        # the proxied backend sees Host as using in connecting to it
+        assert r.response["json"]["x_host"] == f"127.0.0.1:{env.http_port}"