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/09/09 11:25:29 UTC
cvs commit: apache-2.0/src/modules/dav/main mod_dav.c mod_dav.h util.c
gstein 00/09/09 02:25:27
Modified: src/modules/dav/main mod_dav.c mod_dav.h util.c
Log:
update the WebDAV versioning support:
- recognize and dispatch the latest set of DeltaV methods
- refine the CHECKOUT provider hook
- add avail_reports provider hook
- fix the "target" resolution mechanism
Revision Changes Path
1.18 +192 -53 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.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- mod_dav.c 2000/08/08 20:03:51 1.17
+++ mod_dav.c 2000/09/09 09:25:22 1.18
@@ -515,14 +515,13 @@
}
/* handy function for return values of methods that (may) create things */
-static int dav_created(request_rec *r, request_rec *rnew,
- dav_resource *res, const char *what,
- int replaced)
+static int dav_created(request_rec *r, const char *locn, const char *what,
+ int replaced)
{
const char *body;
- if (rnew == NULL) {
- rnew = r;
+ if (locn == NULL) {
+ locn = r->uri;
}
/* did the target resource already exist? */
@@ -534,11 +533,11 @@
/* Per HTTP/1.1, S10.2.2: add a Location header to contain the
* URI that was created. */
- /* ### rnew->uri does not contain an absoluteURI. S14.30 states that
+ /* ### 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", rnew->uri);
+ apr_table_setn(r->headers_out, "Location", locn);
#endif
/* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
@@ -546,8 +545,7 @@
/* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
* we must manufacture the entire response. */
body = apr_psprintf(r->pool, "%s %s has been created.",
- what,
- ap_escape_html(rnew->pool, rnew->uri));
+ what, ap_escape_html(r->pool, locn));
return dav_error_response(r, HTTP_CREATED, body);
}
@@ -599,7 +597,8 @@
}
/* resolve a request URI to a resource descriptor */
-static int dav_get_resource(request_rec *r, dav_resource **res_p)
+static int dav_get_resource(request_rec *r, const char *target,
+ dav_resource **res_p)
{
void *data;
@@ -612,7 +611,7 @@
conf = ap_get_module_config(r->per_dir_config, &dav_module);
/* have somebody store it into the request's user data... */
- rv = ap_run_get_resource(r, conf->dir, dav_get_target_selector(r));
+ rv = ap_run_get_resource(r, conf->dir, target);
if (rv == DECLINED) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
@@ -673,6 +672,46 @@
return 1;
}
+static int available_report(request_rec *r, const dav_resource *resource)
+{
+ const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
+ dav_error *err;
+ const dav_report_elem *reports;
+
+ if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) {
+ err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
+ apr_psprintf(r->pool,
+ "Could not fetch a list of the "
+ "available reports."),
+ err);
+ return dav_handle_err(r, err, NULL);
+ }
+
+ /* set the correct status and Content-Type */
+ r->status = 200;
+ r->content_type = DAV_XML_CONTENT_TYPE;
+
+ /* send all the headers now */
+ ap_send_http_header(r);
+
+ /* send the response... */
+ ap_rputs(DAV_XML_HEADER DEBUG_CR
+ "<D:report-set xmlns:D=\"DAV:\">" DEBUG_CR
+ "<D:available-report/>" DEBUG_CR,
+ r);
+
+ for (; reports->namespace != NULL; ++reports) {
+ /* Note: we presume reports->namespace is propertly XML/URL quoted */
+ ap_rprintf(r, "<%s xmlns=\"%s\"/>" DEBUG_CR,
+ reports->name, reports->namespace);
+ }
+
+ ap_rputs("</D:report-set>" DEBUG_CR, r);
+
+ /* the response has been sent. */
+ return DONE;
+}
+
/* handle the GET method */
static int dav_method_get(request_rec *r)
{
@@ -683,7 +722,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, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -876,7 +915,7 @@
int result;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK) {
return result;
}
@@ -917,7 +956,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK) {
return result;
}
@@ -1100,7 +1139,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", resource_existed);
+ return dav_created(r, NULL, "Resource", resource_existed);
}
/* ### move this to dav_util? */
@@ -1140,7 +1179,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -1268,7 +1307,7 @@
ap_set_content_length(r, 0);
/* resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
@@ -1475,7 +1514,7 @@
dav_walker_ctx ctx = { 0 };
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
@@ -1739,7 +1778,7 @@
dav_prop_ctx *ctx;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -1940,7 +1979,7 @@
&dav_module);
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
@@ -2036,7 +2075,7 @@
}
/* return an appropriate response (HTTP_CREATED) */
- return dav_created(r, NULL, resource, "Collection", 0);
+ return dav_created(r, NULL, "Collection", 0);
}
/* handle the COPY and MOVE methods */
@@ -2064,7 +2103,7 @@
int resource_state;
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2118,7 +2157,7 @@
}
/* Resolve destination resource */
- result = dav_get_resource(lookup.rnew, &resnew);
+ result = dav_get_resource(lookup.rnew, NULL, &resnew);
if (result != OK)
return result;
@@ -2414,7 +2453,7 @@
}
/* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
- return dav_created(r, lookup.rnew, resnew, "Destination", replaced);
+ return dav_created(r, lookup.rnew->uri, "Destination", replaced);
}
/* dav_method_lock: Handler to implement the DAV LOCK method
@@ -2428,7 +2467,7 @@
int result;
int depth;
int new_lock_request = 0;
- ap_xml_doc *doc = NULL;
+ ap_xml_doc *doc;
dav_lock *lock;
dav_response *multi_response = NULL;
dav_lockdb *lockdb;
@@ -2450,7 +2489,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
@@ -2633,7 +2672,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
@@ -2674,17 +2713,10 @@
return HTTP_NO_CONTENT;
}
-/* handle the SEARCH method from DASL */
-static int dav_method_search(request_rec *r)
+static int dav_method_vsn_control(request_rec *r)
{
- /* ### we know this method, but we won't allow it yet */
- /* Apache will supply a default error for this. */
+ /* ### */
return HTTP_METHOD_NOT_ALLOWED;
-
- /* Do some error checking, like if the querygrammar is
- * supported by the content type, and then pass the
- * request on to the appropriate query module.
- */
}
/* handle the CHECKOUT method */
@@ -2694,18 +2726,35 @@
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;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
- /* ### eventually check body for DAV:checkin-policy */
- 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, "checkout")) {
+ /* 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:checkout element.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ target = dav_get_target_selector(r, dav_find_child(doc->root,
+ "version"));
}
+ else {
+ target = dav_get_target_selector(r, NULL);
+ }
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, target, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2734,7 +2783,7 @@
/* ### do lock checks, once behavior is defined */
/* Do the checkout */
- if ((err = (*vsn_hooks->checkout)(resource)) != NULL) {
+ if ((err = (*vsn_hooks->checkout)(resource, &location)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not CHECKOUT resource %s.",
@@ -2742,12 +2791,11 @@
err);
return dav_handle_err(r, err, NULL);
}
-
- /* no body */
- ap_set_content_length(r, 0);
- ap_send_http_header(r);
- return DONE;
+ /* set the Location and Cache-Control headers, per the spec */
+ apr_table_setn(r->headers_out, "Location", location);
+ apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
+ return dav_created(r, location, "Working resource", 0);
}
/* handle the UNCHECKOUT method */
@@ -2767,7 +2815,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2829,7 +2877,7 @@
}
/* Ask repository module to resolve the resource */
- result = dav_get_resource(r, &resource);
+ result = dav_get_resource(r, NULL, &resource);
if (result != OK)
return result;
if (!resource->exists) {
@@ -2874,7 +2922,80 @@
return DONE;
}
+static int dav_method_set_target(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+
+static int dav_method_label(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+
+static int dav_method_report(request_rec *r)
+{
+ dav_resource *resource;
+ const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
+ int result;
+ ap_xml_doc *doc;
+
+ /* If no versioning provider, decline the request */
+ if (vsn_hooks == NULL)
+ return DECLINED;
+
+ if ((result = ap_xml_parse_input(r, &doc)) != OK)
+ return result;
+ if (doc == NULL) {
+ /* This supplies additional information for the default msg. */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+ "The request body must specify a report.");
+ return HTTP_BAD_REQUEST;
+ }
+
+ /* Ask repository module to resolve the resource */
+ result = dav_get_resource(r, NULL, &resource);
+ if (result != OK)
+ return result;
+ if (!resource->exists) {
+ /* Apache will supply a default error for this. */
+ return HTTP_NOT_FOUND;
+ }
+
+ if (dav_validate_root(doc, "available-report")) {
+ return available_report(r, resource);
+ }
+
+ /* ### run report hook */
+ return DECLINED;
+}
+
+static int dav_method_make_workspace(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+static int dav_method_make_activity(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+
+static int dav_method_baseline_control(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+
+static int dav_method_merge(request_rec *r)
+{
+ /* ### */
+ return HTTP_METHOD_NOT_ALLOWED;
+}
+
+
/*
* Response handler for DAV resources
*/
@@ -2993,8 +3114,8 @@
return DECLINED;
}
- if (!strcmp(r->method, "SEARCH")) {
- return dav_method_search(r);
+ if (!strcmp(r->method, "VERSION-CONTROL")) {
+ return dav_method_vsn_control(r);
}
if (!strcmp(r->method, "CHECKOUT")) {
@@ -3009,15 +3130,33 @@
return dav_method_checkin(r);
}
-#if 0
- if (!strcmp(r->method, "MKRESOURCE")) {
- return dav_method_mkresource(r);
+ if (!strcmp(r->method, "SET-TARGET")) {
+ return dav_method_set_target(r);
+ }
+
+ if (!strcmp(r->method, "LABEL")) {
+ return dav_method_label(r);
}
if (!strcmp(r->method, "REPORT")) {
return dav_method_report(r);
}
-#endif
+
+ if (!strcmp(r->method, "MKWORKSPACE")) {
+ return dav_method_make_workspace(r);
+ }
+
+ if (!strcmp(r->method, "MKACTIVITY")) {
+ return dav_method_make_activity(r);
+ }
+
+ if (!strcmp(r->method, "BASELINE-CONTROL")) {
+ return dav_method_baseline_control(r);
+ }
+
+ if (!strcmp(r->method, "MERGE")) {
+ return dav_method_merge(r);
+ }
/* ### add'l methods for Advanced Collections, ACLs, DASL */
1.15 +36 -3 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.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- mod_dav.h 2000/08/02 05:26:59 1.14
+++ mod_dav.h 2000/09/09 09:25:22 1.15
@@ -1455,10 +1455,16 @@
/* dav_get_target_selector:
*
- * Returns any Target-Selector header in a request
+ * 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
+ * request headers are examined for a Target-Selector header.
+ *
+ * The target version, if any, is then returned.
+ *
* (used by versioning clients)
*/
-const char *dav_get_target_selector(request_rec *r);
+const char *dav_get_target_selector(request_rec *r,
+ const ap_xml_elem *version);
/* Ensure that a resource is writable. If there is no versioning
* provider, then this is essentially a no-op. Versioning repositories
@@ -1504,6 +1510,18 @@
int resource_was_writable,
int parent_was_writable);
+/*
+** This structure is used to describe available reports
+**
+** "namespace" 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 *name; /* element name for the XML report */
+} dav_report_elem;
+
+
/* Versioning provider hooks */
struct dav_hooks_vsn
{
@@ -1519,8 +1537,10 @@
/* Checkout a resource. If successful, the resource
* object state is updated appropriately.
+ *
+ * The location of the working resource should be returned in *location.
*/
- dav_error * (*checkout)(dav_resource *resource);
+ dav_error * (*checkout)(dav_resource *resource, const char **location);
/* Uncheckout a resource. If successful, the resource
* object state is updated appropriately.
@@ -1542,6 +1562,19 @@
* Returns != 0 if auto-versioning is enabled.
*/
int (*auto_version_enabled)(const dav_resource *resource);
+
+ /*
+ ** Return the set of reports available at this resource.
+ **
+ ** An array of report elements should be returned, with an end-marker
+ ** element containing namespace==NULL. The report response will be
+ ** constructed and returned.
+ **
+ ** DAV:available-report should not be returned; the mod_dav core will
+ ** handle that.
+ */
+ dav_error * (*avail_reports)(const dav_resource *resource,
+ const dav_report_elem **reports);
};
1.9 +47 -37 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.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- util.c 2000/08/08 20:03:52 1.8
+++ util.c 2000/09/09 09:25:22 1.9
@@ -1480,35 +1480,48 @@
return NULL;
}
-/* dav_get_target_selector:
- *
- * Returns any Target-Selector header in a request
- * (used by versioning clients)
- */
-const char *dav_get_target_selector(request_rec *r)
+static const char *strip_white(const char *s, apr_pool_t *pool)
{
+ apr_size_t idx;
+
+ /* trim leading whitespace */
+ while (apr_isspace(*s)) /* assume: return false for '\0' */
+ ++s;
+
+ /* trim trailing whitespace */
+ idx = strlen(s) - 1;
+ if (apr_isspace(s[idx])) {
+ char *s2 = apr_pstrdup(pool, s);
+
+ while (apr_isspace(s2[idx]) && idx > 0)
+ --idx;
+ s2[idx + 1] = '\0';
+ return s2;
+ }
+
+ return s;
+}
+
+/* see mod_dav.h for docco */
+const char *dav_get_target_selector(request_rec *r, const ap_xml_elem *version)
+{
+ 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 {
+ /* return the contents of the DAV:href element */
+ /* ### this presumes no child elements */
+ return strip_white(version->first_cdata.first->text, r->pool);
+ }
+ }
+
+ /* no element. see if a Target-Selector header was provided. */
return apr_table_get(r->headers_in, "Target-Selector");
}
-/* Ensure that a resource is writable. If there is no versioning
- * provider, then this is essentially a no-op. Versioning repositories
- * require explicit resource creation and checkout before they can
- * be written to. If a new resource is to be created, or an existing
- * resource deleted, the parent collection must be checked out as well.
- *
- * Set the parent_only flag to only make the parent collection writable.
- * 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())
- */
+/* see mod_dav.h for docco */
dav_error *dav_ensure_resource_writable(request_rec *r,
dav_resource *resource,
int parent_only,
@@ -1522,6 +1535,7 @@
const char *body;
int auto_version;
dav_error *err;
+ const char *location;
if (parent_resource != NULL)
*parent_resource = NULL;
@@ -1537,7 +1551,7 @@
/* 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);
+ 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) {
@@ -1577,13 +1591,15 @@
/* parent must be checked out */
if (!parent->working) {
- if ((err = (*vsn_hooks->checkout)(parent)) != NULL) {
+ if ((err = (*vsn_hooks->checkout)(parent, &location)) != NULL) {
body = apr_psprintf(r->pool,
"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? */
}
/* if not just checking parent, create new child resource */
@@ -1608,26 +1624,20 @@
/* if not just checking parent, make sure child resource is checked out */
if (!parent_only && !resource->working) {
- if ((err = (*vsn_hooks->checkout)(resource)) != NULL) {
+ if ((err = (*vsn_hooks->checkout)(resource, &location)) != NULL) {
body = apr_psprintf(r->pool,
"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? */
}
return NULL;
}
-/* Revert the writability of resources back to what they were
- * before they were modified. If undo == 0, then the resource
- * modifications are maintained (i.e. they are checked in).
- * 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).
- */
+/* see mod_dav.h for docco */
dav_error *dav_revert_resource_writability(request_rec *r,
dav_resource *resource,
dav_resource *parent_resource,