summaryrefslogtreecommitdiffstats
path: root/server/request.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/request.c')
-rw-r--r--server/request.c149
1 files changed, 105 insertions, 44 deletions
diff --git a/server/request.c b/server/request.c
index dbe3e07..5599b2c 100644
--- a/server/request.c
+++ b/server/request.c
@@ -59,6 +59,7 @@
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
APR_HOOK_STRUCT(
+ APR_HOOK_LINK(pre_translate_name)
APR_HOOK_LINK(translate_name)
APR_HOOK_LINK(map_to_storage)
APR_HOOK_LINK(check_user_id)
@@ -74,6 +75,8 @@ APR_HOOK_STRUCT(
APR_HOOK_LINK(force_authn)
)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int,pre_translate_name,
+ (request_rec *r), (r), DECLINED)
AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
(request_rec *r), (r), DECLINED)
AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
@@ -157,6 +160,25 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r)
return rv;
}
+static int walk_location_and_if(request_rec *r)
+{
+ int access_status;
+ core_dir_config *d;
+
+ if ((access_status = ap_location_walk(r))) {
+ return access_status;
+ }
+ if ((access_status = ap_if_walk(r))) {
+ return access_status;
+ }
+
+ d = ap_get_core_module_config(r->per_dir_config);
+ if (d->log)
+ r->log = d->log;
+
+ return OK;
+}
+
/* This is the master logic for processing requests. Do NOT duplicate
* this logic elsewhere, or the security model will be broken by future
* API changes. Each phase must be individually optimized to pick up
@@ -164,51 +186,95 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r)
*/
AP_DECLARE(int) ap_process_request_internal(request_rec *r)
{
+ int access_status = DECLINED;
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);
+ unsigned int normalize_flags;
+
+ normalize_flags = AP_NORMALIZE_NOT_ABOVE_ROOT;
+ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) {
+ normalize_flags |= AP_NORMALIZE_MERGE_SLASHES;
+ }
+ if (file_req) {
+ /* File subrequests can have a relative path. */
+ normalize_flags |= AP_NORMALIZE_ALLOW_RELATIVE;
+ }
- /* Ignore embedded %2F's in path for proxy requests */
- if (!r->proxyreq && r->parsed_uri.path) {
- d = ap_get_core_module_config(r->per_dir_config);
- if (d->allow_encoded_slashes) {
- access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes);
+ if (r->parsed_uri.path) {
+ /* Normalize: remove /./ and shrink /../ segments, plus
+ * decode unreserved chars (first time only to avoid
+ * double decoding after ap_unescape_url() below).
+ */
+ if (!ap_normalize_path(r->parsed_uri.path,
+ normalize_flags |
+ AP_NORMALIZE_DECODE_UNRESERVED)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10244)
+ "invalid URI path (%s)", r->unparsed_uri);
+ return HTTP_BAD_REQUEST;
}
- else {
- access_status = ap_unescape_url(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,
+ * otherwise let (pre_)translate_name kill the request.
+ */
+ if (!file_req) {
+ ap_conf_vector_t *per_dir_config = r->per_dir_config;
+
+ if ((access_status = walk_location_and_if(r))) {
+ return access_status;
+ }
+
+ /* Let pre_translate_name hooks work with non-decoded URIs, and
+ * eventually prevent further URI transformations (return DONE).
+ */
+ access_status = ap_run_pre_translate_name(r);
+ if (ap_is_HTTP_ERROR(access_status)) {
+ return access_status;
+ }
+
+ /* Throw away pre_trans only merging */
+ r->per_dir_config = per_dir_config;
+ }
+
+ /* Ignore URL unescaping for translated URIs already */
+ if (access_status != DONE && r->parsed_uri.path) {
+ core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
+ /* Unreserved chars were already decoded by ap_normalize_path() */
+ unsigned int unescape_flags = AP_UNESCAPE_URL_KEEP_UNRESERVED;
+ if (!d->allow_encoded_slashes) {
+ unescape_flags |= AP_UNESCAPE_URL_FORBID_SLASHES;
+ }
+ else if (!d->decode_encoded_slashes) {
+ unescape_flags |= AP_UNESCAPE_URL_KEEP_SLASHES;
}
+ access_status = ap_unescape_url_ex(r->parsed_uri.path, unescape_flags);
if (access_status) {
if (access_status == HTTP_NOT_FOUND) {
if (! d->allow_encoded_slashes) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026)
- "found %%2f (encoded '/') in URI "
- "(decoded='%s'), returning 404",
- r->parsed_uri.path);
+ "found %%2f (encoded '/') in URI path (%s), "
+ "returning 404", r->unparsed_uri);
}
}
return access_status;
}
- }
- ap_getparents(r->uri); /* OK --- shrinking transformations... */
+ if (d->allow_encoded_slashes && d->decode_encoded_slashes) {
+ /* Decoding slashes might have created new // or /./ or /../
+ * segments (e.g. "/.%2F/"), so re-normalize.
+ */
+ ap_normalize_path(r->parsed_uri.path, normalize_flags);
+ }
+ }
- /* All file subrequests are a huge pain... they cannot bubble through the
- * next several steps. Only file subrequests are allowed an empty uri,
- * otherwise let translate_name kill the request.
- */
+ /* Same, translate_name is not suited for file subrequests */
if (!file_req) {
- if ((access_status = ap_location_walk(r))) {
- return access_status;
- }
- if ((access_status = ap_if_walk(r))) {
+ if ((access_status = walk_location_and_if(r))) {
return access_status;
}
- d = ap_get_core_module_config(r->per_dir_config);
- if (d->log) {
- r->log = d->log;
- }
-
if ((access_status = ap_run_translate_name(r))) {
return decl_die(access_status, "translate", r);
}
@@ -225,17 +291,9 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r)
/* Rerun the location walk, which overrides any map_to_storage config.
*/
- if ((access_status = ap_location_walk(r))) {
+ if ((access_status = walk_location_and_if(r))) {
return access_status;
}
- if ((access_status = ap_if_walk(r))) {
- return access_status;
- }
-
- d = ap_get_core_module_config(r->per_dir_config);
- if (d->log) {
- r->log = d->log;
- }
if ((access_status = ap_run_post_perdir_config(r))) {
return access_status;
@@ -1256,6 +1314,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
if (entry_core->refs && entry_core->refs->nelts) {
if (!rxpool) {
apr_pool_create(&rxpool, r->pool);
+ apr_pool_tag(rxpool, "directory_walk_rxpool");
}
nmatch = entry_core->refs->nelts;
pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
@@ -1361,7 +1420,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
r->canonical_filename = r->filename;
if (r->finfo.filetype == APR_DIR) {
- cache->cached = r->filename;
+ cache->cached = apr_pstrdup(r->pool, r->filename);
}
else {
cache->cached = ap_make_dirstr_parent(r->pool, r->filename);
@@ -1412,12 +1471,12 @@ 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] != '/') {
+ /*
+ * When merge_slashes is set to AP_CORE_CONFIG_OFF the slashes in r->uri
+ * have not been merged. But for Location walks we always go with merged
+ * slashes no matter what merge_slashes is set to.
+ */
+ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) {
entry_uri = r->uri;
}
else {
@@ -1458,7 +1517,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
apr_pool_t *rxpool = NULL;
cached &= auth_internal_per_conf;
- cache->cached = entry_uri;
+ cache->cached = apr_pstrdup(r->pool, entry_uri);
/* Go through the location entries, and check for matches.
* We apply the directive sections in given order, we should
@@ -1486,6 +1545,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
if (entry_core->refs && entry_core->refs->nelts) {
if (!rxpool) {
apr_pool_create(&rxpool, r->pool);
+ apr_pool_tag(rxpool, "location_walk_rxpool");
}
nmatch = entry_core->refs->nelts;
pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
@@ -1688,6 +1748,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
if (entry_core->refs && entry_core->refs->nelts) {
if (!rxpool) {
apr_pool_create(&rxpool, r->pool);
+ apr_pool_tag(rxpool, "file_walk_rxpool");
}
nmatch = entry_core->refs->nelts;
pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));