]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
add ProxyFCGISetEnvIf
authorEric Covener <covener@apache.org>
Wed, 1 Feb 2017 23:07:53 +0000 (23:07 +0000)
committerEric Covener <covener@apache.org>
Wed, 1 Feb 2017 23:07:53 +0000 (23:07 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1781329 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/mod/mod_proxy_fcgi.xml
modules/proxy/mod_proxy_fcgi.c

diff --git a/CHANGES b/CHANGES
index a09fdfdc0df5ea9359eda7127916d8fcd93022ab..cc97a4e527b259a11ba981555a681ae067de55d2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_proxy_fcgi: Add ProxyFCGISetEnvIf to fixup CGI environment
+     variables just before invoking the FastCGI. [Eric Covener]
+
   *) mod_proxy: Allow the per-request environment variable "no-proxy" to
      be used as an alternative to ProxyPass /path !. This is primarily
      to set exceptions for ProxyPass specified in <Location> context.
index 9cdeddfa8d41f759135850e97a5219dbfd12e6ff..bbe4813aa582afc405912056f903123cec8ac601 100644 (file)
@@ -224,4 +224,64 @@ scenarios.</p>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>ProxyFCGISetEnvIf</name>
+<description>Allow variables sent to FastCGI servers to be fixed up</description>
+<syntax>ProxyFCGISetEnvIf <var>conditional-expression</var>
+    <var>environment-variable-name</var>
+    <var>value-expression</var></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context><context>directory</context>
+<context>.htaccess</context></contextlist>
+<compatibility>Available in version 2.5 and later</compatibility>
+
+<usage>
+<p>Just before passing a request to the configured FastCGI server, the core of
+the web server sets a number of environment variables based on details of the
+current request. FastCGI programs often uses these environment variables
+as inputs that determine what underlying scripts they will process, or what
+output they directly produce.</p>
+<p>Examples of noteworthy environment variables are:</p>
+<ul>
+  <li>SCRIPT_NAME</li>
+  <li>SCRIPT_FILENAME</li>
+  <li>REQUEST_URI</li>
+  <li>PATH_INFO</li>
+  <li>PATH_TRANSLATED</li>
+</ul>
+
+<p>This directive allows the environment variables above, or any others of 
+interest, to be overridden.  This directive is evaluated after the initial
+values for these variables are set, so they can be used as input into both
+the condition expressions and value expressions.</p>
+<p>Parameter syntax:</p>
+<dl>
+<dt>conditional-expression</dt> 
+<dd>Specifies an expression that controls whether the environmen variable that
+   follows will be modified.  For information on the expression syntax, see 
+   the examples that follow or the full specification at the 
+   <a href="../expr.html">ap_expr</a> documentation.
+   </dd>
+<dt>environment-variable-name</dt> 
+<dd> Specifies the CGI environment variable to change,
+   such as PATH_INFO.</dd>
+<dt>value-expression</dt>
+<dd>Specifies the replacement value for the preceding environment variable.  Backreferences, such as "$1",
+can be included from regular expression captures in <var>conditional-expression</var></dd>
+</dl>
+  
+<example>
+# A basic, unconditional override<br/>
+ProxyFCGISetEnvIf "true" PATH_INFO "/example"<br/>
+<br/>
+# Use an environment variable in the value<br/>
+ProxyFCGISetEnvIf "true" PATH_INFO "%{reqenv:SCRIPT_NAME}"<br/>
+<br/>
+# Use captures in the conditions and backreferences in the replacement<br/>
+ProxyFCGISetEnvIf "reqenv('PATH_TRANSLATED') =~ m#(/.*prefix)(\d+)(.*)#" PATH_TRANSLATED "$1$3"<br/>
+</example>
+
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index 83f6304b42579ec1cbc99829e0f21b1c773f3fb4..4537c06312e41f90a2b6fcc1928783861176af4d 100644 (file)
 #include "mod_proxy.h"
 #include "util_fcgi.h"
 #include "util_script.h"
+#include "ap_expr.h"
 
 module AP_MODULE_DECLARE_DATA proxy_fcgi_module;
 
+typedef struct {
+    ap_expr_info_t *cond;   
+    ap_expr_info_t *subst;   
+    const char *envname;
+} sei_entry;
+
 typedef struct {
     int need_dirwalk;
 } fcgi_req_config_t;
@@ -31,6 +38,7 @@ typedef enum {
     BACKEND_GENERIC,
 } fcgi_backend_t;
 
+
 #define FCGI_MAY_BE_FPM(dconf)                              \
         (dconf &&                                           \
         ((dconf->backend_type == BACKEND_DEFAULT_UNKNOWN) || \
@@ -38,6 +46,7 @@ typedef enum {
 
 typedef struct {
     fcgi_backend_t backend_type;
+    apr_array_header_t *env_fixups;
 } fcgi_dirconf_t;
 
 /*
@@ -149,6 +158,45 @@ static int proxy_fcgi_canon(request_rec *r, char *url)
     return OK;
 }
 
+
+/*
+  ProxyFCGISetEnvIf "reqenv('PATH_INFO') =~ m#/foo(\d+)\.php$#" COVENV1 "$1"
+  ProxyFCGISetEnvIf "reqenv('PATH_INFO') =~ m#/foo(\d+)\.php$#" PATH_INFO "/foo.php"
+  ProxyFCGISetEnvIf "reqenv('PATH_TRANSLATED') =~ m#(/.*foo)(\d+)(.*)#" PATH_TRANSLATED "$1$3"
+*/
+static void fix_cgivars(request_rec *r, fcgi_dirconf_t *dconf)
+{ 
+    sei_entry *entries;
+    const char *err, *src; 
+    int i = 0, rc = 0;
+    ap_regmatch_t regm[AP_MAX_REG_MATCH];
+
+    entries = (sei_entry *) dconf->env_fixups->elts;
+    for (i = 0; i < dconf->env_fixups->nelts; i++) { 
+        sei_entry *entry = &entries[i];
+        if (0 < (rc = ap_expr_exec_re(r, entry->cond, AP_MAX_REG_MATCH, regm, &src, &err)))  { 
+            const char *val = ap_expr_str_exec_re(r, entry->subst, AP_MAX_REG_MATCH, regm, &src, &err);
+            if (err) { 
+                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO()
+                              "Error evaluating expression for replacment of %s: '%s'", 
+                               entry->envname, err);
+                continue;
+            }
+            if (APLOGrtrace4(r)) { 
+                const char *oldval = apr_table_get(r->subprocess_env, entry->envname);
+                ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, 
+                              "fix_cgivars: override %s from '%s' to '%s'", 
+                              entry->envname, oldval, val);
+        
+            }
+            apr_table_setn(r->subprocess_env, entry->envname, val);
+        } 
+        else { 
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, "fix_cgivars: Condition returned %d", rc);
+        }
+    }
+}
+
 /* Wrapper for apr_socket_sendv that handles updating the worker stats. */
 static apr_status_t send_data(proxy_conn_rec *conn,
                               struct iovec *vec,
@@ -323,6 +371,7 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r,
 
     ap_add_common_vars(r);
     ap_add_cgi_vars(r);
+    fix_cgivars(r, dconf);
  
     if (fpm || apr_table_get(r->notes, "virtual_script")) {
         /*
@@ -1035,6 +1084,8 @@ static void *fcgi_create_dconf(apr_pool_t *p, char *path)
 
     a = (fcgi_dirconf_t *)apr_pcalloc(p, sizeof(fcgi_dirconf_t));
     a->backend_type = BACKEND_DEFAULT_UNKNOWN;
+    a->env_fixups = apr_array_make(p, 20, sizeof(sei_entry));
+
     return a;
 }
 
@@ -1049,6 +1100,7 @@ static void *fcgi_merge_dconf(apr_pool_t *p, void *basev, void *overridesv)
     a->backend_type = (over->backend_type != BACKEND_DEFAULT_UNKNOWN) 
                       ? over->backend_type 
                       : base->backend_type;
+    a->env_fixups = apr_array_append(p, base->env_fixups, over->env_fixups);
     return a;
 }
 
@@ -1071,6 +1123,32 @@ static const char *cmd_servertype(cmd_parms *cmd, void *in_dconf,
     return NULL;
 }
 
+
+static const char *cmd_setenv(cmd_parms *cmd, void *in_dconf,
+                              const char *arg1, const char *arg2, 
+                              const char *arg3)
+{
+    fcgi_dirconf_t *dconf = in_dconf;
+    const char *err;
+    sei_entry *new;
+    const char *envvar = arg2;
+
+    new = apr_array_push(dconf->env_fixups);
+    new->cond = ap_expr_parse_cmd(cmd, arg1, 0, &err, NULL);
+    if (err) { 
+        return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s",
+                            arg1, err);
+    }
+    new->subst = ap_expr_parse_cmd(cmd, arg3, AP_EXPR_FLAG_STRING_RESULT, &err, NULL);
+    if (err) { 
+        return apr_psprintf(cmd->pool, "Could not parse expression \"%s\": %s",
+                            arg3, err);
+    }
+
+    new->envname = envvar;
+
+    return NULL;
+}
 static void register_hooks(apr_pool_t *p)
 {
     proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST);
@@ -1080,6 +1158,8 @@ static void register_hooks(apr_pool_t *p)
 static const command_rec command_table[] = {
     AP_INIT_TAKE1("ProxyFCGIBackendType", cmd_servertype, NULL, OR_FILEINFO,
                   "Specify the type of FastCGI server: 'Generic', 'FPM'"),
+    AP_INIT_TAKE3("ProxyFCGISetEnvIf", cmd_setenv, NULL, OR_FILEINFO,
+                  "expr-condition env-name expr-value"),
     { NULL }
 };