--- modules/proxy/proxy_util.c (revision 1526505) +++ modules/proxy/proxy_util.c (working copy) @@ -1333,6 +1333,13 @@ static void init_conn_pool(apr_pool_t *p, proxy_wo worker->cp = cp; } +static void socket_cleanup(proxy_conn_rec *conn) +{ + conn->sock = NULL; + conn->connection = NULL; + apr_pool_clear(conn->scpool); +} + static apr_status_t connection_cleanup(void *theconn) { proxy_conn_rec *conn = (proxy_conn_rec *)theconn; @@ -1351,12 +1358,31 @@ static apr_status_t connection_cleanup(void *theco conn->r = NULL; } - /* Sanity check: Did we already return the pooled connection? */ + /* If the connection was not acquired from the reslist, it was from the + * optional function ap_proxy_acquire_connection_ex (1for1 connection), + * so it will be closed/freed with the client's connection pool. + * + * + * The flag 'inreslist' has been hijacked (to preserve the 2.4.x API), it + * was originally used here to check a double-release of the connection, + * being unset when acquired and set when released (below). + * + * The check was broken (per se) since nothing can help when the same + * connection is released twice, the reslist might have destroy it the + * first time or else given it to another thread before the second time, + * it could also work sometimes... + * + * The flag is now misnamed, but still set/unset in the same place, so its + * value really is 0 here when the connection comes from the reslist (and + * should be put back there) and 1 when it comes from an optional call to + * ap_proxy_acquire_connection_ex (and must not hit the reslist now), hence + * the test below is misleading but valid... + * + */ if (conn->inreslist) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) - "Pooled connection 0x%pp for worker %s has been" - " already returned to the connection pool.", conn, - worker->s->name); + if (conn->close) { + socket_cleanup(conn); + } return APR_SUCCESS; } @@ -1384,13 +1410,6 @@ static apr_status_t connection_cleanup(void *theco return APR_SUCCESS; } -static void socket_cleanup(proxy_conn_rec *conn) -{ - conn->sock = NULL; - conn->connection = NULL; - apr_pool_clear(conn->scpool); -} - PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn, request_rec *r) { @@ -1975,13 +1994,17 @@ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr return connected ? 0 : 1; } -PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, - proxy_conn_rec **conn, - proxy_worker *worker, - server_rec *s) +static int ap_proxy_acquire_connection_ex(const char *proxy_function, + proxy_conn_rec **conn, + proxy_worker *worker, + server_rec *s, + conn_rec *c) { apr_status_t rv; + int one4one = 0; + *conn = NULL; + if (!PROXY_WORKER_IS_USABLE(worker)) { /* Retry the worker */ ap_proxy_retry_worker(proxy_function, worker, s); @@ -1994,6 +2017,17 @@ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr } } + if (c && worker->s->is_address_reusable && !worker->s->disablereuse) { + *conn = (proxy_conn_rec *)ap_get_module_config(c->conn_config, + &proxy_module); + if (!*conn) { + connection_constructor((void **)conn, worker, c->pool); + ap_set_module_config(c->conn_config, &proxy_module, *conn); + } + rv = APR_SUCCESS; + one4one = 1; + } + else if (worker->s->hmax && worker->cp->res) { rv = apr_reslist_acquire(worker->cp->res, (void **)conn); } @@ -2011,28 +2045,40 @@ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00941) - "%s: failed to acquire connection for (%s)", - proxy_function, worker->s->hostname); + "%s: failed to acquire %sconnection for (%s)", + proxy_function, one4one ? "1for1 " : "", + worker->s->hostname); return HTTP_SERVICE_UNAVAILABLE; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00942) - "%s: has acquired connection for (%s)", - proxy_function, worker->s->hostname); + "%s: has acquired %sconnection for (%s)", + proxy_function, one4one ? "1for1 " : "", + worker->s->hostname); (*conn)->worker = worker; (*conn)->close = 0; - (*conn)->inreslist = 0; + (*conn)->inreslist = one4one; return OK; } +PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, + proxy_conn_rec **conn, + proxy_worker *worker, + server_rec *s) +{ + return ap_proxy_acquire_connection_ex(proxy_function, conn, worker, s, + NULL); +} + PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00943) - "%s: has released connection for (%s)", - proxy_function, conn->worker->s->hostname); + "%s: has released %sconnection for (%s)", + proxy_function, conn->inreslist ? "1for1 " : "", + conn->worker->s->hostname); connection_cleanup(conn); return OK; @@ -3217,4 +3263,5 @@ void proxy_util_register_hooks(apr_pool_t *p) { APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker); APR_REGISTER_OPTIONAL_FN(ap_proxy_clear_connection); + APR_REGISTER_OPTIONAL_FN(ap_proxy_acquire_connection_ex); } --- modules/proxy/mod_proxy_http.c (revision 1526505) +++ modules/proxy/mod_proxy_http.c (working copy) @@ -17,6 +17,7 @@ /* HTTP routines for Apache proxy */ #include "mod_proxy.h" +#include "proxy_util.h" /* ap_proxy_acquire_connection_ex() */ #include "ap_regex.h" module AP_MODULE_DECLARE_DATA proxy_http_module; @@ -24,6 +25,13 @@ module AP_MODULE_DECLARE_DATA proxy_http_module; static int (*ap_proxy_clear_connection_fn)(request_rec *r, apr_table_t *headers) = NULL; +static int (*ap_proxy_acquire_connection_ex_fn)(const char *proxy_function, + proxy_conn_rec **conn, + proxy_worker *worker, + server_rec *s, + conn_rec *c) + = NULL; + static apr_status_t ap_proxy_http_cleanup(const char *scheme, request_rec *r, proxy_conn_rec *backend); @@ -1902,9 +1910,17 @@ static int proxy_http_handler(request_rec *r, prox /* create space for state information */ - if ((status = ap_proxy_acquire_connection(proxy_function, &backend, - worker, r->server)) != OK) + if (apr_table_get(r->subprocess_env, "proxy-1for1-connection")) { + status = ap_proxy_acquire_connection_ex_fn(proxy_function, &backend, + worker, r->server, c); + } + else { + status = ap_proxy_acquire_connection(proxy_function, &backend, + worker, r->server); + } + if (status != OK) { goto cleanup; + } backend->is_ssl = is_ssl; @@ -2034,6 +2050,16 @@ static int proxy_http_post_config(apr_pool_t *pcon } } + if (!ap_proxy_acquire_connection_ex_fn) { + ap_proxy_acquire_connection_ex_fn = + APR_RETRIEVE_OPTIONAL_FN(ap_proxy_acquire_connection_ex); + if (!ap_proxy_acquire_connection_ex_fn) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO() + "mod_proxy must be loaded for mod_proxy_http"); + return !OK; + } + } + return OK; } --- modules/proxy/proxy_util.h (revision 1526505) +++ modules/proxy/proxy_util.h (working copy) @@ -40,6 +40,14 @@ PROXY_DECLARE_DATA extern const apr_strmatch_patte */ void proxy_util_register_hooks(apr_pool_t *p); +/** + * Optional function to acquire a backend connection attached to the client's one + * when c is not NULL, otherwise it is ap_proxy_acquire_connection. + */ +APR_DECLARE_OPTIONAL_FN(int, ap_proxy_acquire_connection_ex, + (const char *proxy_function, proxy_conn_rec **conn, + proxy_worker *worker, server_rec *s, conn_rec *c)); + /** @} */ #endif /* PROXY_UTIL_H_ */