summaryrefslogtreecommitdiff
path: root/modules/dav
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2020-06-29 16:21:52 +0000
committerGraham Leggett <minfrin@apache.org>2020-06-29 16:21:52 +0000
commitb1b9013a4c7e846ca750e99f57dd41afbe6c168b (patch)
tree014b66ec8c22d6a0cbaec6507727762d6ee7db1a /modules/dav
parenta1ffe6bfede1f31cce12527e1c7a62642beafc6e (diff)
downloadhttpd-b1b9013a4c7e846ca750e99f57dd41afbe6c168b.tar.gz
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. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1879339 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/dav')
-rw-r--r--modules/dav/main/mod_dav.c197
-rw-r--r--modules/dav/main/mod_dav.h26
2 files changed, 205 insertions, 18 deletions
diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c
index 1abf5b9cd6..3d8393ff31 100644
--- a/modules/dav/main/mod_dav.c
+++ b/modules/dav/main/mod_dav.c
@@ -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 *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);
+ }
+
/* 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 *r)
&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_rec *r)
}
/* 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_rec *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_rec *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_rec *r)
&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 *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) {
/* oops. something was already there! */
@@ -2723,6 +2773,12 @@ static int dav_method_copymove(request_rec *r, int is_move)
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_rec *r, int is_move)
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 *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);
+ }
+
/* 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 *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);
+ }
+
resource_state = dav_get_resource_state(r, resource);
/*
@@ -3409,15 +3483,21 @@ static int dav_method_vsn_control(request_rec *r)
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_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, 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_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 (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
@@ -3815,6 +3907,12 @@ static int dav_method_checkin(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, 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 *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;
@@ -4081,11 +4185,23 @@ static int dav_method_label(request_rec *r)
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 *r)
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 *r)
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(request_rec *r)
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(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);
+ }
+
/* 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 *r)
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 *r)
&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 *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;
@@ -4649,6 +4797,12 @@ static int dav_method_bind(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, 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, DAV, gather_reports,
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)
diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h
index 56ce428706..7b51b604f9 100644
--- a/modules/dav/main/mod_dav.h
+++ b/modules/dav/main/mod_dav.h
@@ -744,6 +744,32 @@ APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, gather_reports,
(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);