diff --git a/docs/manual/mod/mod_proxy_fcgi.xml b/docs/manual/mod/mod_proxy_fcgi.xml index fb3c7f8..c9f5941 100644 --- a/docs/manual/mod/mod_proxy_fcgi.xml +++ b/docs/manual/mod/mod_proxy_fcgi.xml @@ -119,4 +119,33 @@ ProxyPass /myapp/ balancer://myappcluster/ + + ProxyFCGIPassHeader + Header name which will be passed to FastCGI as environment variable. + ProxyFCGIPassHeader name + none + server config virtual host + +

This directive specifies the name of a request header which + will be passed to the FastCGI application as an environment + variable. The name of the environment variable is derived from + the value specified on this directive, as discussed below:

+ +

The value specified on this directive is converted to + upper case, prefixed with HTTP_, and hyphens are + converted to underscores.

+ + Note +

Most request headers are already available to the application + as environment variables, and generally are prefixed with + HTTP_. (Notable exceptions are Content-type + and Content-length, which do not have the + HTTP_ prefix.) Thus, this directive is only required + for request headers that are purposefully omitted, such as + Authorization and Proxy-Authorization. + Only pass these request headers if absolutely required.

+
+
+
+ diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index d7ab5cb..61447a6 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -20,6 +20,10 @@ module AP_MODULE_DECLARE_DATA proxy_fcgi_module; +typedef struct { + apr_array_header_t *pass_headers; +} fcgi_server_conf; + /* * Canonicalise http-like URLs. * scheme is the scheme for the URL @@ -193,6 +197,62 @@ static apr_status_t send_begin_request(proxy_conn_rec *conn, return send_data(conn, vec, 2, &len); } +/* http2env stolen from util_script.c */ +static char *http2env(request_rec *r, const char *w) +{ + char *res = (char *)apr_palloc(r->pool, sizeof("HTTP_") + strlen(w)); + char *cp = res; + char c; + + *cp++ = 'H'; + *cp++ = 'T'; + *cp++ = 'T'; + *cp++ = 'P'; + *cp++ = '_'; + + while ((c = *w++) != 0) { + if (apr_isalnum(c)) { + *cp++ = apr_toupper(c); + } + else if (c == '-') { + *cp++ = '_'; + } + else { + if (APLOGrtrace1(r)) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Not exporting header with invalid name as envvar: %s", + ap_escape_logitem(r->pool, w)); + return NULL; + } + } + *cp = 0; + + return res; +} + +static void fcgi_add_cgi_vars(request_rec * r) +{ + fcgi_server_conf *conf = + ap_get_module_config(r->server->module_config, &proxy_fcgi_module); + apr_array_header_t *passheaders = conf->pass_headers; + + if (passheaders != NULL) { + const char **hdr = (const char **) passheaders->elts; + int hdrcnt = passheaders->nelts; + int i; + + for (i = 0; i < hdrcnt; i++, ++hdr) { + /* standard munging of header name (upcase, HTTP_, etc.) */ + const char *name = http2env(r, *hdr); + const char *val = apr_table_get(r->headers_in, *hdr); + + if (name && val) { + apr_table_setn(r->subprocess_env, name, val); + } + } + } +} + static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, apr_pool_t *temp_pool, apr_uint16_t request_id) @@ -209,6 +269,7 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, ap_add_common_vars(r); ap_add_cgi_vars(r); + fcgi_add_cgi_vars(r); /* XXX are there any FastCGI specific env vars we need to send? */ @@ -840,6 +901,46 @@ cleanup: return status; } +static void *create_config(apr_pool_t *p, server_rec *s) +{ + fcgi_server_conf *conf = apr_palloc(p, sizeof(*conf)); + conf->pass_headers = apr_array_make(p, 10, sizeof(const char *)); + return conf; +} + +static void *merge_config(apr_pool_t *p, void *base_, void *add_) +{ + fcgi_server_conf *base = (fcgi_server_conf *)base_; + fcgi_server_conf *add = (fcgi_server_conf *)add_; + fcgi_server_conf *conf = apr_pcalloc(p, sizeof(*conf)); + + conf->pass_headers = apr_array_append(p, base->pass_headers, + add->pass_headers); + + return conf; +} + +static const char *add_pass_headers(cmd_parms * cmd, void *dummy, + const char *arg) +{ + const char **header; + fcgi_server_conf *conf = + ap_get_module_config(cmd->server->module_config, &proxy_fcgi_module); + + header = (const char **) apr_array_push(conf->pass_headers); + *header = ap_getword_conf(cmd->pool, &arg); + + return header ? NULL : "Invalid ProxyFCGIPassHeader"; +} + +static const command_rec fcgi_cmds[] = +{ + AP_INIT_TAKE1("ProxyFCGIPassHeader", add_pass_headers, + NULL, RSRC_CONF, + "Header name which will be passed to FastCGI as environment variable."), + {NULL} +}; + static void register_hooks(apr_pool_t *p) { proxy_hook_scheme_handler(proxy_fcgi_handler, NULL, NULL, APR_HOOK_FIRST); @@ -850,8 +951,8 @@ AP_DECLARE_MODULE(proxy_fcgi) = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ + create_config, /* create per-server config structure */ + merge_config, /* merge per-server config structures */ + fcgi_cmds, /* command apr_table_t */ register_hooks /* register hooks */ };