On Thu, May 22, 2025 at 9:39 AM jean-frederic clere <jfcl...@gmail.com> wrote: > > On 5/20/25 2:48 PM, Yann Ylavic wrote: > > On Tue, May 20, 2025 at 12:03 PM jean-frederic clere <jfcl...@gmail.com> > > wrote: > >> > >> Find the configuration I have used to reproduce the customer issue, > >> thanks for all explanations for far ;-) > > > > So regression is on vhost "host14.example.com" right? And not > > "fproxy.example.com"? > > > > Yes,
I created [1] to restore the behaviour of < 2.4.59, attached is the 2.4.x backport (including [2] which is trunk only so far, allows to align both codes). Could you test either of those to see if it helps? [1] https://github.com/apache/httpd/pull/531 [2] https://github.com/apache/httpd/commit/d11d0b8aa8b10979344f333581a3a258c62dcdb9 Cheers; Yann.
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 2590b7ed3a..00fedb1adf 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -45,16 +45,16 @@ APLOG_USE_MODULE(proxy); /* - * Opaque structure containing target server info when - * using a forward proxy. - * Up to now only used in combination with HTTP CONNECT to ProxyRemote + * Opaque structure containing infos for CONNECT-ing an origin server through a + * remote (forward) proxy. Saved in the (opaque) proxy_conn_rec::forward pointer + * field for backend connections kept alive, allowing for reuse when subsequent + * requests should be routed through the same remote proxy. */ 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 */ -} 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. @@ -1508,6 +1508,7 @@ static void socket_cleanup(proxy_conn_rec *conn) conn->connection = NULL; conn->ssl_hostname = NULL; apr_pool_clear(conn->scpool); + conn->close = 0; } static void conn_cleanup(proxy_conn_rec *conn) @@ -1525,6 +1526,7 @@ static void conn_cleanup(proxy_conn_rec *conn) static apr_status_t conn_pool_cleanup(void *theworker) { + /* Signal that the child is exiting */ ((proxy_worker *)theworker)->cp = NULL; return APR_SUCCESS; } @@ -1603,10 +1605,7 @@ PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn) { proxy_worker *worker = conn->worker; - return !(conn->close - || conn->forward - || worker->s->disablereuse - || !worker->s->is_address_reusable); + return !(conn->close || worker->s->disablereuse); } static proxy_conn_rec *connection_make(apr_pool_t *p, proxy_worker *worker) @@ -1659,18 +1658,17 @@ static void connection_cleanup(void *theconn) apr_pool_clear(p); conn = connection_make(p, worker); } - else if (conn->close - || conn->forward + else if (!conn->sock || (conn->connection && conn->connection->keepalive == AP_CONN_CLOSE) - || worker->s->disablereuse) { + || !ap_proxy_connection_reusable(conn)) { socket_cleanup(conn); - conn->close = 0; } else if (conn->is_ssl) { - /* Unbind/reset the SSL connection dir config (sslconn->dc) from - * r->per_dir_config, r will likely get destroyed before this proxy - * conn is reused. + /* The current ssl section/dir config of the conn is not necessarily + * the one it will be reused for, so while the conn is in the reslist + * reset its ssl config to the worker's, until a new user sets its own + * ssl config eventually in proxy_connection_create() and so on. */ ap_proxy_ssl_engine(conn->connection, worker->section_config, 1); } @@ -2822,7 +2820,6 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, (int)worker->s->port); (*conn)->worker = worker; - (*conn)->close = 0; (*conn)->inreslist = 0; return OK; @@ -3267,7 +3264,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, /* Close a possible existing socket if we are told to do so */ if (conn->close) { socket_cleanup(conn); - conn->close = 0; } /* @@ -3333,12 +3329,10 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, uri->scheme, conn->uds_path, conn->hostname, conn->port); } else { + remote_connect_info *connect_info = NULL; const char *hostname = uri->hostname; apr_port_t hostport = uri->port; - /* Not a remote CONNECT until further notice */ - conn->forward = NULL; - if (proxyname) { hostname = proxyname; hostport = proxyport; @@ -3349,7 +3343,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, * sending our actual HTTPS requests. */ if (conn->is_ssl) { - forward_info *forward; const char *proxy_auth; /* Do we want to pass Proxy-Authorization along? @@ -3368,13 +3361,15 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, proxy_auth = NULL; } - /* Reset forward info if they changed */ - if (!(forward = conn->forward) - || forward->target_port != uri->port - || ap_cstr_casecmp(forward->target_host, uri->hostname) != 0 - || (forward->proxy_auth != NULL) != (proxy_auth != NULL) - || (forward->proxy_auth != NULL && proxy_auth != NULL && - strcmp(forward->proxy_auth, proxy_auth) != 0)) { + /* Save our real backend data for using it later during HTTP CONNECT */ + connect_info = conn->forward; + if (!connect_info + /* reset connect info if they changed */ + || connect_info->target_port != uri->port + || ap_cstr_casecmp(connect_info->target_host, uri->hostname) != 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; if (worker->s->is_address_reusable) { if (conn->fwd_pool) { @@ -3385,26 +3380,24 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, } fwd_pool = conn->fwd_pool; } - forward = apr_pcalloc(fwd_pool, sizeof(forward_info)); - conn->forward = forward; - - /* - * 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; + connect_info = apr_pcalloc(fwd_pool, sizeof(*connect_info)); + connect_info->target_host = apr_pstrdup(fwd_pool, uri->hostname); + connect_info->target_port = uri->port; 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 - && (conn->port != hostport - || ap_cstr_casecmp(conn->hostname, hostname) != 0)) { + /* Close the connection if the remote proxy or origin server don't match */ + if (conn->forward != connect_info + || (conn->hostname + && (conn->port != hostport + || ap_cstr_casecmp(conn->hostname, hostname) != 0))) { conn_cleanup(conn); + conn->forward = connect_info; } /* Resolve the connection address with the determined hostname/port */ @@ -3448,9 +3441,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, if (dconf->preserve_host) { ssl_hostname = r->hostname; } - else if (conn->forward - && ((forward_info *)(conn->forward))->use_http_connect) { - ssl_hostname = ((forward_info *)conn->forward)->target_host; + else if (conn->forward) { + ssl_hostname = ((remote_connect_info *)conn->forward)->target_host; } else { ssl_hostname = conn->hostname; @@ -3547,7 +3539,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 * is contained in the "forward" member of "backend". */ @@ -3560,24 +3552,24 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, int complete = 0; char 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; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948) "CONNECT: sending the CONNECT request for %s:%d " "to the remote proxy %pI (%s)", - forward->target_host, forward->target_port, + connect_info->target_host, connect_info->target_port, backend->addr, backend->hostname); /* Create the CONNECT request */ nbytes = apr_snprintf(buffer, sizeof(buffer), "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 * request if necessary */ - if (forward->proxy_auth != NULL) { + if (connect_info->proxy_auth != NULL) { nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, "Proxy-Authorization: %s" CRLF, - forward->proxy_auth); + connect_info->proxy_auth); } /* Set a reasonable agent and send everything */ nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, @@ -3621,7 +3613,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, char code_str[4]; 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); /* Extract the returned code */ @@ -3632,7 +3624,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, } else { 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); status = APR_INCOMPLETE; } @@ -3796,7 +3788,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, { apr_status_t rv; int loglevel; - forward_info *forward = conn->forward; + remote_connect_info *connect_info = conn->forward; apr_sockaddr_t *backend_addr; /* the local address to use for the outgoing connection */ apr_sockaddr_t *local_addr; @@ -3997,27 +3989,25 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, conn->sock = newsock; - if (forward && forward->use_http_connect) { - /* - * For HTTP CONNECT we need to prepend CONNECT request before - * sending our actual HTTPS requests. - */ - { - rv = send_http_connect(conn, s); - /* If an error occurred, loop round and try again */ - if (rv != APR_SUCCESS) { - conn->sock = NULL; - apr_socket_close(newsock); - loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; - ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958) - "%s: attempt to connect to %s:%hu " - "via http CONNECT through %pI (%s:%hu) failed", - proxy_function, - forward->target_host, forward->target_port, - backend_addr, conn->hostname, conn->port); - backend_addr = backend_addr->next; - continue; - } + /* + * For HTTP CONNECT we need to prepend CONNECT request before + * sending our actual HTTPS requests. + */ + if (connect_info) { + rv = send_http_connect(conn, s); + /* If an error occurred, loop round and try again */ + if (rv != APR_SUCCESS) { + conn->sock = NULL; + apr_socket_close(newsock); + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958) + "%s: attempt to connect to %s:%hu " + "via http CONNECT through %pI (%s:%hu) failed", + proxy_function, + connect_info->target_host, connect_info->target_port, + backend_addr, conn->hostname, conn->port); + backend_addr = backend_addr->next; + continue; } } } @@ -4058,13 +4048,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, * e.g. for a timeout or bad status. We should respect this and should * not continue with a connection via this worker even if we got one. */ - if (rv == APR_SUCCESS) { - socket_cleanup(conn); - } rv = APR_EINVAL; } - - return rv == APR_SUCCESS ? OK : DECLINED; + if (rv != APR_SUCCESS) { + socket_cleanup(conn); + return DECLINED; + } + return OK; } static apr_status_t connection_shutdown(void *theconn) @@ -4101,9 +4091,9 @@ static int proxy_connection_create(const char *proxy_function, ap_conf_vector_t *per_dir_config = (r) ? r->per_dir_config : conn->worker->section_config; apr_sockaddr_t *backend_addr = conn->addr; - int rc; apr_interval_time_t current_timeout; apr_bucket_alloc_t *bucket_alloc; + int rc = OK; if (conn->connection) { if (conn->is_ssl) { @@ -4115,15 +4105,15 @@ static int proxy_connection_create(const char *proxy_function, return OK; } - bucket_alloc = apr_bucket_alloc_create(conn->scpool); - conn->tmp_bb = apr_brigade_create(conn->scpool, bucket_alloc); - /* - * The socket is now open, create a new backend server connection - */ - conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock, - 0, NULL, - bucket_alloc); - + if (conn->sock) { + bucket_alloc = apr_bucket_alloc_create(conn->scpool); + conn->tmp_bb = apr_brigade_create(conn->scpool, bucket_alloc); + /* + * The socket is now open, create a new backend server connection + */ + conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock, + 0, NULL, bucket_alloc); + } if (!conn->connection) { /* * the peer reset the connection already; ap_run_create_connection() @@ -4131,11 +4121,11 @@ static int proxy_connection_create(const char *proxy_function, */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00960) "%s: an error occurred creating a " - "new connection to %pI (%s)", proxy_function, - backend_addr, conn->hostname); - /* XXX: Will be closed when proxy_conn is closed */ - socket_cleanup(conn); - return HTTP_INTERNAL_SERVER_ERROR; + "new connection to %pI (%s)%s", + proxy_function, backend_addr, conn->hostname, + conn->sock ? "" : " (not connected)"); + rc = HTTP_INTERNAL_SERVER_ERROR; + goto cleanup; } /* For ssl connection to backend */ @@ -4145,7 +4135,8 @@ static int proxy_connection_create(const char *proxy_function, s, APLOGNO(00961) "%s: failed to enable ssl support " "for %pI (%s)", proxy_function, backend_addr, conn->hostname); - return HTTP_INTERNAL_SERVER_ERROR; + rc = HTTP_INTERNAL_SERVER_ERROR; + goto cleanup; } if (conn->ssl_hostname) { /* Set a note on the connection about what CN is requested, @@ -4180,7 +4171,7 @@ static int proxy_connection_create(const char *proxy_function, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00963) "%s: pre_connection setup failed (%d)", proxy_function, rc); - return rc; + goto cleanup; } apr_socket_timeout_set(conn->sock, current_timeout); @@ -4190,6 +4181,10 @@ static int proxy_connection_create(const char *proxy_function, apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown); return OK; + +cleanup: + socket_cleanup(conn); + return rc; } PROXY_DECLARE(int) ap_proxy_connection_create_ex(const char *proxy_function,