request headers earlier. Adds "MergeTrailers" directive to restore
legacy behavior. [Edward Lu, Yann Ylavic, Joe Orton, Eric Covener]
+ *) mod_proxy_fcgi: Enable UDS backends configured with SetHandler/RewriteRule
+ to opt-in to connection reuse and other Proxy options via explicitly
+ declared "proxy workers" (<Proxy unix:... enablereuse=on max=...)
+ [Eric Covener]
+
+ *) mod_proxy: Add "enablereuse" option as the inverse of "disablereuse".
+ [Eric Covener]
+
+ *) mod_proxy_fcgi: Enable opt-in to TCP connection reuse by explicitly
+ setting proxy option disablereuse=off. [Eric Covener] PR 57378.
+
*) event: Update the internal "connection id" when requests
move from thread to thread. Reuse can confuse modules like
mod_cgid. PR 57435. [Michael Thorpe <mike gistnet.com>]
robin DNS. To disable connection pooling reuse,
set this property value to <code>On</code>.
</td></tr>
+ <tr><td>enablereuse</td>
+ <td>On</td>
+ <td>This is the inverse of 'disablereuse' above, provided as a
+ convenience for scheme handlers that require opt-in for connection
+ reuse (such as <module>mod_proxy_fcgi</module>).
+ </td></tr>
<tr><td>flushpackets</td>
<td>off</td>
<td>Determines whether the proxy module will auto-flush the output
</highlight>
</example>
- <p>This application should be able to handle multiple concurrent
- connections. <module>mod_proxy</module> enables connection reuse by
- default, so after a request has been completed the connection will be
- held open by that httpd child process and won't be reused until that
- httpd process routes another request to the application. If the
- FastCGI application is unable to handle enough concurrent connections
- from httpd, requests can block waiting for the application to close
- an existing connection. One way to resolve this is to disable connection
- reuse on the <directive>ProxyPass</directive> directive, as shown in
- the following example:</p>
-
- <example><title>Single application instance, no connection reuse</title>
+ <p> <module>mod_proxy_fcgi</module> disables connection reuse by
+ default, so after a request has been completed the connection will NOT be
+ held open by that httpd child process and won't be reused. If the
+ FastCGI application is able to handle concurrent connections
+ from httpd, you can opt-in to connection reuse as shown in the following
+ example:</p>
+
+ <example><title>Single application instance, connection reuse</title>
<highlight language="config">
- ProxyPass /myapp/ fcgi://localhost:4000/ disablereuse=on
+ ProxyPass /myapp/ fcgi://localhost:4000/ enablereuse=on
</highlight>
</example>
<p> The following example passes the request URI as a filesystem
path for the PHP-FPM daemon to run. The request URL is implicitly added
to the 2nd parameter. The hostname and port following fcgi:// are where
- PHP-FPM is listening.</p>
+ PHP-FPM is listening. Connection pooling is enabled.</p>
<example><title>PHP-FPM</title>
<highlight language="config">
- ProxyPassMatch ^/myapp/.*\.php(/.*)?$ fcgi://localhost:9000/var/www/
+ ProxyPassMatch ^/myapp/.*\.php(/.*)?$ fcgi://localhost:9000/var/www/ enablereuse=on
</highlight>
</example>
the hostname and optional port following fcgi:// are ignored.</p>
<example><title>PHP-FPM with UDS</title>
<highlight language="config">
- ProxyPassMatch ^/(.*\.php(/.*)?)$ "unix:/var/run/php5-fpm.sock|fcgi://localhost/var/www/"
+ # UDS does not currently support connection reuse
+ ProxyPassMatch ^/(.*\.php(/.*)?)$ "unix:/var/run/php5-fpm.sock|fcgi://localhost/var/www/"
</highlight>
</example>
* 20120211.38 (2.4.11-dev) Added ap_shutdown_conn().
* 20120211.39 (2.4.11-dev) Add ap_proxy_connect_uds().
* 20120211.40 (2.4.11-dev) Add ap_log_data(), ap_log_rdata(), etc.
+ * 20120211.41 (2.4.11-dev) Add ap_proxy_de_socketfy to mod_proxy.h
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20120211
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 40 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 41 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
r->filename));
r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL);
- apr_table_setn(r->notes, "rewrite-proxy", "1");
return 1;
}
return "DisableReuse must be On|Off";
worker->s->disablereuse_set = 1;
}
+ else if (!strcasecmp(key, "enablereuse")) {
+ if (!strcasecmp(val, "on"))
+ worker->s->disablereuse = 0;
+ else if (!strcasecmp(val, "off"))
+ worker->s->disablereuse = 1;
+ else
+ return "EnableReuse must be On|Off";
+ worker->s->disablereuse_set = 1;
+ }
else if (!strcasecmp(key, "route")) {
/* Worker route.
*/
strncmp(r->filename, "proxy:", 6) != 0) {
r->proxyreq = PROXYREQ_REVERSE;
r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
- apr_table_setn(r->notes, "rewrite-proxy", "1");
}
else {
return DECLINED;
return add_proxy(cmd, dummy, f1, r1, 1);
}
-static char *de_socketfy(apr_pool_t *p, char *url)
+PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
{
- char *ptr;
+ const char *ptr;
/*
* We could be passed a URL during the config stage that contains
* the UDS path... ignore it
*/
if (!strncasecmp(url, "unix:", 5) &&
- ((ptr = ap_strchr(url, '|')) != NULL)) {
+ ((ptr = ap_strchr_c(url, '|')) != NULL)) {
/* move past the 'unix:...|' UDS path info */
- char *ret, *c;
+ const char *ret, *c;
ret = ptr + 1;
/* special case: "unix:....|scheme:" is OK, expand
* to "unix:....|scheme://localhost"
* */
- c = ap_strchr(ret, ':');
+ c = ap_strchr_c(ret, ':');
if (c == NULL) {
return NULL;
}
}
new->fake = apr_pstrdup(cmd->pool, f);
- new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r));
+ new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r));
new->flags = flags;
if (use_regex) {
new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED);
new->balancer = balancer;
}
else {
- proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r));
+ proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->pool, r));
int reuse = 0;
if (!worker) {
const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0);
}
/* Try to find existing worker */
- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name));
+ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
if (!worker) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147)
"Defining worker '%s' for balancer '%s'",
}
}
else {
- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name));
+ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name));
if (!worker) {
if (in_proxy_section) {
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
}
else {
worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf,
- de_socketfy(cmd->temp_pool, (char*)conf->p));
+ ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p));
if (!worker) {
err = ap_proxy_define_worker(cmd->pool, &worker, NULL,
sconf, conf->p, 0);
*/
PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme);
+/**
+ * Strip a unix domain socket (UDS) prefix from the input URL
+ * @param p pool to allocate result from
+ * @param url a URL potentially prefixed with a UDS path
+ * @return URL with the UDS prefix removed
+ */
+PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url);
+
extern module PROXY_DECLARE_DATA proxy_module;
#endif /*MOD_PROXY_H*/
goto cleanup;
}
- /* XXX Setting close to 0 is a great way to end up with
- * timeouts at this point, since we lack good ways to manage the
- * back end fastcgi processes. This should be revisited when we
- * have a better story on that part of things. */
+ /* This scheme handler does not reuse connections by default, to
+ * avoid tieing up a fastcgi that isn't expecting to work on
+ * parallel requests. But if the user went out of their way to
+ * type the default value of disablereuse=off, we'll allow it.
+ */
backend->close = 1;
+ if (worker->s->disablereuse_set && !worker->s->disablereuse) {
+ backend->close = 0;
+ }
/* Step Two: Make the Connection */
if (ap_proxy_connect_backend(FCGI_SCHEME, backend, worker, r->server)) {
return NULL;
}
+ url = ap_proxy_de_socketfy(p, url);
+
c = ap_strchr_c(url, ':');
if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
return NULL;
}
}
+/*
+ * In the case of the reverse proxy, we need to see if we
+ * were passed a UDS url (eg: from mod_proxy) and adjust uds_path
+ * as required.
+ */
+static void fix_uds_filename(request_rec *r, char **url)
+{
+ char *ptr, *ptr2;
+ if (!r || !r->filename) return;
+
+ if (!strncmp(r->filename, "proxy:", 6) &&
+ (ptr2 = ap_strcasestr(r->filename, "unix:")) &&
+ (ptr = ap_strchr(ptr2, '|'))) {
+ apr_uri_t urisock;
+ apr_status_t rv;
+ *ptr = '\0';
+ rv = apr_uri_parse(r->pool, ptr2, &urisock);
+ if (rv == APR_SUCCESS) {
+ char *rurl = ptr+1;
+ char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
+ apr_table_setn(r->notes, "uds_path", sockpath);
+ *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
+ /* r->filename starts w/ "proxy:", so add after that */
+ memmove(r->filename+6, rurl, strlen(rurl)+1);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "*: rewrite of url due to UDS(%s): %s (%s)",
+ sockpath, *url, r->filename);
+ }
+ else {
+ *ptr = '|';
+ }
+ }
+}
+
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
proxy_balancer **balancer,
request_rec *r,
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
"%s: found worker %s for %s",
(*worker)->s->scheme, (*worker)->s->name, *url);
-
*balancer = NULL;
+ fix_uds_filename(r, url);
access_status = OK;
}
else if (r->proxyreq == PROXYREQ_PROXY) {
}
else if (r->proxyreq == PROXYREQ_REVERSE) {
if (conf->reverse) {
- char *ptr;
- char *ptr2;
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
- "*: found reverse proxy worker for %s", *url);
+ "*: using default reverse proxy worker for %s (no keepalive)", *url);
*balancer = NULL;
*worker = conf->reverse;
access_status = OK;
* regarding the Connection header in the request.
*/
apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
- /*
- * In the case of the generic reverse proxy, we need to see if we
- * were passed a UDS url (eg: from mod_proxy) and adjust uds_path
- * as required.
- *
- * NOTE: Here we use a quick note lookup, but we could also
- * check to see if r->filename starts with 'proxy:'
- */
- if (apr_table_get(r->notes, "rewrite-proxy") &&
- (ptr2 = ap_strcasestr(r->filename, "unix:")) &&
- (ptr = ap_strchr(ptr2, '|'))) {
- apr_uri_t urisock;
- apr_status_t rv;
- *ptr = '\0';
- rv = apr_uri_parse(r->pool, ptr2, &urisock);
- if (rv == APR_SUCCESS) {
- char *rurl = ptr+1;
- char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path);
- apr_table_setn(r->notes, "uds_path", sockpath);
- *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */
- /* r->filename starts w/ "proxy:", so add after that */
- memmove(r->filename+6, rurl, strlen(rurl)+1);
- ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
- "*: rewrite of url due to UDS(%s): %s (%s)",
- sockpath, *url, r->filename);
- }
- else {
- *ptr = '|';
- }
- }
+ fix_uds_filename(r, url);
}
}
}