]> granicus.if.org Git - apache/commitdiff
Revamp the CHECKOUT method handling and various support functions for it.
authorGreg Stein <gstein@apache.org>
Wed, 7 Feb 2001 12:33:17 +0000 (12:33 +0000)
committerGreg Stein <gstein@apache.org>
Wed, 7 Feb 2001 12:33:17 +0000 (12:33 +0000)
Basically, the original CHECKOUT was based on a really old draft of the
DeltaV specification. This brings it up to date.

*) get_resource hook now takes an optional label name and/or a flag on
   whether to use the DAV:checked-in property; if either one is provided,
   then a version resource is looked up and returned.

   WARNING: the parameter types are now the same, but have very different
    semantics. this means you won't get a compile error to figure
    out that something needs to be changed here.

*) mod_dav.c::dav_get_resource no longer cahces the fetched resource in the
   request userdata. Some requests will call this function multiple times,
   for different resources -- we don't want to keep returning the same
   resource (no idea how this ended up working).

*) dav_get_resource()'s parameters have been updated. target_allowed is old
   terminology; it is now label_allowed. The target paramter is obsoleted by
   the simple use_checked_in flag.

*) dav_get_target_selector() is obsolete. XML element processing is done
   within the CHECKOUT method (i.e. only where it occurs). The other half of
   the old function was to simply fetch the Label: header.

*) DAV_TARGET_SELECTOR_HDR is now DAV_LABEL_HDR

*) dav_method_checkout() now processes all the various options for a
   CHECKOUT method and either modifies the initial resource lookup, or
   passes the data to the checkout hook function.

*) the checkout hook grew a bunch of new parameters

*) new utility function: dav_xml_get_cdata() to gather up all the CDATA from
   an XML element. this is used to extract DAV:href values.
   (probably move to util_xml.c at some point)

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88007 13f79535-47bb-0310-9956-ffa450edef68

modules/dav/fs/repos.c
modules/dav/main/mod_dav.c
modules/dav/main/mod_dav.h
modules/dav/main/util.c

index c5917dccb80f1fb1306ef50d8e23a2b533d44192..5ee6e40c94d3bb98486cc5e00da4b0c5b08164f5 100644 (file)
@@ -594,8 +594,8 @@ static dav_error *dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource)
 static dav_error * dav_fs_get_resource(
     request_rec *r,
     const char *root_dir,
-    const char *target,
-    int is_label,
+    const char *label,
+    int use_checked_in,
     dav_resource **result_resource)
 {
     dav_resource_private *ctx;
index 06dd4bf3270ad62ab64c8be476383cfae9af539b..df4b893cc25693e74f96a3d62b419d770621f9aa 100644 (file)
@@ -346,6 +346,8 @@ static const char *dav_cmd_davparam(cmd_parms *cmd, void *config,
 ** Send a nice response back to the user. In most cases, Apache doesn't
 ** allow us to provide details in the body about what happened. This
 ** function allows us to completely specify the response body.
+**
+** ### this function is not logging any errors! (e.g. the body)
 */
 static int dav_error_response(request_rec *r, int status, const char *body)
 {
@@ -614,35 +616,24 @@ static int dav_get_overwrite(request_rec *r)
 }
 
 /* resolve a request URI to a resource descriptor.
- * If target_allowed != 0, then allow the request target to be overridden
- * by either a DAV:version or DAV:label-name element (passed as
- * the target argument), or any Target-Selector header in the request.
+ *
+ * If label_allowed != 0, then allow the request target to be altered by
+ * a Label: header.
+ *
+ * If use_checked_in is true, then the repository provider should return
+ * the resource identified by the DAV:checked-in property of the resource
+ * identified by the Request-URI.
  */
-static dav_error * dav_get_resource(request_rec *r, int target_allowed,
-                                    ap_xml_elem *target, dav_resource **res_p)
+static dav_error * dav_get_resource(request_rec *r, int label_allowed,
+                                    int use_checked_in, dav_resource **res_p)
 {
-    void *data;
     dav_dir_conf *conf;
-    const char *target_selector = NULL;
-    int is_label = 0;
-    int result;
+    const char *label = NULL;
     dav_error *err;
 
-    /* only look for the resource if it isn't already present */
-    (void) apr_get_userdata(&data, DAV_KEY_RESOURCE, r->pool);
-    if (data != NULL) {
-        *res_p = data;
-        return NULL;
-    }
-
     /* if the request target can be overridden, get any target selector */
-    if (target_allowed) {
-        /* ### this should return a dav_error* */
-        if ((result = dav_get_target_selector(r, target,
-                                              &target_selector,
-                                              &is_label)) != OK)
-            return dav_new_error(r->pool, result, 0,
-                                 "Could not process the method target.");
+    if (label_allowed) {
+        label = apr_table_get(r->headers_in, "label");
     }
 
     conf = ap_get_module_config(r->per_dir_config, &dav_module);
@@ -650,7 +641,7 @@ static dav_error * dav_get_resource(request_rec *r, int target_allowed,
 
     /* resolve the resource */
     err = (*conf->provider->repos->get_resource)(r, conf->dir,
-                                                 target_selector, is_label,
+                                                 label, use_checked_in,
                                                  res_p);
     if (err != NULL) {
         err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
@@ -668,9 +659,6 @@ static dav_error * dav_get_resource(request_rec *r, int target_allowed,
                                           ap_escape_html(r->pool, r->uri)));
     }
 
-    (void) apr_set_userdata(*res_p, DAV_KEY_RESOURCE, apr_null_cleanup,
-                            r->pool);
-
     /* ### hmm. this doesn't feel like the right place or thing to do */
     /* if there were any input headers requiring a Vary header in the response,
      * add it now */
@@ -736,7 +724,8 @@ static int dav_method_get(request_rec *r)
      * visible to Apache. We will fetch the resource from the repository,
      * then create a subrequest for Apache to handle.
      */
-    err = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -930,7 +919,8 @@ static int dav_method_post(request_rec *r)
     dav_error *err;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -967,7 +957,8 @@ static int dav_method_put(request_rec *r)
     }
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -1181,7 +1172,8 @@ static int dav_method_delete(request_rec *r)
     }
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -1538,7 +1530,8 @@ static int dav_method_options(request_rec *r)
     dav_error *err;
 
     /* resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -1890,7 +1883,8 @@ static int dav_method_propfind(request_rec *r)
     dav_response *multi_status;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -2154,7 +2148,8 @@ static int dav_method_proppatch(request_rec *r)
     dav_prop_ctx *ctx;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -2354,7 +2349,8 @@ static int dav_method_mkcol(request_rec *r)
                                                 &dav_module);
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -2473,7 +2469,8 @@ static int dav_method_copymove(request_rec *r, int is_move)
     int resource_state;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, !is_move /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, !is_move /* label_allowed */,
+                           0 /* use_checked_in */, &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -2527,7 +2524,8 @@ static int dav_method_copymove(request_rec *r, int is_move)
     }
 
     /* Resolve destination resource */
-    err = dav_get_resource(lookup.rnew, 0 /*target_allowed*/, NULL, &resnew);
+    err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
+                           0 /* use_checked_in */, &resnew);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -2856,7 +2854,9 @@ static int dav_method_lock(request_rec *r)
      * so allow it, and let provider reject the lock attempt
      * on a version if it wants to.
      */
-    err = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
+    /* ### gjs: I'm not sure we want to allow for locking a version... */
+    err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -3043,7 +3043,9 @@ static int dav_method_unlock(request_rec *r)
      * so allow it, and let provider reject the unlock attempt
      * on a version if it wants to.
      */
-    err = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
+    /* ### gjs: I'm not sure we want to allow for locking a version... */
+    err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -3101,7 +3103,8 @@ static int dav_method_vsn_control(request_rec *r)
         return DECLINED;
 
     /* ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -3279,7 +3282,11 @@ static int dav_method_checkout(request_rec *r)
     dav_error *err;
     int result;
     ap_xml_doc *doc;
-    ap_xml_elem *target = NULL;
+    int apply_to_vsn = 0;
+    int is_unreserved = 0;
+    int is_fork_ok = 0;
+    int create_activity = 0;
+    apr_array_header_t *activities = NULL;
 
     /* If no versioning provider, decline the request */
     if (vsn_hooks == NULL)
@@ -3289,6 +3296,8 @@ static int dav_method_checkout(request_rec *r)
        return result;
 
     if (doc != NULL) {
+        const ap_xml_elem *aset;
+
         if (!dav_validate_root(doc, "checkout")) {
             /* This supplies additional information for the default msg. */
             ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
@@ -3297,12 +3306,57 @@ static int dav_method_checkout(request_rec *r)
             return HTTP_BAD_REQUEST;
         }
 
-        if ((target = dav_find_child(doc->root, "version")) == NULL)
-            target = dav_find_child(doc->root, "label-name");
+        if (dav_find_child(doc->root, "apply-to-version") != NULL) {
+            if (apr_table_get(r->headers_in, "label") != NULL) {
+                /* ### we want generic 403/409 XML reporting here */
+                /* ### DAV:must-not-have-label-and-apply-to-version */
+                return dav_error_response(r, HTTP_CONFLICT,
+                                          "DAV:apply-to-version cannot be "
+                                          "used in conjunction with a "
+                                          "Label header.");
+            }
+            apply_to_vsn = 1;
+        }
+
+        is_unreserved = dav_find_child(doc->root, "unreserved") != NULL;
+        is_fork_ok = dav_find_child(doc->root, "fork-ok") != NULL;
+
+        if ((aset = dav_find_child(doc->root, "activity-set")) != NULL) {
+            if (dav_find_child(aset, "new") != NULL) {
+                create_activity = 1;
+            }
+            else {
+                const ap_xml_elem *child = aset->first_child;
+
+                for (; child != NULL; child = child->next) {
+                    if (child->ns == AP_XML_NS_DAV_ID
+                        && strcmp(child->name, "href") == 0) {
+                        const char *href;
+
+                        href = dav_xml_get_cdata(child, r->pool,
+                                                 1 /* strip_white */);
+                        *(const char **)apr_push_array(activities) = href;
+                    }
+                }
+
+                if (activities->nelts == 0) {
+                    /* no href's is a DTD violation:
+                       <!ELEMENT activity-set (href+ | new)>
+                    */
+
+                    /* This supplies additional info for the default msg. */
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                                  "Within the DAV:activity-set element, the "
+                                  "DAV:new element must be used, or at least "
+                                  "one DAV:href must be specified.");
+                    return HTTP_BAD_REQUEST;
+                }
+            }
+        }
     }
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 1 /*target_allowed*/, target, &resource);
+    err = dav_get_resource(r, 1 /*label_allowed*/, apply_to_vsn, &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3331,7 +3385,9 @@ static int dav_method_checkout(request_rec *r)
     /* ### do lock checks, once behavior is defined */
 
     /* Do the checkout */
-    if ((err = (*vsn_hooks->checkout)(resource, &working_resource)) != NULL) {
+    if ((err = (*vsn_hooks->checkout)(resource, is_unreserved, is_fork_ok,
+                                      create_activity, activities,
+                                      &working_resource)) != NULL) {
        err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
                             apr_psprintf(r->pool,
                                         "Could not CHECKOUT resource %s.",
@@ -3367,7 +3423,8 @@ static int dav_method_uncheckout(request_rec *r)
     }
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3430,7 +3487,8 @@ static int dav_method_checkin(request_rec *r)
     }
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /* target_allowed */, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3536,7 +3594,8 @@ static int dav_method_set_target(request_rec *r)
         return DECLINED;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3718,7 +3777,8 @@ static int dav_method_label(request_rec *r)
         return DECLINED;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3829,7 +3889,7 @@ static int dav_method_report(request_rec *r)
     dav_resource *resource;
     const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
     int result;
-    int target_allowed;
+    int label_allowed;
     ap_xml_doc *doc;
     ap_text_header hdr = { 0 };
     ap_text *t;
@@ -3852,8 +3912,9 @@ static int dav_method_report(request_rec *r)
      * First determine whether a Target-Selector header is allowed
      * for this report.
      */
-    target_allowed = (*vsn_hooks->report_target_selector_allowed)(doc);
-    err = dav_get_resource(r, target_allowed, NULL, &resource);
+    label_allowed = (*vsn_hooks->report_target_selector_allowed)(doc);
+    err = dav_get_resource(r, label_allowed, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -3900,7 +3961,8 @@ static int dav_method_make_workspace(request_rec *r)
         return DECLINED;
 
     /* ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -3963,7 +4025,8 @@ static int dav_method_make_activity(request_rec *r)
         return DECLINED;
 
     /* ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
@@ -4034,7 +4097,8 @@ static int dav_method_bind(request_rec *r)
         return DECLINED;
 
     /* Ask repository module to resolve the resource */
-    err = dav_get_resource(r, 0 /*!target_allowed*/, NULL, &resource);
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
+                           &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
     if (!resource->exists) {
@@ -4081,7 +4145,8 @@ static int dav_method_bind(request_rec *r)
     }
 
     /* resolve binding resource */
-    err = dav_get_resource(lookup.rnew, 0 /*!target_allowed*/, NULL, &binding);
+    err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
+                           0 /* use_checked_in */, &binding);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
 
index a73f12901a6a8433c496c3f869c272cafa95f57e..70e29c2d9fe96e4a1f0354b63b328beeef1089a6 100644 (file)
 #ifndef _MOD_DAV_H_
 #define _MOD_DAV_H_
 
-#include "httpd.h"
-#include "util_xml.h"
 #include "apr_hooks.h"
 #include "apr_hash.h"
 #include "apr_dbm.h"
+#include "apr_tables.h"
+
+#include "httpd.h"
+#include "util_xml.h"
 
 #include <limits.h>     /* for INT_MAX */
 
@@ -519,6 +521,10 @@ int dav_get_depth(request_rec *r, int def_depth);
 int dav_validate_root(const ap_xml_doc *doc, const char *tagname);
 ap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname);
 
+/* gather up all the CDATA into a single string */
+const char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool,
+                              int strip_white);
+
 
 /* --------------------------------------------------------------------
 **
@@ -599,9 +605,6 @@ APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, insert_all_liveprops,
                          (request_rec *r, const dav_resource *resource,
                           dav_prop_insert what, ap_text_header *phdr))
 
-/* ### make this internal to mod_dav.c ? */
-#define DAV_KEY_RESOURCE        "dav-resource"
-
 const dav_hooks_locks *dav_get_lock_hooks(request_rec *r);
 const dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r);
 const dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r);
@@ -1573,11 +1576,17 @@ struct dav_hooks_repository
      * URI or accessing the resource or whatever, then an error should be
      * returned.
      *
-     * root_dir: the root of the directory for which this repository is
-     *           configured.
-     * target: is either a label, or a version URI, or NULL. If there is
-     *         a target, then is_label specifies whether the target is a
-     *         label or a URI.
+     * root_dir:
+     *   the root of the directory for which this repository is configured.
+     *
+     * label:
+     *   if a Label: header is present (and allowed), this is the label
+     *   to use to identify a version resource from the resource's
+     *   corresponding version history. Otherwise, it will be NULL.
+     *
+     * use_checked_in:
+     *   use the DAV:checked-in property of the resource identified by the
+     *   Request-URI to identify and return a version resource
      *
      * The provider may associate the request storage pool with the resource
      * (in the resource->pool field), to use in other operations on that
@@ -1586,8 +1595,8 @@ struct dav_hooks_repository
     dav_error * (*get_resource)(
         request_rec *r,
         const char *root_dir,
-       const char *target,
-        int is_label,
+       const char *label,
+        int use_checked_in,
         dav_resource **resource
     );
 
@@ -1786,25 +1795,6 @@ struct dav_hooks_repository
 */
 
 
-/*
- * dav_get_target_selector
- *
- * If a DAV:version or DAV:label-name element is provided,
- * then it is assumed to provide the target version.
- * If no element is provided (version==NULL), then the
- * request headers are examined for a Target-Selector header.
- *
- * The target version, if any, is then returned. If the version
- * was specified by a label, then *is_label is set to 1.
- * Otherwise, the target is a version URI.
- *
- * (used by versioning clients)
- */
-int dav_get_target_selector(request_rec *r,
-                            const ap_xml_elem *version,
-                            const char **target,
-                            int *is_label);
-
 /* dav_add_vary_header
  *
  * If there were any headers in the request which require a Vary header
@@ -1925,8 +1915,19 @@ struct dav_hooks_vsn
      * resource descriptor will refer to the working resource.
      * The working_resource argument can be NULL if the caller
      * is not interested in the working resource.
+     *
+     * If the client has specified DAV:unreserved or DAV:fork-ok in the
+     * checkout request, then the corresponding flags are set. If
+     * DAV:activity-set has been specified, then create_activity is set
+     * if DAV:new was specified; otherwise, the DAV:href elements' CDATA
+     * (the actual href text) is passed in the "activities" array (each
+     * element of the array is a const char *). activities will be NULL
+     * no DAV:activity-set was provided or when create_activity is set.
      */
     dav_error * (*checkout)(dav_resource *resource,
+                            int is_unreserved, int is_fork_ok,
+                            int create_activity,
+                            apr_array_header_t *activities,
                             dav_resource **working_resource);
 
     /* Uncheckout a resource. If successful, the resource
index 51ca37a3435bea4763ae05f8af69c5d564cfac3f..041355c9889b31ff190c5add6885fdc53779a80d 100644 (file)
@@ -305,6 +305,61 @@ ap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname)
     return NULL;
 }
 
+/* gather up all the CDATA into a single string */
+const char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool,
+                              int strip_white)
+{
+    apr_size_t len = 0;
+    ap_text *scan;
+    const ap_xml_elem *child;
+    char *cdata;
+    char *s;
+    apr_size_t tlen;
+
+    for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next)
+        len += strlen(scan->text);
+
+    for (child = elem->first_child; child != NULL; child = child->next) {
+        for (scan = child->following_cdata.first;
+             scan != NULL;
+             scan = scan->next)
+            len += strlen(scan->text);
+    }
+
+    cdata = s = apr_palloc(pool, len + 1);
+
+    for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
+        tlen = strlen(scan->text);
+        memcpy(s, scan->text, tlen);
+        s += tlen;
+    }
+
+    for (child = elem->first_child; child != NULL; child = child->next) {
+        for (scan = child->following_cdata.first;
+             scan != NULL;
+             scan = scan->next) {
+            tlen = strlen(scan->text);
+            memcpy(s, scan->text, tlen);
+            s += tlen;
+        }
+    }
+
+    *s = '\0';
+
+    if (strip_white && len > 0) {
+        /* trim leading whitespace */
+        while (apr_isspace(*cdata))     /* assume: return false for '\0' */
+            ++cdata;
+
+        /* trim trailing whitespace */
+        while (len-- > 0 && apr_isspace(cdata[len]))
+            continue;
+        cdata[len + 1] = '\0';
+    }
+
+    return cdata;
+}
+
 /* ---------------------------------------------------------------
 **
 ** Timeout header processing
@@ -1492,6 +1547,8 @@ dav_error * dav_get_locktoken_list(request_rec *r, dav_locktoken_list **ltl)
     return NULL;
 }
 
+#if 0 /* not needed right now... */
+
 static const char *strip_white(const char *s, apr_pool_t *pool)
 {
     apr_size_t idx;
@@ -1513,53 +1570,9 @@ static const char *strip_white(const char *s, apr_pool_t *pool)
 
     return s;
 }
+#endif
 
-#define DAV_TARGET_SELECTOR_HDR "Target-Selector"
-
-/* see mod_dav.h for docco */
-int dav_get_target_selector(request_rec *r,
-                            const ap_xml_elem *version,
-                            const char **target,
-                            int *is_label)
-{
-    /* Initialize results */
-    *target = NULL;
-    *is_label = 0;
-
-    if (version != NULL) {
-        /* Expect either <DAV:version><DAV:href>URI</DAV:href></DAV:version>
-         * or <DAV:label-name>LABEL</DAV:label-name> */
-        if (strcmp(version->name, "version") == 0) {
-            if ((version = dav_find_child(version, "href")) == NULL) {
-               ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
-                             "Missing DAV:href in DAV:version element");
-                return HTTP_BAD_REQUEST;
-            }
-
-            /* return the contents of the DAV:href element */
-            /* ### this presumes no child elements */
-            *target = strip_white(version->first_cdata.first->text, r->pool);
-        }
-        else if (strcmp(version->name, "label-name") == 0) {
-            /* return contents of the DAV:label-name element */
-            *target = strip_white(version->first_cdata.first->text, r->pool);
-            *is_label = 1;
-        }
-        else {
-           ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
-                         "Unknown version specifier (not DAV:version or DAV:label-name)");
-            return HTTP_BAD_REQUEST;
-        }
-    }
-    else {
-        /* no element. see if a Target-Selector header was provided
-         * (which is always interpreted as a label) */
-        *target = apr_table_get(r->headers_in, DAV_TARGET_SELECTOR_HDR);
-        *is_label = 1;
-    }
-
-    return OK;
-}
+#define DAV_LABEL_HDR "Label"
 
 /* dav_add_vary_header
  *
@@ -1572,18 +1585,22 @@ void dav_add_vary_header(request_rec *in_req,
 {
     const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req);
 
+    /* ### this is probably all wrong... I think there is a function in
+       ### the Apache API to add things to the Vary header. need to check */
+
     /* Only versioning headers require a Vary response header,
      * so only do this check if there is a versioning provider */
     if (vsn_hooks != NULL) {
-       const char *target = apr_table_get(in_req->headers_in, DAV_TARGET_SELECTOR_HDR);
+       const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR);
        const char *vary = apr_table_get(out_req->headers_out, "Vary");
 
         /* If Target-Selector specified, add it to the Vary header */
        if (target != NULL) {
            if (vary == NULL)
-               vary = DAV_TARGET_SELECTOR_HDR;
+               vary = DAV_LABEL_HDR;
            else
-               vary = apr_pstrcat(out_req->pool, vary, "," DAV_TARGET_SELECTOR_HDR, NULL);
+               vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR,
+                                   NULL);
 
            apr_table_setn(out_req->headers_out, "Vary", vary);
        }
@@ -1649,7 +1666,7 @@ dav_error *dav_ensure_resource_writable(request_rec *r,
              * Note that auto-versioning can only be applied to a version selector,
              * so no separate working resource will be created.
              */
-           if ((err = (*vsn_hooks->checkout)(parent, NULL))
+           if ((err = (*vsn_hooks->checkout)(parent, 0, 0, 0, NULL, NULL))
                 != NULL)
             {
                body = apr_psprintf(r->pool,
@@ -1685,7 +1702,7 @@ dav_error *dav_ensure_resource_writable(request_rec *r,
     if (!parent_only && !resource->working) {
         /* Auto-versioning can only be applied to version selectors, so
          * no separate working resource will be created. */
-       if ((err = (*vsn_hooks->checkout)(resource, NULL))
+       if ((err = (*vsn_hooks->checkout)(resource, 0, 0, 0, NULL, NULL))
             != NULL)
         {
            body = apr_psprintf(r->pool,