</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>
#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;
BACKEND_GENERIC,
} fcgi_backend_t;
+
#define FCGI_MAY_BE_FPM(dconf) \
(dconf && \
((dconf->backend_type == BACKEND_DEFAULT_UNKNOWN) || \
typedef struct {
fcgi_backend_t backend_type;
+ apr_array_header_t *env_fixups;
} fcgi_dirconf_t;
/*
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,
ap_add_common_vars(r);
ap_add_cgi_vars(r);
+ fix_cgivars(r, dconf);
if (fpm || apr_table_get(r->notes, "virtual_script")) {
/*
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;
}
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;
}
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);
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 }
};