Skip to content

Commit 2d92bae

Browse files
committed
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 <i hardrain980.com> Github: closes #556 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1929581 13f79535-47bb-0310-9956-ffa450edef68
1 parent 606656e commit 2d92bae

File tree

4 files changed

+148
-2
lines changed

4 files changed

+148
-2
lines changed

changes-entries/dav-mtime.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*) mod_dav: Add DAVHonorMtimeHeader directive, if enabled
2+
the X-Oc-Mtime request header can be used to control
3+
resource modification times. [Leo <i hardrain980.com>]
4+
5+
*) mod_dav_fs: Add support for changing resource modification times.
6+
[Leo <i hardrain980.com>]

modules/dav/fs/repos.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,24 @@ static dav_error * dav_fs_deliver(const dav_resource *resource,
11641164

11651165
#endif /* DEBUG_GET_HANDLER */
11661166

1167+
static dav_error * dav_fs_set_mtime(dav_resource *resource, apr_time_t mtime)
1168+
{
1169+
apr_pool_t *pool;
1170+
apr_status_t status;
1171+
1172+
pool = resource->pool;
1173+
status = apr_file_mtime_set(resource->info->pathname, mtime, pool);
1174+
1175+
if (status != APR_SUCCESS) {
1176+
ap_log_perror(APLOG_MARK, APLOG_ERR, status, pool, APLOGNO(10543)
1177+
"Failed setting modification time for file %s.",
1178+
resource->info->pathname);
1179+
return dav_new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0, status,
1180+
"Could not set modification time.");
1181+
}
1182+
1183+
return NULL;
1184+
}
11671185

11681186
static dav_error * dav_fs_create_collection(dav_resource *resource)
11691187
{
@@ -1972,7 +1990,8 @@ static const dav_hooks_repository dav_hooks_repository_fs =
19721990
dav_fs_getetag,
19731991
NULL,
19741992
dav_fs_get_request_rec,
1975-
dav_fs_pathname
1993+
dav_fs_pathname,
1994+
dav_fs_set_mtime
19761995
};
19771996

19781997
static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource,

modules/dav/main/mod_dav.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ typedef struct {
9090
int allow_depthinfinity;
9191
int allow_lockdiscovery;
9292
int msext_opts;
93+
int honor_mtime_header;
9394
} dav_dir_conf;
9495

9596
/* per-server configuration */
@@ -213,6 +214,8 @@ static void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
213214
allow_depthinfinity);
214215
newconf->allow_lockdiscovery = DAV_INHERIT_VALUE(parent, child,
215216
allow_lockdiscovery);
217+
newconf->honor_mtime_header = DAV_INHERIT_VALUE(parent, child,
218+
honor_mtime_header);
216219
newconf->msext_opts = DAV_INHERIT_VALUE(parent, child,
217220
msext_opts);
218221

@@ -304,6 +307,20 @@ static const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1)
304307
return NULL;
305308
}
306309

310+
/*
311+
* Command handler for the DAVHonorMtimeHeader directive, which is FLAG.
312+
*/
313+
static const char *dav_cmd_davhonormtimeheader(cmd_parms *cmd, void *config, const int arg)
314+
{
315+
dav_dir_conf *conf = (dav_dir_conf *)config;
316+
317+
if (arg)
318+
conf->honor_mtime_header = DAV_ENABLED_ON;
319+
else
320+
conf->honor_mtime_header = DAV_ENABLED_OFF;
321+
return NULL;
322+
}
323+
307324
/*
308325
* Command handler for the DAVBasePath directive, which is TAKE1
309326
*/
@@ -947,6 +964,37 @@ static int dav_parse_range(request_rec *r,
947964
return 1;
948965
}
949966

967+
/**
968+
* @return 1 if valid x-oc-mtime,
969+
* 0 if no x-oc-mtime,
970+
* -1 if malformed x-oc-mtime
971+
*/
972+
static int dav_parse_mtime(request_rec *r, apr_time_t *mtime)
973+
{
974+
const char *hdr;
975+
char *endp;
976+
apr_int64_t n;
977+
apr_size_t i;
978+
979+
if ((hdr = apr_table_get(r->headers_in, "x-oc-mtime")) == NULL) {
980+
return 0;
981+
}
982+
983+
for (i = 0; i < strlen(hdr); i++) {
984+
if (!apr_isdigit(hdr[i])) {
985+
return -1;
986+
}
987+
}
988+
989+
n = apr_strtoi64(hdr, &endp, 10);
990+
if (errno != 0 || endp == hdr) {
991+
return -1;
992+
}
993+
994+
*mtime = (apr_time_t) apr_time_from_sec(n);
995+
return 1;
996+
}
997+
950998
/* handle the GET method */
951999
static int dav_method_get(request_rec *r)
9521000
{
@@ -1050,6 +1098,11 @@ static int dav_method_put(request_rec *r)
10501098
apr_off_t range_start;
10511099
apr_off_t range_end;
10521100
int rc;
1101+
int mtime_ret;
1102+
apr_time_t mtime;
1103+
1104+
/* retrieve module config */
1105+
conf = ap_get_module_config(r->per_dir_config, &dav_module);
10531106

10541107
/* Ask repository module to resolve the resource */
10551108
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
@@ -1114,6 +1167,17 @@ static int dav_method_put(request_rec *r)
11141167
mode = DAV_MODE_WRITE_TRUNC;
11151168
}
11161169

1170+
/* try parsing x-oc-mtime header */
1171+
mtime_ret = 0;
1172+
if (conf->honor_mtime_header == DAV_ENABLED_ON) {
1173+
if ((mtime_ret = dav_parse_mtime(r, &mtime)) == -1) {
1174+
body = apr_psprintf(r->pool,
1175+
"Malformed X-OC-Mtime header for PUT %s.",
1176+
ap_escape_html(r->pool, r->uri));
1177+
return dav_error_response(r, HTTP_BAD_REQUEST, body);
1178+
}
1179+
}
1180+
11171181
/* make sure the resource can be modified (if versioning repository) */
11181182
if ((err = dav_auto_checkout(r, resource,
11191183
0 /* not parent_only */,
@@ -1208,6 +1272,19 @@ static int dav_method_put(request_rec *r)
12081272
err2 = (*resource->hooks->close_stream)(stream,
12091273
err == NULL /* commit */);
12101274
err = dav_join_error(err, err2);
1275+
1276+
if (err == NULL && mtime_ret == 1) {
1277+
if (*resource->hooks->set_mtime != NULL) {
1278+
err2 = (*resource->hooks->set_mtime)(resource, mtime);
1279+
err = dav_join_error(err, err2);
1280+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1281+
"Setting modification time for file.");
1282+
}
1283+
else {
1284+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1285+
"Provider does not support setting modification times.");
1286+
}
1287+
}
12111288
}
12121289

12131290
/*
@@ -1240,7 +1317,6 @@ static int dav_method_put(request_rec *r)
12401317
}
12411318

12421319
/* This performs MS-WDV PROPPATCH combined with PUT */
1243-
conf = ap_get_module_config(r->per_dir_config, &dav_module);
12441320
if (conf->msext_opts & DAV_MSEXT_OPT_WDV)
12451321
(void)dav_mswdv_postprocessing(r);
12461322

@@ -2732,6 +2808,12 @@ static int dav_method_mkcol(request_rec *r)
27322808
int result;
27332809
int rc;
27342810
dav_response *multi_status;
2811+
dav_dir_conf *conf;
2812+
int mtime_ret;
2813+
apr_time_t mtime;
2814+
2815+
/* retrieve module config */
2816+
conf = ap_get_module_config(r->per_dir_config, &dav_module);
27352817

27362818
/* handle the request body */
27372819
/* ### this may move lower once we start processing bodies */
@@ -2759,6 +2841,17 @@ static int dav_method_mkcol(request_rec *r)
27592841
return HTTP_METHOD_NOT_ALLOWED;
27602842
}
27612843

2844+
/* try parsing x-oc-mtime header */
2845+
mtime_ret = 0;
2846+
if (conf->honor_mtime_header == DAV_ENABLED_ON) {
2847+
if ((mtime_ret = dav_parse_mtime(r, &mtime)) == -1) {
2848+
return dav_error_response(r, HTTP_BAD_REQUEST,
2849+
apr_psprintf(r->pool,
2850+
"Malformed X-OC-Mtime header for MKCOL %s.",
2851+
ap_escape_html(r->pool, r->uri)));
2852+
}
2853+
}
2854+
27622855
resource_state = dav_get_resource_state(r, resource);
27632856

27642857
/*
@@ -2839,6 +2932,25 @@ static int dav_method_mkcol(request_rec *r)
28392932
}
28402933
}
28412934

2935+
if (mtime_ret == 1) {
2936+
if (resource->hooks->set_mtime != NULL) {
2937+
err = (resource->hooks->set_mtime)(resource, mtime);
2938+
if (err != NULL) {
2939+
err = dav_push_error(r->pool, err->status, 0,
2940+
"The MKCOL was successful, but there "
2941+
"was a problem setting its modification time.",
2942+
err);
2943+
return dav_handle_err(r, err, NULL);
2944+
}
2945+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2946+
"Setting modification time for directory.");
2947+
}
2948+
else {
2949+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2950+
"Provider does not support setting modification times.");
2951+
}
2952+
}
2953+
28422954
/* return an appropriate response (HTTP_CREATED) */
28432955
rc = dav_created(r, NULL, "Collection", 0);
28442956

@@ -5345,6 +5457,11 @@ static const command_rec dav_cmds[] =
53455457
ACCESS_CONF|RSRC_CONF,
53465458
"allow lock discovery by PROPFIND requests"),
53475459

5460+
/* per directory/location */
5461+
AP_INIT_FLAG("DAVHonorMtimeHeader", dav_cmd_davhonormtimeheader, NULL,
5462+
ACCESS_CONF,
5463+
"Set modification time based on X-OC-Mtime header"),
5464+
53485465
/* per directory/location, or per server */
53495466
AP_INIT_ITERATE("DAVMSext", dav_cmd_davmsext, NULL,
53505467
ACCESS_CONF|RSRC_CONF,

modules/dav/main/mod_dav.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,10 @@ struct dav_hooks_repository
21662166

21672167
/* Get the pathname for a resource */
21682168
const char * (*get_pathname)(const dav_resource *resource);
2169+
2170+
/* Set modification time for a resource. Can be NULL. */
2171+
dav_error * (*set_mtime)(dav_resource *resource, const apr_time_t mtime);
2172+
21692173
};
21702174

21712175

0 commit comments

Comments
 (0)