]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r1886141, r1886151 from trunk:
authorYann Ylavic <ylavic@apache.org>
Tue, 2 Mar 2021 20:50:40 +0000 (20:50 +0000)
committerYann Ylavic <ylavic@apache.org>
Tue, 2 Mar 2021 20:50:40 +0000 (20:50 +0000)
* We need to check for (!scheme && (u = strchr(url, ':')) && (u - url) > 14)
  later as (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') is true
  for requests with the CONNECT method which we need to decline. But in many
  cases requests with the CONNECT method have (u - url) > 14 as in this
  case (u - url) is the length of the FQDN the forward proxy should connect
  to.

mod_proxy_http: follow up to r1886141, axe overlong scheme check.

Since mod_proxy can see CONNECT URIs, "hostname:port" versus "scheme:"
is hardly distinguishable (we don't want to limit the length of hostnames),
and we don't allocate the scheme anymore while parsing, let's simply decline
unrecognized schemes (overlong or not) and be caught by the no-handler case
if there really is no proxy handler interested.

Submitted by: rpluem, ylavic
Reviewed by: ylavic, covener, icing

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1887118 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy_http.c
server/core_filters.c

index de4cdf40205ec2b81d9ec1d5e72182db4bea16f9..6c3504b1cf6eeb8cc1624df1efd08dcfecbe3ec5 100644 (file)
@@ -1861,11 +1861,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
         is_ssl = 0;
     }
     if (!scheme || u[0] != '/' || u[1] != '/' || u[2] == '\0') {
-        if (!scheme && (u = strchr(url, ':')) && (u - url) > 14) {
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10262)
-                          "overlong proxy URL scheme in %s", url);
-            return HTTP_BAD_REQUEST;
-        }
         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01113)
                       "HTTP: declining URL %s", url);
         return DECLINED; /* only interested in HTTP, WS or FTP via proxy */
index 7cd49f6df3d47838b9afbca43440588d39ca82c0..d6a3169c3bec5e04502e5be658f35a6edf608542 100644 (file)
@@ -361,8 +361,7 @@ static apr_status_t sendfile_nonblocking(apr_socket_t *s,
  */
 extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *ap__logio_add_bytes_out;
 
-static apr_status_t should_send_brigade(apr_bucket_brigade *bb,
-                                        conn_rec *c, int *flush)
+static int should_send_brigade(apr_bucket_brigade *bb, conn_rec *c, int *flush)
 {
     core_server_config *conf =
         ap_get_core_module_config(c->base_server->module_config);
@@ -502,7 +501,6 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb)
     if (!new_bb || should_send_brigade(bb, c, NULL)) {
         apr_socket_t *sock = net->client_socket;
         apr_interval_time_t sock_timeout = 0;
-        int flush;
 
         /* Non-blocking writes on the socket in any case. */
         apr_socket_timeout_get(sock, &sock_timeout);
@@ -510,24 +508,28 @@ apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb)
 
         do {
             rv = send_brigade_nonblocking(sock, bb, ctx, c);
-            if (!new_bb || !APR_STATUS_IS_EAGAIN(rv)) {
-                break;
-            }
-
-            should_send_brigade(bb, c, &flush);
-            if (flush) {
-                apr_int32_t nfd;
-                apr_pollfd_t pfd;
-                memset(&pfd, 0, sizeof(pfd));
-                pfd.reqevents = APR_POLLOUT;
-                pfd.desc_type = APR_POLL_SOCKET;
-                pfd.desc.s = sock;
-                pfd.p = c->pool;
-                do {
-                    rv = apr_poll(&pfd, 1, &nfd, sock_timeout);
-                } while (APR_STATUS_IS_EINTR(rv));
+            if (new_bb && APR_STATUS_IS_EAGAIN(rv)) {
+                /* Scan through the brigade and decide whether we must absolutely
+                 * flush the remaining data, based on should_send_brigade() &flush
+                 * rules. If so, wait for writability and retry, otherwise we did
+                 * our best already and can wait for the next call.
+                 */
+                int flush;
+                (void)should_send_brigade(bb, c, &flush);
+                if (flush) {
+                    apr_int32_t nfd;
+                    apr_pollfd_t pfd;
+                    memset(&pfd, 0, sizeof(pfd));
+                    pfd.reqevents = APR_POLLOUT;
+                    pfd.desc_type = APR_POLL_SOCKET;
+                    pfd.desc.s = sock;
+                    pfd.p = c->pool;
+                    do {
+                        rv = apr_poll(&pfd, 1, &nfd, sock_timeout);
+                    } while (APR_STATUS_IS_EINTR(rv));
+                }
             }
-        } while (flush);
+        } while (rv == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb));
 
         /* Restore original socket timeout before leaving. */
         apr_socket_timeout_set(sock, sock_timeout);