From bc290e00b7ea931965db6d0dfa101d813a2fe323 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 17 Jun 2019 18:35:24 +0000 Subject: [PATCH] add RedirectRelative directive to allow relative Redirect targets 2616 forbade relative redirect URLs, but 7231 allows them Early 2.2 maintenance levels did not fix them up, but later 2.2 and all 2.4 fixed them up with ap_construct_url(). Allow opt-in to not fixing up relative URLs with RedirectRelative git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1861542 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_alias.xml | 21 +++++++ modules/mappers/mod_alias.c | 108 +++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 47 deletions(-) diff --git a/docs/manual/mod/mod_alias.xml b/docs/manual/mod/mod_alias.xml index 67f36b3e59..27423178b3 100644 --- a/docs/manual/mod/mod_alias.xml +++ b/docs/manual/mod/mod_alias.xml @@ -621,4 +621,25 @@ ScriptAliasMatch "(?i)^/cgi-bin(.*)" "/usr/local/apache/cgi-bin$1" + +RedirectRelative +Allows relative redirect targets. +RedirectRelative OFF|ON +RedirectRelative OFF +server configvirtual host +directory +2.5.1 and later + + + +

By default, if the target URL of a Redirect + directive is a relative URL beginning with a '/' character, the server + converts it to a an absolute URL before responding to the client. By + setting RedirectRelative to the value "ON", + the relative URL is presented to the client directly.

+ +
+
+ + diff --git a/modules/mappers/mod_alias.c b/modules/mappers/mod_alias.c index 5ff937b1ab..3297a975f6 100644 --- a/modules/mappers/mod_alias.c +++ b/modules/mappers/mod_alias.c @@ -37,6 +37,10 @@ #include "ap_expr.h" +#define ALIAS_FLAG_DEFAULT -1 +#define ALIAS_FLAG_OFF 0 +#define ALIAS_FLAG_ON 1 + typedef struct { const char *real; const char *fake; @@ -58,6 +62,7 @@ typedef struct { char *handler; const ap_expr_info_t *redirect; int redirect_status; /* 301, 302, 303, 410, etc */ + int allow_relative; /* skip ap_construct_url() */ } alias_dir_conf; module AP_MODULE_DECLARE_DATA alias_module; @@ -80,6 +85,7 @@ static void *create_alias_dir_config(apr_pool_t *p, char *d) alias_dir_conf *a = (alias_dir_conf *) apr_pcalloc(p, sizeof(alias_dir_conf)); a->redirects = apr_array_make(p, 2, sizeof(alias_entry)); + a->allow_relative = ALIAS_FLAG_DEFAULT; return a; } @@ -111,7 +117,9 @@ static void *merge_alias_dir_config(apr_pool_t *p, void *basev, void *overridesv a->redirect = (overrides->redirect_set == 0) ? base->redirect : overrides->redirect; a->redirect_status = (overrides->redirect_set == 0) ? base->redirect_status : overrides->redirect_status; a->redirect_set = overrides->redirect_set || base->redirect_set; - + a->allow_relative = (overrides->allow_relative != ALIAS_FLAG_DEFAULT) + ? overrides->allow_relative + : base->allow_relative; return a; } @@ -591,31 +599,33 @@ static int translate_alias_redir(request_rec *r) if (ret == PREGSUB_ERROR) return HTTP_INTERNAL_SERVER_ERROR; if (ap_is_HTTP_REDIRECT(status)) { - if (ret[0] == '/') { - char *orig_target = ret; - - ret = ap_construct_url(r->pool, ret, r); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00673) - "incomplete redirection target of '%s' for " - "URI '%s' modified to '%s'", - orig_target, r->uri, ret); - } - if (!ap_is_url(ret)) { - status = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00674) - "cannot redirect '%s' to '%s'; " - "target is not a valid absoluteURI or abs_path", - r->uri, ret); - } - else { - /* append requested query only, if the config didn't - * supply its own. - */ - if (r->args && !ap_strchr(ret, '?')) { - ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); + alias_dir_conf *dirconf = (alias_dir_conf *) + ap_get_module_config(r->per_dir_config, &alias_module); + if (dirconf->allow_relative != ALIAS_FLAG_ON || ret[0] != '/') { + if (ret[0] == '/') { + char *orig_target = ret; + + ret = ap_construct_url(r->pool, ret, r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00673) + "incomplete redirection target of '%s' for " + "URI '%s' modified to '%s'", + orig_target, r->uri, ret); } - apr_table_setn(r->headers_out, "Location", ret); + if (!ap_is_url(ret)) { + status = HTTP_INTERNAL_SERVER_ERROR; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00674) + "cannot redirect '%s' to '%s'; " + "target is not a valid absoluteURI or abs_path", + r->uri, ret); + } + } + /* append requested query only, if the config didn't + * supply its own. + */ + if (r->args && !ap_strchr(ret, '?')) { + ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); } + apr_table_setn(r->headers_out, "Location", ret); } return status; } @@ -646,31 +656,31 @@ static int fixup_redir(request_rec *r) if (ret == PREGSUB_ERROR) return HTTP_INTERNAL_SERVER_ERROR; if (ap_is_HTTP_REDIRECT(status)) { - if (ret[0] == '/') { - char *orig_target = ret; - - ret = ap_construct_url(r->pool, ret, r); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00675) - "incomplete redirection target of '%s' for " - "URI '%s' modified to '%s'", - orig_target, r->uri, ret); - } - if (!ap_is_url(ret)) { - status = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00676) - "cannot redirect '%s' to '%s'; " - "target is not a valid absoluteURI or abs_path", - r->uri, ret); - } - else { - /* append requested query only, if the config didn't - * supply its own. - */ - if (r->args && !ap_strchr(ret, '?')) { - ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); + if (dirconf->allow_relative != ALIAS_FLAG_ON || ret[0] != '/') { + if (ret[0] == '/') { + char *orig_target = ret; + + ret = ap_construct_url(r->pool, ret, r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00675) + "incomplete redirection target of '%s' for " + "URI '%s' modified to '%s'", + orig_target, r->uri, ret); + } + if (!ap_is_url(ret)) { + status = HTTP_INTERNAL_SERVER_ERROR; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00676) + "cannot redirect '%s' to '%s'; " + "target is not a valid absoluteURI or abs_path", + r->uri, ret); } - apr_table_setn(r->headers_out, "Location", ret); } + /* append requested query only, if the config didn't + * supply its own. + */ + if (r->args && !ap_strchr(ret, '?')) { + ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL); + } + apr_table_setn(r->headers_out, "Location", ret); } return status; } @@ -702,6 +712,10 @@ static const command_rec alias_cmds[] = AP_INIT_TAKE2("RedirectPermanent", add_redirect2, (void *) HTTP_MOVED_PERMANENTLY, OR_FILEINFO, "a document to be redirected, then the destination URL"), + AP_INIT_FLAG("RedirectRelative", ap_set_flag_slot, + (void*)APR_OFFSETOF(alias_dir_conf, allow_relative), OR_FILEINFO, + "Set to ON to allow relative redirect targets to be issued as-is"), + {NULL} }; -- 2.40.0