Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
de7be9c
modules/dav/main/mod_dav.h: define callback `set_mtime` for `struct d…
leo9800 Sep 4, 2025
e77869f
modules/dav/main/mod_dav.c: add new config flag `DavHonorMtimeHeader`
leo9800 Sep 4, 2025
86e42ae
modules/dav/main/mod_dav.c: implement `dav_parse_range`
leo9800 Sep 4, 2025
177801f
modules/dav/main/mod_dav.c: parse x-oc-mtime for PUT requests
leo9800 Sep 4, 2025
66a7657
modules/dav/main/mod_dav.c: only try parse X-Oc-Mtime header and set …
leo9800 Sep 9, 2025
8217af3
modules/dav/fs/repos.c: return 500 instead of 400 upon `apr_file_mtim…
leo9800 Sep 9, 2025
32a4cce
modules/dav/main/mod_dav.c: fix type on request method in error message
leo9800 Sep 20, 2025
76ee8e0
modules/dav/main/mod_dav.c: bugfix: retrieve module config at the ver…
leo9800 Sep 20, 2025
16ec946
modules/dav/main/mod_dav.c: parse x-oc-mtime for MKCOL requests
leo9800 Sep 20, 2025
18c79d2
modules/dav/main/mod_dav.c: code style fixes
leo9800 Sep 23, 2025
b776d4d
modules/dav/main/mod_dav.c: zero-ing `errno` before `apr_strtoi64()` …
leo9800 Sep 23, 2025
44959b9
modules/dav/main/mod_dav.c: use proper language in logs, avoid unnece…
leo9800 Sep 23, 2025
a14efe0
modules/dav/fs/repo.c: avoid unnecessary `apr_strerror` invocation
leo9800 Sep 23, 2025
de608fd
modules/dav/fs/repos.c, modules/dav/main/mod_dav.c: remove APLOGNO() …
leo9800 Sep 30, 2025
ca3b037
modules/dav/fs/repo.c, docs/log-message-tags/next-number: `update-log…
leo9800 Sep 30, 2025
f2d3df8
modules/dav/main/mod_dav.c: rephrase log messages when setting modifi…
leo9800 Sep 30, 2025
87ce719
modules/dav/main/mod_dav.c: `dav_parse_mtime()`: ensure C89 conformity
leo9800 Oct 2, 2025
8170906
modules/dav/main/mod_dav.c: compile errors fixes
leo9800 Oct 2, 2025
f4128dd
modules/dav/fs/repos.c, docs/log-message-tags/next-number: reset `APL…
leo9800 Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/log-message-tags/next-number
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10543
10544
21 changes: 20 additions & 1 deletion modules/dav/fs/repos.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down
120 changes: 119 additions & 1 deletion modules/dav/main/mod_dav.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -947,6 +964,37 @@ static int dav_parse_range(request_rec *r,
return 1;
}

/**
* @return 1 if valid x-oc-mtime,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this with an apr_status_t return value, though it's a minor question of style

Copy link
Author

@leo9800 leo9800 Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am not sure if apr_status_t is proper for this case personally.

since 0 is defined as APR_SUCCESS, while for the returning value of this function both 1 and 0 are considered success, and -1 stands for a failure.

actually i was imitating static int dav_parse_range(request_rec *r, apr_off_t *range_start, apr_off_t *range_end) in mod_dav.c

* 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)
{
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -1207,7 +1271,21 @@ 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.");
}
}
}

/*
Expand Down Expand Up @@ -1240,7 +1318,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);

Expand Down Expand Up @@ -2732,6 +2809,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 */
Expand Down Expand Up @@ -2759,6 +2842,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);

/*
Expand Down Expand Up @@ -2839,6 +2933,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);

Expand Down Expand Up @@ -5345,6 +5458,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,
Expand Down
7 changes: 7 additions & 0 deletions modules/dav/main/mod_dav.h
Original file line number Diff line number Diff line change
Expand Up @@ -2166,6 +2166,13 @@ struct dav_hooks_repository

/* Get the pathname for a resource */
const char * (*get_pathname)(const dav_resource *resource);

/* Set modification time for a resource */
dav_error * (*set_mtime)(
dav_resource *resource,
const apr_time_t mtime
);

};


Expand Down