You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2020/06/29 16:21:52 UTC

svn commit: r1879339 - in /httpd/httpd/trunk: CHANGES include/ap_mmn.h modules/dav/main/mod_dav.c modules/dav/main/mod_dav.h

Author: minfrin
Date: Mon Jun 29 16:21:52 2020
New Revision: 1879339

URL: http://svn.apache.org/viewvc?rev=1879339&view=rev
Log:
mod_dav: Add method_precondition hook. WebDAV extensions define
conditions that must exist before a WebDAV method can be executed.
This hook allows a WebDAV extension to verify these preconditions.

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/modules/dav/main/mod_dav.c
    httpd/httpd/trunk/modules/dav/main/mod_dav.h

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1879339&r1=1879338&r2=1879339&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Mon Jun 29 16:21:52 2020
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.1
 
+  *) mod_dav: Add method_precondition hook. WebDAV extensions define
+     conditions that must exist before a WebDAV method can be executed.
+     This hook allows a WebDAV extension to verify these preconditions.
+     [Graham Leggett]
+
   *) Add hooks deliver_report and gather_reports to mod_dav.h. Allows other
      modules apart from versioning implementations to handle the REPORT method.
      [Graham Leggett]

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1879339&r1=1879338&r2=1879339&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Mon Jun 29 16:21:52 2020
@@ -645,6 +645,7 @@
  *                         dav_close_lockdb() mod_dav.h.
  * 20200420.9 (2.5.1-dev)  Add hooks deliver_report and gather_reports to
  *                         mod_dav.h.
+ * 20200420.10 (2.5.1-dev) Add method_precondition hook to mod_dav.h.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -652,7 +653,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20200420
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 9            /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 10            /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/trunk/modules/dav/main/mod_dav.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/dav/main/mod_dav.c?rev=1879339&r1=1879338&r2=1879339&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/dav/main/mod_dav.c (original)
+++ httpd/httpd/trunk/modules/dav/main/mod_dav.c Mon Jun 29 16:21:52 2020
@@ -874,7 +874,13 @@ static int dav_method_get(request_rec *r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
-    if (!resource->exists) {
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+	if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
     }
@@ -921,6 +927,12 @@ static int dav_method_post(request_rec *
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* Note: depth == 0. Implies no need for a multistatus response. */
     if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
                                     DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
@@ -955,6 +967,12 @@ static int dav_method_put(request_rec *r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* If not a file or collection resource, PUT not allowed */
     if (resource->type != DAV_RESOURCE_TYPE_REGULAR
         && resource->type != DAV_RESOURCE_TYPE_WORKING) {
@@ -1239,6 +1257,13 @@ static int dav_method_delete(request_rec
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
+
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -1686,6 +1711,12 @@ static int dav_method_options(request_re
     }
     /* note: doc == NULL if no request body */
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (doc && !dav_validate_root(doc, "options")) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00584)
                       "The \"options\" element was not found.");
@@ -2101,6 +2132,17 @@ static int dav_method_propfind(request_r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    if ((result = ap_xml_parse_input(r, &doc)) != OK) {
+        return result;
+    }
+    /* note: doc == NULL if no request body */
+
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -2128,11 +2170,6 @@ static int dav_method_propfind(request_r
         }
     }
 
-    if ((result = ap_xml_parse_input(r, &doc)) != OK) {
-        return result;
-    }
-    /* note: doc == NULL if no request body */
-
     if (doc && !dav_validate_root(doc, "propfind")) {
         /* This supplies additional information for the default message. */
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00585)
@@ -2378,16 +2415,23 @@ static int dav_method_proppatch(request_
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
-    if (!resource->exists) {
-        /* Apache will supply a default error for this. */
-        return HTTP_NOT_FOUND;
-    }
 
     if ((result = ap_xml_parse_input(r, &doc)) != OK) {
         return result;
     }
     /* note: doc == NULL if no request body */
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+    if (!resource->exists) {
+        /* Apache will supply a default error for this. */
+        return HTTP_NOT_FOUND;
+    }
+
     if (doc == NULL || !dav_validate_root(doc, "propertyupdate")) {
         /* This supplies additional information for the default message. */
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00587)
@@ -2594,6 +2638,12 @@ static int dav_method_mkcol(request_rec
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (resource->exists) {
         /* oops. something was already there! */
 
@@ -2723,6 +2773,12 @@ static int dav_method_copymove(request_r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -2789,6 +2845,12 @@ static int dav_method_copymove(request_r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, resnew, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* are the two resources handled by the same repository? */
     if (resource->hooks != resnew->hooks) {
         /* ### this message exposes some backend config, but screw it... */
@@ -3151,6 +3213,12 @@ static int dav_method_lock(request_rec *
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* Check if parent collection exists */
     if ((err = resource->hooks->get_parent_resource(resource, &parent)) != NULL) {
         /* ### add a higher-level description? */
@@ -3350,6 +3418,12 @@ static int dav_method_unlock(request_rec
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     resource_state = dav_get_resource_state(r, resource);
 
     /*
@@ -3409,15 +3483,21 @@ static int dav_method_vsn_control(reques
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
-    /* remember the pre-creation resource state */
-    resource_state = dav_get_resource_state(r, resource);
-
     /* parse the request body (may be a version-control element) */
     if ((result = ap_xml_parse_input(r, &doc)) != OK) {
         return result;
     }
     /* note: doc == NULL if no request body */
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
+    /* remember the pre-creation resource state */
+    resource_state = dav_get_resource_state(r, resource);
+
     if (doc != NULL) {
         const apr_xml_elem *child;
         apr_size_t tsize;
@@ -3662,6 +3742,12 @@ static int dav_method_checkout(request_r
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -3738,6 +3824,12 @@ static int dav_method_uncheckout(request
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -3815,6 +3907,12 @@ static int dav_method_checkin(request_re
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -3936,6 +4034,12 @@ static int dav_method_update(request_rec
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -4081,11 +4185,23 @@ static int dav_method_label(request_rec
     if (vsn_hooks == NULL || vsn_hooks->add_label == NULL)
         return DECLINED;
 
+    /* parse the request body */
+    if ((result = ap_xml_parse_input(r, &doc)) != OK) {
+        return result;
+    }
+
     /* Ask repository module to resolve the resource */
     err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
+
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -4097,11 +4213,6 @@ static int dav_method_label(request_rec
         return HTTP_BAD_REQUEST;
     }
 
-    /* parse the request body */
-    if ((result = ap_xml_parse_input(r, &doc)) != OK) {
-        return result;
-    }
-
     if (doc == NULL || !dav_validate_root(doc, "label")) {
         /* This supplies additional information for the default message. */
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00610)
@@ -4261,6 +4372,12 @@ static int dav_method_report(request_rec
         return dav_handle_err(r, err, NULL);
     }
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -4331,6 +4448,12 @@ static int dav_method_make_workspace(req
         return result;
     }
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (doc == NULL
         || !dav_validate_root(doc, "mkworkspace")) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00615)
@@ -4390,6 +4513,12 @@ static int dav_method_make_activity(requ
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* MKACTIVITY does not have a defined request body. */
     if ((result = ap_discard_request_body(r)) != OK) {
         return result;
@@ -4515,6 +4644,12 @@ static int dav_method_merge(request_rec
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, source_resource, NULL, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     no_auto_merge = dav_find_child(doc->root, "no-auto-merge") != NULL;
     no_checkout = dav_find_child(doc->root, "no-checkout") != NULL;
 
@@ -4532,6 +4667,13 @@ static int dav_method_merge(request_rec
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
+
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, source_resource, resource, doc, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -4599,6 +4741,12 @@ static int dav_method_bind(request_rec *
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, NULL, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     if (!resource->exists) {
         /* Apache will supply a default error for this. */
         return HTTP_NOT_FOUND;
@@ -4649,6 +4797,12 @@ static int dav_method_bind(request_rec *
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
+    /* check for any method preconditions */
+	if (dav_run_method_precondition(r, resource, binding, NULL, &err) != DECLINED
+            && err) {
+        return dav_handle_err(r, err, NULL);
+    }
+
     /* are the two resources handled by the same repository? */
     if (resource->hooks != binding->hooks) {
         /* ### this message exposes some backend config, but screw it... */
@@ -5067,6 +5221,7 @@ APR_HOOK_STRUCT(
     APR_HOOK_LINK(insert_all_liveprops)
     APR_HOOK_LINK(deliver_report)
     APR_HOOK_LINK(gather_reports)
+    APR_HOOK_LINK(method_precondition)
     )
 
 APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, gather_propsets,
@@ -5096,3 +5251,9 @@ APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DA
                                     apr_array_header_t *reports, dav_error **err),
                                    (r, resource, reports, err))
 
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dav, DAV, int, method_precondition,
+                                      (request_rec *r,
+                                       dav_resource *src, dav_resource *dest,
+                                       const apr_xml_doc *doc,
+                                       dav_error **err),
+                                       (r, src, dest, doc, err), DECLINED)

Modified: httpd/httpd/trunk/modules/dav/main/mod_dav.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/dav/main/mod_dav.h?rev=1879339&r1=1879338&r2=1879339&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/dav/main/mod_dav.h (original)
+++ httpd/httpd/trunk/modules/dav/main/mod_dav.h Mon Jun 29 16:21:52 2020
@@ -744,6 +744,32 @@ APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void
                           (request_rec *r, const dav_resource *resource,
                            apr_array_header_t *reports, dav_error **err))
 
+/*
+ ** method_precondition: check method preconditions.
+ **
+ ** If a WebDAV extension needs to set any preconditions on a method, this
+ ** hook is where to do it. If the precondition fails, return an error
+ ** response with the tagname set to the value of the failed precondition.
+ **
+ ** If the method requires an XML body, this will be read and provided as
+ ** the doc value. If not, doc is NULL. An extension that needs to verify
+ ** the non-XML body of a request should register an input filter to do so
+ ** within this hook.
+ **
+ ** Methods like PUT will supply a single src resource, and the dest will
+ ** be NULL.
+ **
+ ** Methods like COPY or MOVE will trigger this hook twice. The first
+ ** invocation will supply just the source resource. The second invocation
+ ** will supply a source and destination. This allows preconditions on the
+ ** source resource to be verified before making an attempt to get the
+ ** destination resource.
+ */
+APR_DECLARE_EXTERNAL_HOOK(dav, DAV, int, method_precondition,
+                          (request_rec *r,
+                           dav_resource *src, dav_resource *dst,
+                           const apr_xml_doc *doc, dav_error **err))
+
 
 DAV_DECLARE(const dav_hooks_locks *) dav_get_lock_hooks(request_rec *r);
 DAV_DECLARE(const dav_hooks_propdb *) dav_get_propdb_hooks(request_rec *r);