1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

mod_proxy: Fix potential tunneling infinite loop and spurious timeout.

PRs 65521 and 65519.

* modules/proxy/proxy_util.c(ap_proxy_tunnel_run):
  Avoid an infinite loop by shutting down the connection for write when poll()
  returns POLLHUP and read is already down.  PR 65521.

* modules/proxy/proxy_util.c(ap_proxy_tunnel_run):
  When write completion is finished don't check for ap_filter_input_pending()
  before proxy_tunnel_forward() to flush input data, this is a nonblocking read
  already which will do the same thing implicitely. ap_filter_input_pending()
  is broken in 2.4.x without the whole pending data mechanism (not backported
  yet), so let's align here.  PR 65519.



git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1892740 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yann Ylavic
2021-08-30 18:04:20 +00:00
parent c1619c6843
commit e8228ba4e6
2 changed files with 27 additions and 6 deletions

View File

@@ -4890,12 +4890,16 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel)
return HTTP_INTERNAL_SERVER_ERROR;
}
/* Write if we asked for POLLOUT, and got it or POLLERR
* alone (i.e. not with POLLIN|HUP). We want the output filters
* to know about the socket error if any, by failing the write.
/* We want to write if we asked for POLLOUT and got:
* - POLLOUT: the socket is ready for write;
* - !POLLIN: the socket is in error state (POLLERR) so we let
* the user know by failing the write and log, OR the socket
* is shutdown for read already (POLLHUP) so we have to
* shutdown for write.
*/
if ((tc->pfd->reqevents & APR_POLLOUT)
&& ((pfd->rtnevents & APR_POLLOUT)
|| !(tc->pfd->reqevents & APR_POLLIN)
|| !(pfd->rtnevents & (APR_POLLIN | APR_POLLHUP)))) {
struct proxy_tunnel_conn *out = tc, *in = tc->other;
@@ -4944,12 +4948,25 @@ PROXY_DECLARE(int) ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel)
return rc;
}
}
/* Flush any pending input data now, we don't know when
* the next POLLIN will trigger and retaining data might
* deadlock the underlying protocol. We don't check for
* pending data first with ap_filter_input_pending() since
* the read from proxy_tunnel_forward() is nonblocking
* anyway and returning OK if there's no data.
*/
rc = proxy_tunnel_forward(tunnel, in);
if (rc != OK) {
return rc;
}
}
}
/* Read if we asked for POLLIN|HUP, and got it or POLLERR
* alone (i.e. not with POLLOUT). We want the input filters
* to know about the socket error if any, by failing the read.
/* We want to read if we asked for POLLIN|HUP and got:
* - POLLIN|HUP: the socket is ready for read or EOF (POLLHUP);
* - !POLLOUT: the socket is in error state (POLLERR) so we let
* the user know by failing the read and log.
*/
if ((tc->pfd->reqevents & APR_POLLIN)
&& ((pfd->rtnevents & (APR_POLLIN | APR_POLLHUP))