There is a feature I have wanted in Apache for a little while now: the
ability to preserve the host header when using mod_proxy.  This is
mostly useful for two (or more) tier systems, where it is desirable to
pass certain virtual server requests through to backend servers.

The attached patch adds an option:

    ProxyPreserveHostHeader On|Off

This option, when set, causes the Host: header of the proxy request to
be passed on intact (including port number) to the backend server.  I
know there are other ways of jiggering this, but none I have found are
quite as neat.  My primary goal in implementing this is to leave the
front end server configuration untouched (with a wildcard dns entry
pointed at it) and have unmatched virtual hosts passed through to a
backend server on a different host/port.  The servers running on this
backend server change with time.

Regards,
Matt

-- 
Matt Kern
http://www.undue.org/
diff -ur proxy/mod_proxy.c proxy/mod_proxy.c
--- proxy/mod_proxy.c   Thu May 30 17:11:32 2002
+++ proxy/mod_proxy.c   Thu May 30 17:54:01 2002
@@ -436,6 +436,8 @@
     ps->viaopt_set = 0;         /* 0 means default */
     ps->req = 0;
     ps->req_set = 0;
+    ps->hheader = 0;
+    ps->hheader_set = 0;
     ps->recv_buffer_size = 0;   /* this default was left unset for some
                                  * reason */
     ps->recv_buffer_size_set = 0;
@@ -483,6 +485,7 @@
     ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
     ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
     ps->req = (overrides->req_set == 0) ? base->req : overrides->req;
+    ps->hheader = (overrides->hheader_set == 0) ? base->hheader : overrides->hheader;
     ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? 
base->recv_buffer_size : overrides->recv_buffer_size;
     ps->io_buffer_size = (overrides->io_buffer_size_set == 0) ? base->io_buffer_size 
: overrides->io_buffer_size;
 
@@ -703,6 +706,19 @@
 
 
 static const char *
+     set_proxy_preserve_host_header(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    psf->hheader = flag;
+    psf->hheader_set = 1;
+
+    return NULL;
+}
+
+
+static const char *
      set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
 {
     proxy_server_conf *psf =
@@ -936,6 +952,8 @@
     "a virtual path and a URL"},
     {"ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF, TAKE2,
     "a virtual path and a URL for reverse proxy behaviour"},
+    {"ProxyPreserveHostHeader", set_proxy_preserve_host_header, NULL, RSRC_CONF, FLAG,
+    "on if the original Host: header should be preserved"},
     {"ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE,
     "A list of names, hosts or domains to which the proxy will not connect"},
     {"ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF, TAKE1,
diff -ur proxy/mod_proxy.h proxy/mod_proxy.h
--- proxy/mod_proxy.h   Thu May 30 17:11:32 2002
+++ proxy/mod_proxy.h   Thu May 30 17:52:48 2002
@@ -192,6 +192,8 @@
     char *domain;               /* domain name to use in absence of a domain name in 
the request */
     int req;                    /* true if proxy requests are enabled */
     char req_set;
+    int hheader;               /* true if we want to preserve the host header */
+    char hheader_set;
     enum {
       via_off,
       via_on,
diff -ur proxy/proxy_http.c proxy/proxy_http.c
--- proxy/proxy_http.c  Thu May 30 17:11:32 2002
+++ proxy/proxy_http.c  Thu May 30 18:38:03 2002
@@ -177,6 +177,7 @@
     struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
     struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
     int nocache = 0;
+    int incoming_port = htons ((unsigned short)r->connection->local_addr.sin_port);
 
     if (conf->cache.root == NULL)
         nocache = 1;
@@ -312,10 +313,20 @@
     ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.1" CRLF,
               NULL);
     /* Send Host: now, adding it to req_hdrs wouldn't be much better */
-    if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
+    if (conf->hheader) {
+      i = ap_get_server_port(r);
+      if (ap_is_default_port(i, r))
+       strcpy(portstr, "");
+      else
+       ap_snprintf (portstr, sizeof portstr, ":%d", i);
+      ap_bvputs(f, "Host: ", r->hostname, portstr, CRLF, NULL);
+    }
+    else {
+      if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
         ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
-    else
+      else
         ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
+    }
 
     if (conf->viaopt == via_block) {
         /* Block all outgoing Via: headers */

Reply via email to