mod_dav.c revision cba1beeab00aa7d89ccd51fa18bb2b0f5d3a07d0
842ae4bd224140319ae7feec1872b93dfd491143fielding/* ====================================================================
842ae4bd224140319ae7feec1872b93dfd491143fielding * The Apache Software License, Version 1.1
842ae4bd224140319ae7feec1872b93dfd491143fielding * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
842ae4bd224140319ae7feec1872b93dfd491143fielding * reserved.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 2. Redistributions in binary form must reproduce the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the documentation and/or other materials provided with the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distribution.
e8f95a682820a599fe41b22977010636be5c2717jim * 3. The end-user documentation included with the redistribution,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if any, must include the following acknowledgment:
e8f95a682820a599fe41b22977010636be5c2717jim * "This product includes software developed by the
1747d30b98aa1bdbc43994c02cd46ab4cb9319e4fielding * Apache Software Foundation (http://www.apache.org/)."
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Alternately, this acknowledgment may appear in the software itself,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if and wherever such third-party acknowledgments normally appear.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 4. The names "Apache" and "Apache Software Foundation" must
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * not be used to endorse or promote products derived from this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * software without prior written permission. For written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission, please contact apache@apache.org.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * 5. Products derived from this software may not be called "Apache",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * nor may "Apache" appear in their name, without prior written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission of the Apache Software Foundation.
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * SUCH DAMAGE.
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * ====================================================================
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * This software consists of voluntary contributions made by many
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * individuals on behalf of the Apache Software Foundation. For more
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * information on the Apache Software Foundation, please see
0f60998368b493f90120180a93fc2e1e74490872covener * DAV extension module for Apache 2.0.*
0f60998368b493f90120180a93fc2e1e74490872covener * This module is repository-independent. It depends on hooks provided by a
0f60998368b493f90120180a93fc2e1e74490872covener * repository implementation.
0f60998368b493f90120180a93fc2e1e74490872covener * APACHE ISSUES:
87587593f1a53030e840acc0dec6cc881022ea40covener * - within a DAV hierarchy, if an unknown method is used and we default
87587593f1a53030e840acc0dec6cc881022ea40covener * to Apache's implementation, it sends back an OPTIONS with the wrong
87587593f1a53030e840acc0dec6cc881022ea40covener * set of methods -- there is NO HOOK for us.
87587593f1a53030e840acc0dec6cc881022ea40covener * therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).
43997561b2302d13dee973998e77743a3ddd2374trawick * - process_mkcol_body() had to dup code from ap_setup_client_block().
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - it would be nice to get status lines from Apache for arbitrary
0568280364eb026393be492ebc732795c4934643jorton * status codes
0568280364eb026393be492ebc732795c4934643jorton * - it would be nice to be able to extend Apache's set of response
0568280364eb026393be492ebc732795c4934643jorton * codes so that it doesn't return 500 when an unknown code is placed
0568280364eb026393be492ebc732795c4934643jorton * into r->status.
0568280364eb026393be492ebc732795c4934643jorton * - http_vhost functions should apply "const" to their params
0568280364eb026393be492ebc732795c4934643jorton * DESIGN NOTES:
0568280364eb026393be492ebc732795c4934643jorton * - For PROPFIND, we batch up the entire response in memory before
0568280364eb026393be492ebc732795c4934643jorton * sending it. We may want to reorganize around sending the information
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * as we suck it in from the propdb. Alternatively, we should at least
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * generate a total Content-Length if we're going to buffer in memory
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * so that we can keep the connection open.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* ### what is the best way to set this? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* per-dir configuration */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *dir;
713a2b68bac4aeb1e9c48785006c0732451039depquerna/* per-server configuration */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* forward-declare for use in configuration lookup */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* DAV methods */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowestatic int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DBG0("dav_init_handler"); */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Register DAV methods */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_methods[DAV_M_BIND] = ap_method_register(p, "BIND");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_methods[DAV_M_SEARCH] = ap_method_register(p, "SEARCH");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void *dav_create_server_config(apr_pool_t *p, server_rec *s)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* ### this isn't used at the moment... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### nothing to merge right now... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *dav_create_dir_config(apr_pool_t *p, char *dir)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* NOTE: dir==NULL creates the default per-dir config */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*conf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* clean up the directory to remove any trailing slash */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholesstatic void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *newconf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*newconf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (long)newconf, (long)base, (long)overrides); */
3e6d7277b90d3011db832139afc20efb5f17e203rederpj newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name);
3e6d7277b90d3011db832139afc20efb5f17e203rederpj newconf->provider = DAV_INHERIT_VALUE(parent, child, provider);
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "\"DAV Off\" cannot be used to turn off a subtree "
e8f95a682820a599fe41b22977010636be5c2717jim "of a DAV-enabled location.");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener "A subtree cannot specify a different DAV provider "
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener "than its parent.");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener newconf->dir = DAV_INHERIT_VALUE(parent, child, dir);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic const dav_provider *dav_get_provider(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener conf = ap_get_module_config(r->per_dir_config, &dav_module);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* assert: conf->provider_name != NULL
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener (otherwise, DAV is disabled, and we wouldn't be here) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* assert: conf->provider != NULL
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener (checked when conf->provider_name is set) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_locks *dav_get_lock_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_binding *dav_get_binding_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_search *dav_get_search_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * Command handler for the DAV directive, which is TAKE1.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* lookup and cache the actual provider now */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes conf->provider = dav_lookup_provider(conf->provider_name);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* by the time they use it, the provider should be loaded and
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes registered with us. */
ebe5305f8b22507374358f32b74d12fb50c05a25covener "Unknown DAV provider: %s",
513b324e774c559b579896df131fd7c8471ed529rederpj * Command handler for the DAVDepthInfinity directive, which is FLAG.
513b324e774c559b579896df131fd7c8471ed529rederpjstatic const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Command handler for DAVMinTimeout directive, which is TAKE1
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *arg1)
9ad7b260be233be7d7b5576979825cac72e15498rederpj return "DAVMinTimeout requires a non-negative integer.";
9ad7b260be233be7d7b5576979825cac72e15498rederpj** dav_error_response()
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** Send a nice response back to the user. In most cases, Apache doesn't
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** allow us to provide details in the body about what happened. This
54d22ed1c429b903b029bbd62621f11a9e286137minfrin** function allows us to completely specify the response body.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** ### this function is not logging any errors! (e.g. the body)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic int dav_error_response(request_rec *r, int status, const char *body)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* ### I really don't think this is needed; gotta test */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* begin the response now... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* the response has been sent. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj * ### Use of DONE obviates logging..!
9ad7b260be233be7d7b5576979825cac72e15498rederpj * Send a "standardized" error response based on the error's namespace & tag
9ab21648975dff7e1b680daf8aea627227ba28f7trawick /* ### I really don't think this is needed; gotta test */
87587593f1a53030e840acc0dec6cc881022ea40covener "<D:error xmlns:D=\"DAV:\"", r);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* ### should move this namespace somewhere (with the others!) */
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_rputs(" xmlns:m=\"http://apache.org/dav/xmlns\"", r);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* here's our mod_dav specific tag: */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* the response has been sent. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * ### Use of DONE obviates logging..!
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Apache's URI escaping does not replace '&' since that is a valid character
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * in a URI (to form a query section). We must explicitly handle it so that
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * we can embed the URI into an XML document.
7add8f7fb048534390571801b7794f71cd9e127abnicholesstatic const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* check the easy case... */
ebe5305f8b22507374358f32b74d12fb50c05a25covener /* there was a '&', so more work is needed... sigh. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Note: this is a teeny bit of overkill since we know there are no
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * '<' or '>' characters, but who cares.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic void dav_send_multistatus(request_rec *r, int status,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Set the correct status and Content-Type */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Send the headers and actual multistatus response now... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "<D:multistatus xmlns:D=\"DAV:\"", r);
e8f95a682820a599fe41b22977010636be5c2717jim /* ap_rputc('>', r); */
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* use the Status-Line text from Apache. Note, this will
7dbf29be626018bc389ef94c1846aeac4b72633bsf * default to 500 Internal Server Error if first->status
7dbf29be626018bc389ef94c1846aeac4b72633bsf * is not a known (or valid) status code.
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* assume this includes <propstat> and is quoted properly */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * We supply the description, so we know it doesn't have to
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * have any escaping/encoding applied to it.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * dav_log_err()
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Write error information to the log.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic void dav_log_err(request_rec *r, dav_error *err, int level)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* Log the errors */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* ### should have a directive to log the first or all */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for (errscan = err; errscan != NULL; errscan = errscan->prev) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes errscan->desc, errscan->status, errscan->error_id);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "%s [%d, #%d]",
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * dav_handle_err()
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Handle the standard error processing. <err> must be non-NULL.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * <response> is set by the following:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - dav_validate_request()
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - dav_add_lock()
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * - repos_hooks->remove_resource
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - repos_hooks->move_resource
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - repos_hooks->copy_resource
7dbf29be626018bc389ef94c1846aeac4b72633bsf * - vsn_hooks->update
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* log the errors */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* our error messages are safe; tell Apache this */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(r->notes, "verbose-error-to", "*");
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* Didn't get a multistatus response passed in, but we still
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes might be able to generate a standard <D:error> response.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes Search the error stack for an errortag. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the multistatus and tell Apache the request/response is DONE. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_send_multistatus(r, err->status, response, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handy function for return values of methods that (may) create things */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int dav_created(request_rec *r, const char *locn, const char *what,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin const char *body;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* did the target resource already exist? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default message */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Per HTTP/1.1, S10.2.2: add a Location header to contain the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * URI that was created. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Convert locn to an absolute URI, and return in Location header */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * we must manufacture the entire response. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin body = apr_psprintf(r->pool, "%s %s has been created.",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* ### move to dav_util? */
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener const char *depth = apr_table_get(r->headers_in, "Depth");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The caller will return an HTTP_BAD_REQUEST. This will augment the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message that Apache provides. */
e8f95a682820a599fe41b22977010636be5c2717jim "An invalid Depth header was specified.");
e8f95a682820a599fe41b22977010636be5c2717jim return -1;
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe const char *overwrite = apr_table_get(r->headers_in, "Overwrite");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
9ad7b260be233be7d7b5576979825cac72e15498rederpj if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The caller will return an HTTP_BAD_REQUEST. This will augment the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message that Apache provides. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "An invalid Overwrite header was specified.");
560fd0658902ab57754616c172d8953e69fc4722bnicholes/* resolve a request URI to a resource descriptor.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If label_allowed != 0, then allow the request target to be altered by
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a Label: header.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If use_checked_in is true, then the repository provider should return
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the resource identified by the DAV:checked-in property of the resource
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * identified by the Request-URI.
e8f95a682820a599fe41b22977010636be5c2717jimstatic dav_error *dav_get_resource(request_rec *r, int label_allowed,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if the request target can be overridden, get any target selector */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf = ap_get_module_config(r->per_dir_config, &dav_module);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* assert: conf->provider != NULL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resolve the resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*conf->provider->repos->get_resource)(r, conf->dir,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Note: this shouldn't happen, but just be sure... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener "The provider did not define a "
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "resource for %s.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### hmm. this doesn't feel like the right place or thing to do */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if there were any input headers requiring a Vary header in the response,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * add it now */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
0e05808dc59a321566303084c84b9826a4353cefrederpj /* open the thing lazily */
ebe5305f8b22507374358f32b74d12fb50c05a25covener const char *range_c;
ebe5305f8b22507374358f32b74d12fb50c05a25covener range_c = apr_table_get(r->headers_in, "content-range");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* malformed header. ignore it (per S14.16 of RFC2616) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || (slash[1] != '*' && apr_atoi64(slash + 1) <= *range_end)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* invalid range. ignore it (per S14.16 of RFC2616) */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* we now have a valid range */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* handle the GET method */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This method should only be called when the resource is not
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener * visible to Apache. We will fetch the resource from the repository,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * then create a subrequest for Apache to handle.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* set up the HTTP headers for the response */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Unable to set up HTTP headers.",
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* okay... time to deliver the content */
e8f95a682820a599fe41b22977010636be5c2717jim "Unable to deliver content.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* validate resource on POST, then pass it off to the default handler */
e8f95a682820a599fe41b22977010636be5c2717jim /* Ask repository module to resolve the resource */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Note: depth == 0. Implies no need for a multistatus response. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the PUT method */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *body;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Ask repository module to resolve the resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If not a file or collection resource, PUT not allowed */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Cannot create resource %s with PUT.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_error_response(r, HTTP_CONFLICT, body);
43c3e6a4b559b76b750c245ee95e2782c15b4296jim /* Cannot PUT a collection */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Cannot PUT to a collection.");
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Note: depth == 0 normally requires no multistatus response. However,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes * other than the Request-URI, thereby requiring a multistatus.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If the resource does not exist (DAV_RESOURCE_NULL), then we must
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * check the resource *and* its parent. If the resource exists or is
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * a locknull resource, then we check only the resource.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* make sure the resource can be modified (if versioning repository) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 0 /* not parent_only */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* truncate and rewrite the file unless we see a Content-Range */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes has_range = dav_parse_range(r, &range_start, &range_end);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Create the new file in the repository */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*resource->hooks->open_stream)(resource, mode,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### assuming FORBIDDEN is probably not quite right... */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Unable to PUT new contents for %s.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* a range was provided. seek to the start */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->seek_stream)(stream, range_start);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Once we start reading the request, then we must read the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * whole darn thing. ap_discard_request_body() won't do anything
e8f95a682820a599fe41b22977010636be5c2717jim * for a partially-read request.
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe /* write whatever we read, until we see an error */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### what happens if we read more/less than the amount
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### specified in the Content-Range? eek...
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Error reading request body. This has precedence over
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * prior errors.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "An error occurred while reading the "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "request body.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* no error during the write, but we hit one at close. use it. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Ensure that we think the resource exists now.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### eek. if an error occurred during the write and we did not commit,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### then the resource might NOT exist (e.g. dav_fs_repos.c)
e8f95a682820a599fe41b22977010636be5c2717jim /* restore modifiability of resources back to what they were */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, resource, err != NULL /* undo if error */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* check for errors now */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* just log a warning */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The PUT was successful, but there "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "was a problem automatically checking in "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "the resource or its parent collection.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### place the Content-Type and Content-Language into the propdb */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* The file creation was successful, but the locking failed. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The file was PUT successfully, but there "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "was a problem opening the lock database "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "which prevents inheriting locks from the "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "parent resources.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* notify lock system that we have created/replaced a resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_notify_created(r, lockdb, resource, resource_state, 0);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The file creation was successful, but the locking failed. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The file was PUT successfully, but there "
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener "was a problem updating its lock "
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener "information.",
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf/* ### move this to dav_util? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfDAV_DECLARE(void) dav_add_response(dav_walk_resource *wres,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* just drop some data into an dav_response */
e8f95a682820a599fe41b22977010636be5c2717jim resp->href = apr_pstrdup(wres->pool, wres->resource->uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the DELETE method */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* We don't use the request body right now, so torch it. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Ask repository module to resolve the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* 2518 says that depth must be infinity only for collections.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * For non-collections, depth is ignored, unless it is an illegal value (1).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (resource->collection && depth != DAV_INFINITY) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This supplies additional information for the default message. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth must be \"infinity\" for DELETE of a collection.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This supplies additional information for the default message. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth of \"1\" is not allowed for DELETE.");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** If any resources fail the lock/If: conditions, then we must fail
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** the delete. Each of the failing resources will be listed within
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** a DAV:multistatus body, wrapped into a 424 response.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** Note that a failure on the resource itself does not generate a
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** multistatus response -- only internal members/collections.
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((err = dav_validate_request(r, resource, depth, NULL,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "Could not DELETE %s due to a failed "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "precondition (e.g. locks).",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * locked by the token(s) in the if_header.
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((result = dav_unlock(r, resource, NULL)) != OK) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* if versioned resource, make sure parent is checked out */
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### add a higher-level description? */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* try to remove the resource */
8869662bb1a4078297020e94ae5e928626d877c6rederpj err = (*resource->hooks->remove_resource)(resource, &multi_response);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* restore writability of parent back to what it was */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* check for errors now */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Could not DELETE %s.",
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* just log a warning */
8869662bb1a4078297020e94ae5e928626d877c6rederpj "The DELETE was successful, but there "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "was a problem automatically checking in "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "the parent collection.",
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* Apache will supply a default error for this. */
8869662bb1a4078297020e94ae5e928626d877c6rederpj/* generate DAV:supported-method-set OPTIONS response */
8869662bb1a4078297020e94ae5e928626d877c6rederpjstatic dav_error *dav_gen_supported_methods(request_rec *r,
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_text_append(r->pool, body, "<D:supported-method-set>" DEBUG_CR);
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* show all supported methods */
8869662bb1a4078297020e94ae5e928626d877c6rederpj "<D:supported-method D:name=\"%s\"/>"
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* check for support of specific methods */
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (child = elem->first_child; child != NULL; child = child->next) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* go through attributes to find method name */
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (attr = child->attr; attr != NULL; attr = attr->next) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj "A DAV:supported-method element "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "does not have a \"name\" attribute");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* see if method is supported */
8869662bb1a4078297020e94ae5e928626d877c6rederpj "<D:supported-method D:name=\"%s\"/>"
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_text_append(r->pool, body, "</D:supported-method-set>" DEBUG_CR);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* generate DAV:supported-live-property-set OPTIONS response */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic dav_error *dav_gen_supported_live_props(request_rec *r,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* open lock database, to report on supported lock properties */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ### should open read-only */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "The lock database could not be opened, "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "preventing the reporting of supported lock "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "properties.",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* open the property database (readonly) for the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((err = dav_open_propdb(r, lockdb, resource, 1, NULL,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "The property database could not be opened, "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "preventing report of supported properties.",
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_text_append(r->pool, body, "<D:supported-live-property-set>" DEBUG_CR);
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* show all supported live properties */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED);
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* check for support of specific live property */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj for (child = elem->first_child; child != NULL; child = child->next) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj && strcmp(child->name, "supported-live-property") == 0) {
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg /* go through attributes to find name and namespace */
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg for (attr = child->attr; attr != NULL; attr = attr->next) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "A DAV:supported-live-property "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "element does not have a \"name\" "
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj "attribute");
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* default namespace to DAV: */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* check for support of property */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_get_liveprop_supported(propdb, nmspace, name, body);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_append(r->pool, body, "</D:supported-live-property-set>" DEBUG_CR);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* generate DAV:supported-report-set OPTIONS response */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic dav_error *dav_gen_supported_reports(request_rec *r,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_append(r->pool, body, "<D:supported-report-set>" DEBUG_CR);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "DAV:supported-report-set could not be "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "determined due to a problem fetching the "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "available reports for this resource.",
0e05808dc59a321566303084c84b9826a4353cefrederpj /* show all supported reports */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Note: we presume reports->namespace is
0e05808dc59a321566303084c84b9826a4353cefrederpj * properly XML/URL quoted */
0e05808dc59a321566303084c84b9826a4353cefrederpj "<D:supported-report D:name=\"%s\" "
0e05808dc59a321566303084c84b9826a4353cefrederpj /* check for support of specific report */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (child = elem->first_child; child != NULL; child = child->next) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* go through attributes to find name and namespace */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (attr = child->attr; attr != NULL; attr = attr->next) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "A DAV:supported-report element "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "does not have a \"name\" attribute");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* default namespace to DAV: */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Note: we presume reports->nmspace is
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * properly XML/URL quoted
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "<D:supported-report "
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "D:name=\"%s\" "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "D:namespace=\"%s\"/>"
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR);
0e05808dc59a321566303084c84b9826a4353cefrederpj/* handle the SEARCH method */
0e05808dc59a321566303084c84b9826a4353cefrederpj const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
0e05808dc59a321566303084c84b9826a4353cefrederpj /* If no search provider, decline the request */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* This method should only be called when the resource is not
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * visible to Apache. We will fetch the resource from the repository,
0e05808dc59a321566303084c84b9826a4353cefrederpj * then create a subrequest for Apache to handle.
0e05808dc59a321566303084c84b9826a4353cefrederpj err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Apache will supply a default error for this. */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* set up the HTTP headers for the response */
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj "Unable to set up HTTP headers.",
0e05808dc59a321566303084c84b9826a4353cefrederpj /* okay... time to search the content */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Let's validate XML and process walk function
0e05808dc59a321566303084c84b9826a4353cefrederpj * in the hook function
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((err = (*search_hooks->search_resource)(r, &multi_status)) != NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* ### add a higher-level description? */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* We have results in multi_status */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Should I pass namespace?? */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* handle the OPTIONS method */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const char *dav_level;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* resolve the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* parse any request body */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* note: doc == NULL if no request body */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "The \"options\" element was not found.");
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* determine which providers are available */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * MSFT Web Folders chokes if length of DAV header value > 63 characters!
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * To workaround that, we use separate DAV headers for versioning and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * live prop provider namespace URIs.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If there is a versioning provider, generate DAV headers
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for versioning options.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (*vsn_hooks->get_vsn_options)(r->pool, &vsn_options);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (t = vsn_options.first; t != NULL; t = t->next)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Gather property set URIs from all the liveprop providers,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and generate a separate DAV header for each URI, to avoid
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * problems with long header lengths.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes uri_ary = apr_array_make(r->pool, 5, sizeof(const char *));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(r->headers_out, "DAV", ((char **)uri_ary->elts)[i]);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* this tells MSFT products to skip looking for FrontPage extensions */
e8f95a682820a599fe41b22977010636be5c2717jim * Determine which methods are allowed on the resource.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Three cases: resource is null (3), is lock-null (7.4), or exists.
e8f95a682820a599fe41b22977010636be5c2717jim * All cases support OPTIONS, and if there is a lock provider, LOCK.
e8f95a682820a599fe41b22977010636be5c2717jim * (Lock-) null resources also support MKCOL and PUT.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Lock-null supports PROPFIND and UNLOCK.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Existing resources support lots of stuff.
e8f95a682820a599fe41b22977010636be5c2717jim /* ### take into account resource type */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resource exists */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resource is lock-null. */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* resource is null. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### internal error! */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a versioning provider, add versioning methods */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we might not support this DeltaV option */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a bindings provider, see if resource is bindable */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a search provider, set SEARCH in option */
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* Generate the Allow header */
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* first, compute total length */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* add 1 for comma or null */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is search set_option_head function, set head */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DASL: <DAV:basicsearch>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*search_hooks->set_option_head)(r)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if there was no request body, then there is no response body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### this sends a Content-Type. the default OPTIONS does not. */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* ### the default (ap_send_http_options) returns OK, but I believe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### that is because it is the default handler and nothing else
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### will run after the thing. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* handle each options request */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (elem = doc->root->first_child; elem != NULL; elem = elem->next) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* check for something we recognize first */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (strcmp(elem->name, "supported-method-set") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_gen_supported_methods(r, elem, methods, &body);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(elem->name, "supported-live-property-set") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_gen_supported_live_props(r, resource, elem, &body);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(elem->name, "supported-report-set") == 0) {
e8f95a682820a599fe41b22977010636be5c2717jim err = dav_gen_supported_reports(r, resource, elem, vsn_hooks, &body);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* if unrecognized option, pass to versioning provider */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((err = (*vsn_hooks->get_option)(resource, elem, &body))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the options response */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the headers and response body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we've sent everything necessary to the client. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesstatic void dav_cache_badprops(dav_walker_ctx *ctx)
e8f95a682820a599fe41b22977010636be5c2717jim /* just return if we built the thing already */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes for (elem = elem->first_child; elem; elem = elem->next) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesstatic dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ** dav_get_allprops() does not need to do namespace translation,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ** we're okay.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ** Note: we cast to lose the "const". The propdb won't try to change
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ** the resource, however, since we are opening readonly.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### do something with err! */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* some props were expected on this collection/resource */
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener /* no props on this collection/resource */
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener /* ### what to do about closing the propdb on server failure? */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_prop_insert what = ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes/* handle the PROPFIND method */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* Ask repository module to resolve the resource */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* Apache will supply a default error for this. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* dav_get_depth() supplies additional information for the
e8f95a682820a599fe41b22977010636be5c2717jim * default message. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (depth == DAV_INFINITY && resource->collection) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* default is to DISALLOW these requests */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (conf->allow_depthinfinity != DAV_ENABLED_ON) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "PROPFIND requests with a "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "Depth of \"infinity\" are "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "not allowed for %s.",
490046d2a164ad86cc63bd789f32eaed663d239abnicholes if ((result = ap_xml_parse_input(r, &doc)) != OK) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* note: doc == NULL if no request body */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* This supplies additional information for the default message. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "The \"propfind\" element was not found.");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### validate that only one of these three elements is present */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes || (child = dav_find_child(doc->root, "allprop")) != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* note: no request body implies allprop */
e8f95a682820a599fe41b22977010636be5c2717jim else if ((child = dav_find_child(doc->root, "propname")) != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else if ((child = dav_find_child(doc->root, "prop")) != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* "propfind" element must have one of the above three children */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* This supplies additional information for the default message. */
e8f95a682820a599fe41b22977010636be5c2717jim "The \"propfind\" element does not contain one of "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "the required child elements (the specific command).");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH;
e8f95a682820a599fe41b22977010636be5c2717jim /* ### should open read-only */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = dav_open_lockdb(r, 0, &ctx.w.lockdb)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "The lock database could not be opened, "
e8f95a682820a599fe41b22977010636be5c2717jim "preventing access to the various lock "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "properties for the PROPFIND.",
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes /* if we have a lock database, then we can walk locknull resources */
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### add a higher-level description? */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* return a 207 (Multi-Status) response now. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if a 404 was generated for an HREF, then we need to spit out the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * doc's namespaces for use by the 404. Note that <response> elements
e8f95a682820a599fe41b22977010636be5c2717jim * will override these ns0, ns1, etc, but NOT within the <response>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * scope for the badprops. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* NOTE: propstat_404 != NULL implies doc != NULL */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* the response has been sent. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_text * dav_failed_proppatch(apr_pool_t *p,
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes const char *s;
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes /* ### might be nice to sort by status code and description */
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes for ( ; i-- > 0; ++ctx ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:prop>");
e8f95a682820a599fe41b22977010636be5c2717jim apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* nothing was assigned here yet, so make it a 424 */
e8f95a682820a599fe41b22977010636be5c2717jim err424_set = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Attempted DAV:set operation "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "could not be completed due "
e8f95a682820a599fe41b22977010636be5c2717jim "to other errors.");
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes err424_delete = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0,
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes "Attempted DAV:remove "
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes "operation could not be "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "completed due to other "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:status>"
e8f95a682820a599fe41b22977010636be5c2717jim "HTTP/1.1 %d (status)"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we should use compute_desc if necessary... */
e8f95a682820a599fe41b22977010636be5c2717jim apr_text_append(p, &hdr, "<D:responsedescription>" DEBUG_CR);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_append(p, &hdr, "</D:responsedescription>" DEBUG_CR);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### we probably need to revise the way we assemble the response...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### this code assumes everything will return status==200.
43c3e6a4b559b76b750c245ee95e2782c15b4296jim for ( ; i-- > 0; ++ctx ) {
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Call <func> for each context. This can stop when an error occurs, or
e8f95a682820a599fe41b22977010636be5c2717jim * simply iterate through the whole list.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Returns 1 if an error occurs (and the iteration is aborted). Returns 0
e8f95a682820a599fe41b22977010636be5c2717jim * if all elements are processed.
43c3e6a4b559b76b750c245ee95e2782c15b4296jim * If <reverse> is true (non-zero), then the list is traversed in
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes * reverse order.
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholesstatic int dav_process_ctx_list(void (*func)(dav_prop_ctx *ctx),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_prop_ctx *ctx = (dav_prop_ctx *)ctx_list->elts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (i--) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (stop_on_error && DAV_PROP_CTX_HAS_ERR(*ctx)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the PROPPATCH method */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Ask repository module to resolve the resource */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
88adce5ec0da39b41450ce1d5a77659168097e0cjorton /* Apache will supply a default error for this. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* note: doc == NULL if no request body */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (doc == NULL || !dav_validate_root(doc, "propertyupdate")) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "The request body does not contain "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "a \"propertyupdate\" element.");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Check If-Headers and existing locks */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Note: depth == 0. Implies no need for a multistatus response. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure the resource can be modified (if versioning repository) */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin 0 /* not parent_only */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes if ((err = dav_open_propdb(r, NULL, resource, 0, doc->namespaces,
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* undo any auto-checkout */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not open the property "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "database for %s.",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### what to do about closing the propdb on server failure? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### validate "live" properties */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* set up an array to hold property operation contexts */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx_list = apr_array_make(r->pool, 10, sizeof(dav_prop_ctx));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* do a first pass to ensure that all "remove" properties exist */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin for (child = doc->root->first_child; child; child = child->next) {
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* Ignore children that are not set/remove */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin || (!(is_remove = strcmp(child->name, "remove") == 0)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure that a "prop" child exists for set/remove */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((prop_group = dav_find_child(child, "prop")) == NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* undo any auto-checkout */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "A \"prop\" element is missing inside "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "the propertyupdate command.");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx->operation = is_remove ? DAV_PROP_OP_DELETE : DAV_PROP_OP_SET;
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes ctx->r = r; /* for later use by dav_prop_log_errors() */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### should test that we found at least one set/remove */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* execute all of the operations */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (!failure && dav_process_ctx_list(dav_prop_exec, ctx_list, 1, 0)) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* generate a failure/success response */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_rollback, ctx_list, 0, 1);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin propstat_text = dav_failed_proppatch(r->pool, ctx_list);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_commit, ctx_list, 0, 0);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin propstat_text = dav_success_proppatch(r->pool, ctx_list);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure this gets closed! */
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes /* complete any auto-versioning */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, failure, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* log any errors that occurred */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_log_errors, ctx_list, 0, 0);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### should probably use something new to pass along this text... */
e8f95a682820a599fe41b22977010636be5c2717jim dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* the response has been sent. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This is snarfed from ap_setup_client_block(). We could get pretty
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes * close to this behavior by passing REQUEST_NO_BODY, but we need to
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes * return HTTP_UNSUPPORTED_MEDIA_TYPE (while ap_setup_client_block
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * returns HTTP_REQUEST_ENTITY_TOO_LARGE). */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *lenp = apr_table_get(r->headers_in, "Content-Length");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure to set the Apache request fields properly. */
e8f95a682820a599fe41b22977010636be5c2717jim /* Use this instead of Apache's default error string */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else if (lenp) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* ### log something? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default error for this. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Get rid of the body. this will call ap_setup_client_block(), but
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * our copy above has already verified its work.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* handle the MKCOL method */
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* handle the request body */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### this may move lower once we start processing bodies */
e8f95a682820a599fe41b22977010636be5c2717jim conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Ask repository module to resolve the resource */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* oops. something was already there! */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we should provide a specific error message! */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Check If-Headers and existing locks.
e8f95a682820a599fe41b22977010636be5c2717jim * Note: depth == 0 normally requires no multistatus response. However,
e8f95a682820a599fe41b22977010636be5c2717jim * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * other than the Request-URI, thereby requiring a multistatus.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * If the resource does not exist (DAV_RESOURCE_NULL), then we must
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * check the resource *and* its parent. If the resource exists or is
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * a locknull resource, then we check only the resource.
796e4a7141265d8ed7036e4628161c6eafb2a789jorton if ((err = dav_validate_request(r, resource, 0, NULL, &multi_status,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* if versioned resource, make sure parent is checked out */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* try to create the collection */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = (*resource->hooks->create_collection)(resource);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* restore modifiability of parent back to what it was */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
e8f95a682820a599fe41b22977010636be5c2717jim /* check for errors now */
141e1368614dc7564e1627671361b01b4869b491bnicholes /* just log a warning */
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "The MKCOL was successful, but there "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "was a problem automatically checking in "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "the parent collection.",
141e1368614dc7564e1627671361b01b4869b491bnicholes if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
141e1368614dc7564e1627671361b01b4869b491bnicholes /* The directory creation was successful, but the locking failed. */
141e1368614dc7564e1627671361b01b4869b491bnicholes "The MKCOL was successful, but there "
141e1368614dc7564e1627671361b01b4869b491bnicholes "was a problem opening the lock database "
141e1368614dc7564e1627671361b01b4869b491bnicholes "which prevents inheriting locks from the "
e8f95a682820a599fe41b22977010636be5c2717jim "parent resources.",
e8f95a682820a599fe41b22977010636be5c2717jim /* notify lock system that we have created/replaced a resource */
e8f95a682820a599fe41b22977010636be5c2717jim err = dav_notify_created(r, lockdb, resource, resource_state, 0);
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes /* The dir creation was successful, but the locking failed. */
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "The MKCOL was successful, but there "
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes "was a problem updating its lock "
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes "information.",
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes /* return an appropriate response (HTTP_CREATED) */
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes/* handle the COPY and MOVE methods */
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholesstatic int dav_method_copymove(request_rec *r, int is_move)
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *body;
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *dest;
0f60998368b493f90120180a93fc2e1e74490872covener /* Ask repository module to resolve the resource */
0f60998368b493f90120180a93fc2e1e74490872covener err = dav_get_resource(r, !is_move /* label_allowed */,
0f60998368b493f90120180a93fc2e1e74490872covener /* Apache will supply a default error for this. */
0f60998368b493f90120180a93fc2e1e74490872covener /* If not a file or collection resource, COPY/MOVE not allowed */
0f60998368b493f90120180a93fc2e1e74490872covener /* ### allow COPY/MOVE of DeltaV resource types */
0f60998368b493f90120180a93fc2e1e74490872covener "Cannot COPY/MOVE resource %s.",
0f60998368b493f90120180a93fc2e1e74490872covener return dav_error_response(r, HTTP_METHOD_NOT_ALLOWED, body);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* get the destination URI */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* Look in headers provided by Netscape's Roaming Profiles */
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *nscp_host = apr_table_get(r->headers_in, "Host");
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *nscp_path = apr_table_get(r->headers_in, "New-uri");
67c5e190a7b84528b8895d7ef7be81712d206805covener dest = apr_psprintf(r->pool, "http://%s%s", nscp_host, nscp_path);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* This supplies additional information for the default message. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj "The request is missing a Destination header.");
9ad7b260be233be7d7b5576979825cac72e15498rederpj lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* This supplies additional information for the default message. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* ### this assumes that dav_lookup_uri() only generates a status
9ad7b260be233be7d7b5576979825cac72e15498rederpj * ### that Apache can provide a status line for!! */
9ad7b260be233be7d7b5576979825cac72e15498rederpj return dav_error_response(r, lookup.err.status, lookup.err.desc);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### how best to report this... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Destination URI had an error.");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Resolve destination resource */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* are the two resources handled by the same repository? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### this message exposes some backend config, but screw it... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Destination URI is handled by a "
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "different repository than the source URI. "
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "MOVE or COPY between repositories is "
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "not possible.");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* get and parse the overwrite header value */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* dav_get_overwrite() supplies additional information for the
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * default message. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* quick failure test: if dest exists and overwrite is false. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Supply some text for the error response body. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Destination is not empty and "
b6ce9b03bd0e4d37b21bc430f922a470cc2645d7rpluem "Overwrite is not \"T\"");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* are the source and destination the same? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if ((*resource->hooks->is_same_resource)(resource, resnew)) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Supply some text for the error response body. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Source and Destination URIs are the same.");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* get and parse the Depth header value. "0" and "infinity" are legal. */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe /* dav_get_depth() supplies additional information for the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message. */
a0b44ec81b32ffb946537d4e43e1c3a3f7594137gregames /* This supplies additional information for the default message. */
1233ffe2092021833c2a642f1017d6c332075469gregames "Depth must be \"0\" or \"infinity\" for COPY or MOVE.");
490046d2a164ad86cc63bd789f32eaed663d239abnicholes /* This supplies additional information for the default message. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth must be \"infinity\" when moving a collection.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Check If-Headers and existing locks for each resource in the source
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if we are performing a MOVE. We will return a 424 response with a
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * DAV:multistatus body. The multistatus responses will contain the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * information about any resource that fails the validation.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * We check the parent resource, too, since this is a MOVE. Moving the
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes * resource effectively removes it from the parent collection, so we
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * must ensure that we have met the appropriate conditions.
141e1368614dc7564e1627671361b01b4869b491bnicholes * If a problem occurs with the Request-URI itself, then a plain error
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * (rather than a multistatus) will be returned.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin && (err = dav_validate_request(r, resource, depth, NULL,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not MOVE %s due to a failed "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "precondition on the source "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "(e.g. locks).",
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes * Check If-Headers and existing locks for destination. Note that we
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes * use depth==infinity since the target (hierarchy) will be deleted
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes * before the move/copy is completed.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Note that we are overwriting the target, which implies a DELETE, so
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * we are subject to the error/response rules as a DELETE. Namely, we
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * will return a 424 error if any of the validations fail.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * (see dav_method_delete() for more information)
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes if ((err = dav_validate_request(lookup.rnew, resnew, DAV_INFINITY, NULL,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Could not MOVE/COPY %s due to a "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "failed precondition on the "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "destination (e.g. locks).",
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes && (*resource->hooks->is_parent_resource)(resource, resnew)) {
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes /* Supply some text for the error response body. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Source collection contains the "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "Destination.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && (*resnew->hooks->is_parent_resource)(resnew, resource)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The destination must exist (since it contains the source), and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a condition above implies Overwrite==T. Obviously, we cannot
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * delete the Destination before the MOVE/COPY, as that would
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * delete the Source.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Supply some text for the error response body. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Destination collection contains the Source "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "and Overwrite has been specified.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### for now, we don't need anything in the body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((result = ap_discard_request_body(r)) != OK) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* ### add a higher-level description? */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* remove any locks from the old resources */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * ### this is Yet Another Traversal. if we do a rename(), then we
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * ### really don't have to do this in some cases since the inode
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * ### values will remain constant across the move. but we can't
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * ### know that fact from outside the provider :-(
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * ### note that we now have a problem atomicity in the move/copy
e8f95a682820a599fe41b22977010636be5c2717jim * ### since a failure after this would have removed locks (technically,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### this is okay to do, but really...)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### this is wrong! it blasts direct locks on parent resources */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### pass lockdb! */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* if this is a move, then the source parent collection will be modified */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Remember the initial state of the destination, so the lock system
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * can be notified as to how it changed.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resnew_state = dav_get_resource_state(lookup.rnew, resnew);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* In a MOVE operation, the destination is replaced by the source.
490046d2a164ad86cc63bd789f32eaed663d239abnicholes * In a COPY operation, if the destination exists, is under version
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * control, and is the same resource type as the source,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * then it should not be replaced, but modified to be a copy of
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the source.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe else if ((resource->collection == 0) != (resnew->collection == 0))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If the destination must be created or replaced,
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton * make sure the parent collection is writable
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_auto_checkout(r, resnew, 1 /*parent_only*/,
43997561b2302d13dee973998e77743a3ddd2374trawick /* could not make destination writable:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if move, restore state of source parent
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
f2386b627177c7a80d38fed6ec0aed3c086909c1covener /* If source and destination parents are the same, then
e8f95a682820a599fe41b22977010636be5c2717jim * use the same resource object, so status updates to one are reflected
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * in the other, when doing auto-versioning. Otherwise,
e8f95a682820a599fe41b22977010636be5c2717jim * we may try to checkin the parent twice.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && (*src_av_info.parent_resource->hooks->is_same_resource)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (src_av_info.parent_resource, dst_av_info.parent_resource)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dst_av_info.parent_resource = src_av_info.parent_resource;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* If destination is being replaced, remove it first
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (we know Ovewrite must be TRUE). Then try to copy/move the resource.
e8f95a682820a599fe41b22977010636be5c2717jim err = (*resnew->hooks->remove_resource)(resnew, &multi_response);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->move_resource)(resource, resnew,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->copy_resource)(resource, resnew, depth,
e8f95a682820a599fe41b22977010636be5c2717jim /* perform any auto-versioning cleanup */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes /* check for error from remove/copy/move operations */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not MOVE/COPY %s.",
e8f95a682820a599fe41b22977010636be5c2717jim /* check for errors from auto-versioning */
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton /* just log a warning */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The MOVE/COPY was successful, but there was a "
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes "problem automatically checking in the "
f7edd56768a46a01ae8b43c712c9eeef40e37f59bnicholes "source parent collection.",
0f60998368b493f90120180a93fc2e1e74490872covener /* just log a warning */
0f60998368b493f90120180a93fc2e1e74490872covener "The MOVE/COPY was successful, but there was a "
0f60998368b493f90120180a93fc2e1e74490872covener "problem automatically checking in the "
0f60998368b493f90120180a93fc2e1e74490872covener "destination or its parent collection.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* propagate any indirect locks at the target */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* notify lock system that we have created/replaced a resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_notify_created(r, lockdb, resnew, resnew_state, depth);
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton /* The move/copy was successful, but the locking failed. */
e8f95a682820a599fe41b22977010636be5c2717jim "The MOVE/COPY was successful, but there "
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick "was a problem updating the lock "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "information.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_created(r, lookup.rnew->uri, "Destination",
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe/* dav_method_lock: Handler to implement the DAV LOCK method
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Returns appropriate HTTP_* response.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* If no locks provider, decline the request */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Depth must be 0 or \"infinity\" for LOCK.");
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* Ask repository module to resolve the resource */
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj * Open writable. Unless an error occurs, we'll be
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj * writing into the database.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener /* ### add a higher-level description? */
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj if ((err = dav_lock_parse_lockinfo(r, resource, lockdb, doc,
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj /* ### add a higher-level description to err? */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Check If-Headers and existing locks.
141e1368614dc7564e1627671361b01b4869b491bnicholes * If this will create a locknull resource, then the LOCK will affect
e8f95a682820a599fe41b22977010636be5c2717jim * the parent collection (much like a PUT/MKCOL). For that case, we must
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * validate the parent resource's conditions.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response,
87587593f1a53030e840acc0dec6cc881022ea40covener "Could not LOCK %s due to a failed "
9ad7b260be233be7d7b5576979825cac72e15498rederpj "precondition (e.g. other locks).",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Refresh request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### Assumption: We can renew multiple locks on the same resource
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### at once. First harvest all the positive lock-tokens given in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### the If header. Then modify the lock entries for this resource
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### with the new Timeout val.
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes if ((err = dav_get_locktoken_list(r, <l)) != NULL) {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "The lock refresh for %s failed "
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "because no lock tokens were "
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "specified in an \"If:\" "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*locks_hooks->refresh_locks)(lockdb, resource, ltl,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description to err? */
f05787953018140838ad51456c86c965d6a86267jim /* New lock request */
f05787953018140838ad51456c86c965d6a86267jim conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
goto error;
ap_rprintf(r,
return DONE;
int result;
const char *const_locktoken_txt;
char *locktoken_txt;
int resource_state;
return DECLINED;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
err);
&resource);
return result;
return HTTP_NO_CONTENT;
int resource_state;
int result;
return DECLINED;
&resource);
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (tsize == 0) {
return HTTP_BAD_REQUEST;
ap_set_content_length(r, 0);
return DONE;
err);
err);
err);
err);
int result;
int apply_to_vsn = 0;
int is_unreserved = 0;
int is_fork_ok = 0;
int create_activity = 0;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
const char *href;
return HTTP_BAD_REQUEST;
return HTTP_NOT_FOUND;
err);
ap_set_content_length(r, 0);
return DONE;
int result;
return DECLINED;
return result;
&resource);
return HTTP_NOT_FOUND;
err);
ap_set_content_length(r, 0);
return DONE;
int result;
int keep_checked_out = 0;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
&resource);
return HTTP_NOT_FOUND;
!= NULL) {
err);
int is_label = 0;
int depth;
int result;
const char *target;
return DECLINED;
return HTTP_BAD_REQUEST;
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (tsize == 0) {
return HTTP_BAD_REQUEST;
&resource);
return HTTP_NOT_FOUND;
if (!is_label) {
return HTTP_BAD_REQUEST;
err);
ap_set_content_length(r, 0);
return DONE;
typedef struct dav_label_walker_ctx
const char *label;
int label_op;
return NULL;
int depth;
int result;
return DECLINED;
&resource);
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (tsize == 0) {
return HTTP_BAD_REQUEST;
err);
if (depth == 0) {
ap_set_content_length(r, 0);
return DONE;
int result;
int label_allowed;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
&resource);
return HTTP_NOT_FOUND;
return DONE;
int result;
return DECLINED;
&resource);
return result;
return HTTP_BAD_REQUEST;
err);
int result;
return DECLINED;
&resource);
return result;
err);
return HTTP_METHOD_NOT_ALLOWED;
int result;
const char *source;
int no_auto_merge;
int no_checkout;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
&resource);
return HTTP_NOT_FOUND;
err);
return DONE;
const char *dest;
int overwrite;
return DECLINED;
&resource);
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
err);
err);
err2);
return DECLINED;
if (r->assbackwards) {
return DECLINED;
&dav_module);
r->allowed = 0
r->allowed |= 0
r->allowed |= 0
return dav_method_get(r);
return dav_method_put(r);
return dav_method_post(r);
return dav_method_delete(r);
return dav_method_options(r);
return dav_method_propfind(r);
return dav_method_proppatch(r);
return dav_method_mkcol(r);
return dav_method_lock(r);
return dav_method_unlock(r);
return dav_method_vsn_control(r);
return dav_method_checkout(r);
return dav_method_uncheckout(r);
return dav_method_checkin(r);
return dav_method_update(r);
return dav_method_label(r);
return dav_method_report(r);
return dav_method_make_workspace(r);
return dav_method_make_activity(r);
return dav_method_baseline_control(r);
return dav_method_merge(r);
return dav_method_bind(r);
return dav_method_search(r);
return DECLINED;
&dav_module);
return DECLINED;
return DECLINED;
return OK;
return DECLINED;
{ NULL }
(uris))