Re: [PATCH] support for environment variables in ProxyPassReverse

Carsten Gaebler <[email protected]> Wed, 18 Jun 2003 16:34:27 +0200
Newsgroups gmane.comp.apache.mod-proxy
Message-ID <[email protected]>
Graham Leggett wrote:
> Carsten Gaebler wrote:
[patch for 1.3.27 to support env vars in ProxyPassReverse]
> Is it possible to create a patch for Apache v2.0?

It's attached. I encountered one problem with Apache 1.3.27 and mod_ssl: 
you have to apply the mod_ssl patches (i.e. run configure) *before* the 
proxy patch. Otherwise the mod_ssl proxy patches don't get applied and 
any proxy rewrite rules using https fall back to http. Maybe this is 
something that should be taken care of.

cg.
proxypassreverse-env-2.0.patch (text/plain, 3.3 KB)
--- proxy_http.c.orig	Tue Apr 15 18:36:16 2003
+++ proxy_http.c	Wed Jun 18 11:35:07 2003
@@ -145,11 +145,75 @@
     return OK;
 }
  
+/* Substitute %{ENV:VARIABLE} with the value of the environment variable */
+/* VARIABLE (enhancement of the ProxyPassReverse directive).             */
+/* I found this "feature" in the first edition of Rob Flickenger's       */
+/* Linux Server Hacks book (O'Reilly) but it wasn't actually supported   */
+/* by Apache, so I implemented it. :-)                                   */
+static const char *expand_vars(request_rec *r, const char* s)
+{
+    const char* p;
+    char* var_start;
+    char* var_end;
+    char* var;
+    const char* value;
+    apr_array_header_t* result_array;
+
+    result_array = apr_array_make(r->pool, 4, sizeof(char *));
+    p = s;
+
+    while ((var_start = strstr(p, "%{ENV:")) != NULL) {
+        var_start += 6;
+
+        if ((var_end = strchr(var_start, '}')) == NULL) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                         "proxy: missing closing '}' in ENV expression: %s",
+                         s);
+            return s;
+        }
+
+        var = apr_pstrndup(r->pool, var_start, var_end - var_start);
+
+        /* get env-variable from the parent Apache process */
+        /* first try the internal Apache notes structure */
+        value = apr_table_get(r->notes, var);
+        /* second try the internal Apache env structure */
+        if (value == NULL) {
+            value = apr_table_get(r->subprocess_env, var);
+            /* third try the external OS env */
+            if (value == NULL) {
+                value = getenv(var);
+                if (value == NULL) {
+                    value = "";
+                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                                 "proxy: environment variable %s is empty",
+                                 var);
+                }
+            }
+        }
+      
+        *((const char **) apr_array_push(result_array)) =
+            apr_pstrndup(r->pool, p, var_start - p - 6);
+        
+        *((const char **) apr_array_push(result_array)) = value;
+
+        p = var_end + 1;
+    }
+
+    if ((p != NULL) && (*p != '\0')) {
+        *((const char **) apr_array_push(result_array)) = p;
+    }
+
+    return apr_array_pstrcat(r->pool, result_array, '\0');
+}
+
 static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
 {
     struct proxy_alias *ent;
     int i, l1, l2;
     char *u;
+    const char* fake;
+    const char* real;
 
     /* XXX FIXME: Make sure this handled the ambiguous case of the :80
      * after the hostname */
@@ -157,9 +221,11 @@
     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 = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+        fake = expand_vars(r, ent[i].fake);
+        real = expand_vars(r, ent[i].real);
+        l2 = strlen(real);
+        if (l1 >= l2 && strncmp(real, url, l2) == 0) {
+            u = apr_pstrcat(r->pool, fake, &url[l2], NULL);
             return ap_construct_url(r->pool, u, r);
         }
     }