@@ -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 */
951999static 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 ,
0 commit comments