There seems to be some consensus that we should add a key to r->notes
as a temporary fix ( at least till 2.4 ). Hence, I'm attaching a patch
- ap_meets_conditions_fixes.patch, with the appropriate fixes to
ap_meets_conditions() using "resource-exists" key for this purpose.
To be sure that we do not break anything, we would want
ap_meets_conditions() to behave as it does now when the key is not
set. This implies that the value corresponding to the key needs to
pass two states - one to signify resource exists and another for
resource does not exist ( using "Y" and "N" as the corresponding
values here ). I used "resource-exists" as the key instead of
"NON_EXTANT_RESOURCE" or "NO_RESOURCE" as suggested by Chris Darroch,
to avoid double negatives.

Also attaching a corresponding patch to mod_dav ( mod_dav_fixes.patch
) which sets "resource-exists" appropriately and also the Etag header
by calling resource->hooks->set_headers() before calling
ap_meets_conditions()

Again, the patches are against 2.2.6 and I've tested them against
mod_dav_fs w/ DEBUG_GET_HANDLER set to 1.

Suggestions ? Comments ?

- Paritosh Shah.


On 10/18/07, Chris Darroch <[EMAIL PROTECTED]> wrote:
> Nick Kew wrote:
>
> > My vote goes to r->notes.
> >
> > Anything else relies on something with semantic significance that'll
> > risk breaking random things.
> >
> > For the future (e.g. 2.4), we could review other options.  For example,
> > abstract out r->finfo to a void* with an API for inspecting resources
> > including but not limited to those visible in the filesystem.
>
>    Sounds good; maybe an r->notes key named "NON_EXTANT_RESOURCE" or
> "NO_RESOURCE" or some such?
>
> > Feel free to ignore my totally half-baked ideas, but mod_dav is not
> > the only area where we have issues, with ETags.  There's also the
> > whole question of negotiated content to consider, and I'm still confused
> > by the problems that still surround PR#39727.  If we're reworking
> > ETag logic, we should take the opportunity to deal with this, too.
> > Can we incorporate some kind of tokenisation into ETags that will
> > express dependence on negotiation?
> >
> > For example, Henrik Nordstrom suggests ";gzip".  If we expand that to,
> > say, ";CE=gzip", then we can start to apply semantics to decoding the
> > Etag, and determine equivalence.  So in that case, we could determine
> > that the (uncompressed) file does indeed match the ETag.  Not sure if
> > there's anything we might do with other negotiated headers, but maybe
> > we could leave that open, providing a hook that something like
> > mod_negotiation might someday use.
>
>    I confess I've been following this discussion at an abstract
> level only (at best).  I don't think, though, that it directly affects
> any of the several bugs I'm hoping to tackle, if I understand the
> issue correctly.  But I don't claim to fully understand the details of
> mod_negiotiation.
>
> Chris.
>
> --
> GPG Key ID: 366A375B
> GPG Key Fingerprint: 485E 5041 17E1 E2BB C263  E4DE C8E3 FA36 366A 375B
>
>
Index: modules/http/http_protocol.c
===================================================================
--- modules/http/http_protocol.c	(revision 5021)
+++ modules/http/http_protocol.c	(working copy)
@@ -261,6 +261,7 @@
     apr_time_t tmp_time;
     apr_int64_t mtime;
     int not_modified = 0;
+    const char *resource_exists;
 
     /* Check for conditional requests --- note that we only want to do
      * this if we are successful so far and we are not processing a
@@ -278,6 +279,10 @@
     }
 
     etag = apr_table_get(r->headers_out, "ETag");
+    if((resource_exists = apr_table_get(r->notes, "resource-exists")) == NULL) {
+        /* "resource-exists" tag not set */
+        resource_exists = "U";
+    }
 
     /* All of our comparisons must be in seconds, because that's the
      * highest time resolution the HTTP specification allows.
@@ -286,17 +291,26 @@
     tmp_time = ((r->mtime != 0) ? r->mtime : apr_time_now());
     mtime =  apr_time_sec(tmp_time);
 
-    /* If an If-Match request-header field was given
-     * AND the field value is not "*" (meaning match anything)
-     * AND if our strong ETag does not match any entity tag in that field,
-     *     respond with a status of 412 (Precondition Failed).
-     */
+    /* If an If-Match request-header field was given */
     if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) {
-        if (if_match[0] != '*'
-            && (etag == NULL || etag[0] == 'W'
-                || !ap_find_list_item(r->pool, if_match, etag))) {
-            return HTTP_PRECONDITION_FAILED;
+       /* AND the field value is not "*" (meaning match anything)
+        * AND if our strong ETag does not match any entity tag in that field,
+        *     respond with a status of 412 (Precondition Failed).
+        */
+        if (if_match[0] != '*') {
+            if (etag == NULL || etag[0] == 'W'
+                || !ap_find_list_item(r->pool, if_match, etag)) {
+                return HTTP_PRECONDITION_FAILED;
+            }
         }
+        else {
+            /* Else if the field value is '*' (meaning match anything)
+             * AND resource does not exist,
+             *  respond with a status of 412 (Precondition Failed).
+             */
+            if(resource_exists[0] == 'N')
+                return HTTP_PRECONDITION_FAILED;
+        }
     }
     else {
         /* Else if a valid If-Unmodified-Since request-header field was given
@@ -316,6 +330,7 @@
 
     /* If an If-None-Match request-header field was given
      * AND the field value is "*" (meaning match anything)
+     * AND the resource exists
      *     OR our ETag matches any of the entity tags in that field, fail.
      *
      * If the request method was GET or HEAD, failure means the server
@@ -329,7 +344,7 @@
     if_nonematch = apr_table_get(r->headers_in, "If-None-Match");
     if (if_nonematch != NULL) {
         if (r->method_number == M_GET) {
-            if (if_nonematch[0] == '*') {
+            if (if_nonematch[0] == '*' && resource_exists[0] == 'Y') {
                 not_modified = 1;
             }
             else if (etag != NULL) {
@@ -344,7 +359,7 @@
                 }
             }
         }
-        else if (if_nonematch[0] == '*'
+        else if ((if_nonematch[0] == '*' && resource_exists[0] == 'Y')
                  || (etag != NULL
                      && ap_find_list_item(r->pool, if_nonematch, etag))) {
             return HTTP_PRECONDITION_FAILED;
Index: modules/dav/main/util.c
===================================================================
--- modules/dav/main/util.c	(revision 5021)
+++ modules/dav/main/util.c	(working copy)
@@ -1433,6 +1433,7 @@
     const dav_hooks_repository *repos_hooks = resource->hooks;
     dav_buffer work_buf = { 0 };
     dav_response *new_response;
+    const char *resource_exists;
 
 #if DAV_DEBUG
     if (depth && response == NULL) {
@@ -1449,6 +1450,19 @@
     if (response != NULL)
         *response = NULL;
 
+    resource_exists = 
+        (DAV_RESOURCE_EXISTS == dav_get_resource_state(r, resource)) ? "Y" : "N";
+    
+    /* Set "resource-exists" key in r->notes, required by ap_meets_conditions()
+     * for proper If-* header checking */ 
+    apr_table_set(r->notes, "resource-exists", resource_exists);
+
+    /* Set the Etag header required by ap_meets_conditions() */
+    if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
+        return dav_push_error(r->pool, err->status, 0,
+                              "Unable to setup HTTP headers.", err);
+    }
+
     /* Do the standard checks for conditional requests using
      * If-..-Since, If-Match etc */
     if ((result = ap_meets_conditions(r)) != OK) {

Reply via email to