From: Eric Covener Date: Sun, 17 Mar 2019 14:41:10 +0000 (+0000) Subject: Merge consecutive slashes in the URL by default X-Git-Tag: 2.5.0-alpha2-ci-test-only~2100 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=807a365d9111c366e5314f2b3572501322feb489;p=thirdparty%2Fapache%2Fhttpd.git Merge consecutive slashes in the URL by default opt-out w/ `MergeSlashes OFF`. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1855705 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index afcb891e19e..57f0e9e6565 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) Merge consecutive slashes in URL's. Opt-out with `MergeSlashes OFF`. + [Eric Covener] + *) mod_proxy/ssl: Cleanup per-request SSL configuration anytime a backend connection is recycled/reused to avoid a possible crash with some SSLProxy configurations in or context. PR 63256. [Yann Ylavic] diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index f1516a35175..ac428dfe4ba 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -5332,4 +5332,30 @@ as if 'QualifyRedirectURL ON' was configured. + +MergeSlashes +Controls whether the server merges consecutive slashes in URLs. + +MergeSlashes ON|OFF +MergeSlashes ON +server configvirtual host + +Added in 2.5.1 + + +

By default, the server merges (or collapses) multiple consecutive slash + ('/') characters in the path component of the request URL.

+ +

When mapping URL's to the filesystem, these multiple slashes are not + significant. However, URL's handled other ways, such as by CGI or proxy, + might prefer to retain the significance of multiple consecutive slashes. + In these cases MergeSlashes can be set to + OFF to retain the multiple consecutive slashes. In these + configurations, regular expressions used in the configuration file that match + the path component of the URL (LocationMatch, + RewriteRule, ...) need to take into account multiple + consecutive slashes.

+
+
+ diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 7d400b3db63..5a479c075e6 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -610,6 +610,8 @@ * 20180906.2 (2.5.1-dev) Add ap_state_dir_relative() * 20180906.3 (2.5.1-dev) Add ap_dir_nofnmatch() and ap_dir_fnmatch(). * 20191203.1 (2.5.1-dev) Axe bucket number from struct process_score + * 20191203.2 (2.5.1-dev) Add ap_no2slash_ex() and merge_slashes to + * core_server_conf. */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -617,7 +619,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20191203 #endif -#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 2 /* 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 fe3836fb344..00aeaa7800e 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -771,6 +771,7 @@ typedef struct { apr_size_t flush_max_threshold; apr_int32_t flush_max_pipelined; unsigned int strict_host_check; + unsigned int merge_slashes; } core_server_config; /* for AddOutputFiltersByType in core.c */ diff --git a/include/httpd.h b/include/httpd.h index 0005e0cf8a2..1c6a242a892 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1750,11 +1750,22 @@ AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes); AP_DECLARE(int) ap_unescape_urlencoded(char *query); /** - * Convert all double slashes to single slashes - * @param name The string to convert + * Convert all double slashes to single slashes, except where significant + * to the filesystem on the current platform. + * @param name The string to convert, assumed to be a filesystem path */ AP_DECLARE(void) ap_no2slash(char *name) AP_FN_ATTR_NONNULL_ALL; +/** + * Convert all double slashes to single slashes, except where significant + * to the filesystem on the current platform. + * @param name The string to convert + * @param is_fs_path if set to 0, the significance of any double-slashes is + * ignored. + */ +AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path) + AP_FN_ATTR_NONNULL_ALL; + /** * Remove all ./ and xx/../ substrings from a file name. Also remove diff --git a/server/core.c b/server/core.c index 98197d85e9c..ceb7dd6bb81 100644 --- a/server/core.c +++ b/server/core.c @@ -528,6 +528,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) conf->protocols_honor_order = -1; conf->async_filter = 0; conf->strict_host_check= AP_CORE_CONFIG_UNSET; + conf->merge_slashes = AP_CORE_CONFIG_UNSET; return (void *)conf; } @@ -628,6 +629,7 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) : base->strict_host_check; AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt); + AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt); return conf; } @@ -4922,6 +4924,11 @@ AP_INIT_TAKE1("ProtocolsHonorOrder", set_protocols_honor_order, NULL, RSRC_CONF, AP_INIT_TAKE1("AsyncFilter", set_async_filter, NULL, RSRC_CONF, "'network', 'connection' (default) or 'request' to limit the " "types of filters that support asynchronous handling"), +AP_INIT_FLAG("MergeSlashes", set_core_server_flag, + (void *)APR_OFFSETOF(core_server_config, merge_slashes), + RSRC_CONF, + "Controls whether consecutive slashes in the URI path are merged"), + { NULL } }; diff --git a/server/request.c b/server/request.c index 70812fed594..052e20b3dd5 100644 --- a/server/request.c +++ b/server/request.c @@ -167,6 +167,8 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) int file_req = (r->main && r->filename); int access_status; core_dir_config *d; + core_server_config *sconf = + ap_get_core_module_config(r->server->module_config); /* Ignore embedded %2F's in path for proxy requests */ if (!r->proxyreq && r->parsed_uri.path) { @@ -191,6 +193,10 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) } ap_getparents(r->uri); /* OK --- shrinking transformations... */ + if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { + ap_no2slash(r->uri); + ap_no2slash(r->parsed_uri.path); + } /* All file subrequests are a huge pain... they cannot bubble through the * next several steps. Only file subrequests are allowed an empty uri, @@ -1415,20 +1421,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r); cached = (cache->cached != NULL); - - /* Location and LocationMatch differ on their behaviour w.r.t. multiple - * slashes. Location matches multiple slashes with a single slash, - * LocationMatch doesn't. An exception, for backwards brokenness is - * absoluteURIs... in which case neither match multiple slashes. - */ - if (r->uri[0] != '/') { - entry_uri = r->uri; - } - else { - char *uri = apr_pstrdup(r->pool, r->uri); - ap_no2slash(uri); - entry_uri = uri; - } + entry_uri = r->uri; /* If we have an cache->cached location that matches r->uri, * and the vhost's list of locations hasn't changed, we can skip @@ -1495,7 +1488,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); } - if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) { + if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) { continue; } @@ -1505,7 +1498,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) apr_table_setn(r->subprocess_env, ((const char **)entry_core->refs->elts)[i], apr_pstrndup(r->pool, - r->uri + pmatch[i].rm_so, + entry_uri + pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so)); } } diff --git a/server/util.c b/server/util.c index 3693bfbff15..89c5abef80b 100644 --- a/server/util.c +++ b/server/util.c @@ -568,16 +568,16 @@ AP_DECLARE(void) ap_getparents(char *name) name[l] = '\0'; } } - -AP_DECLARE(void) ap_no2slash(char *name) +AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path) { + char *d, *s; s = d = name; #ifdef HAVE_UNC_PATHS /* Check for UNC names. Leave leading two slashes. */ - if (s[0] == '/' && s[1] == '/') + if (is_fs_path && s[0] == '/' && s[1] == '/') *d++ = *s++; #endif @@ -594,6 +594,10 @@ AP_DECLARE(void) ap_no2slash(char *name) *d = '\0'; } +AP_DECLARE(void) ap_no2slash(char *name) +{ + ap_no2slash_ex(name, 1); +} /* * copy at most n leading directories of s into d