httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@engelschall.com (Ralf S. Engelschall)
Subject [PATCH] Apache as a Reverse Proxy
Date Thu, 12 Feb 1998 15:03:05 GMT

Apache as a Reverse Proxy
-------------------------

Because I'm currently writing an article for WebTechniques where I present a
stripped down Apache (only mod_rewrite+mod_proxy(+mod_mime :-( ) and no other
modules compiled in) which acts a high-performance reverse proxy in front of a
website cluster, I discovered that one really _essential_ feature is missing -
the following patch adds it: A ProxyPassReverse directive for mod_proxy !

Read the HTML snippet in the below patch to understand what is does.  In
short: It rewrites the Location-header on redirect responses so the reverse
proxy is still in the game...

(PS: I don't patches mod_proxy for any content rewriting because I 
     think when someone uses a reverse proxy he should know that his CGI
     scripts and HTML pages either only use non-fully-qualified URLs or at
     least use http://name-of-the-reverse-proxy/ as the prefix)

(PPS: Yes, I know that for the request spreading a reverse proxy
     also needs some way of randomly select its backend-servers
     and that Apache currently is missing this feature, too.
     But I've also already done this: See the recent patch for
     mod_rewrite which adds a RewriteMap type named "rnd" which
     is designed exctly for this! These two patches together
     lets act Apache as a full-featured high-performance Reverse
     Proxy.  The special configuration I will present in the
     article or on apache-core when someone is interested in)

Greetings,
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Index: htdocs/manual/mod/mod_proxy.html
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/htdocs/manual/mod/mod_proxy.html,v
retrieving revision 1.34
diff -u -r1.34 mod_proxy.html
--- mod_proxy.html	1998/02/05 22:34:05	1.34
+++ mod_proxy.html	1998/02/12 14:48:15
@@ -43,6 +43,7 @@
 <LI><A HREF="#proxyrequests">ProxyRequests</A>
 <LI><A HREF="#proxyremote">ProxyRemote</A>
 <LI><A HREF="#proxypass">ProxyPass</A>
+<LI><A HREF="#proxypass">ProxyPassReverse</A>
 <LI><A HREF="#proxyblock">ProxyBlock</A>
 <LI><A HREF="#noproxy">NoProxy</A>
 <LI><A HREF="#proxydomain">ProxyDomain</A>
@@ -197,6 +198,65 @@
 &lt;<SAMP>http://wibble.org/mirror/foo/bar</SAMP>&gt; to be
 internally converted into a proxy request to
 &lt;<SAMP>http://foo.com/bar</SAMP>&gt;.
+
+<HR>
+
+<H2><A NAME="proxypassreverse">ProxyPassReverse</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyPassReverse <EM>&lt;path&gt;
&lt;url&gt;</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>None</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> ProxyPassReverse is only available
in
+Apache 1.3 and later.<P>
+
+This directive lets Apache adjust the URL in the <TT>Location</TT> header on
+redirect responses. This is for instance essential when Apache is used as a
+reverse proxy. But can be a nifty trick in other situations, too.
+&lt;path&gt; is the name of a local virtual path; &lt;url&gt; is a partial
URL
+for the remote server - the same way they are used for the
+<TT>ProxyPass</TT> directive.
+<P>
+Suppose the local server has address <SAMP>http://wibble.org/</SAMP>; then
+<PRE>
+   ProxyPass         /mirror/foo http://foo.com
+   ProxyPassReverse  /mirror/foo http://foo.com
+</PRE>
+will not only cause a local request for the
+&lt;<SAMP>http://wibble.org/mirror/foo/bar</SAMP>&gt; to be
+internally converted into a proxy request to
+&lt;<SAMP>http://foo.com/bar</SAMP>&gt; (the functionality
+<SAMP>ProxyPass</SAMP> provides here). It also takes care of redirects the
+server foo.com sends: when <SAMP>http://foo.com/bar</SAMP> is redirected by him
+to <SAMP>http://foo.com/quux</SAMP> Apache adjusts this to
+<SAMP>http://wibble.org/mirror/foo/quux</SAMP> before forwarding the redirect
+reponse to the client. The <SAMP>ProxyPassReverse</SAMP> directive can also by
+used in conjunction with a ``<SAMP>RewriteRule .. ... [P]</SAMP>'' directive
from
+<A
+ HREF="mod_rewrite.html#RewriteRule"
+><TT>mod_rewrite</TT></A>.
 
 <HR>
 
Index: src/modules/proxy/mod_proxy.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/mod_proxy.c,v
retrieving revision 1.35
diff -u -r1.35 mod_proxy.c
--- mod_proxy.c	1998/02/02 22:33:38	1.35
+++ mod_proxy.c	1998/02/12 14:32:21
@@ -379,6 +379,7 @@
 
     ps->proxies = make_array(p, 10, sizeof(struct proxy_remote));
     ps->aliases = make_array(p, 10, sizeof(struct proxy_alias));
+    ps->raliases = make_array(p, 10, sizeof(struct proxy_alias));
     ps->noproxies = make_array(p, 10, sizeof(struct noproxy_entry));
     ps->dirconn = make_array(p, 10, sizeof(struct dirconn_entry));
     ps->nocaches = make_array(p, 10, sizeof(struct nocache_entry));
@@ -455,6 +456,20 @@
 }
 
 static const char *
+     add_pass_reverse(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    (proxy_server_conf *) get_module_config(s->module_config, &proxy_module);
+    struct proxy_alias *new;
+
+    new = push_array(conf->raliases);
+    new->fake = f;
+    new->real = r;
+    return NULL;
+}
+
+static const char *
      set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
 {
     server_rec *s = parms->server;
@@ -727,6 +742,8 @@
      "a scheme, partial URL or '*' and a proxy server"},
     {"ProxyPass", add_pass, NULL, RSRC_CONF, TAKE2,
      "a virtual path and a URL"},
+    {"ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF, TAKE2,
+     "a virtual path and a URL for reverse mapping"},
     {"ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE,
    "A list of names, hosts or domains to which the proxy will not connect"},
     {"NoProxy", set_proxy_dirconn, NULL, RSRC_CONF, ITERATE,
Index: src/modules/proxy/mod_proxy.h
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/mod_proxy.h,v
retrieving revision 1.26
diff -u -r1.26 mod_proxy.h
--- mod_proxy.h	1998/01/07 16:46:35	1.26
+++ mod_proxy.h	1998/02/12 14:32:26
@@ -191,6 +191,7 @@
     struct cache_conf cache;	/* cache configuration */
     array_header *proxies;
     array_header *aliases;
+    array_header *raliases;
     array_header *noproxies;
     array_header *dirconn;
     array_header *nocaches;
Index: src/modules/proxy/proxy_http.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/proxy_http.c,v
retrieving revision 1.37
diff -u -r1.37 proxy_http.c
--- proxy_http.c	1998/02/02 22:33:38	1.37
+++ proxy_http.c	1998/02/12 14:32:32
@@ -56,6 +56,7 @@
 #include "mod_proxy.h"
 #include "http_log.h"
 #include "http_main.h"
+#include "http_core.h"
 #include "util_date.h"
 
 /*
@@ -113,6 +114,28 @@
 		   path, (search) ? "?" : "", (search) ? search : "", NULL);
     return OK;
 }
+ 
+static char *proxy_location_reverse_map(request_rec *r, char *url)
+{
+    void *sconf;
+    proxy_server_conf *conf;
+	struct proxy_alias *ent;
+    int i, l1, l2;
+	char *u;
+
+    sconf = r->server->module_config;
+    conf = (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    l1 = strlen(url);
+	ent = (struct proxy_alias *)conf->raliases->elts;
+    for (i = 0; i < conf->raliases->nelts; i++) {
+        l2 = strlen(ent[i].real);
+        if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) {
+            u = pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+            return construct_url(r->pool, u, r);
+        }
+    }
+    return url;
+}
 
 /* Clear all connection-based headers from the incoming headers table */
 static void clear_connection(table *headers)
@@ -365,6 +388,9 @@
 	    strcasecmp(strp, "Last-Modified") == 0 ||
 	    strcasecmp(strp, "Expires") == 0)
 	    hdr[i].value = proxy_date_canon(p, hdr[i].value);
+	if (strcasecmp(strp, "Location") == 0 ||
+	    strcasecmp(strp, "URI") == 0)
+	    hdr[i].value = proxy_location_reverse_map(r, hdr[i].value);
     }
 
 /* check if NoCache directive on this host */
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Mime
View raw message