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,