Skip to content

Commit 89b9176

Browse files
committed
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
1 parent 8826336 commit 89b9176

File tree

2 files changed

+61
-67
lines changed

2 files changed

+61
-67
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*) mod_proxy: Reuse ProxyRemote connections when possible, like prior
2+
to 2.4.59. [Jean-Frederic Clere, Yann Ylavic]

modules/proxy/proxy_util.c

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@
4545
APLOG_USE_MODULE(proxy);
4646

4747
/*
48-
* Opaque structure containing target server info when
49-
* using a forward proxy.
50-
* Up to now only used in combination with HTTP CONNECT to ProxyRemote
48+
* Opaque structure containing infos for CONNECT-ing an origin server through a
49+
* remote (forward) proxy. Saved in the (opaque) proxy_conn_rec::forward pointer
50+
* field for backend connections kept alive, allowing for reuse when subsequent
51+
* requests should be routed through the same remote proxy.
5152
*/
5253
typedef struct {
53-
int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
54-
const char *target_host; /* Target hostname */
55-
apr_port_t target_port; /* Target port */
5654
const char *proxy_auth; /* Proxy authorization */
57-
} forward_info;
55+
const char *target_host; /* Target/origin hostname */
56+
apr_port_t target_port; /* Target/origin port */
57+
} remote_connect_info;
5858

5959
/*
6060
* Opaque structure containing a refcounted and TTL'ed address.
@@ -1605,9 +1605,7 @@ PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn)
16051605
{
16061606
proxy_worker *worker = conn->worker;
16071607

1608-
return !(conn->close
1609-
|| conn->forward
1610-
|| worker->s->disablereuse);
1608+
return !(conn->close || worker->s->disablereuse);
16111609
}
16121610

16131611
static proxy_conn_rec *connection_make(apr_pool_t *p, proxy_worker *worker)
@@ -3331,12 +3329,10 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
33313329
uri->scheme, conn->uds_path, conn->hostname, conn->port);
33323330
}
33333331
else {
3332+
remote_connect_info *connect_info = NULL;
33343333
const char *hostname = uri->hostname;
33353334
apr_port_t hostport = uri->port;
33363335

3337-
/* Not a remote CONNECT until further notice */
3338-
conn->forward = NULL;
3339-
33403336
if (proxyname) {
33413337
hostname = proxyname;
33423338
hostport = proxyport;
@@ -3347,7 +3343,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
33473343
* sending our actual HTTPS requests.
33483344
*/
33493345
if (conn->is_ssl) {
3350-
forward_info *forward;
33513346
const char *proxy_auth;
33523347

33533348
/* Do we want to pass Proxy-Authorization along?
@@ -3366,13 +3361,15 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
33663361
proxy_auth = NULL;
33673362
}
33683363

3369-
/* Reset forward info if they changed */
3370-
if (!(forward = conn->forward)
3371-
|| forward->target_port != uri->port
3372-
|| ap_cstr_casecmp(forward->target_host, uri->hostname) != 0
3373-
|| (forward->proxy_auth != NULL) != (proxy_auth != NULL)
3374-
|| (forward->proxy_auth != NULL && proxy_auth != NULL &&
3375-
strcmp(forward->proxy_auth, proxy_auth) != 0)) {
3364+
/* Save our real backend data for using it later during HTTP CONNECT */
3365+
connect_info = conn->forward;
3366+
if (!connect_info
3367+
/* reset connect info if they changed */
3368+
|| connect_info->target_port != uri->port
3369+
|| ap_cstr_casecmp(connect_info->target_host, uri->hostname) != 0
3370+
|| (connect_info->proxy_auth != NULL) != (proxy_auth != NULL)
3371+
|| (connect_info->proxy_auth != NULL && proxy_auth != NULL &&
3372+
strcmp(connect_info->proxy_auth, proxy_auth) != 0)) {
33763373
apr_pool_t *fwd_pool = conn->pool;
33773374
if (worker->s->is_address_reusable) {
33783375
if (conn->fwd_pool) {
@@ -3383,26 +3380,24 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
33833380
}
33843381
fwd_pool = conn->fwd_pool;
33853382
}
3386-
forward = apr_pcalloc(fwd_pool, sizeof(forward_info));
3387-
conn->forward = forward;
3388-
3389-
/*
3390-
* Save our real backend data for using it later during HTTP CONNECT.
3391-
*/
3392-
forward->use_http_connect = 1;
3393-
forward->target_host = apr_pstrdup(fwd_pool, uri->hostname);
3394-
forward->target_port = uri->port;
3383+
connect_info = apr_pcalloc(fwd_pool, sizeof(*connect_info));
3384+
connect_info->target_host = apr_pstrdup(fwd_pool, uri->hostname);
3385+
connect_info->target_port = uri->port;
33953386
if (proxy_auth) {
3396-
forward->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth);
3387+
connect_info->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth);
33973388
}
3389+
conn->forward = NULL;
33983390
}
33993391
}
34003392
}
34013393

3402-
if (conn->hostname
3403-
&& (conn->port != hostport
3404-
|| ap_cstr_casecmp(conn->hostname, hostname) != 0)) {
3394+
/* Close the connection if the remote proxy or origin server don't match */
3395+
if (conn->forward != connect_info
3396+
|| (conn->hostname
3397+
&& (conn->port != hostport
3398+
|| ap_cstr_casecmp(conn->hostname, hostname) != 0))) {
34053399
conn_cleanup(conn);
3400+
conn->forward = connect_info;
34063401
}
34073402

34083403
/* Resolve the connection address with the determined hostname/port */
@@ -3446,9 +3441,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
34463441
if (dconf->preserve_host) {
34473442
ssl_hostname = r->hostname;
34483443
}
3449-
else if (conn->forward
3450-
&& ((forward_info *)(conn->forward))->use_http_connect) {
3451-
ssl_hostname = ((forward_info *)conn->forward)->target_host;
3444+
else if (conn->forward) {
3445+
ssl_hostname = ((remote_connect_info *)conn->forward)->target_host;
34523446
}
34533447
else {
34543448
ssl_hostname = conn->hostname;
@@ -3545,7 +3539,7 @@ PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *sock)
35453539

35463540

35473541
/*
3548-
* Send a HTTP CONNECT request to a forward proxy.
3542+
* Send a HTTP CONNECT request to a remote proxy.
35493543
* The proxy is given by "backend", the target server
35503544
* is contained in the "forward" member of "backend".
35513545
*/
@@ -3558,24 +3552,24 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
35583552
int complete = 0;
35593553
char buffer[HUGE_STRING_LEN];
35603554
char drain_buffer[HUGE_STRING_LEN];
3561-
forward_info *forward = (forward_info *)backend->forward;
3555+
remote_connect_info *connect_info = backend->forward;
35623556
int len = 0;
35633557

35643558
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948)
35653559
"CONNECT: sending the CONNECT request for %s:%d "
35663560
"to the remote proxy %pI (%s)",
3567-
forward->target_host, forward->target_port,
3561+
connect_info->target_host, connect_info->target_port,
35683562
backend->addr, backend->hostname);
35693563
/* Create the CONNECT request */
35703564
nbytes = apr_snprintf(buffer, sizeof(buffer),
35713565
"CONNECT %s:%d HTTP/1.0" CRLF,
3572-
forward->target_host, forward->target_port);
3566+
connect_info->target_host, connect_info->target_port);
35733567
/* Add proxy authorization from the configuration, or initial
35743568
* request if necessary */
3575-
if (forward->proxy_auth != NULL) {
3569+
if (connect_info->proxy_auth != NULL) {
35763570
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
35773571
"Proxy-Authorization: %s" CRLF,
3578-
forward->proxy_auth);
3572+
connect_info->proxy_auth);
35793573
}
35803574
/* Set a reasonable agent and send everything */
35813575
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
@@ -3619,7 +3613,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
36193613
char code_str[4];
36203614

36213615
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00949)
3622-
"send_http_connect: response from the forward proxy: %s",
3616+
"send_http_connect: response from the remote proxy: %s",
36233617
buffer);
36243618

36253619
/* Extract the returned code */
@@ -3630,7 +3624,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend,
36303624
}
36313625
else {
36323626
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950)
3633-
"send_http_connect: the forward proxy returned code is '%s'",
3627+
"send_http_connect: the remote proxy returned code is '%s'",
36343628
code_str);
36353629
status = APR_INCOMPLETE;
36363630
}
@@ -3794,7 +3788,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
37943788
{
37953789
apr_status_t rv;
37963790
int loglevel;
3797-
forward_info *forward = conn->forward;
3791+
remote_connect_info *connect_info = conn->forward;
37983792
apr_sockaddr_t *backend_addr;
37993793
/* the local address to use for the outgoing connection */
38003794
apr_sockaddr_t *local_addr;
@@ -3995,27 +3989,25 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
39953989

39963990
conn->sock = newsock;
39973991

3998-
if (forward && forward->use_http_connect) {
3999-
/*
4000-
* For HTTP CONNECT we need to prepend CONNECT request before
4001-
* sending our actual HTTPS requests.
4002-
*/
4003-
{
4004-
rv = send_http_connect(conn, s);
4005-
/* If an error occurred, loop round and try again */
4006-
if (rv != APR_SUCCESS) {
4007-
conn->sock = NULL;
4008-
apr_socket_close(newsock);
4009-
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
4010-
ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958)
4011-
"%s: attempt to connect to %s:%hu "
4012-
"via http CONNECT through %pI (%s:%hu) failed",
4013-
proxy_function,
4014-
forward->target_host, forward->target_port,
4015-
backend_addr, conn->hostname, conn->port);
4016-
backend_addr = backend_addr->next;
4017-
continue;
4018-
}
3992+
/*
3993+
* For HTTP CONNECT we need to prepend CONNECT request before
3994+
* sending our actual HTTPS requests.
3995+
*/
3996+
if (connect_info) {
3997+
rv = send_http_connect(conn, s);
3998+
/* If an error occurred, loop round and try again */
3999+
if (rv != APR_SUCCESS) {
4000+
conn->sock = NULL;
4001+
apr_socket_close(newsock);
4002+
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
4003+
ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958)
4004+
"%s: attempt to connect to %s:%hu "
4005+
"via http CONNECT through %pI (%s:%hu) failed",
4006+
proxy_function,
4007+
connect_info->target_host, connect_info->target_port,
4008+
backend_addr, conn->hostname, conn->port);
4009+
backend_addr = backend_addr->next;
4010+
continue;
40194011
}
40204012
}
40214013
}

0 commit comments

Comments
 (0)