From a06bf794e590f8876314d6b84ec38c81428e5225 Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Tue, 31 Mar 2015 12:49:45 +0000 Subject: [PATCH] Merge r1661448 from trunk: core: Add expression support to ErrorDocument. Switch from a fixed sized 664 byte array per merge to a hash table. Submitted by: minfrin Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1670320 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 ++ STATUS | 5 --- docs/manual/expr.xml | 1 + docs/manual/mod/core.xml | 8 +++- include/ap_mmn.h | 3 +- include/http_core.h | 14 +++---- server/core.c | 86 ++++++++++++++++++++++++++-------------- 7 files changed, 77 insertions(+), 43 deletions(-) diff --git a/CHANGES b/CHANGES index b213ab2b56..dacac4c549 100644 --- a/CHANGES +++ b/CHANGES @@ -46,6 +46,9 @@ Changes with Apache 2.4.13 a combination of certificate serialNumber and issuer as defined by CertificateExactMatch in RFC4523. [Graham Leggett] + *) core: Add expression support to ErrorDocument. Switch from a fixed + sized 664 byte array per merge to a hash table. [Graham Leggett] + *) ab: Add missing longest request (100%) to CSV export. [Marcin Fabrykowski ] diff --git a/STATUS b/STATUS index 270db57d17..384b32e896 100644 --- a/STATUS +++ b/STATUS @@ -107,11 +107,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) core: Add expression support to ErrorDocument. Switch from a fixed - sized 664 byte array per merge to a hash table. - trunk patch: http://svn.apache.org/r1661448 - 2.4.x patch: http://people.apache.org/~minfrin/httpd-core-errordocument24-3.patch - +1: minfrin, jim, covener PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/docs/manual/expr.xml b/docs/manual/expr.xml index 67b3d04b6a..eed2f0ac49 100644 --- a/docs/manual/expr.xml +++ b/docs/manual/expr.xml @@ -40,6 +40,7 @@ If ElseIf Else +ErrorDocument Alias ScriptAlias Redirect diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index b901850ccd..5612ed6978 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -1208,10 +1208,15 @@ in case of an error or a message. Apache httpd will sometimes offer additional information regarding the problem/error.

+

From 2.4.13, expression syntax can be + used inside the directive to produce dynamic strings and URLs.

+

URLs can begin with a slash (/) for local web-paths (relative to the DocumentRoot), or be a full URL which the client can resolve. Alternatively, a message - can be provided to be displayed by the browser. Examples:

+ can be provided to be displayed by the browser. Note that deciding + whether the parameter is an URL, a path or a message is performed + before any expression is parsed. Examples:

ErrorDocument 500 http://foo.example.com/cgi-bin/tester @@ -1219,6 +1224,7 @@ ErrorDocument 404 /cgi-bin/bad_urls.pl ErrorDocument 401 /subscription_info.html ErrorDocument 403 "Sorry can't allow you access today" ErrorDocument 403 Forbidden! +ErrorDocument 403 /cgi-bin/forbidden.pl?referrer=%{escape:%{HTTP_REFERER}}

Additionally, the special value default can be used diff --git a/include/ap_mmn.h b/include/ap_mmn.h index ca433d6d4b..a992d3cd31 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -437,6 +437,7 @@ * 20120211.39 (2.4.11-dev) Add ap_proxy_connect_uds(). * 20120211.40 (2.4.11-dev) Add ap_log_data(), ap_log_rdata(), etc. * 20120211.41 (2.4.11-dev) Add ap_proxy_de_socketfy to mod_proxy.h + * 20120211.42 (2.4.13-dev) Add response_code_exprs to http_core.h */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -444,7 +445,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 41 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 42 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_core.h b/include/http_core.h index 5cef6224fc..23db3cfce0 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -497,12 +497,7 @@ typedef struct { overrides_t override; allow_options_t override_opts; - /* Custom response config. These can contain text or a URL to redirect to. - * if response_code_strings is NULL then there are none in the config, - * if it's not null then it's allocated to sizeof(char*)*RESPONSE_CODES. - * This lets us do quick merges in merge_core_dir_configs(). - */ - + /* Used to be the custom response config. No longer used. */ char **response_code_strings; /* from ErrorDocument, not from * ap_custom_response() */ @@ -617,10 +612,15 @@ typedef struct { /** Max number of Range reversals (eg: 200-300, 100-125) allowed **/ int max_reversals; - /** Named back references */ apr_array_header_t *refs; + /** Custom response config with expression support. The hash table + * contains compiled expressions keyed against the custom response + * code. + */ + apr_hash_t *response_code_exprs; + } core_dir_config; /* macro to implement off by default behaviour */ diff --git a/server/core.c b/server/core.c index e307e92bb2..749cf5c166 100644 --- a/server/core.c +++ b/server/core.c @@ -252,23 +252,14 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->override_list = new->override_list; } - if (conf->response_code_strings == NULL) { - conf->response_code_strings = new->response_code_strings; + if (conf->response_code_exprs == NULL) { + conf->response_code_exprs = new->response_code_exprs; } - else if (new->response_code_strings != NULL) { - /* If we merge, the merge-result must have its own array - */ - conf->response_code_strings = apr_pmemdup(a, - base->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); - - for (i = 0; i < RESPONSE_CODES; ++i) { - if (new->response_code_strings[i] != NULL) { - conf->response_code_strings[i] = new->response_code_strings[i]; - } - } + else if (new->response_code_exprs != NULL) { + conf->response_code_exprs = apr_hash_overlay(a, + new->response_code_exprs, conf->response_code_exprs); } - /* Otherwise we simply use the base->response_code_strings array + /* Otherwise we simply use the base->response_code_exprs array */ if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) { @@ -796,25 +787,46 @@ char *ap_response_code_string(request_rec *r, int error_index) { core_dir_config *dirconf; core_request_config *reqconf = ap_get_core_module_config(r->request_config); + const char *err; + const char *response; + void *val; + ap_expr_info_t *expr; /* check for string registered via ap_custom_response() first */ - if (reqconf->response_code_strings != NULL && - reqconf->response_code_strings[error_index] != NULL) { + if (reqconf->response_code_strings != NULL + && reqconf->response_code_strings[error_index] != NULL) { return reqconf->response_code_strings[error_index]; } /* check for string specified via ErrorDocument */ dirconf = ap_get_core_module_config(r->per_dir_config); - if (dirconf->response_code_strings == NULL) { + if (!dirconf->response_code_exprs) { + return NULL; + } + + expr = apr_hash_get(dirconf->response_code_exprs, &error_index, + sizeof(error_index)); + if (!expr) { return NULL; } - if (dirconf->response_code_strings[error_index] == &errordocument_default) { + /* special token to indicate revert back to default */ + if ((char *) expr == &errordocument_default) { return NULL; } - return dirconf->response_code_strings[error_index]; + err = NULL; + response = ap_expr_str_exec(r, expr, &err); + if (err) { + ap_log_rerror( + APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02830) "core: ErrorDocument: can't " + "evaluate require expression: %s", err); + return NULL; + } + + /* alas, duplication required as we return not-const */ + return apr_pstrdup(r->pool, response); } @@ -1499,27 +1511,43 @@ static const char *set_error_document(cmd_parms *cmd, void *conf_, "directive --- ignoring!", cmd->directive->filename, cmd->directive->line_num); } else { /* Store it... */ - if (conf->response_code_strings == NULL) { - conf->response_code_strings = - apr_pcalloc(cmd->pool, - sizeof(*conf->response_code_strings) * - RESPONSE_CODES); + if (conf->response_code_exprs == NULL) { + conf->response_code_exprs = apr_hash_make(cmd->pool); } if (strcasecmp(msg, "default") == 0) { /* special case: ErrorDocument 404 default restores the * canned server error response */ - conf->response_code_strings[index_number] = &errordocument_default; + apr_hash_set(conf->response_code_exprs, + apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)), + sizeof(index_number), &errordocument_default); } else { + ap_expr_info_t *expr; + const char *expr_err = NULL; + /* hack. Prefix a " if it is a msg; as that is what * http_protocol.c relies on to distinguish between * a msg and a (local) path. */ - conf->response_code_strings[index_number] = (what == MSG) ? - apr_pstrcat(cmd->pool, "\"", msg, NULL) : - apr_pstrdup(cmd->pool, msg); + const char *response = + (what == MSG) ? apr_pstrcat(cmd->pool, "\"", msg, NULL) : + apr_pstrdup(cmd->pool, msg); + + expr = ap_expr_parse_cmd(cmd, response, AP_EXPR_FLAG_STRING_RESULT, + &expr_err, NULL); + + if (expr_err) { + return apr_pstrcat(cmd->temp_pool, + "Cannot parse expression in ErrorDocument: ", + expr_err, NULL); + } + + apr_hash_set(conf->response_code_exprs, + apr_pmemdup(cmd->pool, &index_number, sizeof(index_number)), + sizeof(index_number), expr); + } } -- 2.50.1