|
|
41a6c3 |
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
|
|
|
41a6c3 |
index 86d9bee..e08034b 100644
|
|
|
41a6c3 |
--- a/docs/manual/mod/core.html.en
|
|
|
41a6c3 |
+++ b/docs/manual/mod/core.html.en
|
|
|
41a6c3 |
@@ -90,6 +90,7 @@ available
|
|
|
41a6c3 |
MaxRangeOverlaps
|
|
|
41a6c3 |
MaxRangeReversals
|
|
|
41a6c3 |
MaxRanges
|
|
|
41a6c3 |
+ MergeSlashes
|
|
|
41a6c3 |
Mutex
|
|
|
41a6c3 |
NameVirtualHost
|
|
|
41a6c3 |
Options
|
|
|
41a6c3 |
@@ -3170,6 +3171,30 @@ resource
|
|
|
41a6c3 |
|
|
|
41a6c3 |
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+Description:Controls whether the server merges consecutive slashes in URLs.
|
|
|
41a6c3 |
+Syntax:MergeSlashes ON | OFF
|
|
|
41a6c3 |
+Default:MergeSlashes ON
|
|
|
41a6c3 |
+Context:server config, virtual host
|
|
|
41a6c3 |
+Status:Core
|
|
|
41a6c3 |
+Module:core
|
|
|
41a6c3 |
+Compatibility:Available in Apache HTTP Server 2.4.6 in Red Hat Enterprise Linux 7
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+ By default, the server merges (or collapses) multiple consecutive slash
|
|
|
41a6c3 |
+ ('/') characters in the path component of the request URL.
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+ When mapping URL's to the filesystem, these multiple slashes are not
|
|
|
41a6c3 |
+ significant. However, URL's handled other ways, such as by CGI or proxy,
|
|
|
41a6c3 |
+ might prefer to retain the significance of multiple consecutive slashes.
|
|
|
41a6c3 |
+ In these cases MergeSlashes can be set to
|
|
|
41a6c3 |
+ OFF to retain the multiple consecutive slashes. In these
|
|
|
41a6c3 |
+ configurations, regular expressions used in the configuration file that match
|
|
|
41a6c3 |
+ the path component of the URL (LocationMatch ,
|
|
|
41a6c3 |
+ RewriteRule , ...) need to take into account multiple
|
|
|
41a6c3 |
+ consecutive slashes.
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
|
|
|
41a6c3 |
|
|
|
41a6c3 |
Description:Configures mutex mechanism and lock file directory for all
|
|
|
41a6c3 |
diff --git a/include/http_core.h b/include/http_core.h
|
|
|
41a6c3 |
index c05d06e..76bf5a4 100644
|
|
|
41a6c3 |
--- a/include/http_core.h
|
|
|
41a6c3 |
+++ b/include/http_core.h
|
|
|
41a6c3 |
@@ -465,6 +465,17 @@ typedef unsigned long etag_components_t;
|
|
|
41a6c3 |
/* This is the default value used */
|
|
|
41a6c3 |
#define ETAG_BACKWARD (ETAG_MTIME | ETAG_SIZE)
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+/* Generic ON/OFF/UNSET for unsigned int foo :2 */
|
|
|
41a6c3 |
+#define AP_CORE_CONFIG_OFF (0)
|
|
|
41a6c3 |
+#define AP_CORE_CONFIG_ON (1)
|
|
|
41a6c3 |
+#define AP_CORE_CONFIG_UNSET (2)
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
+/* Generic merge of flag */
|
|
|
41a6c3 |
+#define AP_CORE_MERGE_FLAG(field, to, base, over) to->field = \
|
|
|
41a6c3 |
+ over->field != AP_CORE_CONFIG_UNSET \
|
|
|
41a6c3 |
+ ? over->field \
|
|
|
41a6c3 |
+ : base->field
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
/**
|
|
|
41a6c3 |
* @brief Server Signature Enumeration
|
|
|
41a6c3 |
*/
|
|
|
41a6c3 |
@@ -682,7 +693,7 @@ typedef struct {
|
|
|
41a6c3 |
#define AP_HTTP_METHODS_LENIENT 1
|
|
|
41a6c3 |
#define AP_HTTP_METHODS_REGISTERED 2
|
|
|
41a6c3 |
char http_methods;
|
|
|
41a6c3 |
-
|
|
|
41a6c3 |
+ unsigned int merge_slashes;
|
|
|
41a6c3 |
} core_server_config;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/* for AddOutputFiltersByType in core.c */
|
|
|
41a6c3 |
diff --git a/include/httpd.h b/include/httpd.h
|
|
|
41a6c3 |
index 176ef5e..a552358 100644
|
|
|
41a6c3 |
--- a/include/httpd.h
|
|
|
41a6c3 |
+++ b/include/httpd.h
|
|
|
41a6c3 |
@@ -1622,11 +1622,21 @@ AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes);
|
|
|
41a6c3 |
AP_DECLARE(int) ap_unescape_urlencoded(char *query);
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/**
|
|
|
41a6c3 |
- * Convert all double slashes to single slashes
|
|
|
41a6c3 |
- * @param name The string to convert
|
|
|
41a6c3 |
+ * Convert all double slashes to single slashes, except where significant
|
|
|
41a6c3 |
+ * to the filesystem on the current platform.
|
|
|
41a6c3 |
+ * @param name The string to convert, assumed to be a filesystem path
|
|
|
41a6c3 |
*/
|
|
|
41a6c3 |
AP_DECLARE(void) ap_no2slash(char *name);
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+/**
|
|
|
41a6c3 |
+ * Convert all double slashes to single slashes, except where significant
|
|
|
41a6c3 |
+ * to the filesystem on the current platform.
|
|
|
41a6c3 |
+ * @param name The string to convert
|
|
|
41a6c3 |
+ * @param is_fs_path if set to 0, the significance of any double-slashes is
|
|
|
41a6c3 |
+ * ignored.
|
|
|
41a6c3 |
+ */
|
|
|
41a6c3 |
+AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path);
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
/**
|
|
|
41a6c3 |
* Remove all ./ and xx/../ substrings from a file name. Also remove
|
|
|
41a6c3 |
* any leading ../ or /../ substrings.
|
|
|
41a6c3 |
diff --git a/server/core.c b/server/core.c
|
|
|
41a6c3 |
index 0e69f8c..67efd7e 100644
|
|
|
41a6c3 |
--- a/server/core.c
|
|
|
41a6c3 |
+++ b/server/core.c
|
|
|
41a6c3 |
@@ -476,6 +476,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s)
|
|
|
41a6c3 |
*/
|
|
|
41a6c3 |
|
|
|
41a6c3 |
conf->trace_enable = AP_TRACE_UNSET;
|
|
|
41a6c3 |
+ conf->merge_slashes = AP_CORE_CONFIG_UNSET;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
return (void *)conf;
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
@@ -536,6 +537,8 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv)
|
|
|
41a6c3 |
? virt->merge_trailers
|
|
|
41a6c3 |
: base->merge_trailers;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+ AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt);
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
return conf;
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
|
|
|
41a6c3 |
@@ -1673,6 +1676,13 @@ static const char *set_override(cmd_parms *cmd, void *d_, const char *l)
|
|
|
41a6c3 |
return NULL;
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+static const char *set_core_server_flag(cmd_parms *cmd, void *s_, int flag)
|
|
|
41a6c3 |
+{
|
|
|
41a6c3 |
+ core_server_config *conf =
|
|
|
41a6c3 |
+ ap_get_core_module_config(cmd->server->module_config);
|
|
|
41a6c3 |
+ return ap_set_flag_slot(cmd, conf, flag);
|
|
|
41a6c3 |
+}
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[])
|
|
|
41a6c3 |
{
|
|
|
41a6c3 |
core_dir_config *d = d_;
|
|
|
41a6c3 |
@@ -4216,6 +4226,10 @@ AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CON
|
|
|
41a6c3 |
,
|
|
|
41a6c3 |
AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
|
|
|
41a6c3 |
"Registers non-standard HTTP methods"),
|
|
|
41a6c3 |
+AP_INIT_FLAG("MergeSlashes", set_core_server_flag,
|
|
|
41a6c3 |
+ (void *)APR_OFFSETOF(core_server_config, merge_slashes),
|
|
|
41a6c3 |
+ RSRC_CONF,
|
|
|
41a6c3 |
+ "Controls whether consecutive slashes in the URI path are merged"),
|
|
|
41a6c3 |
{ NULL }
|
|
|
41a6c3 |
};
|
|
|
41a6c3 |
|
|
|
41a6c3 |
diff --git a/server/request.c b/server/request.c
|
|
|
41a6c3 |
index 4eef097..cba3891 100644
|
|
|
41a6c3 |
--- a/server/request.c
|
|
|
41a6c3 |
+++ b/server/request.c
|
|
|
41a6c3 |
@@ -167,6 +167,8 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r)
|
|
|
41a6c3 |
int file_req = (r->main && r->filename);
|
|
|
41a6c3 |
int access_status;
|
|
|
41a6c3 |
core_dir_config *d;
|
|
|
41a6c3 |
+ core_server_config *sconf =
|
|
|
41a6c3 |
+ ap_get_core_module_config(r->server->module_config);
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/* Ignore embedded %2F's in path for proxy requests */
|
|
|
41a6c3 |
if (!r->proxyreq && r->parsed_uri.path) {
|
|
|
41a6c3 |
@@ -191,6 +193,12 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r)
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
|
|
|
41a6c3 |
ap_getparents(r->uri); /* OK --- shrinking transformations... */
|
|
|
41a6c3 |
+ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) {
|
|
|
41a6c3 |
+ ap_no2slash(r->uri);
|
|
|
41a6c3 |
+ if (r->parsed_uri.path) {
|
|
|
41a6c3 |
+ ap_no2slash(r->parsed_uri.path);
|
|
|
41a6c3 |
+ }
|
|
|
41a6c3 |
+ }
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/* All file subrequests are a huge pain... they cannot bubble through the
|
|
|
41a6c3 |
* next several steps. Only file subrequests are allowed an empty uri,
|
|
|
41a6c3 |
@@ -1383,20 +1391,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
|
|
41a6c3 |
|
|
|
41a6c3 |
cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r);
|
|
|
41a6c3 |
cached = (cache->cached != NULL);
|
|
|
41a6c3 |
-
|
|
|
41a6c3 |
- /* Location and LocationMatch differ on their behaviour w.r.t. multiple
|
|
|
41a6c3 |
- * slashes. Location matches multiple slashes with a single slash,
|
|
|
41a6c3 |
- * LocationMatch doesn't. An exception, for backwards brokenness is
|
|
|
41a6c3 |
- * absoluteURIs... in which case neither match multiple slashes.
|
|
|
41a6c3 |
- */
|
|
|
41a6c3 |
- if (r->uri[0] != '/') {
|
|
|
41a6c3 |
- entry_uri = r->uri;
|
|
|
41a6c3 |
- }
|
|
|
41a6c3 |
- else {
|
|
|
41a6c3 |
- char *uri = apr_pstrdup(r->pool, r->uri);
|
|
|
41a6c3 |
- ap_no2slash(uri);
|
|
|
41a6c3 |
- entry_uri = uri;
|
|
|
41a6c3 |
- }
|
|
|
41a6c3 |
+ entry_uri = r->uri;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/* If we have an cache->cached location that matches r->uri,
|
|
|
41a6c3 |
* and the vhost's list of locations hasn't changed, we can skip
|
|
|
41a6c3 |
@@ -1449,7 +1444,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
|
|
|
41a6c3 |
* terminated (or at the end of the string) to match.
|
|
|
41a6c3 |
*/
|
|
|
41a6c3 |
if (entry_core->r
|
|
|
41a6c3 |
- ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0)
|
|
|
41a6c3 |
+ ? ap_regexec(entry_core->r, entry_uri, 0, NULL, 0)
|
|
|
41a6c3 |
: (entry_core->d_is_fnmatch
|
|
|
41a6c3 |
? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
|
|
|
41a6c3 |
: (strncmp(entry_core->d, cache->cached, len)
|
|
|
41a6c3 |
diff --git a/server/util.c b/server/util.c
|
|
|
41a6c3 |
index f9e3b51..4eac462 100644
|
|
|
41a6c3 |
--- a/server/util.c
|
|
|
41a6c3 |
+++ b/server/util.c
|
|
|
41a6c3 |
@@ -561,16 +561,20 @@ AP_DECLARE(void) ap_getparents(char *name)
|
|
|
41a6c3 |
name[l] = '\0';
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
-
|
|
|
41a6c3 |
-AP_DECLARE(void) ap_no2slash(char *name)
|
|
|
41a6c3 |
+AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
|
|
|
41a6c3 |
{
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
char *d, *s;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+ if (!*name) {
|
|
|
41a6c3 |
+ return;
|
|
|
41a6c3 |
+ }
|
|
|
41a6c3 |
+
|
|
|
41a6c3 |
s = d = name;
|
|
|
41a6c3 |
|
|
|
41a6c3 |
#ifdef HAVE_UNC_PATHS
|
|
|
41a6c3 |
/* Check for UNC names. Leave leading two slashes. */
|
|
|
41a6c3 |
- if (s[0] == '/' && s[1] == '/')
|
|
|
41a6c3 |
+ if (is_fs_path && s[0] == '/' && s[1] == '/')
|
|
|
41a6c3 |
*d++ = *s++;
|
|
|
41a6c3 |
#endif
|
|
|
41a6c3 |
|
|
|
41a6c3 |
@@ -587,6 +591,10 @@ AP_DECLARE(void) ap_no2slash(char *name)
|
|
|
41a6c3 |
*d = '\0';
|
|
|
41a6c3 |
}
|
|
|
41a6c3 |
|
|
|
41a6c3 |
+AP_DECLARE(void) ap_no2slash(char *name)
|
|
|
41a6c3 |
+{
|
|
|
41a6c3 |
+ ap_no2slash_ex(name, 1);
|
|
|
41a6c3 |
+}
|
|
|
41a6c3 |
|
|
|
41a6c3 |
/*
|
|
|
41a6c3 |
* copy at most n leading directories of s into d
|