On Wed, 11 Apr 2007, Niklas Edmundsson wrote:

Looking a bit further, I think that something like this would actually be enough:
<snip, included as an attachment>

I have now tested this patch, and it seems to solve the problem. This is on httpd-2.2.4 + patch for PR41475 + our mod_disk_cache patches.

Without the patch a HEAD on a cached expired object that isn't modified will unconditionally return 304 and furthermore cause the cached object to be deleted. We believe that this is the explanation to why it has been so hard to track down this bug - it only bites one user and that user usually has no clue on what happens, and even if we try to reproduce it immediately afterwards it won't trigger.

With the patch stuff works like expected:
- A HEAD on a cached expired object that isn't modified will update
  the cache header and return the proper return code, it follows the
  same code path as other requests on expired unmodified objects.
- A HEAD on a cached expired object that IS modified will remove the
  object from cache and then decline the opportunity to cache the
  object.

I request that this is reviewed, commited and proposed for backport to httpd 2.2.5.


/Nikke
--
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 Niklas Edmundsson, Admin @ {acc,hpc2n}.umu.se      |     [EMAIL PROTECTED]
---------------------------------------------------------------------------
 "The pain is bad enough. Don't go poetic on me." - Madeline
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
--- mod_cache.c.orig    2007-04-11 13:29:14.000000000 +0200
+++ mod_cache.c 2007-04-11 14:06:29.000000000 +0200
@@ -456,7 +456,7 @@ static int cache_save_filter(ap_filter_t
          */
         reason = "No Last-Modified, Etag, or Expires headers";
     }
-    else if (r->header_only) {
+    else if (r->header_only && !cache->stale_handle) {
         /* HEAD requests */
         reason = "HTTP HEAD request";
     }
@@ -589,11 +589,12 @@ static int cache_save_filter(ap_filter_t
             cache->provider->remove_entity(cache->stale_handle);
             /* Treat the request as if it wasn't conditional. */
             cache->stale_handle = NULL;
+            rv = !OK;
         }
     }
 
-    /* no cache handle, create a new entity */
-    if (!cache->handle) {
+    /* no cache handle, create a new entity only for non-HEAD request */
+    if (!cache->handle && !r->header_only) {
         rv = cache_create_entity(r, size);
         info = apr_pcalloc(r->pool, sizeof(cache_info));
         /* We only set info->status upon the initial creation. */

Reply via email to