mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_proxy: restore reuse of ProxyRemote connections when possible.
Fixes a regression from 2.4.59 (r1913907). For a reverse proxy setup with a worker (enablereuse=on) and a forward/CONNECT ProxyRemote to reach it, an open connection/tunnel to/through the remote proxy for the same origin server (and using the same proxy auth) should be reusable. Avoid closing them like r1913534 did. * modules/proxy/proxy_util.c: Rename the struct to remote_connect_info since it's only used for connecting through remote CONNECT proxies. Axe the use_http_connect field, always true. * modules/proxy/proxy_util.c(ap_proxy_connection_reusable): Remote CONNECT (forward) proxy connections can be reused if the auth and origin server infos are the same, so conn->forward != NULL is not a condition to prevent reusability. * modules/proxy/proxy_util.c(ap_proxy_determine_connection): Fix the checks around conn->forward reuse and connection cleanup if that's not possible. Submitted by: jfclere, ylavic GH: closes #531 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1925743 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
2
changes-entries/proxyremote_reuse.txt
Normal file
2
changes-entries/proxyremote_reuse.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*) mod_proxy: Reuse ProxyRemote connections when possible, like prior
|
||||||
|
to 2.4.59. [Jean-Frederic Clere, Yann Ylavic]
|
@@ -45,16 +45,16 @@
|
|||||||
APLOG_USE_MODULE(proxy);
|
APLOG_USE_MODULE(proxy);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opaque structure containing target server info when
|
* Opaque structure containing infos for CONNECT-ing an origin server through a
|
||||||
* using a forward proxy.
|
* remote (forward) proxy. Saved in the (opaque) proxy_conn_rec::forward pointer
|
||||||
* Up to now only used in combination with HTTP CONNECT to ProxyRemote
|
* field for backend connections kept alive, allowing for reuse when subsequent
|
||||||
|
* requests should be routed through the same remote proxy.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
|
|
||||||
const char *target_host; /* Target hostname */
|
|
||||||
apr_port_t target_port; /* Target port */
|
|
||||||
const char *proxy_auth; /* Proxy authorization */
|
const char *proxy_auth; /* Proxy authorization */
|
||||||
} forward_info;
|
const char *target_host; /* Target/origin hostname */
|
||||||
|
apr_port_t target_port; /* Target/origin port */
|
||||||
|
} remote_connect_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opaque structure containing a refcounted and TTL'ed address.
|
* Opaque structure containing a refcounted and TTL'ed address.
|
||||||
@@ -1608,9 +1608,7 @@ PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn)
|
|||||||
{
|
{
|
||||||
proxy_worker *worker = conn->worker;
|
proxy_worker *worker = conn->worker;
|
||||||
|
|
||||||
return !(conn->close
|
return !(conn->close || worker->s->disablereuse);
|
||||||
|| conn->forward
|
|
||||||
|| worker->s->disablereuse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static proxy_conn_rec *connection_make(apr_pool_t *p, proxy_worker *worker)
|
static proxy_conn_rec *connection_make(apr_pool_t *p, proxy_worker *worker)
|
||||||
@@ -3329,12 +3327,10 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
|||||||
uri->scheme, conn->uds_path, conn->hostname, conn->port);
|
uri->scheme, conn->uds_path, conn->hostname, conn->port);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
remote_connect_info *connect_info = NULL;
|
||||||
const char *hostname = uri->hostname;
|
const char *hostname = uri->hostname;
|
||||||
apr_port_t hostport = uri->port;
|
apr_port_t hostport = uri->port;
|
||||||
|
|
||||||
/* Not a remote CONNECT until further notice */
|
|
||||||
conn->forward = NULL;
|
|
||||||
|
|
||||||
if (proxyname) {
|
if (proxyname) {
|
||||||
hostname = proxyname;
|
hostname = proxyname;
|
||||||
hostport = proxyport;
|
hostport = proxyport;
|
||||||
@@ -3345,7 +3341,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
|||||||
* sending our actual HTTPS requests.
|
* sending our actual HTTPS requests.
|
||||||
*/
|
*/
|
||||||
if (conn->is_ssl) {
|
if (conn->is_ssl) {
|
||||||
forward_info *forward;
|
|
||||||
const char *proxy_auth;
|
const char *proxy_auth;
|
||||||
|
|
||||||
/* Do we want to pass Proxy-Authorization along?
|
/* Do we want to pass Proxy-Authorization along?
|
||||||
@@ -3364,13 +3359,15 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
|||||||
proxy_auth = NULL;
|
proxy_auth = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset forward info if they changed */
|
/* Save our real backend data for using it later during HTTP CONNECT */
|
||||||
if (!(forward = conn->forward)
|
connect_info = conn->forward;
|
||||||
|| forward->target_port != uri->port
|
if (!connect_info
|
||||||
|| ap_cstr_casecmp(forward->target_host, uri->hostname) != 0
|
/* reset connect info if they changed */
|
||||||
|| (forward->proxy_auth != NULL) != (proxy_auth != NULL)
|
|| connect_info->target_port != uri->port
|
||||||
|| (forward->proxy_auth != NULL && proxy_auth != NULL &&
|
|| ap_cstr_casecmp(connect_info->target_host, uri->hostname) != 0
|
||||||
strcmp(forward->proxy_auth, proxy_auth) != 0)) {
|
|| (connect_info->proxy_auth != NULL) != (proxy_auth != NULL)
|
||||||
|
|| (connect_info->proxy_auth != NULL && proxy_auth != NULL &&
|
||||||
|
strcmp(connect_info->proxy_auth, proxy_auth) != 0)) {
|
||||||
apr_pool_t *fwd_pool = conn->pool;
|
apr_pool_t *fwd_pool = conn->pool;
|
||||||
if (worker->s->is_address_reusable) {
|
if (worker->s->is_address_reusable) {
|
||||||
if (conn->fwd_pool) {
|
if (conn->fwd_pool) {
|
||||||
@@ -3381,26 +3378,24 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
|||||||
}
|
}
|
||||||
fwd_pool = conn->fwd_pool;
|
fwd_pool = conn->fwd_pool;
|
||||||
}
|
}
|
||||||
forward = apr_pcalloc(fwd_pool, sizeof(forward_info));
|
connect_info = apr_pcalloc(fwd_pool, sizeof(*connect_info));
|
||||||
conn->forward = forward;
|
connect_info->target_host = apr_pstrdup(fwd_pool, uri->hostname);
|
||||||
|
connect_info->target_port = uri->port;
|
||||||
/*
|
|
||||||
* Save our real backend data for using it later during HTTP CONNECT.
|
|
||||||
*/
|
|
||||||
forward->use_http_connect = 1;
|
|
||||||
forward->target_host = apr_pstrdup(fwd_pool, uri->hostname);
|
|
||||||
forward->target_port = uri->port;
|
|
||||||
if (proxy_auth) {
|
if (proxy_auth) {
|
||||||
forward->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth);
|
connect_info->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth);
|
||||||
}
|
}
|
||||||
|
conn->forward = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->hostname
|
/* Close the connection if the remote proxy or origin server don't match */
|
||||||
|
if (conn->forward != connect_info
|
||||||
|
|| (conn->hostname
|
||||||
&& (conn->port != hostport
|
&& (conn->port != hostport
|
||||||
|| ap_cstr_casecmp(conn->hostname, hostname) != 0)) {
|
|| ap_cstr_casecmp(conn->hostname, hostname) != 0))) {
|
||||||
conn_cleanup(conn);
|
conn_cleanup(conn);
|
||||||
|
conn->forward = connect_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resolve the connection address with the determined hostname/port */
|
/* Resolve the connection address with the determined hostname/port */
|
||||||
@@ -3444,9 +3439,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
|
|||||||
if (dconf->preserve_host) {
|
if (dconf->preserve_host) {
|
||||||
ssl_hostname = r->hostname;
|
ssl_hostname = r->hostname;
|
||||||
}
|
}
|
||||||
else if (conn->forward
|
else if (conn->forward) {
|
||||||
&& ((forward_info *)(conn->forward))->use_http_connect) {
|
ssl_hostname = ((remote_connect_info *)conn->forward)->target_host;
|
||||||
ssl_hostname = ((forward_info *)conn->forward)->target_host;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ssl_hostname = conn->hostname;
|
ssl_hostname = conn->hostname;
|
||||||
@@ -3543,7 +3537,7 @@ PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *sock)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send a HTTP CONNECT request to a forward proxy.
|
* Send a HTTP CONNECT request to a remote proxy.
|
||||||
* The proxy is given by "backend", the target server
|
* The proxy is given by "backend", the target server
|
||||||
* is contained in the "forward" member of "backend".
|
* is contained in the "forward" member of "backend".
|
||||||
*/
|
*/
|
||||||
@@ -3556,24 +3550,24 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
|
|||||||
int complete = 0;
|
int complete = 0;
|
||||||
char buffer[HUGE_STRING_LEN];
|
char buffer[HUGE_STRING_LEN];
|
||||||
char drain_buffer[HUGE_STRING_LEN];
|
char drain_buffer[HUGE_STRING_LEN];
|
||||||
forward_info *forward = (forward_info *)backend->forward;
|
remote_connect_info *connect_info = backend->forward;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948)
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948)
|
||||||
"CONNECT: sending the CONNECT request for %s:%d "
|
"CONNECT: sending the CONNECT request for %s:%d "
|
||||||
"to the remote proxy %pI (%s)",
|
"to the remote proxy %pI (%s)",
|
||||||
forward->target_host, forward->target_port,
|
connect_info->target_host, connect_info->target_port,
|
||||||
backend->addr, backend->hostname);
|
backend->addr, backend->hostname);
|
||||||
/* Create the CONNECT request */
|
/* Create the CONNECT request */
|
||||||
nbytes = apr_snprintf(buffer, sizeof(buffer),
|
nbytes = apr_snprintf(buffer, sizeof(buffer),
|
||||||
"CONNECT %s:%d HTTP/1.0" CRLF,
|
"CONNECT %s:%d HTTP/1.0" CRLF,
|
||||||
forward->target_host, forward->target_port);
|
connect_info->target_host, connect_info->target_port);
|
||||||
/* Add proxy authorization from the configuration, or initial
|
/* Add proxy authorization from the configuration, or initial
|
||||||
* request if necessary */
|
* request if necessary */
|
||||||
if (forward->proxy_auth != NULL) {
|
if (connect_info->proxy_auth != NULL) {
|
||||||
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
|
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
|
||||||
"Proxy-Authorization: %s" CRLF,
|
"Proxy-Authorization: %s" CRLF,
|
||||||
forward->proxy_auth);
|
connect_info->proxy_auth);
|
||||||
}
|
}
|
||||||
/* Set a reasonable agent and send everything */
|
/* Set a reasonable agent and send everything */
|
||||||
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
|
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
|
||||||
@@ -3617,7 +3611,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
|
|||||||
char code_str[4];
|
char code_str[4];
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00949)
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00949)
|
||||||
"send_http_connect: response from the forward proxy: %s",
|
"send_http_connect: response from the remote proxy: %s",
|
||||||
buffer);
|
buffer);
|
||||||
|
|
||||||
/* Extract the returned code */
|
/* Extract the returned code */
|
||||||
@@ -3628,7 +3622,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950)
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950)
|
||||||
"send_http_connect: the forward proxy returned code is '%s'",
|
"send_http_connect: the remote proxy returned code is '%s'",
|
||||||
code_str);
|
code_str);
|
||||||
status = APR_INCOMPLETE;
|
status = APR_INCOMPLETE;
|
||||||
}
|
}
|
||||||
@@ -3792,7 +3786,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
|
|||||||
{
|
{
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
int loglevel;
|
int loglevel;
|
||||||
forward_info *forward = conn->forward;
|
remote_connect_info *connect_info = conn->forward;
|
||||||
apr_sockaddr_t *backend_addr;
|
apr_sockaddr_t *backend_addr;
|
||||||
/* the local address to use for the outgoing connection */
|
/* the local address to use for the outgoing connection */
|
||||||
apr_sockaddr_t *local_addr;
|
apr_sockaddr_t *local_addr;
|
||||||
@@ -3993,12 +3987,11 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
|
|||||||
|
|
||||||
conn->sock = newsock;
|
conn->sock = newsock;
|
||||||
|
|
||||||
if (forward && forward->use_http_connect) {
|
|
||||||
/*
|
/*
|
||||||
* For HTTP CONNECT we need to prepend CONNECT request before
|
* For HTTP CONNECT we need to prepend CONNECT request before
|
||||||
* sending our actual HTTPS requests.
|
* sending our actual HTTPS requests.
|
||||||
*/
|
*/
|
||||||
{
|
if (connect_info) {
|
||||||
rv = send_http_connect(conn, s);
|
rv = send_http_connect(conn, s);
|
||||||
/* If an error occurred, loop round and try again */
|
/* If an error occurred, loop round and try again */
|
||||||
if (rv != APR_SUCCESS) {
|
if (rv != APR_SUCCESS) {
|
||||||
@@ -4009,14 +4002,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
|
|||||||
"%s: attempt to connect to %s:%hu "
|
"%s: attempt to connect to %s:%hu "
|
||||||
"via http CONNECT through %pI (%s:%hu) failed",
|
"via http CONNECT through %pI (%s:%hu) failed",
|
||||||
proxy_function,
|
proxy_function,
|
||||||
forward->target_host, forward->target_port,
|
connect_info->target_host, connect_info->target_port,
|
||||||
backend_addr, conn->hostname, conn->port);
|
backend_addr, conn->hostname, conn->port);
|
||||||
backend_addr = backend_addr->next;
|
backend_addr = backend_addr->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (PROXY_WORKER_IS_USABLE(worker)) {
|
if (PROXY_WORKER_IS_USABLE(worker)) {
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user