From 7d55e44913e25cd5545052a9ca36dc308854359e Mon Sep 17 00:00:00 2001 From: "William A. Rowe Jr" Date: Mon, 27 Aug 2001 04:29:09 +0000 Subject: [PATCH] Clean up location_walk, so that this step performs a minimum amount of redundant effort (it must be run twice, but it will no longer reparse all blocks when the request uri hadn't changed.) The location walk block is refactored, with some significant changes in variable names for legibility. Cooler still, it uses pool data instead of 'notes' for the important cache info :) Note the patch builds the per dir config from _nothing_, and then merges it into the per_dir_config. When the underlying per_dir_config changes between passes, the location_walk can simply tack back on this preconstruct onto the new per_dir_config. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90713 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 ++ server/request.c | 137 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 98 insertions(+), 44 deletions(-) diff --git a/CHANGES b/CHANGES index 54717adddf..55f29a7d2b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ Changes with Apache 2.0.25-dev + *) Clean up location_walk, so that this step performs a minimum + amount of redundant effort (it must be run twice, but it will no + longer reparse all blocks when the request uri + hadn't changed.) [William Rowe] + *) Eliminate proxy: (and all other 'special') processing from the ap_directory_walk() phase. Modules that want to use special walk logic should refer to the mod_proxy map_to_location example, diff --git a/server/request.c b/server/request.c index 5fe486f029..f59ccde311 100644 --- a/server/request.c +++ b/server/request.c @@ -963,68 +963,117 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) core_server_config *sconf = ap_get_module_config(r->server->module_config, &core_module); ap_conf_vector_t *per_dir_defaults = r->per_dir_config; - ap_conf_vector_t **url = (ap_conf_vector_t **) sconf->sec_url->elts; - int len, num_url = sconf->sec_url->nelts; + ap_conf_vector_t *per_uri_defaults = NULL; + ap_conf_vector_t **locations = (ap_conf_vector_t **) sconf->sec_url->elts; + ap_conf_vector_t **loc_done = NULL; + int len, num_loc = sconf->sec_url->nelts; char *test_location; ap_conf_vector_t *this_conf; ap_conf_vector_t *entry_config; core_dir_config *entry_core; - char *entry_url; + char *entry_uri; int j; - if (!num_url) { + /* No tricks here, there are no to parse in this vhost + */ + if (!num_loc) { + apr_pool_userdata_set(NULL, "ap_location_walk::dir_conf", + apr_pool_cleanup_null, r->pool); + apr_pool_userdata_set(NULL, "ap_location_walk::loc_done", + apr_pool_cleanup_null, r->pool); + apr_pool_userdata_set(NULL, "ap_location_walk::last_uri", + apr_pool_cleanup_null, r->pool); return OK; } - /* 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. + apr_pool_userdata_get(&entry_uri, "ap_location_walk::last_uri", r->pool); + apr_pool_userdata_get(&(void*)loc_done, "ap_location_walk::loc_done", r->pool); + + /* If we have an ap_location_walk::last_uri that matches r->uri, + * and the vhost's list of locations hasn't changed, + * we will go through the location_walk entries. */ - if (r->uri[0] != '/') { - test_location = r->uri; - } - else { - test_location = apr_pstrdup(r->pool, r->uri); - ap_no2slash(test_location); - } + if (!entry_uri || (loc_done != locations) + || (strcmp(r->uri, entry_uri) != 0)) + { + /* 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] != '/') { + test_location = r->uri; + } + else { + test_location = apr_pstrdup(r->pool, r->uri); + ap_no2slash(test_location); + } - /* Go through the location entries, and check for matches. */ + /* Go through the location entries, and check for matches. */ - /* we apply the directive sections in some order; - * should really try them with the most general first. - */ - for (j = 0; j < num_url; ++j) { + /* we apply the directive sections in some order; + * should really try them with the most general first. + */ + for (j = 0; j < num_loc; ++j) { - entry_config = url[j]; + entry_config = locations[j]; - entry_core = ap_get_module_config(entry_config, &core_module); - entry_url = entry_core->d; + entry_core = ap_get_module_config(entry_config, &core_module); + entry_uri = entry_core->d; - len = strlen(entry_url); + len = strlen(entry_uri); - this_conf = NULL; + this_conf = NULL; + + /* Test the regex, fnmatch or string as appropriate. + * If it's a strcmp, and the pattern was + * not slash terminated, then this uri must be slash + * terminated (or at the end of the string) to match. + */ + if (entry_core->r + ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0) + : (entry_core->d_is_fnmatch + ? apr_fnmatch(entry_uri, test_location, FNM_PATHNAME) + : (strncmp(test_location, entry_uri, len) + || (entry_uri[len - 1] != '/' + && test_location[len] != '/' + && test_location[len] != '\0')))) { + continue; + } - if (entry_core->r) { - if (!ap_regexec(entry_core->r, r->uri, 0, NULL, 0)) - this_conf = entry_config; - } - else if (entry_core->d_is_fnmatch) { - if (!apr_fnmatch(entry_url, test_location, FNM_PATHNAME)) { - this_conf = entry_config; - } - } - else if (!strncmp(test_location, entry_url, len) && - (entry_url[len - 1] == '/' || - test_location[len] == '/' || test_location[len] == '\0')) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - this_conf); + if (per_uri_defaults) + per_uri_defaults = ap_merge_per_dir_configs(r->pool, + per_uri_defaults, + entry_config); + else + per_uri_defaults = entry_config; + } + + /* Set aside this walk result, in case we end up back here with + * the same uri again. + */ + apr_pool_userdata_set(per_uri_defaults, "ap_location_walk::dir_conf", + apr_pool_cleanup_null, r->pool); + apr_pool_userdata_set(locations, "ap_location_walk::loc_done", + apr_pool_cleanup_null, r->pool); + apr_pool_userdata_set(r->uri, "ap_location_walk::last_uri", + apr_pool_cleanup_null, r->pool); } - r->per_dir_config = per_dir_defaults; + else { + /* Well this looks familiar! Get back our per_uri_defaults + * from the last location walk. + */ + apr_pool_userdata_get(&per_uri_defaults, "ap_location_walk::dir_conf", + r->pool); + } + + /* We might be able to optimize further, if r->per_dir_config never changed. + * In any case, merge our per_uri_defaults onto + */ + if (per_uri_defaults) + r->per_dir_config = ap_merge_per_dir_configs(r->pool, + r->per_dir_config, + per_uri_defaults); return OK; } -- 2.40.0