From: Eric Covener Date: Wed, 14 Jan 2015 13:28:00 +0000 (+0000) Subject: Merge the following revisions from trunk: X-Git-Tag: 2.4.11~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bf91e089a09ddeaab17cf9e97558f2aa29cf7eca;p=apache Merge the following revisions from trunk: trunk patch: http://svn.apache.org/r1588544 (rewrite+UDS) http://svn.apache.org/r1641636 ('using default worker' msg tweak) http://svn.apache.org/r1647005 (tcp reuse) http://svn.apache.org/r1647009 (uds reuse) http://svn.apache.org/r1647334 (uds reuse fix) + 1 additional de_socketfy call in mod_proxy git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1651662 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index ca55b165fe..8714492413 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,17 @@ Changes with Apache 2.4.11 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" (] diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml index 6bd2803b34..38ae444c79 100644 --- a/docs/manual/mod/mod_proxy.xml +++ b/docs/manual/mod/mod_proxy.xml @@ -1018,6 +1018,12 @@ ProxyPass /mirror/foo http://backend.example.com robin DNS. To disable connection pooling reuse, set this property value to On. + enablereuse + On + This is the inverse of 'disablereuse' above, provided as a + convenience for scheme handlers that require opt-in for connection + reuse (such as mod_proxy_fcgi). + flushpackets off Determines whether the proxy module will auto-flush the output diff --git a/docs/manual/mod/mod_proxy_fcgi.xml b/docs/manual/mod/mod_proxy_fcgi.xml index 3dd95790a6..6fddb4403c 100644 --- a/docs/manual/mod/mod_proxy_fcgi.xml +++ b/docs/manual/mod/mod_proxy_fcgi.xml @@ -68,30 +68,26 @@ -

This application should be able to handle multiple concurrent - connections. mod_proxy 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 ProxyPass directive, as shown in - the following example:

- - Single application instance, no connection reuse +

mod_proxy_fcgi 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:

+ + Single application instance, connection reuse - ProxyPass /myapp/ fcgi://localhost:4000/ disablereuse=on + ProxyPass /myapp/ fcgi://localhost:4000/ enablereuse=on

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.

+ PHP-FPM is listening. Connection pooling is enabled.

PHP-FPM - ProxyPassMatch ^/myapp/.*\.php(/.*)?$ fcgi://localhost:9000/var/www/ + ProxyPassMatch ^/myapp/.*\.php(/.*)?$ fcgi://localhost:9000/var/www/ enablereuse=on @@ -101,7 +97,8 @@ the hostname and optional port following fcgi:// are ignored.

PHP-FPM with UDS - 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/" diff --git a/include/ap_mmn.h b/include/ap_mmn.h index b8f0bb5343..ca433d6d4b 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -436,6 +436,7 @@ * 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" */ @@ -443,7 +444,7 @@ #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 diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 2fe9bf9e07..de0c11ba54 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -4161,7 +4161,6 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) r->filename)); r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); - apr_table_setn(r->notes, "rewrite-proxy", "1"); return 1; } diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index b0c1a9c0ce..885a2c9eed 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -174,6 +174,15 @@ static const char *set_worker_param(apr_pool_t *p, 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. */ @@ -938,7 +947,6 @@ static int proxy_handler(request_rec *r) 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; @@ -1461,23 +1469,23 @@ static const char * 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; } @@ -1582,7 +1590,7 @@ static const char * } 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); @@ -1631,7 +1639,7 @@ static const char * 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); @@ -2110,7 +2118,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) } /* 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'", @@ -2196,7 +2204,7 @@ static const char * } } 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, @@ -2336,7 +2344,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) } 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); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 5b3473b029..89f5c0951a 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -1023,6 +1023,14 @@ int ap_proxy_lb_workers(void); */ 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*/ diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index 3079debf65..54a4e8dc48 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -835,11 +835,15 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, 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)) { diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 5809c02094..83131c1288 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1528,6 +1528,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, 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; @@ -1901,6 +1903,40 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke } } +/* + * 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, @@ -1915,8 +1951,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, 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) { @@ -1936,10 +1972,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, } 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; @@ -1949,36 +1983,7 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, * 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); } } }