mod_dav.c revision 4f01ee597f569d80e2e81f912e425a572002328c
* - For PROPFIND, we batch up the entire response in memory before * sending it. We may want to reorganize around sending the information * as we suck it in from the propdb. Alternatively, we should at least * generate a total Content-Length if we're going to buffer in memory * so that we can keep the connection open. /* ### what is the best way to set this? */ /* used to denote that mod_dav will be handling this request */ /* per-dir configuration */ /* per-server configuration */ /* forward-declare for use in configuration lookup */ /* DBG0("dav_init_handler"); */ /* Register DAV methods */ /* ### this isn't used at the moment... */ /* ### nothing to merge right now... */ /* NOTE: dir==NULL creates the default per-dir config */ /* clean up the directory to remove any trailing slash */ if (l >
1 && d[l -
1] ==
'/')
/* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx", (long)newconf, (long)base, (long)overrides); */ "\"DAV Off\" cannot be used to turn off a subtree " "of a DAV-enabled location.");
"A subtree cannot specify a different DAV provider " /* assert: conf->provider_name != NULL (otherwise, DAV is disabled, and we wouldn't be here) */ /* assert: conf->provider != NULL (checked when conf->provider_name is set) */ * Command handler for the DAV directive, which is TAKE1. /* lookup and cache the actual provider now */ /* by the time they use it, the provider should be loaded and "Unknown DAV provider: %s",
* Command handler for the DAVDepthInfinity directive, which is FLAG. * Command handler for DAVMinTimeout directive, which is TAKE1 return "DAVMinTimeout requires a non-negative integer.";
** Send a nice response back to the user. In most cases, Apache doesn't ** allow us to provide details in the body about what happened. This ** function allows us to completely specify the response body. ** ### this function is not logging any errors! (e.g. the body) /* begin the response now... */ /* the response has been sent. */ * ### Use of DONE obviates logging..! * Send a "standardized" error response based on the error's namespace & tag "<D:error xmlns:D=\"DAV:\"", r);
/* ### should move this namespace somewhere (with the others!) */ /* here's our mod_dav specific tag: */ "<m:human-readable errcode=\"%d\">" DEBUG_CR /* the response has been sent. */ * ### Use of DONE obviates logging..! * Apache's URI escaping does not replace '&' since that is a valid character * in a URI (to form a query section). We must explicitly handle it so that * we can embed the URI into an XML document. /* check the easy case... */ /* there was a '&', so more work is needed... sigh. */ * Note: this is a teeny bit of overkill since we know there are no * '<' or '>' characters, but who cares. /* Write a complete RESPONSE object out as a <DAV:repsonse> xml element. Data is sent into brigade BB, which is auto-flushed into OUTPUT filter stack. Use POOL for any temporary allocations. [Presumably the <multistatus> tag has already been written; this routine is shared by dav_send_multistatus and dav_stream_response.] /* use the Status-Line text from Apache. Note, this will * default to 500 Internal Server Error if first->status * is not a known (or valid) status code. /* assume this includes <propstat> and is quoted properly */ * We supply the description, so we know it doesn't have to "<D:responsedescription>",
/* Factorized helper function: prep request_rec R for a multistatus response and write <multistatus> tag into BB, destined for R->output_filters. Use xml NAMESPACES in initial tag, if /* Set the correct status and Content-Type */ /* Send the headers and actual multistatus response now... */ "<D:multistatus xmlns:D=\"DAV:\"");
/* Finish a multistatus response started by dav_begin_multistatus: */ /* indicate the end of the response body */ /* deliver whatever might be remaining in the brigade */ * Write error information to the log. /* ### should have a directive to log the first or all */ * Handle the standard error processing. <err> must be non-NULL. * <response> is set by the following: * - dav_validate_request() * - repos_hooks->remove_resource * - repos_hooks->move_resource * - repos_hooks->copy_resource /* our error messages are safe; tell Apache this */ /* Didn't get a multistatus response passed in, but we still might be able to generate a standard <D:error> response. Search the error stack for an errortag. */ /* handy function for return values of methods that (may) create things. * locn if provided is assumed to be escaped. */ /* did the target resource already exist? */ /* Apache will supply a default message */ /* Per HTTP/1.1, S10.2.2: add a Location header to contain the * URI that was created. */ /* Convert locn to an absolute URI, and return in Location header */ /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */ /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so * we must manufacture the entire response. */ /* ### move to dav_util? */ /* The caller will return an HTTP_BAD_REQUEST. This will augment the * default message that Apache provides. */ "An invalid Depth header was specified.");
return 1;
/* default is "T" */ /* The caller will return an HTTP_BAD_REQUEST. This will augment the * default message that Apache provides. */ "An invalid Overwrite header was specified.");
/* resolve a request URI to a resource descriptor. * If label_allowed != 0, then allow the request target to be altered by * If use_checked_in is true, then the repository provider should return * the resource identified by the DAV:checked-in property of the resource * identified by the Request-URI. /* if the request target can be overridden, get any target selector */ /* assert: conf->provider != NULL */ "DAV not enabled for %s",
/* resolve the resource */ "Could not fetch resource information.",
err);
/* Note: this shouldn't happen, but just be sure... */ /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */ "The provider did not define a " /* ### 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, /* open the thing lazily */ * @return 1 if valid content-range, * -1 if malformed content-range /* detect invalid ranges */ /* we now have a valid range */ /* handle the GET method */ /* This method should only be called when the resource is not * visible to Apache. We will fetch the resource from the repository, * then create a subrequest for Apache to handle. /* Apache will supply a default error for this. */ /* set up the HTTP headers for the response */ "Unable to set up HTTP headers.",
/* Handle conditional requests */ /* okay... time to deliver the content */ "Unable to deliver content.",
/* validate resource/locks on POST, then pass to the default handler */ /* Ask repository module to resolve the resource */ /* Note: depth == 0. Implies no need for a multistatus response. */ /* ### add a higher-level description? */ /* handle the PUT method */ /* Ask repository module to resolve the resource */ /* If not a file or collection resource, PUT not allowed */ "Cannot create resource %s with PUT.",
/* Cannot PUT a collection */ "Cannot PUT to a collection.");
* Note: depth == 0 normally requires no multistatus response. However, * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI * other than the Request-URI, thereby requiring a multistatus. * If the resource does not exist (DAV_RESOURCE_NULL), then we must * check the resource *and* its parent. If the resource exists or is * a locknull resource, then we check only the resource. /* ### add a higher-level description? */ /* RFC 2616 14.16: If we receive an invalid Content-Range we must "Malformed Content-Range header for PUT %s.",
/* make sure the resource can be modified (if versioning repository) */ /* ### add a higher-level description? */ /* Create the new file in the repository */ "Unable to PUT new contents for %s.",
/* a range was provided. seek to the start */ /* XXX: should this actually be HTTP_BAD_REQUEST? */ "An error occurred while reading" " the request body (URI: %s)",
msg);
/* write whatever we read, until we see an error */ "An error occurred while" " reading the request body" " from the bucket (URI: %s)",
* Ensure that we think the resource exists now. * ### eek. if an error occurred during the write and we did not commit, /* restore modifiability of resources back to what they were */ /* check for errors now */ "The PUT was successful, but there " "was a problem automatically checking in " "the resource or its parent collection.",
/* ### place the Content-Type and Content-Language into the propdb */ /* The file creation was successful, but the locking failed. */ "The file was PUT successfully, but there " "was a problem opening the lock database " "which prevents inheriting locks from the " /* The file creation was successful, but the locking failed. */ "The file was PUT successfully, but there " "was a problem updating its lock " /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */ /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ /* Use POOL to temporarily construct a dav_response object (from WRES STATUS, and PROPSTATS) and stream it via WRES's ctx->brigade. */ /* ### move this to dav_util? */ /* just drop some data into an dav_response */ /* handle the DELETE method */ /* We don't use the request body right now, so torch it. */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* 2518 says that depth must be infinity only for collections. * For non-collections, depth is ignored, unless it is an illegal value (1). /* This supplies additional information for the default message. */ "Depth must be \"infinity\" for DELETE of a collection.");
/* This supplies additional information for the default message. */ "Depth of \"1\" is not allowed for DELETE.");
** If any resources fail the lock/If: conditions, then we must fail ** the delete. Each of the failing resources will be listed within ** a DAV:multistatus body, wrapped into a 424 response. ** Note that a failure on the resource itself does not generate a "Could not DELETE %s due to a failed " "precondition (e.g. locks).",
/* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those * locked by the token(s) in the if_header. /* if versioned resource, make sure parent is checked out */ /* ### add a higher-level description? */ /* try to remove the resource */ /* restore writability of parent back to what it was */ /* check for errors now */ "The DELETE was successful, but there " "was a problem automatically checking in " "the parent collection.",
/* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */ /* Apache will supply a default error for this. */ /* generate DAV:supported-method-set OPTIONS response */ /* show all supported methods */ "<D:supported-method D:name=\"%s\"/>" /* check for support of specific methods */ /* go through attributes to find method name */ "A DAV:supported-method element " "does not have a \"name\" attribute");
/* see if method is supported */ "<D:supported-method D:name=\"%s\"/>" /* generate DAV:supported-live-property-set OPTIONS response */ /* open lock database, to report on supported lock properties */ /* ### should open read-only */ "The lock database could not be opened, " "preventing the reporting of supported lock " /* open the property database (readonly) for the resource */ "The property database could not be opened, " "preventing report of supported properties.",
/* show all supported live properties */ /* check for support of specific live property */ /* go through attributes to find name and namespace */ "A DAV:supported-live-property " "element does not have a \"name\" " /* default namespace to DAV: */ /* check for support of property */ /* generate DAV:supported-report-set OPTIONS response */ "DAV:supported-report-set could not be " "determined due to a problem fetching the " "available reports for this resource.",
/* show all supported reports */ /* Note: we presume reports->namespace is "<D:supported-report D:name=\"%s\" " /* check for support of specific report */ /* go through attributes to find name and namespace */ "A DAV:supported-report element " "does not have a \"name\" attribute");
/* default namespace to DAV: */ /* Note: we presume reports->nmspace is /* handle the SEARCH method */ /* If no search provider, decline the request */ /* This method should only be called when the resource is not * visible to Apache. We will fetch the resource from the repository, * then create a subrequest for Apache to handle. /* Apache will supply a default error for this. */ /* set up the HTTP headers for the response */ "Unable to set up HTTP headers.",
/* okay... time to search the content */ /* Let's validate XML and process walk function /* ### add a higher-level description? */ /* We have results in multi_status */ /* Should I pass namespace?? */ /* handle the OPTIONS method */ /* resolve the resource */ /* parse any request body */ /* note: doc == NULL if no request body */ "The \"options\" element was not found.");
/* determine which providers are available */ /* DAV header additions registered by external modules */ * MSFT Web Folders chokes if length of DAV header value > 63 characters! * To workaround that, we use separate DAV headers for versioning and * live prop provider namespace URIs. * If there is a versioning provider, generate DAV headers * for versioning options. * Gather property set URIs from all the liveprop providers, * and generate a separate DAV header for each URI, to avoid * problems with long header lengths. /* this tells MSFT products to skip looking for FrontPage extensions */ * Determine which methods are allowed on the resource. * Three cases: resource is null (3), is lock-null (7.4), or exists. * All cases support OPTIONS, and if there is a lock provider, LOCK. * (Lock-) null resources also support MKCOL and PUT. * Lock-null supports PROPFIND and UNLOCK. * Existing resources support lots of stuff. /* ### take into account resource type */ /* resource is lock-null. */ /* ### internal error! */ /* If there is a versioning provider, add versioning methods */ /* ### we might not support this DeltaV option */ /* If there is a bindings provider, see if resource is bindable */ /* If there is a search provider, set SEARCH in option */ /* additional methods registered by external modules */ /* Generate the Allow header */ /* first, compute total length */ /* add 1 for comma or null */ /* If there is search set_option_head function, set head */ /* DASL: <DAV:basicsearch> /* if there was no request body, then there is no response body */ /* ### this sends a Content-Type. the default OPTIONS does not. */ /* ### the default (ap_send_http_options) returns OK, but I believe * ### that is because it is the default handler and nothing else * ### will run after the thing. */ /* handle each options request */ /* check for something we recognize first */ /* if unrecognized option, pass to versioning provider */ /* send the options response */ /* send the headers and response body */ "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r);
/* we've sent everything necessary to the client. */ /* just return if we built the thing already */ "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since ** dav_get_allprops() does not need to do namespace translation, ** Note: we cast to lose the "const". The propdb won't try to change ** the resource, however, since we are opening readonly. /* ### do something with err! */ /* ### what to do about closing the propdb on server failure? */ /* at this point, ctx->scratchpool has been used to stream a single response. this function fully controls the pool, and thus has the right to clear it for the next iteration of this /* handle the PROPFIND method */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* dav_get_depth() supplies additional information for the /* default is to DISALLOW these requests */ "PROPFIND requests with a " "Depth of \"infinity\" are " /* note: doc == NULL if no request body */ /* This supplies additional information for the default message. */ "The \"propfind\" element was not found.");
/* ### validate that only one of these three elements is present */ /* note: no request body implies allprop */ /* "propfind" element must have one of the above three children */ /* This supplies additional information for the default message. */ "The \"propfind\" element does not contain one of " "the required child elements (the specific command).");
/* ### should open read-only */ "The lock database could not be opened, " "preventing access to the various lock " "properties for the PROPFIND.",
/* if we have a lock database, then we can walk locknull resources */ /* send <multistatus> tag, with all doc->namespaces attached. */ /* NOTE: we *cannot* leave out the doc's namespaces from the initial <multistatus> tag. if a 404 was generated for an HREF, then we need to spit out the doc's namespaces for use by the 404. Note that <response> elements will override these ns0, ns1, etc, but NOT within the <response> scope for the /* Have the provider walk the resource. */ /* If an error occurred during the resource walk, there's basically nothing we can do but abort the connection and log an error. This is one of the limitations of HTTP; it needs to "know" the entire status of the response before generating it, which is just impossible in these streamy "Provider encountered an error while streaming" " a multistatus PROPFIND response.",
err);
/* the response has been sent. */ /* ### might be nice to sort by status code and description */ for ( ; i-- > 0; ++
ctx ) {
/* nothing was assigned here yet, so make it a 424 */ "Attempted DAV:set operation " "could not be completed due " "operation could not be " "completed due to other " /* ### we should use compute_desc if necessary... */ * ### we probably need to revise the way we assemble the response... * ### this code assumes everything will return status==200. for ( ; i-- > 0; ++
ctx ) {
"<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR * Call <func> for each context. This can stop when an error occurs, or * simply iterate through the whole list. * Returns 1 if an error occurs (and the iteration is aborted). Returns 0 * if all elements are processed. * If <reverse> is true (non-zero), then the list is traversed in /* handle the PROPPATCH method */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* note: doc == NULL if no request body */ /* This supplies additional information for the default message. */ "The request body does not contain " "a \"propertyupdate\" element.");
/* Check If-Headers and existing locks */ /* Note: depth == 0. Implies no need for a multistatus response. */ /* ### add a higher-level description? */ /* make sure the resource can be modified (if versioning repository) */ /* ### add a higher-level description? */ /* undo any auto-checkout */ "Could not open the property " /* ### what to do about closing the propdb on server failure? */ /* ### validate "live" properties */ /* set up an array to hold property operation contexts */ /* do a first pass to ensure that all "remove" properties exist */ /* Ignore children that are not set/remove */ /* make sure that a "prop" child exists for set/remove */ /* undo any auto-checkout */ /* This supplies additional information for the default message. */ "A \"prop\" element is missing inside " "the propertyupdate command.");
ctx->r = r;
/* for later use by dav_prop_log_errors() */ /* ### should test that we found at least one set/remove */ /* execute all of the operations */ /* make sure this gets closed! */ /* complete any auto-versioning */ /* log any errors that occurred */ /* ### should probably use something new to pass along this text... */ /* the response has been sent. */ /* This is snarfed from ap_setup_client_block(). We could get pretty * close to this behavior by passing REQUEST_NO_BODY, but we need to * return HTTP_UNSUPPORTED_MEDIA_TYPE (while ap_setup_client_block * returns HTTP_REQUEST_ENTITY_TOO_LARGE). */ /* make sure to set the Apache request fields properly. */ /* Use this instead of Apache's default error string */ "Unknown Transfer-Encoding %s",
tenc);
/* This supplies additional information for the default message. */ "Invalid Content-Length %s",
lenp);
/* Apache will supply a default error for this. */ * Get rid of the body. this will call ap_setup_client_block(), but * our copy above has already verified its work. /* handle the MKCOL method */ /* handle the request body */ /* ### this may move lower once we start processing bodies */ /* Ask repository module to resolve the resource */ /* oops. something was already there! */ /* Apache will supply a default error for this. */ /* ### we should provide a specific error message! */ * Check If-Headers and existing locks. * Note: depth == 0 normally requires no multistatus response. However, * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI * other than the Request-URI, thereby requiring a multistatus. * If the resource does not exist (DAV_RESOURCE_NULL), then we must * check the resource *and* its parent. If the resource exists or is * a locknull resource, then we check only the resource. /* ### add a higher-level description? */ /* if versioned resource, make sure parent is checked out */ /* ### add a higher-level description? */ /* try to create the collection */ /* restore modifiability of parent back to what it was */ /* check for errors now */ "The MKCOL was successful, but there " "was a problem automatically checking in " "the parent collection.",
/* The directory creation was successful, but the locking failed. */ "The MKCOL was successful, but there " "was a problem opening the lock database " "which prevents inheriting locks from the " /* The dir creation was successful, but the locking failed. */ "The MKCOL was successful, but there " "was a problem updating its lock " /* return an appropriate response (HTTP_CREATED) */ /* handle the COPY and MOVE methods */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* If not a file or collection resource, COPY/MOVE not allowed */ /* ### allow COPY/MOVE of DeltaV resource types */ /* get the destination URI */ /* Look in headers provided by Netscape's Roaming Profiles */ /* This supplies additional information for the default message. */ "The request is missing a Destination header.");
/* This supplies additional information for the default message. */ /* ### this assumes that dav_lookup_uri() only generates a status * ### that Apache can provide a status line for!! */ /* propagate the WWW-Authorization header up from the * subreq so the client sees it. */ /* ### how best to report this... */ "Destination URI had an error.");
/* Resolve destination resource */ 0
/* use_checked_in */, &
resnew);
/* are the two resources handled by the same repository? */ /* ### this message exposes some backend config, but screw it... */ "Destination URI is handled by a " "different repository than the source URI. " "MOVE or COPY between repositories is " /* get and parse the overwrite header value */ /* dav_get_overwrite() supplies additional information for the /* quick failure test: if dest exists and overwrite is false. */ /* Supply some text for the error response body. */ "Destination is not empty and " "Overwrite is not \"T\"");
/* are the source and destination the same? */ /* Supply some text for the error response body. */ "Source and Destination URIs are the same.");
/* get and parse the Depth header value. "0" and "infinity" are legal. */ /* dav_get_depth() supplies additional information for the /* This supplies additional information for the default message. */ "Depth must be \"0\" or \"infinity\" for COPY or MOVE.");
/* This supplies additional information for the default message. */ "Depth must be \"infinity\" when moving a collection.");
* Check If-Headers and existing locks for each resource in the source. * We will return a 424 response with a DAV:multistatus body. * The multistatus responses will contain the information about any * resource that fails the validation. * We check the parent resource, too, if this is a MOVE. Moving the * resource effectively removes it from the parent collection, so we * must ensure that we have met the appropriate conditions. * If a problem occurs with the Request-URI itself, then a plain error * (rather than a multistatus) will be returned. "Could not %s %s due to a failed " "precondition on the source " * Check If-Headers and existing locks for destination. Note that we * use depth==infinity since the target (hierarchy) will be deleted * Note that we are overwriting the target, which implies a DELETE, so * we are subject to the error/response rules as a DELETE. Namely, we * will return a 424 error if any of the validations fail. * (see dav_method_delete() for more information) "failed precondition on the " "destination (e.g. locks).",
/* Supply some text for the error response body. */ "Source collection contains the " /* The destination must exist (since it contains the source), and * a condition above implies Overwrite==T. Obviously, we cannot * delete the Destination before the MOVE/COPY, as that would /* Supply some text for the error response body. */ "Destination collection contains the Source " "and Overwrite has been specified.");
/* ### for now, we don't need anything in the body */ /* ### add a higher-level description? */ /* remove any locks from the old resources */ * ### this is Yet Another Traversal. if we do a rename(), then we * ### really don't have to do this in some cases since the inode * ### values will remain constant across the move. but we can't * ### know that fact from outside the provider :-( * ### note that we now have a problem atomicity in the move/copy * ### since a failure after this would have removed locks (technically, * ### this is okay to do, but really...) /* ### this is wrong! it blasts direct locks on parent resources */ /* if this is a move, then the source parent collection will be modified */ /* ### add a higher-level description? */ * Remember the initial state of the destination, so the lock system * can be notified as to how it changed. /* In a MOVE operation, the destination is replaced by the source. * In a COPY operation, if the destination exists, is under version * control, and is the same resource type as the source, * then it should not be replaced, but modified to be a copy of /* If the destination must be created or replaced, * make sure the parent collection is writable /* could not make destination writable: * if move, restore state of source parent /* ### add a higher-level description? */ /* If source and destination parents are the same, then * use the same resource object, so status updates to one are reflected * in the other, when doing auto-versioning. Otherwise, * we may try to checkin the parent twice. /* If destination is being replaced, remove it first * (we know Ovewrite must be TRUE). Then try to copy/move the resource. /* perform any auto-versioning cleanup */ /* check for errors from auto-versioning */ "The MOVE/COPY was successful, but there was a " "problem automatically checking in the " "source parent collection.",
"The MOVE/COPY was successful, but there was a " "problem automatically checking in the " "destination or its parent collection.",
/* propagate any indirect locks at the target */ /* The move/copy was successful, but the locking failed. */ "The MOVE/COPY was successful, but there " "was a problem updating the lock " /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ /* dav_method_lock: Handler to implement the DAV LOCK method * Returns appropriate HTTP_* response. /* If no locks provider, decline the request */ "Depth must be 0 or \"infinity\" for LOCK.");
/* Ask repository module to resolve the resource */ /* Check if parent collection exists */ /* ### add a higher-level description? */ "The parent resource of %s does not " "exist or is not a collection.",
* Open writable. Unless an error occurs, we'll be * writing into the database. /* ### add a higher-level description? */ /* ### add a higher-level description to err? */ * Check If-Headers and existing locks. * If this will create a locknull resource, then the LOCK will affect * the parent collection (much like a PUT/MKCOL). For that case, we must * validate the parent resource's conditions. "Could not LOCK %s due to a failed " "precondition (e.g. other locks).",
* ### Assumption: We can renew multiple locks on the same resource * ### at once. First harvest all the positive lock-tokens given in * ### the If header. Then modify the lock entries for this resource * ### with the new Timeout val. "The lock refresh for %s failed " "because no lock tokens were " "specified in an \"If:\" " /* ### add a higher-level description to err? */ /* apply lower bound (if any) from DAVMinTimeout directive */ /* ### add a higher-level description to err? */ /* the response has been sent. */ /* dav_method_unlock: Handler to implement the DAV UNLOCK method * Returns appropriate HTTP_* response. /* If no locks provider, decline the request */ "Lock-Token")) ==
NULL) {
"No Lock-Token specified in header", r->
filename);
/* ### should provide more specifics... */ /* ### should provide more specifics... */ "The UNLOCK on %s failed -- an " "invalid lock token was specified " "in the \"If:\" header.",
/* Ask repository module to resolve the resource */ * Check If-Headers and existing locks. * Note: depth == 0 normally requires no multistatus response. However, * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI * other than the Request-URI, thereby requiring a multistatus. * If the resource is a locknull resource, then the UNLOCK will affect * the parent collection (much like a delete). For that case, we must * validate the parent resource's conditions. /* ### add a higher-level description? */ /* ### RFC 2518 s. 8.11: If this resource is locked by locktoken, * _all_ resources locked by locktoken are released. It does not say * resource has to be the root of an infinte lock. Thus, an UNLOCK * on any part of an infinte lock will remove the lock on all resources. * For us, if r->filename represents an indirect lock (part of an infinity lock), * we must actually perform an UNLOCK on the direct lock for this resource. /* if no versioning provider, decline the request */ /* ask repository module to resolve the resource */ /* remember the pre-creation resource state */ /* parse the request body (may be a version-control element) */ /* note: doc == NULL if no request body */ "The request body does not contain " "a \"version-control\" element.");
/* get the version URI */ "The \"version-control\" element does not contain " "a \"version\" element.");
"The \"version\" element does not contain " "An \"href\" element does not contain a URI.");
/* Check request preconditions */ /* ### need a general mechanism for reporting precondition violations * ### (should be returning XML document for 403/409 responses) /* if not versioning existing resource, must specify version to select */ "<DAV:initial-version-required/>");
/* cannot add resource to existing version history */ "<DAV:cannot-add-to-existing-history/>");
/* resource must be unversioned and versionable, or version selector */ "<DAV:must-be-versionable/>");
/* the DeltaV spec says if resource is a version selector, * then VERSION-CONTROL is a no-op /* set the Cache-Control header, per the spec */ /* Check If-Headers and existing locks */ /* Note: depth == 0. Implies no need for a multistatus response. */ /* if in versioned collection, make sure parent is checked out */ /* attempt to version-control the resource */ "Could not VERSION-CONTROL resource %s.",
/* revert writability of parent directory */ "The VERSION-CONTROL was successful, but there " "was a problem automatically checking in " "the parent collection.",
/* if the resource is lockable, let lock system know of new resource */ /* The resource creation was successful, but the locking failed. */ "The VERSION-CONTROL was successful, but there " "was a problem opening the lock database " "which prevents inheriting locks from the " /* The dir creation was successful, but the locking failed. */ "The VERSION-CONTROL was successful, but there " "was a problem updating its lock " /* set the Cache-Control header, per the spec */ /* return an appropriate response (HTTP_CREATED) */ /* handle the CHECKOUT method */ /* If no versioning provider, decline the request */ /* This supplies additional information for the default msg. */ "The request body, if present, must be a " "DAV:checkout element.");
/* ### we want generic 403/409 XML reporting here */ /* ### DAV:must-not-have-label-and-apply-to-version */ "DAV:apply-to-version cannot be " "used in conjunction with a " /* no href's is a DTD violation: <!ELEMENT activity-set (href+ | new)> /* This supplies additional info for the default msg. */ "Within the DAV:activity-set element, the " "DAV:new element must be used, or at least " "one DAV:href must be specified.");
/* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* Check the state of the resource: must be a file or collection, * must be versioned, and must not already be checked out. "Cannot checkout this type of resource.");
"Cannot checkout unversioned resource.");
"The resource is already checked out to the workspace.");
/* ### do lock checks, once behavior is defined */ "Could not CHECKOUT resource %s.",
/* set the Cache-Control header, per the spec */ /* if no working resource created, return OK, * else return CREATED with working resource URL in Location header /* handle the UNCHECKOUT method */ /* If no versioning provider, decline the request */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* Check the state of the resource: must be a file or collection, * must be versioned, and must be checked out. "Cannot uncheckout this type of resource.");
"Cannot uncheckout unversioned resource.");
"The resource is not checked out to the workspace.");
/* ### do lock checks, once behavior is defined */ "Could not UNCHECKOUT resource %s.",
/* handle the CHECKIN method */ /* If no versioning provider, decline the request */ /* This supplies additional information for the default msg. */ "The request body, if present, must be a " /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* Check the state of the resource: must be a file or collection, * must be versioned, and must be checked out. "Cannot checkin this type of resource.");
"Cannot checkin unversioned resource.");
"The resource is not checked out.");
/* ### do lock checks, once behavior is defined */ "Could not CHECKIN resource %s.",
/* If no versioning provider, or UPDATE not supported, /* dav_get_depth() supplies additional information for the /* parse the request body */ /* This supplies additional information for the default message. */ "The request body does not contain " "an \"update\" element.");
/* check for label-name or version element, but not both */ /* get the href element */ "The version element does not contain " "The \"update\" element does not contain " "a \"label-name\" or \"version\" element.");
/* a depth greater than zero is only allowed for a label */ "Depth must be zero for UPDATE with a version");
/* get the target value (a label or a version URI) */ "A \"label-name\" or \"href\" element does not contain " /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* ### need a general mechanism for reporting precondition violations * ### (should be returning XML document for 403/409 responses) "<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? */ /* This supplies additional information for the default message. */ /* ### this assumes that dav_lookup_uri() only generates a status * ### that Apache can provide a status line for!! */ /* ### how best to report this... */ "Version URI had an error.");
/* resolve version resource */ /* NULL out target, since we're using a version resource */ /* do the UPDATE operation */ /* set the Cache-Control header, per the spec */ /* context maintained during LABEL treewalk */ /* label being manipulated */ /* version provider hooks */ /* Check the state of the resource: must be a version or * non-checkedout version selector /* ### need a general mechanism for reporting precondition violations * ### (should be returning XML document for 403/409 responses) "<DAV:must-be-version-or-version-selector/>");
"<DAV:must-not-be-checked-out/>");
/* do the label operation */ /* ### need utility routine to add response with description? */ /* If no versioning provider, or the provider doesn't support * labels, decline the request */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* dav_get_depth() supplies additional information for the /* parse the request body */ /* This supplies additional information for the default message. */ "The request body does not contain " /* check for add, set, or remove element */ "The \"label\" element does not contain " "an \"add\", \"set\", or \"remove\" element.");
/* get the label string */ "The label command element does not contain " "a \"label-name\" element.");
"A \"label-name\" element does not contain " /* do the label operation walk */ /* some sort of error occurred which terminated the walk */ "The LABEL operation was terminated prematurely.",
/* 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() "Errors occurred during the LABEL operation.");
/* set the Cache-Control header, per the spec */ /* If no versioning provider, decline the request */ /* This supplies additional information for the default msg. */ "The request body must specify a report.");
/* Ask repository module to resolve the resource. * First determine whether a Target-Selector header is allowed /* Apache will supply a default error for this. */ /* set up defaults for the report response */ /* No data has been sent to client yet; throw normal error. */ /* If an error occurred during the report delivery, there's basically nothing we can do but abort the connection and log an error. This is one of the limitations of HTTP; it needs to "know" the entire status of the response before generating it, which is just impossible in these streamy "Provider encountered an error while streaming" " a REPORT response.",
err);
/* if no versioning provider, or the provider does not support workspaces, /* ask repository module to resolve the resource */ /* parse the request body (must be a mkworkspace element) */ "The request body does not contain " "a \"mkworkspace\" element.");
/* Check request preconditions */ /* ### need a general mechanism for reporting precondition violations * ### (should be returning XML document for 403/409 responses) /* resource must not already exist */ "<DAV:resource-must-be-null/>");
/* ### what about locking? */ /* attempt to create the workspace */ "Could not create workspace %s.",
/* set the Cache-Control header, per the spec */ /* return an appropriate response (HTTP_CREATED) */ /* if no versioning provider, or the provider does not support activities, /* ask repository module to resolve the resource */ /* MKACTIVITY does not have a defined request body. */ /* Check request preconditions */ /* ### need a general mechanism for reporting precondition violations * ### (should be returning XML document for 403/409 responses) /* resource must not already exist */ "<DAV:resource-must-be-null/>");
/* the provider must say whether the resource can be created as an activity, i.e. whether the location is ok. */ "<DAV:activity-location-ok/>");
/* ### what about locking? */ /* attempt to create the activity */ "Could not create activity %s.",
/* set the Cache-Control header, per the spec */ /* return an appropriate response (HTTP_CREATED) */ /* If no versioning provider, decline the request */ /* This supplies additional information for the default msg. */ "The request body must be present and must be a " /* This supplies additional information for the default msg. */ "The DAV:merge element must contain a DAV:source " /* This supplies additional information for the default msg. */ "The DAV:source element must contain a DAV:href " /* get a subrequest for the source, so that we can get a dav_resource /* This supplies additional information for the default message. */ /* ### this assumes that dav_lookup_uri() only generates a status * ### that Apache can provide a status line for!! */ /* ### how best to report this... */ "Merge source URI had an error.");
/* ### check RFC. I believe the DAV:merge element may contain any ### element also allowed within DAV:checkout. need to extract them ### here, and pass them along. ### if so, then refactor the CHECKOUT method handling so we can reuse ### the code. maybe create a structure to hold CHECKOUT parameters ### which can be passed to the checkout() and merge() hooks. */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* ### check the source and target resources flags/types */ /* ### do lock checks, once behavior is defined */ /* set the Cache-Control header, per the spec */ /* Initialize these values for a standard MERGE response. If the MERGE is going to do something different (i.e. an error), then it must return a dav_error, and we'll reset these values properly. */ /* ### should we do any preliminary response generation? probably not, ### because we may have an error, thus demanding something else in ### the response body. */ /* Do the merge, including any response generation. */ /* ### is err->status the right error here? */ "Could not MERGE resource \"%s\" " /* the response was fully generated by the merge() hook. */ /* ### urk. does this prevent logging? need to check... */ /* If no bindings provider, decline the request */ /* Ask repository module to resolve the resource */ /* Apache will supply a default error for this. */ /* get the destination URI */ /* This supplies additional information for the default message. */ "The request is missing a Destination header.");
/* This supplies additional information for the default message. */ /* ### Bindings protocol draft 02 says to return 507 * ### (Cross Server Binding Forbidden); Apache already defines 507 * ### as HTTP_INSUFFICIENT_STORAGE. So, for now, we'll return "Cross server bindings are not " "allowed by this server.");
/* ### this assumes that dav_lookup_uri() only generates a status * ### that Apache can provide a status line for!! */ /* ### how best to report this... */ "Destination URI had an error.");
/* resolve binding resource */ /* are the two resources handled by the same repository? */ /* ### this message exposes some backend config, but screw it... */ "Destination URI is handled by a " "different repository than the source URI. " "BIND between repositories is not possible.");
/* get and parse the overwrite header value */ /* dav_get_overwrite() supplies additional information for the /* quick failure test: if dest exists and overwrite is false. */ "Destination is not empty and " "Overwrite is not \"T\"");
/* are the source and destination the same? */ "Source and Destination URIs are the same.");
* Check If-Headers and existing locks for destination. Note that we * use depth==infinity since the target (hierarchy) will be deleted * Note that we are overwriting the target, which implies a DELETE, so * we are subject to the error/response rules as a DELETE. Namely, we * will return a 424 error if any of the validations fail. * (see dav_method_delete() for more information) "Could not BIND %s due to a " "failed precondition on the " "destination (e.g. locks).",
/* guard against creating circular bindings */ "Source collection contains the Destination.");
/* The destination must exist (since it contains the source), and * a condition above implies Overwrite==T. Obviously, we cannot * delete the Destination before the BIND, as that would "Destination collection contains the Source and " "Overwrite has been specified.");
/* prepare the destination collection for modification */ /* could not make destination writable */ /* If target exists, remove it first (we know Ovewrite must be TRUE). * Then try to bind to the resource. /* restore parent collection states */ /* check for errors from reverting writability */ "The BIND was successful, but there was a " "problem automatically checking in the " "source parent collection.",
/* return an appropriate response (HTTP_CREATED) */ /* ### spec doesn't say what happens when destination was replaced */ * Response handler for DAV resources /* Reject requests with an unescaped hash character, as these may * be more destructive than the user intended. */ "buggy client used un-escaped hash in Request-URI");
"The request was invalid: the URI included " "an un-escaped hash character");
/* ### do we need to do anything with r->proxyreq ?? */ * ### anything else to do here? could another module and/or * ### config option "take over" the handler here? i.e. how do * ### we lock down this hierarchy so that we are the ultimate * ### arbiter? (or do we simply depend on the administrator * ### to avoid conflicting configurations?) * Set up the methods mask, since that's one of the reasons this handler * gets called, and lower-level things may need the info. * First, set the mask to the methods we handle directly. Since by * definition we own our managed space, we unconditionally set * the r->allowed field rather than ORing our values with anything * any other module may have put in there. * These are the HTTP-defined methods that we handle directly. * These are the DAV methods we handle. * These are methods that we don't handle directly, but let the * server's default handler do for us as our agent. /* ### hrm. if we return HTTP_METHOD_NOT_ALLOWED, then an Allow header * ### is sent; it will need the other allowed states; since the default * ### handler is not called on error, then it doesn't add the other * ### allowed states, so we must /* ### we might need to refine this for just where we return the error. * ### also, there is the issue with other methods (see ISSUES) /* dispatch the appropriate method handler */ /* ### add'l methods for Advanced Collections, ACLs */ /* quickly ignore any HTTP/0.9 requests which aren't subreqs. */ /* if DAV is not enabled, then we've got nothing to do */ /* We are going to handle almost every request. In certain cases, the provider maps to the filesystem (thus, handle_get is FALSE), and core Apache will handle it. a For that case, we just return right away. */ * ### need some work to pull Content-Type and Content-Language * ### from the property database. * If the repository hasn't indicated that it will handle the * GET method, then just punt. * ### this isn't quite right... taking over the response can break * ### things like mod_negotiation. need to look into this some more. /* ### this is wrong. We should only be setting the r->handler for the * requests that mod_dav knows about. If we set the handler for M_POST * requests, then CGI scripts that use POST will return the source for the * script. However, mod_dav DOES handle POST, so something else needs /* We are going to be handling the response for this resource. */ /*--------------------------------------------------------------------------- * Configuration info for the module "specify the DAV provider for a directory or location"),
"specify minimum allowed timeout"),
"allow Depth infinity PROPFIND requests"),