From: Graham Leggett Date: Fri, 10 Dec 2021 13:23:51 +0000 (+0000) Subject: Backport: X-Git-Tag: candidate-2.4.52-rc1~80 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c28fdf37f872fe1a0c1fb9d782842f8416f39846;p=thirdparty%2Fapache%2Fhttpd.git Backport: *) mod_proxy_connect: Honor the smallest of the backend or client timeout while tunneling, and handle "proxy-nohalfclose" as opt-out for hlaf-close tunneling. PR 65631, 65662, 65689. trunk patch: http://svn.apache.org/r1894290 http://svn.apache.org/r1895304 backport PR: https://github.com/apache/httpd/pull/278 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/278.patch +1: ylavic, rpluem, minfrin git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1895762 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 6bbe0383ec1..37fda08f544 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.52 + *) mod_proxy_connect: Honor the smallest of the backend or client timeout + while tunneling. [Yann Ylavic] + + *) mod_proxy: SetEnv proxy-nohalfclose (or alike) allows to disable TCP + half-close forwarding when tunneling protocols. [Yann Ylavic] + *) core: Be safe with ap_lingering_close() called with a socket NULL-ed by a third-party module. PR 65627. [acmondor , Yann Ylavic] diff --git a/STATUS b/STATUS index a6a7ee2beb1..92794c13376 100644 --- a/STATUS +++ b/STATUS @@ -144,14 +144,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_proxy_connect: Honor the smallest of the backend or client timeout - while tunneling, and handle "proxy-nohalfclose" as opt-out for hlaf-close - tunneling. PR 65631, 65662, 65689. - trunk patch: http://svn.apache.org/r1894290 - http://svn.apache.org/r1895304 - backport PR: https://github.com/apache/httpd/pull/278 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/278.patch - +1: ylavic, rpluem, minfrin PATCHES PROPOSED TO BACKPORT FROM TRUNK: diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 1219e9f1727..35acc49a4a3 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -1335,7 +1335,8 @@ typedef struct { struct proxy_tunnel_conn *client, *origin; apr_size_t read_buf_size; - int replied; + int replied; /* TODO 2.5+: one bit to merge in below bitmask */ + unsigned int nohalfclose :1; } proxy_tunnel_rec; /** diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index f291a0d55f2..a3cf5460487 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -4673,6 +4673,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_tunnel_create(proxy_tunnel_rec **ptunnel, { apr_status_t rv; conn_rec *c_i = r->connection; + apr_interval_time_t timeout = -1; proxy_tunnel_rec *tunnel; *ptunnel = NULL; @@ -4712,6 +4713,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_tunnel_create(proxy_tunnel_rec **ptunnel, tunnel->origin->pfd->desc.s = ap_get_conn_socket(c_o); tunnel->origin->pfd->client_data = tunnel->origin; + /* Defaults to the smallest timeout of both connections */ + apr_socket_timeout_get(tunnel->client->pfd->desc.s, &timeout); + apr_socket_timeout_get(tunnel->origin->pfd->desc.s, &tunnel->timeout); + if (timeout >= 0 && (tunnel->timeout < 0 || tunnel->timeout > timeout)) { + tunnel->timeout = timeout; + } + /* We should be nonblocking from now on the sockets */ apr_socket_opt_set(tunnel->client->pfd->desc.s, APR_SO_NONBLOCK, 1); apr_socket_opt_set(tunnel->origin->pfd->desc.s, APR_SO_NONBLOCK, 1); @@ -4733,6 +4741,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_tunnel_create(proxy_tunnel_rec **ptunnel, c_i->keepalive = AP_CONN_CLOSE; c_o->keepalive = AP_CONN_CLOSE; + /* Disable half-close forwarding for this request? */ + if (apr_table_get(r->subprocess_env, "proxy-nohalfclose")) { + tunnel->nohalfclose = 1; + } + /* Start with POLLOUT and let ap_proxy_tunnel_run() schedule both * directions when there are no output data pending (anymore). */ @@ -4838,6 +4851,12 @@ static int proxy_tunnel_forward(proxy_tunnel_rec *tunnel, ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, tunnel->r, "proxy: %s: %s read shutdown", tunnel->scheme, in->name); + if (tunnel->nohalfclose) { + /* No half-close forwarding, we are done both ways as + * soon as one side shuts down. + */ + return DONE; + } in->down_in = 1; } else { @@ -4854,7 +4873,7 @@ static int proxy_tunnel_forward(proxy_tunnel_rec *tunnel, PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) { - int rc = OK; + int status = OK, rc; request_rec *r = tunnel->r; apr_pollset_t *pollset = tunnel->pollset; struct proxy_tunnel_conn *client = tunnel->client, @@ -4889,14 +4908,14 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) "(client=%hx, origin=%hx)", scheme, client->pfd->reqevents, origin->pfd->reqevents); - rc = HTTP_GATEWAY_TIME_OUT; + status = HTTP_GATEWAY_TIME_OUT; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10214) "proxy: %s: polling failed", scheme); - rc = HTTP_INTERNAL_SERVER_ERROR; + status = HTTP_INTERNAL_SERVER_ERROR; } - return rc; + goto done; } ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, APLOGNO(10215) @@ -4915,7 +4934,8 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) && pfd->desc.s != origin->pfd->desc.s) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10222) "proxy: %s: unknown socket in pollset", scheme); - return HTTP_INTERNAL_SERVER_ERROR; + status = HTTP_INTERNAL_SERVER_ERROR; + goto done; } if (!(pfd->rtnevents & (APR_POLLIN | APR_POLLOUT | @@ -4924,7 +4944,8 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10220) "proxy: %s: polling events error (%x)", scheme, pfd->rtnevents); - return HTTP_INTERNAL_SERVER_ERROR; + status = HTTP_INTERNAL_SERVER_ERROR; + goto done; } /* We want to write if we asked for POLLOUT and got: @@ -4954,7 +4975,8 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10221) "proxy: %s: %s flushing failed (%i)", scheme, out->name, rc); - return rc; + status = rc; + goto done; } /* No more pending data. If the other side is not readable @@ -4984,7 +5006,8 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) */ rc = proxy_tunnel_forward(tunnel, in); if (rc != OK) { - return rc; + status = rc; + goto done; } } } @@ -4999,15 +5022,20 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel) || !(pfd->rtnevents & APR_POLLOUT))) { rc = proxy_tunnel_forward(tunnel, tc); if (rc != OK) { - return rc; + status = rc; + goto done; } } } } while (!client->down_out || !origin->down_out); +done: ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(10223) - "proxy: %s: tunnel finished", scheme); - return OK; + "proxy: %s: tunneling returns (%i)", scheme, status); + if (status == DONE) { + status = OK; + } + return status; } PROXY_DECLARE (const char *) ap_proxy_show_hcmethod(hcmethod_t method)