From 9bc1917a27a2323e535aadb081e38172ae0e3fc2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 18 Mar 2019 08:49:59 +0000 Subject: [PATCH] Merge of r1855705 from trunk: core: merge consecutive slashes in the path git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1855737 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 ++++ docs/manual/mod/core.xml | 26 ++++++++++++++++++++++++++ include/ap_mmn.h | 4 +++- include/http_core.h | 2 +- include/httpd.h | 14 ++++++++++++-- server/core.c | 13 +++++++++++++ server/request.c | 25 +++++++++---------------- server/util.c | 10 +++++++--- 8 files changed, 75 insertions(+), 23 deletions(-) #diff --git a/CHANGES b/CHANGES #index e3e8a98db24..9dd7045c232 100644 #--- a/CHANGES #+++ b/CHANGES #@@ -1,6 +1,10 @@ # -*- coding: utf-8 -*- # Changes with Apache 2.4.39 # #+ *) core: new configuration option 'MergeSlashes on|off' that controls handling of #+ multiple, consecutive slash ('/') characters in the path component of the request URL. #+ [Eric Covener] #+ # *) mod_http2: when SSL renegotiation is inhibited and a 403 ErrorDocument is # in play, the proper HTTP/2 stream reset did not trigger with H2_ERR_HTTP_1_1_REQUIRED. # Fixed. [Michael Kaufmann] #diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml #index fc664116727..460b4367621 100644 #--- a/docs/manual/mod/core.xml #+++ b/docs/manual/mod/core.xml #@@ -5138,4 +5138,30 @@ recognized methods to modules.

# AllowMethods # # #+ #+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 2167baa0325..4739f7f64d3 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -523,6 +523,8 @@ * 20120211.82 (2.4.35-dev) Add optional function declaration for * ap_proxy_balancer_get_best_worker to mod_proxy.h. * 20120211.83 (2.4.35-dev) Add client64 field to worker_score struct + * 20120211.84 (2.4.35-dev) Add ap_no2slash_ex() and merge_slashes to + * core_server_conf. * */ @@ -531,7 +533,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 83 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 84 /* 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 35df5dc9601..8e109882244 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -740,7 +740,7 @@ typedef struct { #define AP_HTTP_METHODS_LENIENT 1 #define AP_HTTP_METHODS_REGISTERED 2 char http_methods; - + unsigned int merge_slashes; } core_server_config; /* for AddOutputFiltersByType in core.c */ diff --git a/include/httpd.h b/include/httpd.h index 65392f83546..99f7f041aea 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1697,11 +1697,21 @@ 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); +/** + * 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); + /** * Remove all ./ and xx/../ substrings from a file name. Also remove * any leading ../ or /../ substrings. diff --git a/server/core.c b/server/core.c index e2a91c7a0c6..eacb54fecec 100644 --- a/server/core.c +++ b/server/core.c @@ -490,6 +490,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) conf->protocols = apr_array_make(a, 5, sizeof(const char *)); conf->protocols_honor_order = -1; + conf->merge_slashes = AP_CORE_CONFIG_UNSET; return (void *)conf; } @@ -555,6 +556,7 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) conf->protocols_honor_order = ((virt->protocols_honor_order < 0)? base->protocols_honor_order : virt->protocols_honor_order); + AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt); return conf; } @@ -1863,6 +1865,13 @@ static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag) return NULL; } +static const char *set_core_server_flag(cmd_parms *cmd, void *s_, int flag) +{ + core_server_config *conf = + ap_get_core_module_config(cmd->server->module_config); + return ap_set_flag_slot(cmd, conf, flag); +} + static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[]) { core_dir_config *d = d_; @@ -4562,6 +4571,10 @@ AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CON "'Unsafe' or 'Strict' (default). Sets HTTP acceptance rules"), AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF, "Registers non-standard HTTP methods"), +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 dbe3e07f150..1ce8908824b 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, @@ -1411,20 +1417,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 @@ -1491,7 +1484,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; } @@ -1501,7 +1494,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 fd7a0a14763..607c4850d86 100644 --- a/server/util.c +++ b/server/util.c @@ -561,16 +561,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 @@ -587,6 +587,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