Bug 27578

Summary: made getlastmodified a writable property
Product: Apache httpd-2 Reporter: Oliver Dewdney <ojd>
Component: mod_davAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: RESOLVED LATER    
Severity: enhancement CC: wiml
Priority: P3 Keywords: MassUpdate, PatchAvailable
Version: 2.0.48   
Target Milestone: ---   
Hardware: Other   
OS: other   
Attachments: Updated patch against trunk

Description Oliver Dewdney 2004-03-10 18:18:32 UTC
we have a load-balanced array of apache web servers and are trying to 
syncronise content between them using webdav. to make the content optimally 
cacheable we have switched off using the inode number in the etag and have to 
have the Last-Modified date the same across all the servers so the If-Modified-
Since request header works as it hopes to.

Oli


diff -u repos.c.orig repos.c
--- repos.c.orig        2004-03-10 17:32:57.000000000 +0000
+++ repos.c     2004-03-10 12:35:14.000000000 +0000
@@ -60,6 +60,7 @@
 #include "apr_file_io.h"
 #include "apr_strings.h"
 #include "apr_buckets.h"
+#include "apr_date.h"
 
 #if APR_HAVE_STDIO_H
 #include <stdio.h>              /* for sprintf() */
@@ -1940,10 +1959,32 @@
         return 1;
 #endif
 
+    if (propid == DAV_PROPID_getlastmodified )
+        return 1;
+
     (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
     return info->is_writable;
 }
 
+struct dav_fs_context
+{
+    int propid;
+    union rollback
+    {
+        apr_time_t modtime;
+        apr_fileperms_t perms;
+    } oldvalue;
+    union context
+    {
+        apr_time_t modtime;
+        int perms;
+    } value;
+};
+
+apr_time_t xapr_date_parse_http(char*s)
+{
+return 12345000000000LL + (int)s;
+}
 static dav_error *dav_fs_patch_validate(const dav_resource *resource,
                                         const apr_xml_elem *elem,
                                         int operation,
@@ -1954,7 +1995,34 @@
     const apr_text *f_cdata;
     char value;
     dav_elem_private *priv = elem->priv;
+    struct dav_fs_context *fscontext;
+
+    fscontext = apr_pcalloc(resource->info->pool, sizeof(*fscontext) );
+    fscontext->propid = priv->propid;
+
+    if ( priv->propid == DAV_PROPID_getlastmodified ) {
+        if (operation == DAV_PROP_OP_DELETE)
+            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0,
+                             "The 'lastmodified' property cannot be removed.");
+        if ( elem->first_cdata.first )
+            cdata = elem->first_cdata.first;
+        else if ( elem->first_child )
+            cdata = elem->first_child->following_cdata.first;
+        else
+            cdata = NULL;
 
+       if ( cdata == NULL )
+            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0,
+                             "The 'lastmodified' property cannot be found.");
+        fscontext->value.modtime = apr_date_parse_http(cdata->text);
+        short ttt = apr_date_parse_http(cdata->text);
+        if ( fscontext->value.modtime == 0 ) {
+            return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0,
+                             "The 'lastmodified' property cannot be parsed.");
+        }
+        *context = (void*)fscontext;
+       return NULL;
+    }
     if (priv->propid != DAV_PROPID_FS_executable) {
         *defer_to_dead = 1;
         return NULL;
@@ -1997,8 +2065,8 @@
                              "submitted is invalid.");
     }
 
-    *context = (void *)(value == 'T');
-
+    fscontext->value.perms = (value == 'T');
+    *context = (void*)fscontext;
     return NULL;
 
   too_long:
@@ -2009,37 +2077,49 @@
 
 }
 
+
 static dav_error *dav_fs_patch_exec(const dav_resource *resource,
                                     const apr_xml_elem *elem,
                                     int operation,
                                     void *context,
                                     dav_liveprop_rollback **rollback_ctx)
 {
-    int value = context != NULL;
-    apr_fileperms_t perms = resource->info->finfo.protection;
-    int old_value = (perms & APR_UEXECUTE) != 0;
-
-    /* assert: prop == executable. operation == SET. */
-
-    /* don't do anything if there is no change. no rollback info either. */
-    /* DBG2("new value=%d  (old=%d)", value, old_value); */
-    if (value == old_value)
-        return NULL;
-
-    perms &= ~APR_UEXECUTE;
-    if (value)
-        perms |= APR_UEXECUTE;
-
-    if (apr_file_perms_set(resource->info->pathname, perms) != APR_SUCCESS) {
-        return dav_new_error(resource->info->pool,
+    struct dav_fs_context *fscontext;
+    
+    fscontext = (struct dav_fs_context*)context;
+    if ( fscontext->propid == DAV_PROPID_getlastmodified ) {
+        fscontext->oldvalue.modtime = resource->info->finfo.mtime;
+        if ( apr_file_mtime_set(resource->info->pathname, fscontext-
>value.modtime, resource->info->pool) != APR_SUCCESS )
+            return dav_new_error(resource->info->pool,
+                             HTTP_INTERNAL_SERVER_ERROR, 0,
+                             "Could not set the lastmodified date of the "
+                             "target resource.");
+        resource->info->finfo.mtime = fscontext->value.modtime;
+    } else if (fscontext->propid == DAV_PROPID_FS_executable ) {
+        apr_fileperms_t perms = resource->info->finfo.protection;
+        fscontext->oldvalue.perms = perms;
+
+        /* assert: prop == executable. operation == SET. */
+
+        /* don't do anything if there is no change. no rollback info either. */
+        /* DBG2("new value=%d  (old=%d)", value, old_value); */
+
+        perms &= ~APR_UEXECUTE;
+        if (fscontext->value.perms != 0 )
+            perms |= APR_UEXECUTE;
+
+        if ( perms != fscontext->oldvalue.perms )
+            if (apr_file_perms_set(resource->info->pathname, perms) != 
APR_SUCCESS) {
+            return dav_new_error(resource->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR, 0,
                              "Could not set the executable flag of the "
                              "target resource.");
-    }
+            }
 
-    /* update the resource and set up the rollback context */
-    resource->info->finfo.protection = perms;
-    *rollback_ctx = (dav_liveprop_rollback *)old_value;
+        /* update the resource and set up the rollback context */
+        resource->info->finfo.protection = perms;
+    }
+    *rollback_ctx = (dav_liveprop_rollback *)fscontext;
 
     return NULL;
 }
@@ -2057,8 +2137,17 @@
                                         void *context,
                                         dav_liveprop_rollback *rollback_ctx)
 {
+    struct dav_fs_context *rollback = (struct dav_fs_context*)rollback_ctx;
+    if ( rollback->propid == DAV_PROPID_getlastmodified ) {
+        if ( apr_file_mtime_set(resource->info->pathname, rollback-
>oldvalue.modtime, resource->info->pool) != APR_SUCCESS )
+            return dav_new_error(resource->info->pool,
+                             HTTP_INTERNAL_SERVER_ERROR, 0,
+                             "Could not set the lastmodified date of the "
+                             "target resource.");
+        return NULL;
+    }
     apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE;
-    int value = rollback_ctx != NULL;
+    int value = (rollback->oldvalue.perms & APR_UEXECUTE) != 0;
 
     /* assert: prop == executable. operation == SET. */
Comment 1 Wim Lewis 2013-03-19 22:11:05 UTC
++. I have also run into situation where I'd like to be able to set the last-modified-date via PROPPATCH.
Comment 2 Wim Lewis 2015-03-11 23:48:29 UTC
Created attachment 32560 [details]
Updated patch against trunk

I've attached an updated patch for this feature based on Oliver Dewdney's patch.

This patch applies to trunk or 2.4.x-dev, and also includes a configuration directive "DAVAllowSetModTime" which allows the feature to be enabled. By default it is disabled so that no one will be surprised by a change in behavior, but I think it might make sense to enable it in the 2.5.x versions.

I also took the opportunity to clean up some code in _exec and _rollback. I think this fixes a bug where the executable flag of files could be spuriously cleared during rollback of a PROPPATCH that affects multiple files.
Comment 3 William A. Rowe Jr. 2018-11-07 21:08:43 UTC
Please help us to refine our list of open and current defects; this is a mass update of old and inactive Bugzilla reports which reflect user error, already resolved defects, and still-existing defects in httpd.

As repeatedly announced, the Apache HTTP Server Project has discontinued all development and patch review of the 2.2.x series of releases. The final release 2.2.34 was published in July 2017, and no further evaluation of bug reports or security risks will be considered or published for 2.2.x releases. All reports older than 2.4.x have been updated to status RESOLVED/LATER; no further action is expected unless the report still applies to a current version of httpd.

If your report represented a question or confusion about how to use an httpd feature, an unexpected server behavior, problems building or installing httpd, or working with an external component (a third party module, browser etc.) we ask you to start by bringing your question to the User Support and Discussion mailing list, see [https://httpd.apache.org/lists.html#http-users] for details. Include a link to this Bugzilla report for completeness with your question.

If your report was clearly a defect in httpd or a feature request, we ask that you retest using a modern httpd release (2.4.33 or later) released in the past year. If it can be reproduced, please reopen this bug and change the Version field above to the httpd version you have reconfirmed with.

Your help in identifying defects or enhancements still applicable to the current httpd server software release is greatly appreciated.