From: Joe Orton Date: Fri, 7 Nov 2025 12:57:48 +0000 (+0000) Subject: mod_dav, mod_dav_fs: Add opt-in support for controlling resource X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2d92bae1277bb3fd84237c7465b1d1cb83346834;p=thirdparty%2Fapache%2Fhttpd.git mod_dav, mod_dav_fs: Add opt-in support for controlling resource modification times via the X-Oc-Mtime header in the PUT and MKCOL method implementations. * modules/dav/fs/mod_dav.h: Extend dav_hooks_repository struct with set_mtime function pointer. * modules/dav/fs/repos.c (dav_fs_set_mtime): New function. * modules/dav/main/mod_dav.c (dav_cmd_davhonormtimeheader, dav_parse_mtime): New functions. (dav_method_put, dav_method_mkcol): Add X-Oc-Mtime handling. (dav_cmds): Add DAVHonorMtimeHeader directive. Submitted by: Leo Github: closes #556 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1929581 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/dav-mtime.txt b/changes-entries/dav-mtime.txt new file mode 100644 index 0000000000..4c101a714c --- /dev/null +++ b/changes-entries/dav-mtime.txt @@ -0,0 +1,6 @@ + *) mod_dav: Add DAVHonorMtimeHeader directive, if enabled + the X-Oc-Mtime request header can be used to control + resource modification times. [Leo ] + + *) mod_dav_fs: Add support for changing resource modification times. + [Leo ] diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 614154502e..746681877f 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -1164,6 +1164,24 @@ static dav_error * dav_fs_deliver(const dav_resource *resource, #endif /* DEBUG_GET_HANDLER */ +static dav_error * dav_fs_set_mtime(dav_resource *resource, apr_time_t mtime) +{ + apr_pool_t *pool; + apr_status_t status; + + pool = resource->pool; + status = apr_file_mtime_set(resource->info->pathname, mtime, pool); + + if (status != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_ERR, status, pool, APLOGNO(10543) + "Failed setting modification time for file %s.", + resource->info->pathname); + return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, status, + "Could not set modification time."); + } + + return NULL; +} static dav_error * dav_fs_create_collection(dav_resource *resource) { @@ -1972,7 +1990,8 @@ static const dav_hooks_repository dav_hooks_repository_fs = dav_fs_getetag, NULL, dav_fs_get_request_rec, - dav_fs_pathname + dav_fs_pathname, + dav_fs_set_mtime }; static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index fdfe2c6094..69aa811a3e 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -90,6 +90,7 @@ typedef struct { int allow_depthinfinity; int allow_lockdiscovery; int msext_opts; + int honor_mtime_header; } dav_dir_conf; /* per-server configuration */ @@ -213,6 +214,8 @@ static void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides) allow_depthinfinity); newconf->allow_lockdiscovery = DAV_INHERIT_VALUE(parent, child, allow_lockdiscovery); + newconf->honor_mtime_header = DAV_INHERIT_VALUE(parent, child, + honor_mtime_header); newconf->msext_opts = DAV_INHERIT_VALUE(parent, child, msext_opts); @@ -304,6 +307,20 @@ static const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1) return NULL; } +/* + * Command handler for the DAVHonorMtimeHeader directive, which is FLAG. + */ +static const char *dav_cmd_davhonormtimeheader(cmd_parms *cmd, void *config, const int arg) +{ + dav_dir_conf *conf = (dav_dir_conf *)config; + + if (arg) + conf->honor_mtime_header = DAV_ENABLED_ON; + else + conf->honor_mtime_header = DAV_ENABLED_OFF; + return NULL; +} + /* * Command handler for the DAVBasePath directive, which is TAKE1 */ @@ -947,6 +964,37 @@ static int dav_parse_range(request_rec *r, return 1; } +/** + * @return 1 if valid x-oc-mtime, + * 0 if no x-oc-mtime, + * -1 if malformed x-oc-mtime + */ +static int dav_parse_mtime(request_rec *r, apr_time_t *mtime) +{ + const char *hdr; + char *endp; + apr_int64_t n; + apr_size_t i; + + if ((hdr = apr_table_get(r->headers_in, "x-oc-mtime")) == NULL) { + return 0; + } + + for (i = 0; i < strlen(hdr); i++) { + if (!apr_isdigit(hdr[i])) { + return -1; + } + } + + n = apr_strtoi64(hdr, &endp, 10); + if (errno != 0 || endp == hdr) { + return -1; + } + + *mtime = (apr_time_t) apr_time_from_sec(n); + return 1; +} + /* handle the GET method */ static int dav_method_get(request_rec *r) { @@ -1050,6 +1098,11 @@ static int dav_method_put(request_rec *r) apr_off_t range_start; apr_off_t range_end; int rc; + int mtime_ret; + apr_time_t mtime; + + /* retrieve module config */ + conf = ap_get_module_config(r->per_dir_config, &dav_module); /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */, @@ -1114,6 +1167,17 @@ static int dav_method_put(request_rec *r) mode = DAV_MODE_WRITE_TRUNC; } + /* try parsing x-oc-mtime header */ + mtime_ret = 0; + if (conf->honor_mtime_header == DAV_ENABLED_ON) { + if ((mtime_ret = dav_parse_mtime(r, &mtime)) == -1) { + body = apr_psprintf(r->pool, + "Malformed X-OC-Mtime header for PUT %s.", + ap_escape_html(r->pool, r->uri)); + return dav_error_response(r, HTTP_BAD_REQUEST, body); + } + } + /* make sure the resource can be modified (if versioning repository) */ if ((err = dav_auto_checkout(r, resource, 0 /* not parent_only */, @@ -1208,6 +1272,19 @@ static int dav_method_put(request_rec *r) err2 = (*resource->hooks->close_stream)(stream, err == NULL /* commit */); err = dav_join_error(err, err2); + + if (err == NULL && mtime_ret == 1) { + if (*resource->hooks->set_mtime != NULL) { + err2 = (*resource->hooks->set_mtime)(resource, mtime); + err = dav_join_error(err, err2); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Setting modification time for file."); + } + else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Provider does not support setting modification times."); + } + } } /* @@ -1240,7 +1317,6 @@ static int dav_method_put(request_rec *r) } /* This performs MS-WDV PROPPATCH combined with PUT */ - conf = ap_get_module_config(r->per_dir_config, &dav_module); if (conf->msext_opts & DAV_MSEXT_OPT_WDV) (void)dav_mswdv_postprocessing(r); @@ -2732,6 +2808,12 @@ static int dav_method_mkcol(request_rec *r) int result; int rc; dav_response *multi_status; + dav_dir_conf *conf; + int mtime_ret; + apr_time_t mtime; + + /* retrieve module config */ + conf = ap_get_module_config(r->per_dir_config, &dav_module); /* handle the request body */ /* ### this may move lower once we start processing bodies */ @@ -2759,6 +2841,17 @@ static int dav_method_mkcol(request_rec *r) return HTTP_METHOD_NOT_ALLOWED; } + /* try parsing x-oc-mtime header */ + mtime_ret = 0; + if (conf->honor_mtime_header == DAV_ENABLED_ON) { + if ((mtime_ret = dav_parse_mtime(r, &mtime)) == -1) { + return dav_error_response(r, HTTP_BAD_REQUEST, + apr_psprintf(r->pool, + "Malformed X-OC-Mtime header for MKCOL %s.", + ap_escape_html(r->pool, r->uri))); + } + } + resource_state = dav_get_resource_state(r, resource); /* @@ -2839,6 +2932,25 @@ static int dav_method_mkcol(request_rec *r) } } + if (mtime_ret == 1) { + if (resource->hooks->set_mtime != NULL) { + err = (resource->hooks->set_mtime)(resource, mtime); + if (err != NULL) { + err = dav_push_error(r->pool, err->status, 0, + "The MKCOL was successful, but there " + "was a problem setting its modification time.", + err); + return dav_handle_err(r, err, NULL); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Setting modification time for directory."); + } + else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Provider does not support setting modification times."); + } + } + /* return an appropriate response (HTTP_CREATED) */ rc = dav_created(r, NULL, "Collection", 0); @@ -5345,6 +5457,11 @@ static const command_rec dav_cmds[] = ACCESS_CONF|RSRC_CONF, "allow lock discovery by PROPFIND requests"), + /* per directory/location */ + AP_INIT_FLAG("DAVHonorMtimeHeader", dav_cmd_davhonormtimeheader, NULL, + ACCESS_CONF, + "Set modification time based on X-OC-Mtime header"), + /* per directory/location, or per server */ AP_INIT_ITERATE("DAVMSext", dav_cmd_davmsext, NULL, ACCESS_CONF|RSRC_CONF, diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index 6b42d8203f..8d9be2ad42 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -2166,6 +2166,10 @@ struct dav_hooks_repository /* Get the pathname for a resource */ const char * (*get_pathname)(const dav_resource *resource); + + /* Set modification time for a resource. Can be NULL. */ + dav_error * (*set_mtime)(dav_resource *resource, const apr_time_t mtime); + };