mod_dav.c revision 1b21d7b3d97def358b2e923655edeb16613a1c31
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco/* ====================================================================
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * The Apache Software License, Version 1.1
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Copyright (c) 2000 The Apache Software Foundation. All rights
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Redistribution and use in source and binary forms, with or without
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * modification, are permitted provided that the following conditions
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * 1. Redistributions of source code must retain the above copyright
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * notice, this list of conditions and the following disclaimer.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 2. Redistributions in binary form must reproduce the above copyright
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * notice, this list of conditions and the following disclaimer in
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * the documentation and/or other materials provided with the
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * distribution.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 3. The end-user documentation included with the redistribution,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * if any, must include the following acknowledgment:
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * "This product includes software developed by the
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Apache Software Foundation (http://www.apache.org/)."
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Alternately, this acknowledgment may appear in the software itself,
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * if and wherever such third-party acknowledgments normally appear.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * 4. The names "Apache" and "Apache Software Foundation" must
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * not be used to endorse or promote products derived from this
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * software without prior written permission. For written
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco * permission, please contact apache@apache.org.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 5. Products derived from this software may not be called "Apache",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * nor may "Apache" appear in their name, without prior written
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * permission of the Apache Software Foundation.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * SUCH DAMAGE.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * ====================================================================
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * This software consists of voluntary contributions made by many
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * individuals on behalf of the Apache Software Foundation. For more
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * information on the Apache Software Foundation, please see
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** DAV extension module for Apache 2.0.*
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** This module is repository-independent. It depends on hooks provided by a
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco** repository implementation.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** APACHE ISSUES:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - within a DAV hierarchy, if an unknown method is used and we default
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** to Apache's implementation, it sends back an OPTIONS with the wrong
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** set of methods -- there is NO HOOK for us.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - process_mkcol_body() had to dup code from ap_setup_client_block().
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - it would be nice to get status lines from Apache for arbitrary
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** status codes
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - it would be nice to be able to extend Apache's set of response
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco** codes so that it doesn't return 500 when an unknown code is placed
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** into r->status.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - http_vhost functions should apply "const" to their params
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** DESIGN NOTES:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - For PROPFIND, we batch up the entire response in memory before
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** sending it. We may want to reorganize around sending the information
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** as we suck it in from the propdb. Alternatively, we should at least
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** generate a total Content-Length if we're going to buffer in memory
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** so that we can keep the connection open.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ### what is the best way to set this? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* per-dir configuration */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescotypedef struct {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *dir;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_table_t *d_params; /* per-directory DAV config parameters */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* per-server configuration */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescotypedef struct {
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco#define DAV_INHERIT_VALUE(parent, child, field) \
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ((child)->field ? (child)->field : (parent)->field)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* forward-declare for use in configuration lookup */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic void dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* DBG0("dav_init_handler"); */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic void *dav_create_server_config(apr_pool_t *p, server_rec *s)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### this isn't used at the moment... */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### nothing to merge right now... */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riescostatic void *dav_create_dir_config(apr_pool_t *p, char *dir)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* NOTE: dir==NULL creates the default per-dir config */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco conf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*conf));
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* clean up the directory to remove any trailing slash */
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riescostatic void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco dav_dir_conf *newconf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*newconf));
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx",
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (long)newconf, (long)base, (long)overrides); */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco newconf->provider = DAV_INHERIT_VALUE(parent, child, provider);
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco "\"DAV Off\" cannot be used to turn off a subtree "
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco "of a DAV-enabled location.");
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco "A subtree cannot specify a different DAV provider "
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco "than its parent.");
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf->dir = DAV_INHERIT_VALUE(parent, child, dir);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco newconf->d_params = apr_table_copy(p, parent->d_params);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco apr_table_overlap(newconf->d_params, child->d_params,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescoapr_table_t *dav_get_dir_params(const request_rec *r)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco conf = ap_get_module_config(r->per_dir_config, &dav_module);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic const dav_provider * dav_get_provider(request_rec *r)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco conf = ap_get_module_config(r->per_dir_config, &dav_module);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* assert: conf->provider_name != NULL
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (otherwise, DAV is disabled, and we wouldn't be here) */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* assert: conf->provider != NULL
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco (checked when conf->provider_name is set) */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescoconst dav_hooks_locks *dav_get_lock_hooks(request_rec *r)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescoconst dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescoconst dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescoconst dav_hooks_binding *dav_get_binding_hooks(request_rec *r)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * Command handler for the DAV directive, which is TAKE1.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco conf->provider_name = apr_pstrdup(cmd->pool, arg1);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* lookup and cache the actual provider now */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco conf->provider = dav_lookup_provider(conf->provider_name);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* by the time they use it, the provider should be loaded and
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco registered with us. */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco "Unknown DAV provider: %s",
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * Command handler for the DAVDepthInfinity directive, which is FLAG.
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescostatic const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Command handler for DAVMinTimeout directive, which is TAKE1
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return "DAVMinTimeout requires a non-negative integer.";
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Command handler for DAVParam directive, which is TAKE2
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic const char *dav_cmd_davparam(cmd_parms *cmd, void *config,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** dav_error_response()
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco** Send a nice response back to the user. In most cases, Apache doesn't
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** allow us to provide details in the body about what happened. This
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** function allows us to completely specify the response body.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** ### this function is not logging any errors! (e.g. the body)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic int dav_error_response(request_rec *r, int status, const char *body)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* since we're returning DONE, ensure the request body is consumed. */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* begin the response now... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* the response has been sent. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * ### Use of DONE obviates logging..!
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** Apache's URI escaping does not replace '&' since that is a valid character
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** in a URI (to form a query section). We must explicitly handle it so that
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** we can embed the URI into an XML document.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* check the easy case... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* more work needed... sigh. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** Note: this is a teeny bit of overkill since we know there are no
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** '<' or '>' characters, but who cares.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic void dav_send_multistatus(request_rec *r, int status,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Set the correct status and Content-Type */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Send all of the headers now */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Send the actual multistatus response now... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "<D:multistatus xmlns:D=\"DAV:\"", r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ap_rputc('>', r); */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco for (t = first->propresult.xmlns; t; t = t->next) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_rputs(dav_xml_escape_uri(r->pool, first->href), r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* use the Status-Line text from Apache. Note, this will
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * default to 500 Internal Server Error if first->status
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * is not a known (or valid) status code. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* assume this includes <propstat> and is quoted properly */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco for (t = first->propresult.propstats; t; t = t->next) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** We supply the description, so we know it doesn't have to
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** have any escaping/encoding applied to it.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_rputs("</D:responsedescription>" DEBUG_CR, r);
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco** dav_log_err()
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** Write error information to the log.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic void dav_log_err(request_rec *r, dav_error *err, int level)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Log the errors */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### should have a directive to log the first or all */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco for (errscan = err; errscan != NULL; errscan = errscan->prev) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco errscan->desc, errscan->status, errscan->error_id);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_log_rerror(APLOG_MARK, level | APLOG_NOERRNO, 0, r,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "%s [%d, #%d]",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco errscan->desc, errscan->status, errscan->error_id);
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco** dav_handle_err()
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco** Handle the standard error processing. <err> must be non-NULL.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** <response> is set by the following:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - dav_validate_request()
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** - dav_add_lock()
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** - repos_hooks->remove_resource
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** - repos_hooks->move_resource
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** - repos_hooks->copy_resource
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riescostatic int dav_handle_err(request_rec *r, dav_error *err,
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* log the errors */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* our error messages are safe; tell Apache this */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco apr_table_setn(r->notes, "verbose-error-to", "*");
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* since we're returning DONE, ensure the request body is consumed. */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* send the multistatus and tell Apache the request/response is DONE. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_send_multistatus(r, err->status, response, NULL);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* handy function for return values of methods that (may) create things */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic int dav_created(request_rec *r, const char *locn, const char *what,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* did the target resource already exist? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Apache will supply a default message */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Per HTTP/1.1, S10.2.2: add a Location header to contain the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * URI that was created. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Convert locn to an absolute URI, and return in Location header */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r));
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * we must manufacture the entire response. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco body = apr_psprintf(r->pool, "%s %s has been created.",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return dav_error_response(r, HTTP_CREATED, body);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ### move to dav_util? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescoint dav_get_depth(request_rec *r, int def_depth)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *depth = apr_table_get(r->headers_in, "Depth");
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* The caller will return an HTTP_BAD_REQUEST. This will augment the
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco * default message that Apache provides. */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco "An invalid Depth header was specified.");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const char *overwrite = apr_table_get(r->headers_in, "Overwrite");
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* The caller will return an HTTP_BAD_REQUEST. This will augment the
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * default message that Apache provides. */
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco "An invalid Overwrite header was specified.");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* resolve a request URI to a resource descriptor.
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco * If label_allowed != 0, then allow the request target to be altered by
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco * a Label: header.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * If use_checked_in is true, then the repository provider should return
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the resource identified by the DAV:checked-in property of the resource
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * identified by the Request-URI.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic dav_error * dav_get_resource(request_rec *r, int label_allowed,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* if the request target can be overridden, get any target selector */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco label = apr_table_get(r->headers_in, "label");
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco conf = ap_get_module_config(r->per_dir_config, &dav_module);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* assert: conf->provider != NULL */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* resolve the resource */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco err = (*conf->provider->repos->get_resource)(r, conf->dir,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "Could not fetch resource information.", err);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Note: this shouldn't happen, but just be sure... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return dav_new_error(r->pool, HTTP_NOT_FOUND, 0,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "The provider did not define a "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "resource for %s.",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### hmm. this doesn't feel like the right place or thing to do */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* if there were any input headers requiring a Vary header in the response,
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco * add it now */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescostatic dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* open the thing lazily */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return (*hooks->open_lockdb)(r, ro, 0, lockdb);
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco range_c = apr_table_get(r->headers_in, "content-range");
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* malformed header. ignore it (per S14.16 of RFC2616) */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco || (slash[1] != '*' && atol(slash + 1) <= *range_end)) {
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* invalid range. ignore it (per S14.16 of RFC2616) */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* we now have a valid range */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco/* handle the GET method */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* This method should only be called when the resource is not
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * visible to Apache. We will fetch the resource from the repository,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * then create a subrequest for Apache to handle.
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* Apache will supply a default error for this. */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* Check resource type */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if (resource->type != DAV_RESOURCE_TYPE_REGULAR &&
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco resource->type != DAV_RESOURCE_TYPE_VERSION &&
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco "Cannot GET this type of resource.");
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* Cannot handle GET of a collection from a repository */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco "No default response to GET for a "
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco "collection.");
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ** We can use two different approaches for a GET.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ** 1) get_pathname will return a pathname to a file which should be
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ** sent to the client. If the repository provides this, then we
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ** This is the best alternative since it allows us to do a sub-
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** request on the file, which gives the Apache framework a chance
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ** to deal with negotiation, MIME types, or whatever.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco ** 2) open_stream and read_stream.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Ask repository for copy of file */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco pathname = (*resource->hooks->get_pathname)(resource, &fhandle);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Convert to canonical filename, so Apache detects component
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * separators (on Windows, it only looks for '/', not '\')
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco pathname = ap_os_case_canonical_filename(r->pool, pathname);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Create a sub-request with the new filename */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco new_req = ap_sub_req_lookup_file(pathname, r, NULL);
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* This may be a HEAD request */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* ### this enables header generation */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco /* Run the sub-request */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Free resources */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* set up the HTTP headers for the response */
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco "Unable to set up HTTP headers.",
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* use plain READ mode unless we see a Content-Range */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* process the Content-Range header (if present) */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco has_range = dav_parse_range(r, &range_start, &range_end);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* use a read mode which is seekable */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* prep the output */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco "Content-Range",
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ap_set_content_length(r, range_end - range_start + 1);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = (*resource->hooks->open_stream)(resource, mode,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### assuming FORBIDDEN is probably not quite right... */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "Unable to GET contents for %s.",
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco && (err = (*resource->hooks->seek_stream)(stream,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "Could not seek to beginning of the "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* all set. send the headers now. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else if ((range_end - range_start + 1) > DAV_READ_BLOCKSIZE)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* note: range_end - range_start is an ssize_t */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = (*resource->hooks->read_stream)(stream, buffer,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* no more content */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### what to do with this error? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### range_start should equal range_end+1. if it doesn't, then
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### we did not send enough data to the client. the client will
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### hang (and timeout) waiting for the data.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### what to do? abort the connection?
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* NOTREACHED */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* validate resource on POST, then pass it off to the default handler */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Ask repository module to resolve the resource */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* Note: depth == 0. Implies no need for a multistatus response. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### add a higher-level description? */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco/* handle the PUT method */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) {
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* Ask repository module to resolve the resource */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* If not a file or collection resource, PUT not allowed */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco "Cannot create resource %s with PUT.",
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco return dav_error_response(r, HTTP_CONFLICT, body);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* Cannot PUT a collection */
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco "Cannot PUT to a collection.");
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco resource_state = dav_get_resource_state(r, resource);
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** Note: depth == 0 normally requires no multistatus response. However,
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** other than the Request-URI, thereby requiring a multistatus.
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** If the resource does not exist (DAV_RESOURCE_NULL), then we must
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** check the resource *and* its parent. If the resource exists or is
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco ** a locknull resource, then we check only the resource.
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response,
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco /* ### add a higher-level description? */
if (has_range) {
err);
if (ap_should_client_block(r)) {
long len;
DAV_READ_BLOCKSIZE)) > 0) {
** ### then the resource might NOT exist (e.g. dav_fs_repos.c)
&av_info);
err2);
err);
err);
if (propstats) {
int result;
int depth;
return result;
&resource);
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
** multistatus response -- only internal members/collections.
err);
return result;
&av_info);
err);
err2);
return HTTP_NO_CONTENT;
name);
return NULL;
err);
err);
return err;
err);
return NULL;
const char *dav_level;
char *allow;
ap_text *t;
int text_size;
int result;
&resource);
return result;
return HTTP_BAD_REQUEST;
case DAV_RESOURCE_EXISTS:
case DAV_RESOURCE_LOCK_NULL:
case DAV_RESOURCE_NULL:
text_size = 0;
if (s != allow)
s += strlen(s);
ap_set_content_length(r, 0);
return DONE;
int core_option = 0;
if (!core_option) {
!= NULL) {
return DONE;
/* some props were expected on this collection/resource */
/* no props on this collection/resource */
return NULL;
return NULL;
int depth;
int result;
&resource);
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
&dav_module);
r->uri)));
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
ctx.r = r;
err);
return DONE;
for ( ; i-- > 0; ++ctx ) {
s = apr_psprintf(p,
for ( ; i-- > 0; ++ctx ) {
int reverse)
if (reverse)
ctx += i;
if (reverse)
--ctx;
if (!reverse)
++ctx;
int result;
int failure = 0;
&resource);
return HTTP_NOT_FOUND;
return result;
return HTTP_BAD_REQUEST;
err);
int is_remove;
return HTTP_BAD_REQUEST;
if (failure) {
return DONE;
r->read_chunked = 0;
r->remaining = 0;
if (tenc) {
return HTTP_NOT_IMPLEMENTED;
else if (lenp) {
++pos;
return HTTP_BAD_REQUEST;
return HTTP_UNSUPPORTED_MEDIA_TYPE;
return ap_discard_request_body(r);
int resource_state;
int result;
return result;
&dav_module);
&resource);
return HTTP_METHOD_NOT_ALLOWED;
&av_info);
err2);
err);
err);
const char *body;
const char *dest;
int is_dir;
int overwrite;
int depth;
int result;
int replaced;
int resource_state;
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (is_move
err);
err);
if (is_dir
if (is_dir
return result;
if (is_move) {
if (is_move) {
&src_av_info);
if (is_move)
&dst_av_info);
if (is_move) {
&src_av_info);
err);
err2);
err3);
err);
int result;
int depth;
int new_lock_request = 0;
int resource_state;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
&resource);
goto error;
err);
goto error;
if (new_lock_request == 0) {
err);
goto error;
dav_get_timeout(r),
goto error;
char *locktoken_txt;
&dav_module);
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);
int result;
return DECLINED;
return result;
&resource);
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);
typedef struct dav_set_target_walker_ctx
const char *target;
int is_label;
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;
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;
ap_text *t;
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;
return HTTP_METHOD_NOT_ALLOWED;
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);
&av_info);
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 DECLINED;
return dav_method_vsn_control(r);
return dav_method_checkout(r);
return dav_method_uncheckout(r);
return dav_method_checkin(r);
return dav_method_set_target(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 DECLINED;
&dav_module);
return DECLINED;
return DECLINED;
return OK;
return DECLINED;
{ NULL }
(uris))