-*- 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>].
<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
<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>
* 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" */
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 */
= 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
}
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)
{
"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"),
unsigned int ppinherit_set:1;
} proxy_server_conf;
-
typedef struct {
const char *p; /* The path */
ap_regex_t *r; /* Is this a regex? */
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
*/
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
/* 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
*/
* 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;
}
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,
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
}
}
- 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
*/
/* 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";
* 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;
* 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;
}
#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;
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)