You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Justin Erenkrantz <ju...@erenkrantz.com> on 2004/08/01 19:29:11 UTC

[PATCH] mod_cache fixes: #4

--On Sunday, August 1, 2004 11:25 AM -0400 Bill Stoddard <bi...@wstoddard.com> 
wrote:

> Too many changes in one patch. Break this up into multiple consumable in 15
> minute patches and I'll review them.

(This is probably the largest and most complicated one.  At the bottom, I've 
also pasted the current quick_handler function as I have it in my tree.)

* modules/experimental/mod_cache.c: Rewrite quick_handler.

Index: modules/experimental/mod_cache.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/experimental/mod_cache.c,v
retrieving revision 1.83
diff -u -r1.83 mod_cache.c
--- modules/experimental/mod_cache.c	25 May 2004 18:01:02 -0000	1.83
+++ modules/experimental/mod_cache.c	1 Aug 2004 08:24:52 -0000
@@ -48,24 +48,30 @@
 static int cache_url_handler(request_rec *r, int lookup)
 {
     apr_status_t rv;
-    const char *cc_in, *pragma, *auth;
-    apr_uri_t uri = r->parsed_uri;
-    char *url = r->unparsed_uri;
+    const char *pragma, *auth;
+    apr_uri_t uri;
+    char *url;
     apr_size_t urllen;
-    char *path = uri.path;
+    char *path;
     const char *types;
-    cache_info *info = NULL;
+    cache_info *info;
     cache_request_rec *cache;
     cache_server_conf *conf;
+    apr_bucket_brigade *out;

-    conf = (cache_server_conf *) 
ap_get_module_config(r->server->module_config,
-                                                      &cache_module);
-
-    /* we don't handle anything but GET */
+    /* Delay initialization until we know we are handling a GET */
     if (r->method_number != M_GET) {
         return DECLINED;
     }

+    uri = r->parsed_uri;
+    url = r->unparsed_uri;
+    path = uri.path;
+    info = NULL;
+
+    conf = (cache_server_conf *) 
ap_get_module_config(r->server->module_config,
+                                                      &cache_module);
+
     /*
      * Which cache module (if any) should handle this request?
      */
@@ -73,19 +79,8 @@
         return DECLINED;
     }

-    urllen = strlen(url);
-    if (urllen > MAX_URL_LENGTH) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                     "cache: URL exceeds length threshold: %s", url);
-        return DECLINED;
-    }
-    /* DECLINE urls ending in / ??? EGP: why? */
-    if (url[urllen-1] == '/') {
-        return DECLINED;
-    }
-
     /* make space for the per request config */
-    cache = (cache_request_rec *) ap_get_module_config(r->request_config,
+    cache = (cache_request_rec *) ap_get_module_config(r->request_config,
                                                        &cache_module);
     if (!cache) {
         cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
@@ -137,171 +132,106 @@
     /*
      * Try to serve this request from the cache.
      *
-     * If no existing cache file
-     *   add cache_in filter
-     * If stale cache file
-     *   If conditional request
-     *     add cache_in filter
-     *   If non-conditional request
-     *     fudge response into a conditional
-     *     add cache_conditional filter
-     * If fresh cache file
-     *   clear filter stack
-     *   add cache_out filter
+     * If no existing cache file (DECLINED)
+     *   add cache_save filter
+     * If cached file (OK)
+     *   If fresh cache file
+     *     clear filter stack
+     *     add cache_out filter
+     *     return OK
+     *   If stale cache file
+     *       add cache_conditional filter (which updates cache)
      */

     rv = cache_select_url(r, cache->types, url);
-    if (DECLINED == rv) {
-        if (!lookup) {
-            /* no existing cache file */
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "cache: no cache - add cache_in filter and DECLINE");
-            /* add cache_in filter to cache this request */
-            ap_add_output_filter_handle(cache_in_filter_handle, NULL, r,
-                                        r->connection);
+    if (rv != OK) {
+        if (rv == DECLINED) {
+            if (!lookup) {
+                /* add cache_save filter to cache this request */
+                ap_add_output_filter_handle(cache_save_filter_handle, NULL, r,
+                                            r->connection);
+            }
+        }
+        else {
+            /* error */
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                         "cache: error returned while checking for cached "
+                         "file by %s cache", cache->type);
         }
         return DECLINED;
     }
-    else if (OK == rv) {
-        /* RFC2616 13.2 - Check cache object expiration */
-        cache->fresh = ap_cache_check_freshness(cache, r);
-        if (cache->fresh) {
-            /* fresh data available */
-            apr_bucket_brigade *out;
-            conn_rec *c = r->connection;

-            if (lookup) {
-                return OK;
-            }
+    /* We have located a suitable cache file now. */

+    /* RFC2616 13.2 - Check cache object expiration */
+    cache->fresh = ap_cache_check_freshness(cache, r);
+
+    /* What we have in our cache isn't fresh. */
+    if (!cache->fresh) {
+        /* If our stale cached response was conditional... */
+        if (!lookup && ap_cache_request_is_conditional(r)) {
             info = &(cache->handle->cache_obj->info);

-            if (info && info->lastmod) {
-                ap_update_mtime(r, info->lastmod);
+            /* fudge response into a conditional */
+            if (info && info->etag) {
+                /* if we have a cached etag */
+                apr_table_set(r->headers_in, "If-None-Match", info->etag);
             }
-
-            rv = ap_meets_conditions(r);
-            if (rv != OK) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                             "cache: fresh cache - returning status %d", rv);
-                return rv;
+            else if (info && info->lastmods) {
+                /* if we have a cached IMS */
+                apr_table_set(r->headers_in, "If-Modified-Since",
+                              info->lastmods);
             }
+        }

-            /*
-             * Not a conditionl request. Serve up the content
-             */
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "cache: fresh cache - add cache_out filter and "
-                         "handle request");
+        /* Add cache_conditional_filter to see if we can salvage
+         * later.
+         */
+        ap_add_output_filter_handle(cache_conditional_filter_handle,
+                                    NULL, r, r->connection);
+        return DECLINED;
+    }

-            /* We are in the quick handler hook, which means that no output
-             * filters have been set. So lets run the insert_filter hook.
-             */
-            ap_run_insert_filter(r);
-            ap_add_output_filter_handle(cache_out_filter_handle, NULL,
-                                        r, r->connection);
-
-            /* kick off the filter stack */
-            out = apr_brigade_create(r->pool, c->bucket_alloc);
-            if (APR_SUCCESS
-                != (rv = ap_pass_brigade(r->output_filters, out))) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
-                             "cache: error returned while trying to return %s 
"
-                             "cached data",
-                             cache->type);
-                return rv;
-            }
-            return OK;
-        }
-        else {
-            if (!r->err_headers_out) {
-                r->err_headers_out = apr_table_make(r->pool, 3);
-            }
-            /* stale data available */
-            if (lookup) {
-                return DECLINED;
-            }
+    /* fresh data available */

-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "cache: stale cache - test conditional");
-            /* if conditional request */
-            if (ap_cache_request_is_conditional(r)) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                             r->server,
-                             "cache: conditional - add cache_in filter and "
-                             "DECLINE");
-                /* Why not add CACHE_CONDITIONAL? */
-                ap_add_output_filter_handle(cache_in_filter_handle, NULL,
-                                            r, r->connection);
+    info = &(cache->handle->cache_obj->info);

-                return DECLINED;
-            }
-            /* else if non-conditional request */
-            else {
-                /* Temporarily hack this to work the way it had been. Its 
broken,
-                 * but its broken the way it was before. I'm working on 
figuring
-                 * out why the filter add in the conditional filter doesn't 
work. pjr
-                 *
-                 * info = &(cache->handle->cache_obj->info);
-                 *
-                 * Uncomment the above when the code in 
cache_conditional_filter_handle
-                 * is properly fixed...  pjr
-                 */
-
-                /* fudge response into a conditional */
-                if (info && info->etag) {
-                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                                 r->server,
-                                 "cache: nonconditional - fudge conditional "
-                                 "by etag");
-                    /* if we have a cached etag */
-                    apr_table_set(r->headers_in, "If-None-Match", info->etag);
-                }
-                else if (info && info->lastmods) {
-                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                                 r->server,
-                                 "cache: nonconditional - fudge conditional "
-                                 "by lastmod");
-                    /* if we have a cached IMS */
-                    apr_table_set(r->headers_in,
-                                  "If-Modified-Since",
-                                  info->lastmods);
-                }
-                else {
-                    /* something else - pretend there was no cache */
-                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                                 r->server,
-                                 "cache: nonconditional - no cached "
-                                 "etag/lastmods - add cache_in and DECLINE");
-
-                    ap_add_output_filter_handle(cache_in_filter_handle, NULL,
-                                                r, r->connection);
-
-                    return DECLINED;
-                }
-                /* add cache_conditional filter */
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                             r->server,
-                             "cache: nonconditional - add cache_conditional "
-                             "and DECLINE");
-                ap_add_output_filter_handle(cache_conditional_filter_handle,
-                                            NULL,
-                                            r,
-                                            r->connection);
+    if (info && info->lastmod) {
+        ap_update_mtime(r, info->lastmod);
+    }

-                return DECLINED;
-            }
-        }
+    rv = ap_meets_conditions(r);
+    if (rv != OK) {
+        /* Return cached status. */
+        return rv;
     }
-    else {
-        /* error */
-        ap_log_error(APLOG_MARK, APLOG_ERR, rv,
-                     r->server,
-                     "cache: error returned while checking for cached file by 
"
-                     "%s cache",
+
+    /* If we're a lookup, we can exit now instead of serving the content. */
+    if (lookup) {
+        return OK;
+    }
+
+    /* Serve up the content */
+
+    /* We are in the quick handler hook, which means that no output
+     * filters have been set. So lets run the insert_filter hook.
+     */
+    ap_run_insert_filter(r);
+    ap_add_output_filter_handle(cache_out_filter_handle, NULL,
+                                r, r->connection);
+
+    /* kick off the filter stack */
+    out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    rv = ap_pass_brigade(r->output_filters, out);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                     "cache: error returned while trying to return %s "
+                     "cached data",
                      cache->type);
-        return DECLINED;
+        return rv;
     }
+
+    return OK;
 }

 /*

---new function---
static int cache_url_handler(request_rec *r, int lookup)
{
    apr_status_t rv;
    const char *pragma, *auth;
    apr_uri_t uri;
    char *url;
    apr_size_t urllen;
    char *path;
    const char *types;
    cache_info *info;
    cache_request_rec *cache;
    cache_server_conf *conf;
    apr_bucket_brigade *out;

    /* Delay initialization until we know we are handling a GET */
    if (r->method_number != M_GET) {
        return DECLINED;
    }

    uri = r->parsed_uri;
    url = r->unparsed_uri;
    path = uri.path;
    info = NULL;

    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                      &cache_module);

    /*
     * Which cache module (if any) should handle this request?
     */
    if (!(types = ap_cache_get_cachetype(r, conf, path))) {
        return DECLINED;
    }

    /* make space for the per request config */
    cache = (cache_request_rec *) ap_get_module_config(r->request_config,
                                                       &cache_module);
    if (!cache) {
        cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
        ap_set_module_config(r->request_config, &cache_module, cache);
    }

    /* save away the type */
    cache->types = types;

    /*
     * Are we allowed to serve cached info at all?
     */

    /* find certain cache controlling headers */
    pragma = apr_table_get(r->headers_in, "Pragma");
    auth = apr_table_get(r->headers_in, "Authorization");

    /* first things first - does the request allow us to return
     * cached information at all? If not, just decline the request.
     *
     * Note that there is a big difference between not being allowed
     * to cache a request (no-store) and not being allowed to return
     * a cached request without revalidation (max-age=0).
     *
     * Caching is forbidden under the following circumstances:
     *
     * - RFC2616 14.9.2 Cache-Control: no-store
     * - Pragma: no-cache
     * - Any requests requiring authorization.
     */
    if (conf->ignorecachecontrol == 1 && auth == NULL) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                     "incoming request is asking for a uncached version of "
                     "%s, but we know better and are ignoring it", url);
    }
    else {
        if (ap_cache_liststr(NULL, pragma, "no-cache", NULL) ||
            auth != NULL) {
            /* delete the previously cached file */
            cache_remove_url(r, cache->types, url);

            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "cache: no-cache or authorization forbids caching "
                         "of %s", url);
            return DECLINED;
        }
    }

    /*
     * Try to serve this request from the cache.
     *
     * If no existing cache file (DECLINED)
     *   add cache_save filter
     * If cached file (OK)
     *   If fresh cache file
     *     clear filter stack
     *     add cache_out filter
     *     return OK
     *   If stale cache file
     *       add cache_conditional filter (which updates cache)
     */

    rv = cache_select_url(r, cache->types, url);
    if (rv != OK) {
        if (rv == DECLINED) {
            if (!lookup) {
                /* add cache_save filter to cache this request */
                ap_add_output_filter_handle(cache_save_filter_handle, NULL, r,
                                            r->connection);
            }
        }
        else {
            /* error */
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
                         "cache: error returned while checking for cached "
                         "file by %s cache", cache->type);
        }
        return DECLINED;
    }

    /* We have located a suitable cache file now. */

    /* RFC2616 13.2 - Check cache object expiration */
    cache->fresh = ap_cache_check_freshness(cache, r);

    /* What we have in our cache isn't fresh. */
    if (!cache->fresh) {
        /* If our stale cached response was conditional... */
        if (!lookup && ap_cache_request_is_conditional(r)) {
            info = &(cache->handle->cache_obj->info);

            /* fudge response into a conditional */
            if (info && info->etag) {
                /* if we have a cached etag */
                apr_table_set(r->headers_in, "If-None-Match", info->etag);
            }
            else if (info && info->lastmods) {
                /* if we have a cached IMS */
                apr_table_set(r->headers_in, "If-Modified-Since",
                              info->lastmods);
            }
        }

        /* Add cache_conditional_filter to see if we can salvage
         * later.
         */
        ap_add_output_filter_handle(cache_conditional_filter_handle,
                                    NULL, r, r->connection);
        return DECLINED;
    }

    /* fresh data available */

    info = &(cache->handle->cache_obj->info);

    if (info && info->lastmod) {
        ap_update_mtime(r, info->lastmod);
    }

    rv = ap_meets_conditions(r);
    if (rv != OK) {
        /* Return cached status. */
        return rv;
    }

    /* If we're a lookup, we can exit now instead of serving the content. */
    if (lookup) {
        return OK;
    }

    /* Serve up the content */

    /* We are in the quick handler hook, which means that no output
     * filters have been set. So lets run the insert_filter hook.
     */
    ap_run_insert_filter(r);
    ap_add_output_filter_handle(cache_out_filter_handle, NULL,
                                r, r->connection);

    /* kick off the filter stack */
    out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
    rv = ap_pass_brigade(r->output_filters, out);
    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
                     "cache: error returned while trying to return %s "
                     "cached data",
                     cache->type);
        return rv;
    }

    return OK;
}



Re: [PATCH] mod_cache fixes: #4

Posted by Bill Stoddard <bi...@wstoddard.com>.
Justin Erenkrantz wrote:

> --On Sunday, August 1, 2004 11:25 AM -0400 Bill Stoddard 
> <bi...@wstoddard.com> wrote:
> 
>> Too many changes in one patch. Break this up into multiple consumable 
>> in 15
>> minute patches and I'll review them.
> 
> 
> (This is probably the largest and most complicated one.  At the bottom, 
> I've also pasted the current quick_handler function as I have it in my 
> tree.)
> 

+1, nice cleanup.  I had second thoughts about removing the MAX_URL_LENGTH check, but what the heck, whack it. 
Remove the #define from mod_cache.h.

Bill