]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Patch to sync with some changes to mod_dav 1.1:
authorGreg Stein <gstein@apache.org>
Wed, 28 Mar 2001 07:37:25 +0000 (07:37 +0000)
committerGreg Stein <gstein@apache.org>
Wed, 28 Mar 2001 07:37:25 +0000 (07:37 +0000)
*) revamp the set_target stuff -- latest draft calls this UPDATE
*) update the CHECKIN method handling
*) liveprop providers can catch/define "core" properties before the core
   gets a chance.

Submitted by: John Vasta <jvasta@rational.com>
Reviewed by: Greg Stein

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

modules/dav/main/mod_dav.c
modules/dav/main/mod_dav.h
modules/dav/main/props.c
modules/dav/main/util.c

index 9a80b1577a954f43ba141136e265bef089e0b188..b703871c69326dd900df774eb882bcffe22a54b0 100644 (file)
@@ -517,6 +517,7 @@ static void dav_log_err(request_rec *r, dav_error *err, int level)
 **   - repos_hooks->remove_resource
 **   - repos_hooks->move_resource
 **   - repos_hooks->copy_resource
+**   - vsn_hooks->update
 */
 static int dav_handle_err(request_rec *r, dav_error *err,
                          dav_response *response)
@@ -2848,13 +2849,8 @@ static int dav_method_lock(request_rec *r)
        return HTTP_BAD_REQUEST;
     }
 
-    /* Ask repository module to resolve the resource.
-     * DeltaV says result of target selector is undefined,
-     * so allow it, and let provider reject the lock attempt
-     * on a version if it wants to.
-     */
-    /* ### 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 */,
+    /* Ask repository module to resolve the resource */
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
@@ -3035,13 +3031,8 @@ static int dav_method_unlock(request_rec *r)
        return dav_handle_err(r, err, NULL);
     }
 
-    /* Ask repository module to resolve the resource.
-     * DeltaV says result of target selector is undefined,
-     * so allow it, and let provider reject the unlock attempt
-     * on a version if it wants to.
-     */
-    /* ### 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 */,
+    /* Ask repository module to resolve the resource */
+    err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
                            &resource);
     if (err != NULL)
         return dav_handle_err(r, err, NULL);
@@ -3475,13 +3466,26 @@ static int dav_method_checkin(request_rec *r)
     const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
     dav_error *err;
     int result;
+    ap_xml_doc *doc;
+    int keep_checked_out = 0;
 
     /* If no versioning provider, decline the request */
     if (vsn_hooks == NULL)
         return DECLINED;
 
-    if ((result = ap_discard_request_body(r)) != OK) {
+    if ((result = ap_xml_parse_input(r, &doc)) != OK)
        return result;
+
+    if (doc != NULL) {
+        if (!dav_validate_root(doc, "checkin")) {
+            /* This supplies additional information for the default msg. */
+            ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                          "The request body, if present, must be a "
+                          "DAV:checkin element.");
+            return HTTP_BAD_REQUEST;
+        }
+
+        keep_checked_out = dav_find_child(doc->root, "keep-checked-out") != NULL;
     }
 
     /* Ask repository module to resolve the resource */
@@ -3509,13 +3513,14 @@ static int dav_method_checkin(request_rec *r)
 
     if (!resource->working) {
        return dav_error_response(r, HTTP_CONFLICT,
-                                 "The resource is not checked out to the workspace.");
+                                 "The resource is not checked out.");
     }
 
     /* ### do lock checks, once behavior is defined */
 
     /* Do the checkin */
-    if ((err = (*vsn_hooks->checkin)(resource, &new_version)) != NULL) {
+    if ((err = (*vsn_hooks->checkin)(resource, keep_checked_out, &new_version))
+        != NULL) {
        err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
                             apr_psprintf(r->pool,
                                         "Could not CHECKIN resource %s.",
@@ -3527,80 +3532,27 @@ static int dav_method_checkin(request_rec *r)
     return dav_created(r, new_version->uri, "Version", 0);
 }
 
-/* context maintained during SET-TARGET treewalk */
-typedef struct dav_set_target_walker_ctx
-{
-    /* input: */
-    dav_walk_params w;
-
-    /* target specifier */
-    const char *target;
-
-    /* flag for whether target is version URI or label */
-    int is_label;
-
-    /* version provider hooks */
-    const dav_hooks_vsn *vsn_hooks;
-
-} dav_set_target_walker_ctx;
-
-static dav_error * dav_set_target_walker(dav_walk_resource *wres, int calltype)
-{
-    dav_set_target_walker_ctx *ctx = wres->walk_ctx;
-    dav_error *err = NULL;
-
-    /* Check the state of the resource: must be a checked-in version
-     * or baseline selector
-     */
-    /* ### need a general mechanism for reporting precondition violations
-     * ### (should be returning XML document for 403/409 responses)
-     */
-    if (wres->resource->type != DAV_RESOURCE_TYPE_REGULAR
-        || !wres->resource->versioned || wres->resource->working) {
-       err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0,
-                           "<DAV:must-be-checked-in-version-selector/>");
-    }
-    else {
-        /* do the set-target operation */
-        err = (*ctx->vsn_hooks->set_target)(wres->resource, ctx->target, ctx->is_label);
-    }
-
-    if (err != NULL) {
-        /* ### need utility routine to add response with description? */
-        dav_add_response(wres, err->status, NULL);
-        wres->response->desc = err->desc;
-    }
-
-    return NULL;
-}
-
-static int dav_method_set_target(request_rec *r)
+static int dav_method_update(request_rec *r)
 {
     dav_resource *resource;
+    dav_resource *version = NULL;
     const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
     ap_xml_doc *doc;
     ap_xml_elem *child;
+    int is_label = 0;
     int depth;
     int result;
-    apr_size_t tsize;
+    int tsize;
+    const char *target;
+    dav_response *multi_response;
     dav_error *err;
-    dav_set_target_walker_ctx ctx = { { 0 } };
-    dav_response *multi_status;
+    dav_lookup_result lookup;
 
-    /* If no versioning provider, decline the request */
-    if (vsn_hooks == NULL)
+    /* If no versioning provider, or UPDATE not supported,
+     * decline the request */
+    if (vsn_hooks == NULL || vsn_hooks->update == NULL)
         return DECLINED;
 
-    /* Ask repository module to resolve the 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) {
-        /* Apache will supply a default error for this. */
-        return HTTP_NOT_FOUND;
-    }
-
     if ((depth = dav_get_depth(r, 0)) < 0) {
        /* dav_get_depth() supplies additional information for the
         * default message. */
@@ -3612,21 +3564,18 @@ static int dav_method_set_target(request_rec *r)
        return result;
     }
 
-    if (doc == NULL || !dav_validate_root(doc, "set-target")) {
+    if (doc == NULL || !dav_validate_root(doc, "update")) {
        /* This supplies additional information for the default message. */
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
                      "The request body does not contain "
-                     "a \"set-target\" element.");
+                     "an \"update\" element.");
        return HTTP_BAD_REQUEST;
     }
 
-    /* check for label-name or version element */
-    if ((child = dav_find_child(doc->root, "label-name")) != NULL) {
-        ctx.is_label = 1;
-    }
+    /* check for label-name or version element, but not both */
+    if ((child = dav_find_child(doc->root, "label-name")) != NULL)
+        is_label = 1;
     else if ((child = dav_find_child(doc->root, "version")) != NULL) {
-        ctx.is_label = 0;
-
         /* get the href element */
         if ((child = dav_find_child(child, "href")) == NULL) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
@@ -3637,14 +3586,21 @@ static int dav_method_set_target(request_rec *r)
     }
     else {
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
-                     "The \"set-target\" element does not contain "
+                     "The \"update\" element does not contain "
                      "a \"label-name\" or \"version\" element.");
        return HTTP_BAD_REQUEST;
     }
 
-    /* get the target value (a label or a version URI */
+    /* a depth greater than zero is only allowed for a label */
+    if (!is_label && depth != 0) {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                     "Depth must be zero for UPDATE with a version");
+       return HTTP_BAD_REQUEST;
+    }
+
+    /* get the target value (a label or a version URI) */
     ap_xml_to_text(r->pool, child, AP_XML_X2T_INNER, NULL, NULL,
-                   &ctx.target, &tsize);
+                   &target, &tsize);
     if (tsize == 0) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
                      "A \"label-name\" or \"href\" element does not contain "
@@ -3652,39 +3608,69 @@ static int dav_method_set_target(request_rec *r)
        return HTTP_BAD_REQUEST;
     }
 
-    /* do the set-target operation walk */
-    ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
-    ctx.w.func = dav_set_target_walker;
-    ctx.w.walk_ctx = &ctx;
-    ctx.w.pool = r->pool;
-    ctx.w.root = resource;
-    ctx.vsn_hooks = vsn_hooks;
-
-    err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
+    /* Ask repository module to resolve the 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 (err != NULL) {
-        /* some sort of error occurred which terminated the walk */
-        err = dav_push_error(r->pool, err->status, 0,
-                             "The SET-TARGET operation was terminated prematurely.",
-                             err);
-        return dav_handle_err(r, err, multi_status);
+    if (!resource->exists) {
+        /* Apache will supply a default error for this. */
+        return HTTP_NOT_FOUND;
     }
 
-    if (multi_status != NULL) {
-        /* One or more resources had errors. If depth was zero, convert
-         * response to simple error, else make sure there is an
-         * overall error to pass to dav_handle_err()
-         */
-        if (depth == 0) {
-            err = dav_new_error(r->pool, multi_status->status, 0, multi_status->desc);
-            multi_status = NULL;
+    /* ### need a general mechanism for reporting precondition violations
+     * ### (should be returning XML document for 403/409 responses)
+     */
+    if (resource->type != DAV_RESOURCE_TYPE_REGULAR
+        || !resource->versioned || resource->working) {
+       return dav_error_response(r, HTTP_CONFLICT,
+                                 "<DAV:must-be-checked-in-version-controlled-resource>");
+    }
+
+    /* if target is a version, resolve the version resource */
+    /* ### dav_lookup_uri only allows absolute URIs; is that OK? */
+    if (!is_label) {
+        lookup = dav_lookup_uri(target, r);
+        if (lookup.rnew == NULL) {
+           if (lookup.err.status == HTTP_BAD_REQUEST) {
+               /* This supplies additional information for the default message. */
+               ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                             lookup.err.desc);
+               return HTTP_BAD_REQUEST;
+           }
+
+           /* ### this assumes that dav_lookup_uri() only generates a status
+            * ### that Apache can provide a status line for!! */
+
+           return dav_error_response(r, lookup.err.status, lookup.err.desc);
         }
-        else {
-            err = dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
-                                "Errors occurred during the SET-TARGET operation.");
+        if (lookup.rnew->status != HTTP_OK) {
+           /* ### how best to report this... */
+           return dav_error_response(r, lookup.rnew->status,
+                                     "Version URI had an error.");
         }
 
-        return dav_handle_err(r, err, multi_status);
+        /* resolve version resource */
+        err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
+                               0 /* use_checked_in */, &version);
+        if (err != NULL)
+            return dav_handle_err(r, err, NULL);
+
+        /* NULL out target, since we're using a version resource */
+        target = NULL;
+    }
+
+    /* do the UPDATE operation */
+    err = (*vsn_hooks->update)(resource, version, target, depth, &multi_response);
+
+    if (err != NULL) {
+        err = dav_push_error(r->pool, err->status, 0,
+                            ap_psprintf(r->pool,
+                                        "Could not UPDATE %s.",
+                                        ap_escape_html(r->pool, r->uri)),
+                             err);
+        return dav_handle_err(r, err, multi_response);
     }
 
     /* set the Cache-Control header, per the spec */
@@ -4402,8 +4388,8 @@ static int dav_handler(request_rec *r)
        return dav_method_checkin(r);
     }
 
-    if (!strcmp(r->method, "SET-TARGET")) {
-       return dav_method_set_target(r);
+    if (!strcmp(r->method, "UPDATE")) {
+       return dav_method_update(r);
     }
 
     if (!strcmp(r->method, "LABEL")) {
index e71c06462b8eee2a223d9018bfbeaea00b7780c0..6278624ce9dcbac60ebe14080db5bf35bd51e3e9 100644 (file)
@@ -321,12 +321,12 @@ typedef struct dav_resource_private dav_resource_private;
 **     baselined  = 0
 **     working    = 0
 **
-** version/baseline selector:
+** version-controlled resource or configuration:
 **     type       = DAV_RESOURCE_TYPE_REGULAR
 **     exists     = 1
 **     collection = ? (1 if collection)
 **     versioned  = 1
-**     baselined  = ? (1 if baseline selector)
+**     baselined  = ? (1 if configuration)
 **     working    = ? (1 if checked out)
 **
 ** version/baseline history:
@@ -357,9 +357,9 @@ typedef struct dav_resource_private dav_resource_private;
 **     type       = DAV_RESOURCE_TYPE_WORKSPACE
 **     exists     = ? (1 if exists)
 **     collection = 1
-**     versioned  = * (jvasta: I'm seeking clarification on whether a
-**     baselined  = *  workspace can be versioned or baselined)
-**     working    = *
+**     versioned  = ? (1 if version-controlled)
+**     baselined  = ? (1 if baseline-controlled)
+**     working    = ? (1 if checked out)
 **
 ** activity:
 **     type       = DAV_RESOURCE_TYPE_ACTIVITY
@@ -383,7 +383,7 @@ typedef struct dav_resource {
                          * and is always 1 for VERSION and WORKING */
 
     int baselined;      /* 0 => not baselined; can be 1 for
-                         * REGULAR and VERSION resources;
+                         * REGULAR, VERSION, and WORKSPACE resources;
                          * versioned == 1 when baselined == 1 */
 
     int working;       /* 0 => not checked out; can be 1 for
@@ -1937,31 +1937,26 @@ struct dav_hooks_vsn
                             apr_array_header_t *activities,
                             dav_resource **working_resource);
 
-    /* Uncheckout a resource. If successful, the resource
+    /* Uncheckout a checked-out resource. If successful, the resource
      * object state is updated appropriately.
      */
     dav_error * (*uncheckout)(dav_resource *resource);
 
-    /* Checkin a working resource. If successful, the resource
+    /* Checkin a checked-out resource. If successful, the resource
      * object state is updated appropriately, and the
      * version_resource descriptor will refer to the new version.
      * The version_resource argument can be NULL if the caller
      * is not interested in the new version resource.
+     *
+     * If the client has specified DAV:keep-checked-out in the checkin
+     * request, then the keep_checked_out flag is set. The provider
+     * should create a new version, but keep the resource in the
+     * checked-out state.
      */
     dav_error * (*checkin)(dav_resource *resource,
+                           int keep_checked_out,
                            dav_resource **version_resource);
 
-    /*
-    ** Set the default target of a version selector or
-    ** baseline selector resource.
-    ** The target argument specifies the new target, which
-    ** can be a label, if is_label != 0, or a version URI,
-    ** if is_label == 0.
-    */
-    dav_error * (*set_target)(const dav_resource *resource,
-                             const char *target,
-                              int is_label);
-
     /* Determine whether a non-versioned (or non-existent) resource
      * is versionable. Returns != 0 if resource can be versioned.
      */
@@ -2015,6 +2010,29 @@ struct dav_hooks_vsn
     ** corresponding protocol methods will be unsupported.
     */
 
+    /*
+    ** Set the state of a checked-in version-controlled resource.
+    **
+    ** If the request specified a version, the version resource
+    ** represents that version. If the request specified a label,
+    ** then "version" is NULL, and "label" is the label.
+    **
+    ** The depth argument is ignored for a file, and can be 0, 1, or
+    ** DAV_INFINITY for a collection. The depth argument only applies
+    ** with a label, not a version.
+    **
+    ** If an error occurs in a child resource, then the return value is
+    ** non-NULL, and *response is set to a multistatus response.
+    **
+    ** This hook is optional; if not defined, then the UPDATE method
+    ** will not be supported.
+    */
+    dav_error * (*update)(const dav_resource *resource,
+                          const dav_resource *version,
+                          const char *label,
+                          int depth,
+                          dav_response **response);
+
     /*
     ** Add a label to a version. The resource is either a specific
     ** version, or a version selector, in which case the label should
index 9f2c6d7daa5a142ff93ae3a7c716e285e146bc57..2929a9a297151a69f82d8d4e048b650f947d4dee 100644 (file)
@@ -337,22 +337,22 @@ static int dav_find_liveprop_provider(dav_propdb *propdb,
        /* policy: liveprop providers cannot define no-namespace properties */
        return DAV_PROPID_CORE_UNKNOWN;
     }
-    else if (strcmp(ns_uri, "DAV:") == 0) {
+
+    /* check liveprop providers first, so they can define core properties */
+    propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname,
+                                   provider);
+    if (propid != 0) {
+        return propid;
+    }
+
+    /* check for core property */
+    if (strcmp(ns_uri, "DAV:") == 0) {
        const char * const *p = dav_core_props;
 
        for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid)
            if (strcmp(propname, *p) == 0) {
                return propid;
            }
-
-       /* didn't find it. fall thru. a provider can define DAV: props */
-    }
-
-    /* is there a liveprop provider for this property? */
-    propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname,
-                                   provider);
-    if (propid != 0) {
-        return propid;
     }
 
     /* no provider for this property */
index 09df3b429eb7888e7ff29280975345091897c6a1..7c3d844a8b7e29baf2851d3c590c9054c9d8341f 100644 (file)
@@ -1739,7 +1739,8 @@ dav_error *dav_revert_resource_writability(
             if (undo)
                 err = (*vsn_hooks->uncheckout)(resource);
             else
-                err = (*vsn_hooks->checkin)(resource, NULL);
+                err = (*vsn_hooks->checkin)(resource,
+                                            0 /*keep_checked_out*/, NULL);
 
             if (err != NULL) {
                body = apr_psprintf(r->pool,
@@ -1774,7 +1775,8 @@ dav_error *dav_revert_resource_writability(
        if (undo)
            err = (*vsn_hooks->uncheckout)(av_info->parent_resource);
        else
-           err = (*vsn_hooks->checkin)(av_info->parent_resource, NULL);
+           err = (*vsn_hooks->checkin)(av_info->parent_resource,
+                                        0 /*keep_checked_out*/, NULL);
 
        if (err != NULL) {
            body = apr_psprintf(r->pool,