1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
From 9bc1917a27a2323e535aadb081e38172ae0e3fc2 Mon Sep 17 00:00:00 2001
From: Stefan Eissing <icing@apache.org>
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.</p>
# <seealso><directive module="mod_allowmethods">AllowMethods</directive></seealso>
# </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>
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
|