You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by gs...@locus.apache.org on 2000/10/07 02:50:43 UTC
cvs commit: apache-2.0/src/modules/dav/main mod_dav.c mod_dav.h props.c util.c
gstein 00/10/06 17:50:42
Modified: src/modules/dav/fs lock.c
src/modules/dav/main mod_dav.c mod_dav.h props.c util.c
Log:
forward-port John Vasta's checkin to mod_dav 1.1.x (on Sep 25, 2000). this
begins some work to upgrade the versioning support to some of the more
recent drafts.
- get_resource hook has new params
- create_collection hook no longer takes a pool
- new dav_auto_version_info structure to group up autoversion
rollback/commit handling data
- new functions for getting workspace, target-selector, etc
- supportedlock hook now takes the resource in question (since different
resources may have different locks)
- new resource types; tweaks in props.c to support them
- some tweaks with resource creation, Location header, etc.
Revision Changes Path
1.10 +1 -1 apache-2.0/src/modules/dav/fs/lock.c
Index: lock.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/dav/fs/lock.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- lock.c 2000/10/06 12:49:20 1.9
+++ lock.c 2000/10/07 00:50:41 1.10
@@ -777,7 +777,7 @@
** properties. I think we save more returning a static string than
** constructing it every time, though it might look cleaner.
*/
-static const char *dav_fs_get_supportedlock(void)
+static const char *dav_fs_get_supportedlock(const dav_resource *resource)
{
static const char supported[] = DEBUG_CR
"<D:lockentry>" DEBUG_CR
1.22 +110 -117 apache-2.0/src/modules/dav/main/mod_dav.c
Index: mod_dav.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/dav/main/mod_dav.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- mod_dav.c 2000/10/06 12:49:21 1.21
+++ mod_dav.c 2000/10/07 00:50:42 1.22
@@ -541,12 +541,8 @@
/* Per HTTP/1.1, S10.2.2: add a Location header to contain the
* URI that was created. */
- /* ### locn does not contain an absoluteURI. S14.30 states that
- * ### the Location header requires an absoluteURI. where to get it? */
- /* ### disable until we get the right value */
-#if 0
- apr_table_setn(r->headers_out, "Location", locn);
-#endif
+ /* Convert locn to an absolute URI, and return in Location header */
+ apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r));
/* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
@@ -604,13 +600,21 @@
return -1;
}
-/* resolve a request URI to a resource descriptor */
-static int dav_get_resource(request_rec *r, const char *target,
- dav_resource **res_p)
+/* 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.
+ */
+static int dav_get_resource(request_rec *r, int target_allowed,
+ ap_xml_elem *target, dav_resource **res_p)
{
void *data;
dav_dir_conf *conf;
const dav_hooks_repository *repos_hooks;
+ const char *workspace = NULL;
+ const char *target_selector = NULL;
+ int is_label = 0;
+ int result;
/* go look for the resource if it isn't already present */
(void) apr_get_userdata(&data, DAV_KEY_RESOURCE, r->pool);
@@ -623,8 +627,22 @@
/* assert: provider != NULL */
repos_hooks = dav_lookup_repository(conf->provider);
+
+ /* get any workspace header */
+ if ((result = dav_get_workspace(r, &workspace)) != OK)
+ return result;
- *res_p = (*repos_hooks->get_resource)(r, conf->dir, target);
+ /* if the request target can be overridden, get any target selector */
+ if (target_allowed) {
+ if ((result = dav_get_target_selector(r, target,
+ &target_selector,
+ &is_label)) != OK)
+ return result;
+ }
+
+ /* resolve the resource */
+ *res_p = (*repos_hooks->get_resource)(r, conf->dir, workspace,
+ target_selector, is_label);
if (*res_p == NULL) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
@@ -632,6 +650,12 @@
(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 */
+ dav_add_vary_header(r, r, *res_p);
+
return OK;
}
@@ -709,10 +733,10 @@
"<D:available-report/>" DEBUG_CR,
r);
- for (; reports->namespace != NULL; ++reports) {
+ for (; reports->nmspace != NULL; ++reports) {
/* Note: we presume reports->namespace is propertly XML/URL quoted */
ap_rprintf(r, "<%s xmlns=\"%s\"/>" DEBUG_CR,
- reports->name, reports->namespace);
+ reports->name, reports->nmspace);
}
ap_rputs("</D:report-set>" DEBUG_CR, r);
@@ -731,7 +755,7 @@
* visible to Apache. We will fetch the resource from the repository,
* then create a subrequest for Apache to handle.
*/
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -741,7 +765,9 @@
/* Check resource type */
if (resource->type != DAV_RESOURCE_TYPE_REGULAR &&
- resource->type != DAV_RESOURCE_TYPE_REVISION) {
+ resource->type != DAV_RESOURCE_TYPE_VERSION &&
+ resource->type != DAV_RESOURCE_TYPE_WORKING)
+ {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot GET this type of resource.");
}
@@ -924,7 +950,7 @@
int result;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK) {
return result;
}
@@ -944,15 +970,12 @@
{
dav_resource *resource;
int resource_state;
- dav_resource *resource_parent;
+ dav_auto_version_info av_info;
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
const char *body;
dav_error *err;
dav_error *err2;
int result;
- int resource_existed = 0;
- int resource_was_writable = 0;
- int parent_was_writable = 0;
dav_stream_mode mode;
dav_stream *stream;
dav_response *multi_response;
@@ -965,7 +988,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK) {
return result;
}
@@ -1007,10 +1030,7 @@
/* make sure the resource can be modified (if versioning repository) */
if ((err = dav_ensure_resource_writable(r, resource,
0 /* not parent_only */,
- &resource_parent,
- &resource_existed,
- &resource_was_writable,
- &parent_was_writable)) != NULL) {
+ &av_info)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
@@ -1093,11 +1113,8 @@
}
/* restore modifiability of resources back to what they were */
- err2 = dav_revert_resource_writability(r, resource, resource_parent,
- err != NULL /* undo if error */,
- resource_existed,
- resource_was_writable,
- parent_was_writable);
+ err2 = dav_revert_resource_writability(r, resource, err != NULL /* undo if error */,
+ &av_info);
/* check for errors now */
if (err != NULL) {
@@ -1148,7 +1165,7 @@
/* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */
/* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
- return dav_created(r, NULL, "Resource", resource_existed);
+ return dav_created(r, NULL, "Resource", !av_info.resource_created);
}
/* ### move this to dav_util? */
@@ -1173,14 +1190,12 @@
static int dav_method_delete(request_rec *r)
{
dav_resource *resource;
- dav_resource *resource_parent = NULL;
+ dav_auto_version_info av_info;
dav_error *err;
dav_error *err2;
dav_response *multi_response;
- const char *body;
int result;
int depth;
- int parent_was_writable = 0;
/* We don't use the request body right now, so torch it. */
if ((result = ap_discard_request_body(r)) != OK) {
@@ -1188,7 +1203,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -1214,16 +1229,6 @@
return HTTP_BAD_REQUEST;
}
- /* Check for valid resource type */
- /* ### allow DAV_RESOURCE_TYPE_REVISION with All-Bindings header */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR &&
- resource->type != DAV_RESOURCE_TYPE_WORKSPACE) {
- body = apr_psprintf(r->pool,
- "Cannot delete resource %s.",
- ap_escape_html(r->pool, r->uri));
- return dav_error_response(r, HTTP_CONFLICT, body);
- }
-
/*
** If any resources fail the lock/If: conditions, then we must fail
** the delete. Each of the failing resources will be listed within
@@ -1254,9 +1259,7 @@
/* if versioned resource, make sure parent is checked out */
if ((err = dav_ensure_resource_writable(r, resource, 1 /* parent_only */,
- &resource_parent,
- NULL, NULL,
- &parent_was_writable)) != NULL) {
+ &av_info)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
@@ -1265,9 +1268,8 @@
err = (*resource->hooks->remove_resource)(resource, &multi_response);
/* restore writability of parent back to what it was */
- err2 = dav_revert_resource_writability(r, NULL, resource_parent,
- err != NULL /* undo if error */,
- 0, 0, parent_was_writable);
+ err2 = dav_revert_resource_writability(r, NULL, err != NULL /* undo if error */,
+ &av_info);
/* check for errors now */
if (err != NULL) {
@@ -1316,7 +1318,7 @@
ap_set_content_length(r, 0);
/* resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
@@ -1523,7 +1525,7 @@
dav_walker_ctx ctx = { 0 };
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
@@ -1787,7 +1789,7 @@
dav_prop_ctx *ctx;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -1969,13 +1971,12 @@
{
dav_resource *resource;
int resource_state;
- dav_resource *resource_parent;
+ dav_auto_version_info av_info;
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
dav_error *err;
dav_error *err2;
int result;
dav_dir_conf *conf;
- int parent_was_writable = 0;
dav_response *multi_status;
/* handle the request body */
@@ -1988,7 +1989,7 @@
&dav_module);
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
@@ -2023,21 +2024,18 @@
/* if versioned resource, make sure parent is checked out */
if ((err = dav_ensure_resource_writable(r, resource, 1 /* parent_only */,
- &resource_parent,
- NULL, NULL,
- &parent_was_writable)) != NULL) {
+ &av_info)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* try to create the collection */
resource->collection = 1;
- err = (*resource->hooks->create_collection)(r->pool, resource);
+ err = (*resource->hooks->create_collection)(resource);
/* restore modifiability of parent back to what it was */
- err2 = dav_revert_resource_writability(r, NULL, resource_parent,
- err != NULL /* undo if error */,
- 0, 0, parent_was_writable);
+ err2 = dav_revert_resource_writability(r, NULL, err != NULL /* undo if error */,
+ &av_info);
/* check for errors now */
if (err != NULL) {
@@ -2091,9 +2089,9 @@
static int dav_method_copymove(request_rec *r, int is_move)
{
dav_resource *resource;
- dav_resource *resource_parent = NULL;
+ dav_auto_version_info src_av_info;
dav_resource *resnew;
- dav_resource *resnew_parent = NULL;
+ dav_auto_version_info dst_av_info;
const char *body;
const char *dest;
dav_error *err;
@@ -2107,12 +2105,10 @@
int result;
dav_lockdb *lockdb;
int replaced;
- int src_parent_was_writable = 0;
- int dst_parent_was_writable = 0;
int resource_state;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, !is_move /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2166,7 +2162,7 @@
}
/* Resolve destination resource */
- result = dav_get_resource(lookup.rnew, NULL, &resnew);
+ result = dav_get_resource(lookup.rnew, 0 /*target_allowed*/, NULL, &resnew);
if (result != OK)
return result;
@@ -2332,11 +2328,8 @@
/* if this is a move, then the source parent collection will be modified */
if (is_move) {
- if ((err = dav_ensure_resource_writable(r, resource,
- 1 /* parent_only */,
- &resource_parent,
- NULL, NULL,
- &src_parent_was_writable)) != NULL) {
+ if ((err = dav_ensure_resource_writable(r, resource, 1 /* parent_only */,
+ &src_av_info)) != NULL) {
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
@@ -2347,17 +2340,13 @@
/* prepare the destination collection for modification */
if ((err = dav_ensure_resource_writable(r, resnew, 1 /* parent_only */,
- &resnew_parent,
- NULL, NULL,
- &dst_parent_was_writable)) != NULL) {
+ &dst_av_info)) != NULL) {
/* could not make destination writable:
* if move, restore state of source parent
*/
if (is_move) {
- (void) dav_revert_resource_writability(r, NULL, resource_parent,
- 1 /* undo */,
- 0, 0,
- src_parent_was_writable);
+ (void) dav_revert_resource_writability(r, NULL, 1 /* undo */,
+ &src_av_info);
}
if (lockdb != NULL)
@@ -2369,12 +2358,14 @@
/* If source and destination parents are the same, then
* use the same object, so status updates to one are reflected
- * in the other.
+ * in the other, when reverting their writable states.
*/
- if (resource_parent != NULL
- && (*resource_parent->hooks->is_same_resource)(resource_parent,
- resnew_parent))
- resnew_parent = resource_parent;
+ if (src_av_info.parent_resource != NULL
+ && (*src_av_info.parent_resource->hooks->is_same_resource)
+ (src_av_info.parent_resource, dst_av_info.parent_resource)) {
+
+ dst_av_info.parent_resource = src_av_info.parent_resource;
+ }
/* New resource will be same kind as source */
resnew->collection = resource->collection;
@@ -2397,14 +2388,12 @@
}
/* restore parent collection states */
- err2 = dav_revert_resource_writability(r, NULL, resnew_parent,
- err != NULL /* undo if error */,
- 0, 0, dst_parent_was_writable);
+ err2 = dav_revert_resource_writability(r, NULL, err != NULL /* undo if error */,
+ &dst_av_info);
if (is_move) {
- err3 = dav_revert_resource_writability(r, NULL, resource_parent,
- err != NULL /* undo if error */,
- 0, 0, src_parent_was_writable);
+ err3 = dav_revert_resource_writability(r, NULL, err != NULL /* undo if error */,
+ &src_av_info);
}
else
err3 = NULL;
@@ -2497,8 +2486,12 @@
return HTTP_BAD_REQUEST;
}
- /* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ /* 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.
+ */
+ result = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
@@ -2680,8 +2673,12 @@
return dav_handle_err(r, err, NULL);
}
- /* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ /* 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.
+ */
+ result = dav_get_resource(r, 1 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
@@ -2732,12 +2729,12 @@
static int dav_method_checkout(request_rec *r)
{
dav_resource *resource;
+ dav_resource *working_resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
ap_xml_doc *doc;
- const char *target;
- const char *location;
+ ap_xml_elem *target = NULL;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
@@ -2755,15 +2752,12 @@
return HTTP_BAD_REQUEST;
}
- target = dav_get_target_selector(r, dav_find_child(doc->root,
- "version"));
+ if ((target = dav_find_child(doc->root, "version")) == NULL)
+ target = dav_find_child(doc->root, "label-name");
}
- else {
- target = dav_get_target_selector(r, NULL);
- }
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, target, &resource);
+ result = dav_get_resource(r, 1 /*target_allowed*/, target, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2792,7 +2786,7 @@
/* ### do lock checks, once behavior is defined */
/* Do the checkout */
- if ((err = (*vsn_hooks->checkout)(resource, &location)) != NULL) {
+ if ((err = (*vsn_hooks->checkout)(resource, &working_resource)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not CHECKOUT resource %s.",
@@ -2801,10 +2795,9 @@
return dav_handle_err(r, err, NULL);
}
- /* set the Location and Cache-Control headers, per the spec */
- apr_table_setn(r->headers_out, "Location", location);
+ /* set the Cache-Control headers, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
- return dav_created(r, location, "Working resource", 0);
+ return dav_created(r, working_resource->uri, "Working resource", 0);
}
/* handle the UNCHECKOUT method */
@@ -2824,7 +2817,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2873,6 +2866,7 @@
static int dav_method_checkin(request_rec *r)
{
dav_resource *resource;
+ dav_resource *new_version;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
@@ -2886,7 +2880,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ result = dav_get_resource(r, 0 /* target_allowed */, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2915,7 +2909,7 @@
/* ### do lock checks, once behavior is defined */
/* Do the checkin */
- if ((err = (*vsn_hooks->checkin)(resource)) != NULL) {
+ if ((err = (*vsn_hooks->checkin)(resource, &new_version)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not CHECKIN resource %s.",
@@ -2924,11 +2918,7 @@
return dav_handle_err(r, err, NULL);
}
- /* no body */
- ap_set_content_length(r, 0);
- ap_send_http_header(r);
-
- return DONE;
+ return dav_created(r, new_version->uri, "Version", 0);
}
static int dav_method_set_target(request_rec *r)
@@ -2948,6 +2938,7 @@
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
int result;
+ int target_allowed;
ap_xml_doc *doc;
/* If no versioning provider, decline the request */
@@ -2964,7 +2955,9 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, NULL, &resource);
+ /* ### need to compute target_allowed based on report type */
+ target_allowed = 0;
+ result = dav_get_resource(r, target_allowed, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
1.17 +118 -50 apache-2.0/src/modules/dav/main/mod_dav.h
Index: mod_dav.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/dav/main/mod_dav.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- mod_dav.h 2000/09/09 23:23:42 1.16
+++ mod_dav.h 2000/10/07 00:50:42 1.17
@@ -246,15 +246,31 @@
** The base protocol defines only file and collection resources.
** The versioning protocol defines several additional resource types
** to represent artifacts of a version control system.
+**
+** This enumeration identifies the type of URL used to identify the
+** resource. Since the same resource may have more than one type of
+** URL which can identify it, dav_resource_type cannot be used
+** alone to determine the type of the resource; attributes of the
+** dav_resource object must also be consulted.
*/
typedef enum {
- DAV_RESOURCE_TYPE_REGULAR, /* file or collection, working resource
- or revision */
- DAV_RESOURCE_TYPE_REVISION, /* explicit revision-id */
- DAV_RESOURCE_TYPE_HISTORY, /* explicit history-id */
- DAV_RESOURCE_TYPE_WORKSPACE, /* workspace */
- DAV_RESOURCE_TYPE_ACTIVITY, /* activity */
- DAV_RESOURCE_TYPE_CONFIGURATION /* configuration */
+ DAV_RESOURCE_TYPE_UNKNOWN,
+
+ DAV_RESOURCE_TYPE_REGULAR, /* file or collection; could be
+ * unversioned or version selector */
+
+ DAV_RESOURCE_TYPE_VERSION, /* version URL */
+
+ DAV_RESOURCE_TYPE_HISTORY, /* version history URL */
+
+ DAV_RESOURCE_TYPE_WORKING, /* working resource URL */
+
+ DAV_RESOURCE_TYPE_WORKSPACE, /* workspace URL */
+
+ DAV_RESOURCE_TYPE_ACTIVITY, /* activity URL */
+
+ DAV_RESOURCE_TYPE_BASELINE /* baseline URL */
+
} dav_resource_type;
/*
@@ -271,14 +287,23 @@
dav_resource_type type;
int exists; /* 0 => null resource */
- int collection; /* 0 => file (if type == DAV_RESOURCE_TYPE_REGULAR) */
- int versioned; /* 0 => unversioned */
- int working; /* 0 => revision (if versioned) */
- int baselined; /* 0 => not baselined */
+
+ int collection; /* 0 => file; can be 1 for
+ * REGULAR, VERSION, and WORKING resources,
+ * and is always 1 for WORKSPACE */
+
+ int versioned; /* 0 => unversioned; can be 1 for
+ * REGULAR and WORKSPACE resources,
+ * and is always 1 for VERSION, WORKING,
+ * and BASELINE */
+
+ int working; /* 0 => not checked out; can be 1 for
+ * REGULAR, WORKSPACE, and BASELINE,
+ * and is always 1 for WORKING */
const char *uri; /* the URI for this resource */
- dav_resource_private *info;
+ dav_resource_private *info; /* repository provider's private info */
const dav_hooks_repository *hooks; /* hooks used for this resource */
@@ -852,9 +877,10 @@
*/
struct dav_hooks_locks
{
- /* Return the supportedlock property for this provider */
- /* ### maybe this should take a resource argument? */
- const char * (*get_supportedlock)(void);
+ /* Return the supportedlock property for a resource */
+ const char * (*get_supportedlock)(
+ const dav_resource *resource
+ );
/* Parse a lock token URI, returning a lock token object allocated
* in the given pool.
@@ -1254,8 +1280,11 @@
*
* The root_dir is the root of the directory for which this repository
* is configured.
- * The workspace is the value of any Target-Selector header, or NULL
+ * The workspace is the value of any Workspace header, or NULL
* if there is none.
+ * The 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.
*
* The provider may associate the request storage pool with the resource,
* to use in other operations on that resource.
@@ -1263,7 +1292,9 @@
dav_resource * (*get_resource)(
request_rec *r,
const char *root_dir,
- const char *workspace
+ const char *workspace,
+ const char *target,
+ int is_label
);
/* Get a resource descriptor for the parent of the given resource.
@@ -1387,7 +1418,7 @@
* is a collection.
*/
dav_error * (*create_collection)(
- apr_pool_t *p, dav_resource *resource
+ dav_resource *resource
);
/* Copy one resource to another. The destination must not exist.
@@ -1453,18 +1484,53 @@
** VERSIONING FUNCTIONS
*/
-/* dav_get_target_selector:
+
+/* dav_get_workspace:
*
- * If a DAV:version element is provided, then it is assumed to provide the
- * target version. If no element is provided (version==NULL), then the
+ * Returns the value of any Workspace header in a request
+ * (used by versioning clients)
+ */
+int dav_get_workspace(request_rec *r, const char **workspace);
+
+/*
+ * 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.
+ * 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)
*/
-const char *dav_get_target_selector(request_rec *r,
- const ap_xml_elem *version);
+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
+ * in the response, add it.
+ */
+void dav_add_vary_header(request_rec *in_req,
+ request_rec *out_req,
+ const dav_resource *resource);
+
+/*
+** This structure is used to record what auto-versioning operations
+** were done to make a resource writable, so that they can be undone
+** at the end of a request.
+*/
+typedef struct {
+ int resource_created; /* 0 => resource existed previously */
+ int resource_checkedout; /* 0 => resource was checked out */
+ int parent_checkedout; /* 0 => parent was checked out */
+ dav_resource *parent_resource; /* parent resource, if it was needed */
+} dav_auto_version_info;
/* Ensure that a resource is writable. If there is no versioning
* provider, then this is essentially a no-op. Versioning repositories
@@ -1476,22 +1542,15 @@
* Otherwise, both parent and child are made writable as needed. If the
* child does not exist, then a new versioned resource is created and
* checked out.
- *
- * The parent_resource and parent_was_writable arguments are optional
- * (i.e. they may be NULL). If parent_only is set, then the
- * resource_existed and resource_was_writable arguments are ignored.
*
- * The previous states of the resources are returned, so they can be
- * restored after the operation completes (see
- * dav_revert_resource_writability())
+ * The dav_auto_version_info structure is filled in with enough information
+ * to restore both parent and child resources to the state they were in
+ * before the auto-versioning operations occurred.
*/
dav_error *dav_ensure_resource_writable(request_rec *r,
dav_resource *resource,
int parent_only,
- dav_resource **parent_resource,
- int *resource_existed,
- int *resource_was_writable,
- int *parent_was_writable);
+ dav_auto_version_info *av_info);
/* Revert the writability of resources back to what they were
* before they were modified. If undo == 0, then the resource
@@ -1499,25 +1558,24 @@
* If undo != 0, then resource modifications are discarded
* (i.e. they are unchecked out).
*
- * The resource and parent_resource arguments are optional
- * (i.e. they may be NULL).
+ * The resource argument may be NULL if only the parent resource
+ * was made writable (i.e. the parent_only was != 0 in the
+ * dav_ensure_resource_writable call).
*/
-dav_error *dav_revert_resource_writability(request_rec *r,
- dav_resource *resource,
- dav_resource *parent_resource,
- int undo,
- int resource_existed,
- int resource_was_writable,
- int parent_was_writable);
+dav_error *dav_revert_resource_writability(
+ request_rec *r,
+ dav_resource *resource,
+ int undo,
+ const dav_auto_version_info *av_info);
/*
** This structure is used to describe available reports
**
-** "namespace" should be valid XML and URL-quoted. mod_dav will place
+** "nmspace" should be valid XML and URL-quoted. mod_dav will place
** double-quotes around it and use it in an xmlns declaration.
*/
typedef struct {
- const char *namespace; /* namespace of the XML report element */
+ const char *nmspace; /* namespace of the XML report element */
const char *name; /* element name for the XML report */
} dav_report_elem;
@@ -1538,9 +1596,15 @@
/* Checkout a resource. If successful, the resource
* object state is updated appropriately.
*
- * The location of the working resource should be returned in *location.
+ * If the working resource has a different URL from the
+ * target resource, a dav_resource descriptor is returned
+ * for the new working resource. Otherwise, the original
+ * 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.
*/
- dav_error * (*checkout)(dav_resource *resource, const char **location);
+ dav_error * (*checkout)(dav_resource *resource,
+ dav_resource **working_resource);
/* Uncheckout a resource. If successful, the resource
* object state is updated appropriately.
@@ -1548,9 +1612,13 @@
dav_error * (*uncheckout)(dav_resource *resource);
/* Checkin a working resource. If successful, the resource
- * object state is updated appropriately.
+ * 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.
*/
- dav_error * (*checkin)(dav_resource *resource);
+ dav_error * (*checkin)(dav_resource *resource,
+ dav_resource **version_resource);
/* Determine whether a non-versioned (or non-existent) resource
* is versionable. Returns != 0 if resource can be versioned.
1.14 +8 -9 apache-2.0/src/modules/dav/main/props.c
Index: props.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/dav/main/props.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- props.c 2000/08/08 20:03:52 1.13
+++ props.c 2000/10/07 00:50:42 1.14
@@ -431,6 +431,8 @@
case DAV_PROPID_CORE_resourcetype:
switch (propdb->resource->type) {
case DAV_RESOURCE_TYPE_REGULAR:
+ case DAV_RESOURCE_TYPE_VERSION:
+ case DAV_RESOURCE_TYPE_WORKING:
if (propdb->resource->collection) {
value = "<D:collection/>";
}
@@ -441,22 +443,19 @@
}
break;
case DAV_RESOURCE_TYPE_HISTORY:
- value = "<D:history/>";
+ value = "<D:version-history/>";
break;
case DAV_RESOURCE_TYPE_WORKSPACE:
- value = "<D:workspace/>";
+ value = "<D:collection/>";
break;
case DAV_RESOURCE_TYPE_ACTIVITY:
value = "<D:activity/>";
break;
- case DAV_RESOURCE_TYPE_CONFIGURATION:
- value = "<D:configuration/>";
+ case DAV_RESOURCE_TYPE_BASELINE:
+ value = "<D:baseline/>";
break;
- case DAV_RESOURCE_TYPE_REVISION:
- value = "<D:revision/>";
- break;
- default:
+ default:
/* ### bad juju */
break;
}
@@ -496,7 +495,7 @@
case DAV_PROPID_CORE_supportedlock:
if (propdb->lockdb != NULL) {
- value = (*propdb->lockdb->hooks->get_supportedlock)();
+ value = (*propdb->lockdb->hooks->get_supportedlock)(propdb->resource);
}
break;
1.10 +180 -87 apache-2.0/src/modules/dav/main/util.c
Index: util.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/dav/main/util.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- util.c 2000/09/09 09:25:22 1.9
+++ util.c 2000/10/07 00:50:42 1.10
@@ -1502,78 +1502,155 @@
return s;
}
+#define DAV_WORKSPACE_HDR "Workspace"
+#define DAV_TARGET_SELECTOR_HDR "Target-Selector"
+
/* see mod_dav.h for docco */
-const char *dav_get_target_selector(request_rec *r, const ap_xml_elem *version)
+int dav_get_workspace(request_rec *r, const char **workspace)
{
+ const char *ws_uri;
+
+ *workspace = NULL;
+ ws_uri = apr_table_get(r->headers_in, DAV_WORKSPACE_HDR);
+
+ if (ws_uri != NULL) {
+ dav_lookup_result lookup;
+
+ /* make the URI server-relative */
+ lookup = dav_lookup_uri(ws_uri, 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;
+ }
+
+ return lookup.err.status;
+ }
+
+ *workspace = lookup.rnew->uri;
+ }
+
+ return OK;
+}
+
+/* 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) {
- /* DAV:version contains a DAV:href element. find it. */
- if ((version = dav_find_child(version, "href")) == NULL) {
- /* ### this should generate an error... fallthru for now */
- }
- else {
+ /* 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 */
- return strip_white(version->first_cdata.first->text, r->pool);
+ *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;
+ }
- /* no element. see if a Target-Selector header was provided. */
- return apr_table_get(r->headers_in, "Target-Selector");
+ return OK;
}
+/* dav_add_vary_header
+ *
+ * If there were any headers in the request which require a Vary header
+ * in the response, add it.
+ */
+void dav_add_vary_header(request_rec *in_req,
+ request_rec *out_req,
+ const dav_resource *resource)
+{
+ const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req);
+
+ /* 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 *workspace = apr_table_get(in_req->headers_in, DAV_WORKSPACE_HDR);
+ const char *target = apr_table_get(in_req->headers_in, DAV_TARGET_SELECTOR_HDR);
+ const char *vary = apr_table_get(out_req->headers_out, "Vary");
+
+ /* If Workspace header specified, add it to Vary header */
+ if (workspace != NULL) {
+ if (vary == NULL)
+ vary = DAV_WORKSPACE_HDR;
+ else
+ vary = apr_pstrcat(out_req->pool, vary, "," DAV_WORKSPACE_HDR, NULL);
+ }
+
+ /* If Target-Selector specified, add it to the Vary header */
+ if (target != NULL) {
+ if (vary == NULL)
+ vary = DAV_TARGET_SELECTOR_HDR;
+ else
+ vary = apr_pstrcat(out_req->pool, vary, "," DAV_TARGET_SELECTOR_HDR, NULL);
+ }
+
+ if (workspace != NULL || target != NULL)
+ apr_table_setn(out_req->headers_out, "Vary", vary);
+ }
+}
+
/* see mod_dav.h for docco */
dav_error *dav_ensure_resource_writable(request_rec *r,
- dav_resource *resource,
- int parent_only,
- dav_resource **parent_resource,
- int *resource_existed,
- int *resource_was_writable,
- int *parent_was_writable)
+ dav_resource *resource,
+ int parent_only,
+ dav_auto_version_info *av_info)
{
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_resource *parent = NULL;
const char *body;
- int auto_version;
dav_error *err;
- const char *location;
- if (parent_resource != NULL)
- *parent_resource = NULL;
+ /* Initialize results */
+ memset(av_info, 0, sizeof(*av_info));
if (!parent_only) {
- *resource_existed = resource->exists;
- *resource_was_writable = 0;
+ av_info->resource_created = !resource->exists;
}
- if (parent_was_writable != NULL)
- *parent_was_writable = 0;
-
- /* if a Target-Selector header is present, then the client knows about
- * versioning, so it should not be relying on implicit versioning
- */
- auto_version = (dav_get_target_selector(r, NULL) == NULL);
-
/* check parent resource if requested or if resource must be created */
if (!resource->exists || parent_only) {
- parent = (*resource->hooks->get_parent_resource)(resource);
+ dav_resource *parent = (*resource->hooks->get_parent_resource)(resource);
if (parent == NULL || !parent->exists) {
body = apr_psprintf(r->pool,
- "Missing one or more intermediate collections. "
- "Cannot create resource %s.",
- ap_escape_html(r->pool, resource->uri));
+ "Missing one or more intermediate collections. "
+ "Cannot create resource %s.",
+ ap_escape_html(r->pool, resource->uri));
return dav_new_error(r->pool, HTTP_CONFLICT, 0, body);
}
- if (parent_resource != NULL)
- *parent_resource = parent;
+ av_info->parent_resource = parent;
/* if parent not versioned, assume child can be created */
if (!parent->versioned) {
- if (!parent_only)
- *resource_was_writable = 1;
-
- if (parent_was_writable != NULL)
- *parent_was_writable = 1;
return NULL;
}
@@ -1585,118 +1662,134 @@
"provider?");
}
- /* remember whether parent was already writable */
- if (parent_was_writable != NULL)
- *parent_was_writable = parent->working;
-
/* parent must be checked out */
if (!parent->working) {
- if ((err = (*vsn_hooks->checkout)(parent, &location)) != NULL) {
+ /* if parent cannot be automatically checked out, fail */
+ if (!(*vsn_hooks->auto_version_enabled)(parent)) {
+ body = apr_psprintf(r->pool,
+ "Parent collection must be checked out. "
+ "Cannot create resource %s.",
+ ap_escape_html(r->pool, resource->uri));
+ return dav_new_error(r->pool, HTTP_CONFLICT, 0, body);
+ }
+
+ /* Try to checkout the parent collection.
+ * 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))
+ != NULL)
+ {
body = apr_psprintf(r->pool,
- "Unable to checkout parent collection. "
- "Cannot create resource %s.",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to checkout parent collection. "
+ "Cannot create resource %s.",
+ ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
- /* ### what to do with the location? */
+ /* remember that parent was checked out */
+ av_info->parent_checkedout = 1;
}
/* if not just checking parent, create new child resource */
if (!parent_only) {
if ((err = (*vsn_hooks->mkresource)(resource)) != NULL) {
body = apr_psprintf(r->pool,
- "Unable to create versioned resource %s.",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to create versioned resource %s.",
+ ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
+
+ /* remember that resource was created */
+ av_info->resource_created = 1;
}
}
- else {
- /* resource exists: if not versioned, then assume it is writable */
- if (!resource->versioned) {
- *resource_was_writable = 1;
- return NULL;
- }
-
- *resource_was_writable = resource->working;
+ else if (!resource->versioned) {
+ /* resource exists and is not versioned; assume it is writable */
+ return NULL;
}
/* if not just checking parent, make sure child resource is checked out */
if (!parent_only && !resource->working) {
- if ((err = (*vsn_hooks->checkout)(resource, &location)) != NULL) {
+ /* Auto-versioning can only be applied to version selectors, so
+ * no separate working resource will be created. */
+ if ((err = (*vsn_hooks->checkout)(resource, NULL))
+ != NULL)
+ {
body = apr_psprintf(r->pool,
- "Unable to checkout resource %s.",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to checkout resource %s.",
+ ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
- /* ### what to do with the location? */
+ /* remember that resource was checked out */
+ av_info->resource_checkedout = 1;
}
return NULL;
}
/* see mod_dav.h for docco */
-dav_error *dav_revert_resource_writability(request_rec *r,
- dav_resource *resource,
- dav_resource *parent_resource,
- int undo,
- int resource_existed,
- int resource_was_writable,
- int parent_was_writable)
+dav_error *dav_revert_resource_writability(
+ request_rec *r,
+ dav_resource *resource,
+ int undo,
+ const dav_auto_version_info *av_info)
{
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
const char *body;
dav_error *err;
+ /* If a resource was provided, restore its writable state.
+ * Otherwise, only the parent must have been modified */
if (resource != NULL) {
- if (!resource_was_writable
- && resource->versioned && resource->working) {
+ if (av_info->resource_checkedout) {
if (undo)
err = (*vsn_hooks->uncheckout)(resource);
else
- err = (*vsn_hooks->checkin)(resource);
+ err = (*vsn_hooks->checkin)(resource, NULL);
if (err != NULL) {
body = apr_psprintf(r->pool,
- "Unable to %s resource %s.",
- undo ? "uncheckout" : "checkin",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to %s resource %s.",
+ undo ? "uncheckout" : "checkin",
+ ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}
}
- if (undo && !resource_existed && resource->exists) {
+ /* If undoing because of an error, and the resource was created,
+ * then remove it */
+ if (undo && av_info->resource_created) {
dav_response *response;
/* ### should we do anything with the response? */
if ((err = (*resource->hooks->remove_resource)(resource,
&response)) != NULL) {
body = apr_psprintf(r->pool,
- "Unable to undo creation of resource %s.",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to undo creation of resource %s.",
+ ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}
}
}
- if (parent_resource != NULL && !parent_was_writable
- && parent_resource->versioned && parent_resource->working) {
+ /* If parent resource was made writable, restore its state */
+ if (av_info->parent_resource != NULL && av_info->parent_checkedout) {
if (undo)
- err = (*vsn_hooks->uncheckout)(parent_resource);
+ err = (*vsn_hooks->uncheckout)(av_info->parent_resource);
else
- err = (*vsn_hooks->checkin)(parent_resource);
+ err = (*vsn_hooks->checkin)(av_info->parent_resource, NULL);
if (err != NULL) {
body = apr_psprintf(r->pool,
- "Unable to %s parent collection of %s.",
- undo ? "uncheckout" : "checkin",
- ap_escape_html(r->pool, resource->uri));
+ "Unable to %s parent collection %s.",
+ undo ? "uncheckout" : "checkin",
+ ap_escape_html(r->pool, av_info->parent_resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}