From 3ea93a65e0b8769cada48297fa8b917fc4363ecc Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Fri, 18 Apr 2014 15:27:42 +0000 Subject: [PATCH] Merge r1543174, r1560367, r1560546, r1560689, r1560979, r1561137, r1561660 from trunk: Correct logic... if this is a UDS socket, then bypass all this. make mod_rewrite and mod_proxy UDS work together... Adjust url as required, following what we did to r->filename. Save some cycles when searching... Tuck away UDS path in request-rec, since worker isn't thread-safe. Protect from NULL refs. Reflow logic... pull UDS stuff out handle leak. thx to Y^2 r->filename should maintain the proxy: prefix for PHP-FPM Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1588494 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 12 -- modules/mappers/mod_rewrite.c | 1 + modules/proxy/mod_proxy.c | 4 + modules/proxy/mod_proxy.h | 4 + modules/proxy/proxy_util.c | 227 ++++++++++++++++++++-------------- 5 files changed, 143 insertions(+), 105 deletions(-) diff --git a/STATUS b/STATUS index aa83dca0f4..eec238a4e1 100644 --- a/STATUS +++ b/STATUS @@ -100,18 +100,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * proxy_util.c: Allow mod_rewrite to also use UDS for proxied links. - trunk patch: http://svn.apache.org/r1543174 - http://svn.apache.org/r1560367 - http://svn.apache.org/r1560546 - http://svn.apache.org/r1560689 - http://svn.apache.org/r1560979 - http://svn.apache.org/r1561137 - http://svn.apache.org/r1561660 - 2.4.x patch: trunk works - http://people.apache.org/~jim/patches/uds-rewrite.patch - +1: jim, humbedooh, ylavic - * mod_proxy_wstunnel: wstunnel rollup for connection handling trunk patch: http://svn.apache.org/r1587036 (set backend->close) http://svn.apache.org/r1587040 (remove reqtimeout) diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 7646407bf3..ad77fd6c34 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -4161,6 +4161,7 @@ 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 22a022099b..57f9e41b87 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -2631,6 +2631,8 @@ static void child_init(apr_pool_t *p, server_rec *s) ap_proxy_hashfunc(conf->forward->s->name, PROXY_HASHFUNC_FNV); /* Do not disable worker in case of errors */ conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS; + /* Mark as the "generic" worker */ + conf->forward->s->status |= PROXY_WORKER_GENERIC; ap_proxy_initialize_worker(conf->forward, s, conf->pool); /* Disable address cache for generic forward worker */ conf->forward->s->is_address_reusable = 0; @@ -2646,6 +2648,8 @@ static void child_init(apr_pool_t *p, server_rec *s) ap_proxy_hashfunc(reverse->s->name, PROXY_HASHFUNC_FNV); /* Do not disable worker in case of errors */ reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS; + /* Mark as the "generic" worker */ + reverse->s->status |= PROXY_WORKER_GENERIC; conf->reverse = reverse; ap_proxy_initialize_worker(conf->reverse, s, conf->pool); /* Disable address cache for generic reverse worker */ diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 67a9015be9..585ace89eb 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -275,6 +275,7 @@ struct proxy_conn_pool { #define PROXY_WORKER_INITIALIZED 0x0001 #define PROXY_WORKER_IGNORE_ERRORS 0x0002 #define PROXY_WORKER_DRAIN 0x0004 +#define PROXY_WORKER_GENERIC 0x0008 #define PROXY_WORKER_IN_SHUTDOWN 0x0010 #define PROXY_WORKER_DISABLED 0x0020 #define PROXY_WORKER_STOPPED 0x0040 @@ -286,6 +287,7 @@ struct proxy_conn_pool { #define PROXY_WORKER_INITIALIZED_FLAG 'O' #define PROXY_WORKER_IGNORE_ERRORS_FLAG 'I' #define PROXY_WORKER_DRAIN_FLAG 'N' +#define PROXY_WORKER_GENERIC_FLAG 'G' #define PROXY_WORKER_IN_SHUTDOWN_FLAG 'U' #define PROXY_WORKER_DISABLED_FLAG 'D' #define PROXY_WORKER_STOPPED_FLAG 'S' @@ -306,6 +308,8 @@ PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR ) #define PROXY_WORKER_IS_DRAINING(f) ( (f)->s->status & PROXY_WORKER_DRAIN ) +#define PROXY_WORKER_IS_GENERIC(f) ( (f)->s->status & PROXY_WORKER_GENERIC ) + /* default worker retry timeout in seconds */ #define PROXY_WORKER_DEFAULT_RETRY 60 diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index b9944ccbdc..741830c0b8 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1931,6 +1931,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); *balancer = NULL; @@ -1942,6 +1944,36 @@ 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 = '|'; + } + } } } } @@ -2101,29 +2133,6 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, (*conn)->close = 0; (*conn)->inreslist = 0; - if (*worker->s->uds_path) { - if ((*conn)->uds_path == NULL) { - /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ - (*conn)->uds_path = apr_pstrdup((*conn)->pool, worker->s->uds_path); - } - if ((*conn)->uds_path) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02545) - "%s: has determined UDS as %s", - proxy_function, (*conn)->uds_path); - } - else { - /* should never happen */ - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02546) - "%s: cannot determine UDS (%s)", - proxy_function, worker->s->uds_path); - - } - } - else { - (*conn)->uds_path = NULL; - } - - return OK; } @@ -2154,6 +2163,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, int server_port; apr_status_t err = APR_SUCCESS; apr_status_t uerr = APR_SUCCESS; + const char *uds_path; /* * Break up the URL to determine the host to connect to @@ -2194,85 +2204,116 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, * to check host and port on the conn and be careful about * spilling the cached addr from the worker. */ - if (!conn->hostname || !worker->s->is_address_reusable || - worker->s->disablereuse || *worker->s->uds_path) { - if (proxyname) { - conn->hostname = apr_pstrdup(conn->pool, proxyname); - conn->port = proxyport; - /* - * If we have a forward proxy and the protocol is HTTPS, - * then we need to prepend a HTTP CONNECT request before - * sending our actual HTTPS requests. - * Save our real backend data for using it later during HTTP CONNECT. - */ - if (conn->is_ssl) { - const char *proxy_auth; - - forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); - conn->forward = forward; - forward->use_http_connect = 1; - forward->target_host = apr_pstrdup(conn->pool, uri->hostname); - forward->target_port = uri->port; - /* Do we want to pass Proxy-Authorization along? - * If we haven't used it, then YES - * If we have used it then MAYBE: RFC2616 says we MAY propagate it. - * So let's make it configurable by env. - * The logic here is the same used in mod_proxy_http. - */ - proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); - if (proxy_auth != NULL && - proxy_auth[0] != '\0' && - r->user == NULL && /* we haven't yet authenticated */ - apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { - forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); - } - } + uds_path = (*worker->s->uds_path ? worker->s->uds_path : apr_table_get(r->notes, "uds_path")); + if (uds_path) { + if (conn->uds_path == NULL) { + /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ + conn->uds_path = apr_pstrdup(conn->pool, uds_path); } - else { - conn->hostname = apr_pstrdup(conn->pool, uri->hostname); - conn->port = uri->port; + if (conn->uds_path) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02545) + "%s: has determined UDS as %s", + uri->scheme, conn->uds_path); } - socket_cleanup(conn); - if (!(*worker->s->uds_path) && - (!worker->s->is_address_reusable || worker->s->disablereuse)) { - /* - * Only do a lookup if we should not reuse the backend address. - * Otherwise we will look it up once for the worker. - */ - err = apr_sockaddr_info_get(&(conn->addr), - conn->hostname, APR_UNSPEC, - conn->port, 0, - conn->pool); + else { + /* should never happen */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02546) + "%s: cannot determine UDS (%s)", + uri->scheme, uds_path); + } - } - if (!(*worker->s->uds_path) && worker->s->is_address_reusable && !worker->s->disablereuse) { /* - * Looking up the backend address for the worker only makes sense if - * we can reuse the address. + * In UDS cases, some structs are NULL. Protect from de-refs + * and provide info for logging at the same time. */ - if (!worker->cp->addr) { - if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); - return HTTP_INTERNAL_SERVER_ERROR; + if (!conn->addr) { + apr_sockaddr_t *sa; + apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 0, 0, conn->pool); + conn->addr = sa; + } + conn->hostname = "httpd-UDS"; + conn->port = 0; + } + else { + int will_reuse = worker->s->is_address_reusable && !worker->s->disablereuse; + if (!conn->hostname || !will_reuse) { + if (proxyname) { + conn->hostname = apr_pstrdup(conn->pool, proxyname); + conn->port = proxyport; + /* + * If we have a forward proxy and the protocol is HTTPS, + * then we need to prepend a HTTP CONNECT request before + * sending our actual HTTPS requests. + * Save our real backend data for using it later during HTTP CONNECT. + */ + if (conn->is_ssl) { + const char *proxy_auth; + + forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); + conn->forward = forward; + forward->use_http_connect = 1; + forward->target_host = apr_pstrdup(conn->pool, uri->hostname); + forward->target_port = uri->port; + /* Do we want to pass Proxy-Authorization along? + * If we haven't used it, then YES + * If we have used it then MAYBE: RFC2616 says we MAY propagate it. + * So let's make it configurable by env. + * The logic here is the same used in mod_proxy_http. + */ + proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); + if (proxy_auth != NULL && + proxy_auth[0] != '\0' && + r->user == NULL && /* we haven't yet authenticated */ + apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { + forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); + } + } } - + else { + conn->hostname = apr_pstrdup(conn->pool, uri->hostname); + conn->port = uri->port; + } + if (!will_reuse) { + /* + * Only do a lookup if we should not reuse the backend address. + * Otherwise we will look it up once for the worker. + */ + err = apr_sockaddr_info_get(&(conn->addr), + conn->hostname, APR_UNSPEC, + conn->port, 0, + conn->pool); + } + socket_cleanup(conn); + } + if (will_reuse) { /* - * Worker can have the single constant backend adress. - * The single DNS lookup is used once per worker. - * If dynamic change is needed then set the addr to NULL - * inside dynamic config to force the lookup. + * Looking up the backend address for the worker only makes sense if + * we can reuse the address. */ - err = apr_sockaddr_info_get(&(worker->cp->addr), - conn->hostname, APR_UNSPEC, - conn->port, 0, - worker->cp->pool); - conn->addr = worker->cp->addr; - if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); + if (!worker->cp->addr) { + if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* + * Worker can have the single constant backend adress. + * The single DNS lookup is used once per worker. + * If dynamic change is needed then set the addr to NULL + * inside dynamic config to force the lookup. + */ + err = apr_sockaddr_info_get(&(worker->cp->addr), + conn->hostname, APR_UNSPEC, + conn->port, 0, + worker->cp->pool); + conn->addr = worker->cp->addr; + if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); + } + } + else { + conn->addr = worker->cp->addr; } - } - else { - conn->addr = worker->cp->addr; } } /* Close a possible existing socket if we are told to do so */ -- 2.40.0