]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge consecutive slashes in the URL by default
authorEric Covener <covener@apache.org>
Sun, 17 Mar 2019 14:41:10 +0000 (14:41 +0000)
committerEric Covener <covener@apache.org>
Sun, 17 Mar 2019 14:41:10 +0000 (14:41 +0000)
opt-out w/ `MergeSlashes OFF`.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1855705 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/manual/mod/core.xml
include/ap_mmn.h
include/http_core.h
include/httpd.h
server/core.c
server/request.c
server/util.c

diff --git a/CHANGES b/CHANGES
index afcb891e19ebd70cbaa05f031bf09f5831e6bdf3..57f0e9e65658d200112a79f90d4392f9c8fdd335 100644 (file)
--- 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 <Location> or <Proxy> context. PR 63256. [Yann Ylavic]
index f1516a35175ecd1e6eec1ee9bdf068733402291a..ac428dfe4ba97c26cfe74897259428c2287dd79a 100644 (file)
@@ -5332,4 +5332,30 @@ as if 'QualifyRedirectURL ON' was configured.</compatibility>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>MergeSlashes</name>
+<description>Controls whether the server merges consecutive slashes in URLs.
+</description>
+<syntax>MergeSlashes ON|OFF</syntax>
+<default>MergeSlashes ON</default>
+<contextlist><context>server config</context><context>virtual host</context>
+</contextlist>
+<compatibility>Added in 2.5.1</compatibility>
+
+<usage>
+    <p>By default, the server merges (or collapses) multiple consecutive slash
+    ('/') characters in the path component of the request URL.</p>
+
+    <p>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 <directive>MergeSlashes</directive> can be set to 
+    <em>OFF</em> to retain the multiple consecutive slashes.  In these
+    configurations, regular expressions used in the configuration file that match
+    the path component of the URL (<directive>LocationMatch</directive>,
+    <directive>RewriteRule</directive>, ...) need to take into account multiple 
+    consecutive slashes.</p>
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index 7d400b3db630755f56af198b6116beb57d10b660..5a479c075e6263c22f2886c6c4d3168e04b339b9 100644 (file)
  * 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" */
 #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
index fe3836fb344325b458958d76fe24eba6d4a98b1f..00aeaa7800e04d8559ef99cc67d38382e1ea6126 100644 (file)
@@ -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 */
index 0005e0cf8a27bd0a1636d554f430672c928cd6a7..1c6a242a89210e767ea832d052e53646989ee461 100644 (file)
@@ -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
index 98197d85e9c74acba19dbf7b7e7c17cc366a49cb..ceb7dd6bb81365f2b6737dde7031a2c72d3fb21d 100644 (file)
@@ -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 }
 };
 
index 70812fed59481137d951339ef74760a27308d7eb..052e20b3dd5847ba71334a59b5aab25ade87e3de 100644 (file)
@@ -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));
                     }
                 }
index 3693bfbff1535448e1820d221afb0ce2e1cc60fd..89c5abef80b2cdb7f222eaa325bd04e3adb7893b 100644 (file)
@@ -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