]> granicus.if.org Git - apache/commitdiff
Clean up location_walk, so that this step performs a minimum
authorWilliam A. Rowe Jr <wrowe@apache.org>
Mon, 27 Aug 2001 04:29:09 +0000 (04:29 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Mon, 27 Aug 2001 04:29:09 +0000 (04:29 +0000)
  amount of redundant effort (it must be run twice, but it will no
  longer reparse all <Location > 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 <Location > 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
server/request.c

diff --git a/CHANGES b/CHANGES
index 54717adddfff5ef8773b3a516b0bdba01b22be07..55f29a7d2becb88ee05507aa874250d13a6269d3 100644 (file)
--- 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 <Location > 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,
index 5fe486f0296f49d1f108166f7624bea6b8b7a26b..f59ccde311e3e6c37e3d0baab3488dabc150bd83 100644 (file)
@@ -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 <Locations > 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 <Location > 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;
 }