]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
PR63628: individual status codes for ProxyErrorOverride.
authorEric Covener <covener@apache.org>
Sat, 11 Apr 2020 21:19:08 +0000 (21:19 +0000)
committerEric Covener <covener@apache.org>
Sat, 11 Apr 2020 21:19:08 +0000 (21:19 +0000)
Support specifying the http status codes to be considered by ProxyErrorOverride

Submitted By: Martin Drößler <mail martindroessler.de>
Committed By: covener

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1876404 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/mod/mod_proxy.xml
include/ap_mmn.h
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/mod_proxy_ajp.c
modules/proxy/mod_proxy_fcgi.c
modules/proxy/mod_proxy_http.c
modules/proxy/mod_proxy_uwsgi.c
modules/proxy/proxy_util.c

diff --git a/CHANGES b/CHANGES
index b8e8f907592b187e295bd23f464bc44029766fb6..9c5f2588771bc9778891b3661e5b3856e12d8b47 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) mod_proxy: Allow ProxyErrorOverride to be restricted to specific status 
+     codes.  PR63628. [Martin Drößler <mail martindroessler.de>]
+
   *) configtest: Issue a warning for non-existent directories in <Directory> config
      sections. PR63079. [Stephane Blondon <stephane.blondon gmail.com>].
 
index 6672ca440586ece9aa05c56dc7274251ea4556f4..99659a06e64a69aba390a6a7053a72e84f4fce66 100644 (file)
@@ -2029,11 +2029,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
@@ -2046,6 +2047,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>
 
index 30c156fbfa71ae7dc37431bd1a4aed8b3436258b..53dee4c025f606d28fe71651df1ae47354a78e36 100644 (file)
  * 20200331.0 (2.5.1-dev)  Remove ap_request_core_filter() and
  *                         ap_request_core_filter_handle.
  * 20200331.1 (2.5.1-dev)  Add flushed:1 to request_rec
+ * 20200331.2 (2.5.1-dev)  Add ap_proxy_should_override to mod_proxy.h
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
index bb973e121fd6a565cf252ee750bad0e21e1a01c5..7294e5a0b3a83952b79debe1097b0e486b3fa3df 100644 (file)
@@ -1583,6 +1583,7 @@ static void *create_proxy_dir_config(apr_pool_t *p, char *dummy)
     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 */
@@ -1613,6 +1614,8 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
         = 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);
     new->interpolate_env = (add->interpolate_env == -1) ? base->interpolate_env
                                                         : add->interpolate_env;
     new->preserve_host = (add->preserve_host_set == 0) ? base->preserve_host
@@ -2123,14 +2126,39 @@ 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;
+        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;
+    }
+    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)
 {
@@ -2714,7 +2742,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"),
index 7d501bf5d0a30838b5602caf0e315eb2962bc865..bb47d9a01fc6e418d3fa6200131f2722c654df21 100644 (file)
@@ -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
@@ -1278,6 +1279,15 @@ PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket);
  */
 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
index 54e2d1a70d5b2e9b6f5e3445c8c593fba6263df0..9799c784bbec1ae1112e208c313c46c4e5268d1f 100644 (file)
@@ -474,7 +474,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
                     /* 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
                          */
@@ -497,8 +497,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
                              * 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, r->status)
+                                    && ap_proxy_should_override(conf, original_status)) {
                                 r->status = original_status;
                                 r->status_line = original_status_line;
                             }
@@ -547,7 +547,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
                 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,
@@ -642,7 +642,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
                       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
index 2e97408f3f7bba3a0913747d6918901699524791..77ad661c27353a0ab7eded53864c7c918392a464 100644 (file)
@@ -771,8 +771,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
index c5e1777623e987fee665d0121e90da54246576a1..3f356d40e75051ce27eaaf09dae5506af9a2fb4a 100644 (file)
@@ -1630,7 +1630,7 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
          */
 
         /* PR 41646: get HEAD right with ProxyErrorOverride */
-        if (ap_is_HTTP_ERROR(proxy_status) && dconf->error_override) {
+        if (ap_proxy_should_override(dconf, proxy_status)) {
             if (proxy_status == HTTP_UNAUTHORIZED) {
                 const char *buf;
                 const char *wa = "WWW-Authenticate";
@@ -1723,7 +1723,7 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
              * if we are overriding the errors, we can't put the content
              * of the page into the brigade
              */
-            if (!dconf->error_override || !ap_is_HTTP_ERROR(proxy_status)) {
+            if (!ap_proxy_should_override(dconf, proxy_status)) {
                 /* read the body, pass it to the output filters */
                 apr_read_type_e mode = APR_NONBLOCK_READ;
                 int finish = FALSE;
@@ -1733,8 +1733,8 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
                  * 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)) {
+                if (!ap_proxy_should_override(dconf, proxy_status)
+                        && ap_proxy_should_override(dconf, original_status)) {
                     r->status = original_status;
                     r->status_line = original_status_line;
                 }
index bce4fc21b80dece4ad1ad0a550fc92bbda805628..98b8579d0b7c9adb38e5a34f6edac5c686523d5b 100644 (file)
@@ -362,9 +362,9 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
 #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;
index 1fcf52f6b0a6af918c2f9a5ebf14362940dd4bd0..bb12774a553e48f3a37d2faa14be9e3c5fd33f9b 100644 (file)
@@ -3377,6 +3377,33 @@ int ap_proxy_lb_workers(void)
     return lb_workers_limit;
 }
 
+static int error_code_overridden(proxy_dir_conf *conf, int code)
+{
+    int i;
+    int *list = (int *) conf->error_override_codes->elts;
+
+    if (apr_is_empty_array(conf->error_override_codes))
+        return 0;
+
+    for (i = 0; i < conf->error_override_codes->nelts; i++) {
+        if (code == list[i])
+            return 1;
+    }
+
+    return 0;
+}
+
+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);
+
+    return error_code_overridden(conf, code);
+}
+
 /* deprecated - to be removed in v2.6 */
 PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
                                            apr_bucket_brigade *brigade)