You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2021/01/16 14:22:41 UTC

svn commit: r1885575 - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ include/ modules/proxy/

Author: minfrin
Date: Sat Jan 16 14:22:41 2021
New Revision: 1885575

URL: http://svn.apache.org/viewvc?rev=1885575&view=rev
Log:
Backport 2.4:

  *) mod_proxy_http: individual status codes for ProxyErrorOverride. BZ 63628
     trunk patch: https://svn.apache.org/r1754974
                  https://svn.apache.org/r1754975
                  https://svn.apache.org/r1876404
                  https://svn.apache.org/r1877696
                  https://svn.apache.org/r1877697
                  https://svn.apache.org/r1877728
     2.4.x patch: http://people.apache.org/~ylavic/patches/2.4.x-mod_proxy_http-override-3on5.patch
                  https://github.com/apache/httpd/pull/157
     +1: ylavic, covener, minfrin
     ylavic: Besides ProxyErrorOverride individual status codes, merging now
             the non-functional changes in ap_proxy_http_process_response()
             around ProxyErrorOverride code helps reducing conflicts with the
             following commits, and with trunk/2.4 alignment still.


Modified:
    httpd/httpd/branches/2.4.x/CHANGES
    httpd/httpd/branches/2.4.x/STATUS
    httpd/httpd/branches/2.4.x/docs/manual/mod/mod_proxy.xml
    httpd/httpd/branches/2.4.x/include/ap_mmn.h
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_ajp.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c
    httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_uwsgi.c
    httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c

Modified: httpd/httpd/branches/2.4.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/CHANGES?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.4.x/CHANGES [utf-8] Sat Jan 16 14:22:41 2021
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.4.47
 
+  *) mod_proxy: Allow ProxyErrorOverride to be restricted to specific status 
+     codes.  PR63628. [Martin Drößler <mail martindroessler.de>]
+
   *) core: add ReadBufferSize, FlushMaxThreshold and FlushMaxPipelined
      directives.  [Yann Ylavic]
 

Modified: httpd/httpd/branches/2.4.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/STATUS?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/STATUS (original)
+++ httpd/httpd/branches/2.4.x/STATUS Sat Jan 16 14:22:41 2021
@@ -138,20 +138,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  *) mod_proxy_http: individual status codes for ProxyErrorOverride. BZ 63628
-     trunk patch: https://svn.apache.org/r1754974
-                  https://svn.apache.org/r1754975
-                  https://svn.apache.org/r1876404
-                  https://svn.apache.org/r1877696
-                  https://svn.apache.org/r1877697
-                  https://svn.apache.org/r1877728
-     2.4.x patch: http://people.apache.org/~ylavic/patches/2.4.x-mod_proxy_http-override-3on5.patch
-                  https://github.com/apache/httpd/pull/157
-     +1: ylavic, covener, minfrin
-     ylavic: Besides ProxyErrorOverride individual status codes, merging now
-             the non-functional changes in ap_proxy_http_process_response()
-             around ProxyErrorOverride code helps reducing conflicts with the
-             following commits, and with trunk/2.4 alignment still.
 
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:

Modified: httpd/httpd/branches/2.4.x/docs/manual/mod/mod_proxy.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/docs/manual/mod/mod_proxy.xml?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/docs/manual/mod/mod_proxy.xml (original)
+++ httpd/httpd/branches/2.4.x/docs/manual/mod/mod_proxy.xml Sat Jan 16 14:22:41 2021
@@ -1968,11 +1968,12 @@ header for proxied requests</description
 <directivesynopsis>
 <name>ProxyErrorOverride</name>
 <description>Override error pages for proxied content</description>
-<syntax>ProxyErrorOverride On|Off</syntax>
+<syntax>ProxyErrorOverride Off|On [<var>code</var> ...]</syntax>
 <default>ProxyErrorOverride Off</default>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context>
 </contextlist>
+<compatibility>The list of status codes was added in 2.5.1</compatibility>
 
 <usage>
     <p>This directive is useful for reverse-proxy setups where you want to
@@ -1985,6 +1986,26 @@ header for proxied requests</description
 
     <p>This directive does not affect the processing of informational (1xx),
     normal success (2xx), or redirect (3xx) responses.</p>
+
+    <p>By default <directive>ProxyErrorOverride</directive> affects all responses with codes between 400 (including)
+        and 600 (excluding).</p>
+
+    <example><title>Example for default behavior</title>
+        <highlight language="config">
+            ProxyErrorOverride  On
+        </highlight>
+    </example>
+
+    <p>To change the default behavior, you can specify the status codes to consider, separated by spaces.
+        If you do so, all other status codes will be ignored.
+        You can only specify status codes, that are considered error codes: between 400 (including)
+        and 600 (excluding).</p>
+
+    <example><title>Example for custom status codes</title>
+        <highlight language="config">
+            ProxyErrorOverride  On 403 405 500 501 502 503 504
+        </highlight>
+    </example>
 </usage>
 </directivesynopsis>
 

Modified: httpd/httpd/branches/2.4.x/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/include/ap_mmn.h?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/include/ap_mmn.h (original)
+++ httpd/httpd/branches/2.4.x/include/ap_mmn.h Sat Jan 16 14:22:41 2021
@@ -541,6 +541,7 @@
  * 20120211.97 (2.4.47-dev) Add read_buf_size member to core_dir_config,
  *                          flush_max_threshold and flush_max_pipelined to
  *                          core_server_config, and ap_get_read_buf_size().
+ * 20120211.98 (2.4.47-dev) Add ap_proxy_should_override to mod_proxy.h
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -548,7 +549,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20120211
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 97                  /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 98                  /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.c Sat Jan 16 14:22:41 2021
@@ -1575,6 +1575,7 @@ static void *create_proxy_dir_config(apr
     new->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
     new->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
     new->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
+    new->error_override_codes = apr_array_make(p, 10, sizeof(int));
     new->preserve_host_set = 0;
     new->preserve_host = 0;
     new->interpolate_env = -1; /* unset */
@@ -1588,6 +1589,11 @@ static void *create_proxy_dir_config(apr
     return (void *) new;
 }
 
+static int int_order(const void *i1, const void *i2)
+{
+    return *(const int *)i1 - *(const int *)i2;
+}
+
 static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
 {
     proxy_dir_conf *new = (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
@@ -1605,6 +1611,17 @@ static void *merge_proxy_dir_config(apr_
         = apr_array_append(p, base->cookie_paths, add->cookie_paths);
     new->cookie_domains
         = apr_array_append(p, base->cookie_domains, add->cookie_domains);
+    new->error_override_codes
+        = apr_array_append(p, base->error_override_codes, add->error_override_codes);
+    /* Keep the array sorted for binary search (since "base" and "add" are
+     * already sorted, it's only needed only if both are merged).
+     */
+    if (base->error_override_codes->nelts
+            && add->error_override_codes->nelts) {
+        qsort(new->error_override_codes->elts,
+              new->error_override_codes->nelts,
+              sizeof(int), int_order);
+    }
     new->interpolate_env = (add->interpolate_env == -1) ? base->interpolate_env
                                                         : add->interpolate_env;
     new->preserve_host = (add->preserve_host_set == 0) ? base->preserve_host
@@ -2126,14 +2143,50 @@ static const char *
 }
 
 static const char *
-    set_proxy_error_override(cmd_parms *parms, void *dconf, int flag)
+    set_proxy_error_override(cmd_parms *parms, void *dconf, const char *arg)
 {
     proxy_dir_conf *conf = dconf;
 
-    conf->error_override = flag;
-    conf->error_override_set = 1;
+    if (strcasecmp(arg, "Off") == 0) {
+        conf->error_override = 0;
+        conf->error_override_set = 1;
+    }
+    else if (strcasecmp(arg, "On") == 0) {
+        conf->error_override = 1;
+        conf->error_override_set = 1;
+    }
+    else if (conf->error_override_set == 1) {
+        int *newcode;
+        int argcode, i;
+        if (!apr_isdigit(arg[0]))
+            return "ProxyErrorOverride: status codes to intercept must be numeric";
+        if (!conf->error_override) 
+            return "ProxyErrorOverride: status codes must follow a value of 'on'";
+
+        argcode = strtol(arg, NULL, 10);
+        if (!ap_is_HTTP_ERROR(argcode))
+            return "ProxyErrorOverride: status codes to intercept must be valid HTTP Status Codes >=400 && <600";
+
+        newcode = apr_array_push(conf->error_override_codes);
+        *newcode = argcode;
+
+        /* Keep the array sorted for binary search. */
+        for (i = conf->error_override_codes->nelts - 1; i > 0; --i) {
+            int *oldcode = &((int *)conf->error_override_codes->elts)[i - 1];
+            if (*oldcode <= argcode) {
+                break;
+            }
+            *newcode = *oldcode;
+            *oldcode = argcode;
+            newcode = oldcode;
+        }
+    }
+    else
+        return "ProxyErrorOverride first parameter must be one of: off | on";
+
     return NULL;
 }
+
 static const char *
    add_proxy_http_headers(cmd_parms *parms, void *dconf, int flag)
 {
@@ -2723,7 +2776,7 @@ static const command_rec proxy_cmds[] =
      "The default intranet domain name (in absence of a domain in the URL)"),
     AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF,
      "Configure Via: proxy header header to one of: on | off | block | full"),
-    AP_INIT_FLAG("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF|ACCESS_CONF,
+    AP_INIT_ITERATE("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF|ACCESS_CONF,
      "use our error handling pages instead of the servers' we are proxying"),
     AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF|ACCESS_CONF,
      "on if we should preserve host header while proxying"),

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy.h Sat Jan 16 14:22:41 2021
@@ -201,7 +201,6 @@ typedef struct {
     unsigned int ppinherit_set:1;
 } proxy_server_conf;
 
-
 typedef struct {
     const char *p;            /* The path */
     ap_regex_t  *r;            /* Is this a regex? */
@@ -242,6 +241,8 @@ typedef struct {
 
     unsigned int forward_100_continue:1;
     unsigned int forward_100_continue_set:1;
+
+    apr_array_header_t *error_override_codes;
 } proxy_dir_conf;
 
 /* if we interpolate env vars per-request, we'll need a per-request
@@ -1232,6 +1233,15 @@ PROXY_DECLARE(int) ap_proxy_is_socket_co
 int ap_proxy_lb_workers(void);
 
 /**
+ * Returns 1 if a response with the given status should be overridden.
+ *
+ * @param conf   proxy directory configuration
+ * @param code   http status code
+ * @return       1 if code is considered an error-code, 0 otherwise
+ */
+PROXY_DECLARE(int) ap_proxy_should_override(proxy_dir_conf *conf, int code);
+
+/**
  * Return the port number of a known scheme (eg: http -> 80).
  * @param scheme        scheme to test
  * @return              port number or 0 if unknown

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_ajp.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_ajp.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_ajp.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_ajp.c Sat Jan 16 14:22:41 2021
@@ -475,7 +475,7 @@ static int ap_proxy_ajp_request(apr_pool
                     /* If we are overriding the errors, we can't put the content
                      * of the page into the brigade.
                      */
-                    if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
+                    if (!ap_proxy_should_override(conf, r->status)) {
                         /* AJP13_SEND_BODY_CHUNK with zero length
                          * is explicit flush message
                          */
@@ -498,8 +498,7 @@ static int ap_proxy_ajp_request(apr_pool
                              * error status so that an underlying error (eg HTTP_NOT_FOUND)
                              * doesn't become an HTTP_OK.
                              */
-                            if (conf->error_override && !ap_is_HTTP_ERROR(r->status)
-                                    && ap_is_HTTP_ERROR(original_status)) {
+                            if (ap_proxy_should_override(conf, original_status)) {
                                 r->status = original_status;
                                 r->status_line = original_status_line;
                             }
@@ -548,7 +547,7 @@ static int ap_proxy_ajp_request(apr_pool
                 if (status != APR_SUCCESS) {
                     backend_failed = 1;
                 }
-                if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) {
+                if (!ap_proxy_should_override(conf, r->status)) {
                     e = apr_bucket_eos_create(r->connection->bucket_alloc);
                     APR_BRIGADE_INSERT_TAIL(output_brigade, e);
                     if (ap_pass_brigade(r->output_filters,
@@ -643,7 +642,7 @@ static int ap_proxy_ajp_request(apr_pool
                       conn->worker->cp->addr,
                       conn->worker->s->hostname_ex);
 
-        if (conf->error_override && ap_is_HTTP_ERROR(r->status)) {
+        if (ap_proxy_should_override(conf, r->status)) {
             /* clear r->status for override error, otherwise ErrorDocument
              * thinks that this is a recursive error, and doesn't find the
              * custom error page

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_fcgi.c Sat Jan 16 14:22:41 2021
@@ -782,8 +782,7 @@ recv_again:
                                 }
                             }
 
-                            if (conf->error_override
-                                && ap_is_HTTP_ERROR(r->status) && ap_is_initial_req(r)) {
+                            if (ap_proxy_should_override(conf, r->status) && ap_is_initial_req(r)) {
                                 /*
                                  * set script_error_status to discard
                                  * everything after the headers

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_http.c Sat Jan 16 14:22:41 2021
@@ -1480,7 +1480,7 @@ int ap_proxy_http_process_response(proxy
         } else {
             /* an http/0.9 response */
             backasswards = 1;
-            r->status = 200;
+            r->status = proxy_status = 200;
             r->status_line = "200 OK";
             backend->close = 1;
         }
@@ -1616,45 +1616,20 @@ int ap_proxy_http_process_response(proxy
          * ProxyPassReverse/etc from here to ap_proxy_read_headers
          */
 
-        if ((proxy_status == 401) && (dconf->error_override)) {
-            const char *buf;
-            const char *wa = "WWW-Authenticate";
-            if ((buf = apr_table_get(r->headers_out, wa))) {
-                apr_table_set(r->err_headers_out, wa, buf);
-            } else {
-                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01109)
-                              "origin server sent 401 without "
-                              "WWW-Authenticate header");
+        /* PR 41646: get HEAD right with ProxyErrorOverride */
+        if (ap_proxy_should_override(dconf, proxy_status)) {
+            if (proxy_status == HTTP_UNAUTHORIZED) {
+                const char *buf;
+                const char *wa = "WWW-Authenticate";
+                if ((buf = apr_table_get(r->headers_out, wa))) {
+                    apr_table_set(r->err_headers_out, wa, buf);
+                } else {
+                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01109)
+                                  "origin server sent 401 without "
+                                  "WWW-Authenticate header");
+                }
             }
-        }
 
-        r->sent_bodyct = 1;
-        /*
-         * Is it an HTTP/0.9 response or did we maybe preread the 1st line of
-         * the response? If so, load the extra data. These are 2 mutually
-         * exclusive possibilities, that just happen to require very
-         * similar behavior.
-         */
-        if (backasswards || pread_len) {
-            apr_ssize_t cntr = (apr_ssize_t)pread_len;
-            if (backasswards) {
-                /*@@@FIXME:
-                 * At this point in response processing of a 0.9 response,
-                 * we don't know yet whether data is binary or not.
-                 * mod_charset_lite will get control later on, so it cannot
-                 * decide on the conversion of this buffer full of data.
-                 * However, chances are that we are not really talking to an
-                 * HTTP/0.9 server, but to some different protocol, therefore
-                 * the best guess IMHO is to always treat the buffer as "text/x":
-                 */
-                ap_xlate_proto_to_ascii(buffer, len);
-                cntr = (apr_ssize_t)len;
-            }
-            e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
-            APR_BRIGADE_INSERT_TAIL(bb, e);
-        }
-        /* PR 41646: get HEAD right with ProxyErrorOverride */
-        if (ap_is_HTTP_ERROR(r->status) && dconf->error_override) {
             /* clear r->status for override error, otherwise ErrorDocument
              * thinks that this is a recursive error, and doesn't find the
              * custom error page
@@ -1684,10 +1659,38 @@ int ap_proxy_http_process_response(proxy
             return proxy_status;
         }
 
+        r->sent_bodyct = 1;
+        /*
+         * Is it an HTTP/0.9 response or did we maybe preread the 1st line of
+         * the response? If so, load the extra data. These are 2 mutually
+         * exclusive possibilities, that just happen to require very
+         * similar behavior.
+         */
+        if (backasswards || pread_len) {
+            apr_ssize_t cntr = (apr_ssize_t)pread_len;
+            if (backasswards) {
+                /*@@@FIXME:
+                 * At this point in response processing of a 0.9 response,
+                 * we don't know yet whether data is binary or not.
+                 * mod_charset_lite will get control later on, so it cannot
+                 * decide on the conversion of this buffer full of data.
+                 * However, chances are that we are not really talking to an
+                 * HTTP/0.9 server, but to some different protocol, therefore
+                 * the best guess IMHO is to always treat the buffer as "text/x":
+                 */
+                ap_xlate_proto_to_ascii(buffer, len);
+                cntr = (apr_ssize_t)len;
+            }
+            e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
+        }
+
         /* send body - but only if a body is expected */
         if ((!r->header_only) &&                   /* not HEAD request */
             (proxy_status != HTTP_NO_CONTENT) &&      /* not 204 */
             (proxy_status != HTTP_NOT_MODIFIED)) {    /* not 304 */
+            apr_read_type_e mode;
+            int finish;
 
             /* We need to copy the output headers and treat them as input
              * headers as well.  BUT, we need to do this before we remove
@@ -1708,150 +1711,144 @@ int ap_proxy_http_process_response(proxy
 
             ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "start body send");
 
-            /*
-             * if we are overriding the errors, we can't put the content
-             * of the page into the brigade
+            /* read the body, pass it to the output filters */
+
+            /* Handle the case where the error document is itself reverse
+             * proxied and was successful. We must maintain any previous
+             * error status so that an underlying error (eg HTTP_NOT_FOUND)
+             * doesn't become an HTTP_OK.
              */
-            if (!dconf->error_override || !ap_is_HTTP_ERROR(proxy_status)) {
-                /* read the body, pass it to the output filters */
-                apr_read_type_e mode = APR_NONBLOCK_READ;
-                int finish = FALSE;
-
-                /* Handle the case where the error document is itself reverse
-                 * proxied and was successful. We must maintain any previous
-                 * error status so that an underlying error (eg HTTP_NOT_FOUND)
-                 * doesn't become an HTTP_OK.
-                 */
-                if (dconf->error_override && !ap_is_HTTP_ERROR(proxy_status)
-                        && ap_is_HTTP_ERROR(original_status)) {
-                    r->status = original_status;
-                    r->status_line = original_status_line;
-                }
-
-                do {
-                    apr_off_t readbytes;
-                    apr_status_t rv;
-
-                    rv = ap_get_brigade(backend->r->input_filters, bb,
-                                        AP_MODE_READBYTES, mode,
-                                        req->sconf->io_buffer_size);
-
-                    /* ap_get_brigade will return success with an empty brigade
-                     * for a non-blocking read which would block: */
-                    if (mode == APR_NONBLOCK_READ
-                        && (APR_STATUS_IS_EAGAIN(rv)
-                            || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)))) {
-                        /* flush to the client and switch to blocking mode */
-                        e = apr_bucket_flush_create(c->bucket_alloc);
-                        APR_BRIGADE_INSERT_TAIL(bb, e);
-                        if (ap_pass_brigade(r->output_filters, bb)
-                            || c->aborted) {
-                            backend->close = 1;
-                            break;
-                        }
-                        apr_brigade_cleanup(bb);
-                        mode = APR_BLOCK_READ;
-                        continue;
-                    }
-                    else if (rv == APR_EOF) {
-                        backend->close = 1;
-                        break;
-                    }
-                    else if (rv != APR_SUCCESS) {
-                        /* In this case, we are in real trouble because
-                         * our backend bailed on us. Pass along a 502 error
-                         * error bucket
-                         */
-                        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01110)
-                                      "error reading response");
-                        ap_proxy_backend_broke(r, bb);
-                        ap_pass_brigade(r->output_filters, bb);
-                        backend_broke = 1;
+            if (ap_proxy_should_override(dconf, original_status)) {
+                r->status = original_status;
+                r->status_line = original_status_line;
+            }
+
+            mode = APR_NONBLOCK_READ;
+            finish = FALSE;
+            do {
+                apr_off_t readbytes;
+                apr_status_t rv;
+
+                rv = ap_get_brigade(backend->r->input_filters, bb,
+                                    AP_MODE_READBYTES, mode,
+                                    req->sconf->io_buffer_size);
+
+                /* ap_get_brigade will return success with an empty brigade
+                 * for a non-blocking read which would block: */
+                if (mode == APR_NONBLOCK_READ
+                    && (APR_STATUS_IS_EAGAIN(rv)
+                        || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)))) {
+                    /* flush to the client and switch to blocking mode */
+                    e = apr_bucket_flush_create(c->bucket_alloc);
+                    APR_BRIGADE_INSERT_TAIL(bb, e);
+                    if (ap_pass_brigade(r->output_filters, bb)
+                        || c->aborted) {
                         backend->close = 1;
                         break;
                     }
-                    /* next time try a non-blocking read */
-                    mode = APR_NONBLOCK_READ;
+                    apr_brigade_cleanup(bb);
+                    mode = APR_BLOCK_READ;
+                    continue;
+                }
+                else if (rv == APR_EOF) {
+                    backend->close = 1;
+                    break;
+                }
+                else if (rv != APR_SUCCESS) {
+                    /* In this case, we are in real trouble because
+                     * our backend bailed on us. Pass along a 502 error
+                     * error bucket
+                     */
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01110)
+                                  "error reading response");
+                    ap_proxy_backend_broke(r, bb);
+                    ap_pass_brigade(r->output_filters, bb);
+                    backend_broke = 1;
+                    backend->close = 1;
+                    break;
+                }
+                /* next time try a non-blocking read */
+                mode = APR_NONBLOCK_READ;
 
-                    if (!apr_is_empty_table(backend->r->trailers_in)) {
-                        apr_table_do(add_trailers, r->trailers_out,
-                                backend->r->trailers_in, NULL);
-                        apr_table_clear(backend->r->trailers_in);
-                    }
+                if (!apr_is_empty_table(backend->r->trailers_in)) {
+                    apr_table_do(add_trailers, r->trailers_out,
+                            backend->r->trailers_in, NULL);
+                    apr_table_clear(backend->r->trailers_in);
+                }
 
-                    apr_brigade_length(bb, 0, &readbytes);
-                    backend->worker->s->read += readbytes;
+                apr_brigade_length(bb, 0, &readbytes);
+                backend->worker->s->read += readbytes;
 #if DEBUGGING
-                    {
-                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01111)
-                                  "readbytes: %#x", readbytes);
-                    }
+                {
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01111)
+                              "readbytes: %#x", readbytes);
+                }
 #endif
-                    /* sanity check */
-                    if (APR_BRIGADE_EMPTY(bb)) {
-                        break;
-                    }
-
-                    /* Switch the allocator lifetime of the buckets */
-                    ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
+                /* sanity check */
+                if (APR_BRIGADE_EMPTY(bb)) {
+                    break;
+                }
 
-                    /* found the last brigade? */
-                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
+                /* Switch the allocator lifetime of the buckets */
+                ap_proxy_buckets_lifetime_transform(r, bb, pass_bb);
 
-                        /* signal that we must leave */
-                        finish = TRUE;
+                /* found the last brigade? */
+                if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pass_bb))) {
 
-                        /* the brigade may contain transient buckets that contain
-                         * data that lives only as long as the backend connection.
-                         * Force a setaside so these transient buckets become heap
-                         * buckets that live as long as the request.
-                         */
-                        for (e = APR_BRIGADE_FIRST(pass_bb); e
-                                != APR_BRIGADE_SENTINEL(pass_bb); e
-                                = APR_BUCKET_NEXT(e)) {
-                            apr_bucket_setaside(e, r->pool);
-                        }
-
-                        /* finally it is safe to clean up the brigade from the
-                         * connection pool, as we have forced a setaside on all
-                         * buckets.
-                         */
-                        apr_brigade_cleanup(bb);
-
-                        /* make sure we release the backend connection as soon
-                         * as we know we are done, so that the backend isn't
-                         * left waiting for a slow client to eventually
-                         * acknowledge the data.
-                         */
-                        ap_proxy_release_connection(backend->worker->s->scheme,
-                                backend, r->server);
-                        /* Ensure that the backend is not reused */
-                        req->backend = NULL;
+                    /* signal that we must leave */
+                    finish = TRUE;
 
+                    /* the brigade may contain transient buckets that contain
+                     * data that lives only as long as the backend connection.
+                     * Force a setaside so these transient buckets become heap
+                     * buckets that live as long as the request.
+                     */
+                    for (e = APR_BRIGADE_FIRST(pass_bb); e
+                            != APR_BRIGADE_SENTINEL(pass_bb); e
+                            = APR_BUCKET_NEXT(e)) {
+                        apr_bucket_setaside(e, r->pool);
                     }
 
-                    /* try send what we read */
-                    if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS
-                        || c->aborted) {
-                        /* Ack! Phbtt! Die! User aborted! */
-                        /* Only close backend if we haven't got all from the
-                         * backend. Furthermore if req->backend is NULL it is no
-                         * longer safe to fiddle around with backend as it might
-                         * be already in use by another thread.
-                         */
-                        if (req->backend) {
-                            /* this causes socket close below */
-                            req->backend->close = 1;
-                        }
-                        finish = TRUE;
+                    /* finally it is safe to clean up the brigade from the
+                     * connection pool, as we have forced a setaside on all
+                     * buckets.
+                     */
+                    apr_brigade_cleanup(bb);
+
+                    /* make sure we release the backend connection as soon
+                     * as we know we are done, so that the backend isn't
+                     * left waiting for a slow client to eventually
+                     * acknowledge the data.
+                     */
+                    ap_proxy_release_connection(backend->worker->s->scheme,
+                            backend, r->server);
+                    /* Ensure that the backend is not reused */
+                    req->backend = NULL;
+
+                }
+
+                /* try send what we read */
+                if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS
+                    || c->aborted) {
+                    /* Ack! Phbtt! Die! User aborted! */
+                    /* Only close backend if we haven't got all from the
+                     * backend. Furthermore if req->backend is NULL it is no
+                     * longer safe to fiddle around with backend as it might
+                     * be already in use by another thread.
+                     */
+                    if (req->backend) {
+                        /* this causes socket close below */
+                        req->backend->close = 1;
                     }
+                    finish = TRUE;
+                }
 
-                    /* make sure we always clean up after ourselves */
-                    apr_brigade_cleanup(pass_bb);
-                    apr_brigade_cleanup(bb);
+                /* make sure we always clean up after ourselves */
+                apr_brigade_cleanup(pass_bb);
+                apr_brigade_cleanup(bb);
+
+            } while (!finish);
 
-                } while (!finish);
-            }
             ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "end body send");
         }
         else {

Modified: httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_uwsgi.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_uwsgi.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_uwsgi.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/mod_proxy_uwsgi.c Sat Jan 16 14:22:41 2021
@@ -371,9 +371,9 @@ static int uwsgi_response(request_rec *r
 #if AP_MODULE_MAGIC_AT_LEAST(20101106,0)
     dconf =
         ap_get_module_config(r->per_dir_config, &proxy_module);
-    if (dconf->error_override && ap_is_HTTP_ERROR(r->status)) {
+    if (ap_proxy_should_override(dconf, r->status)) {
 #else
-    if (conf->error_override && ap_is_HTTP_ERROR(r->status)) {
+    if (ap_proxy_should_override(conf, r->status)) {
 #endif
         int status = r->status;
         r->status = HTTP_OK;

Modified: httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c?rev=1885575&r1=1885574&r2=1885575&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/branches/2.4.x/modules/proxy/proxy_util.c Sat Jan 16 14:22:41 2021
@@ -3401,6 +3401,45 @@ int ap_proxy_lb_workers(void)
     return lb_workers_limit;
 }
 
+static APR_INLINE int error_code_overridden(const int *elts, int nelts,
+                                            int code)
+{
+    int min = 0;
+    int max = nelts - 1;
+    AP_DEBUG_ASSERT(max >= 0);
+
+    while (min < max) {
+        int mid = (min + max) / 2;
+        int val = elts[mid];
+
+        if (val < code) {
+            min = mid + 1;
+        }
+        else if (val > code) {
+            max = mid - 1;
+        }
+        else {
+            return 1;
+        }
+    }
+
+    return elts[min] == code;
+}
+
+PROXY_DECLARE(int) ap_proxy_should_override(proxy_dir_conf *conf, int code)
+{
+    if (!conf->error_override) 
+        return 0;
+
+    if (apr_is_empty_array(conf->error_override_codes))
+        return ap_is_HTTP_ERROR(code);
+
+    /* Since error_override_codes is sorted, apply binary search. */
+    return error_code_overridden((int *)conf->error_override_codes->elts,
+                                 conf->error_override_codes->nelts,
+                                 code);
+}
+
 PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
                                            apr_bucket_brigade *brigade)
 {