mod_dav.c revision cba1beeab00aa7d89ccd51fa18bb2b0f5d3a07d0
842ae4bd224140319ae7feec1872b93dfd491143fielding/* ====================================================================
842ae4bd224140319ae7feec1872b93dfd491143fielding * The Apache Software License, Version 1.1
842ae4bd224140319ae7feec1872b93dfd491143fielding *
842ae4bd224140319ae7feec1872b93dfd491143fielding * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
842ae4bd224140319ae7feec1872b93dfd491143fielding * reserved.
842ae4bd224140319ae7feec1872b93dfd491143fielding *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * are met:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
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 *
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
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 *
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
cd3bbd6d2df78d6c75e5d159a81ef8bdd5f70df9trawick * <http://www.apache.org/>.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
0f60998368b493f90120180a93fc2e1e74490872covener
0f60998368b493f90120180a93fc2e1e74490872covener/*
0f60998368b493f90120180a93fc2e1e74490872covener * DAV extension module for Apache 2.0.*
0f60998368b493f90120180a93fc2e1e74490872covener *
0f60998368b493f90120180a93fc2e1e74490872covener * This module is repository-independent. It depends on hooks provided by a
0f60998368b493f90120180a93fc2e1e74490872covener * repository implementation.
0f60998368b493f90120180a93fc2e1e74490872covener *
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 *
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "apr_strings.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "apr_lib.h" /* for apr_is* */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define APR_WANT_STRFUNC
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "apr_want.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
796e4a7141265d8ed7036e4628161c6eafb2a789jorton#include "httpd.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_config.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_core.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_log.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_main.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_protocol.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_request.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "util_script.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "mod_dav.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* ### what is the best way to set this? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define DAV_DEFAULT_PROVIDER "filesystem"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesenum {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe DAV_ENABLED_UNSET = 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_ENABLED_OFF,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe DAV_ENABLED_ON
e8f95a682820a599fe41b22977010636be5c2717jim};
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* per-dir configuration */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *provider_name;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const dav_provider *provider;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *dir;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int locktimeout;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int allow_depthinfinity;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} dav_dir_conf;
a1790fb35c4b352dab721370985c623a9f8f5062rpluem
713a2b68bac4aeb1e9c48785006c0732451039depquerna/* per-server configuration */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int unused;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} dav_server_conf;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe#define DAV_INHERIT_VALUE(parent, child, field) \
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ((child)->field ? (child)->field : (parent)->field)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* forward-declare for use in configuration lookup */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesextern module DAV_DECLARE_DATA dav_module;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* DAV methods */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesenum {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_M_BIND = 0,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener DAV_M_SEARCH,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_M_LAST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes};
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholesstatic int dav_methods[DAV_M_LAST];
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
8113dac419143273351446c3ad653f3fe5ba5cfdwrowestatic int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes server_rec *s)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DBG0("dav_init_handler"); */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_add_version_component(p, "DAV/2");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return OK;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void *dav_create_server_config(apr_pool_t *p, server_rec *s)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener dav_server_conf *newconf;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* ### this isn't used at the moment... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return newconf;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#if 0
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_server_conf *child = overrides;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener#endif
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_server_conf *newconf;
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### nothing to merge right now... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return newconf;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void *dav_create_dir_config(apr_pool_t *p, char *dir)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* NOTE: dir==NULL creates the default per-dir config */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *conf;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*conf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* clean up the directory to remove any trailing slash */
1f299703465bd9975d94e9f229f76af807442de2covener if (dir != NULL) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener char *d;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener apr_size_t l;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes d = apr_pstrdup(p, dir);
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe l = strlen(d);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (l > 1 && d[l - 1] == '/')
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes d[l - 1] = '\0';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf->dir = d;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj return conf;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholesstatic void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *parent = base;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *child = overrides;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *newconf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*newconf));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (long)newconf, (long)base, (long)overrides); */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
3e6d7277b90d3011db832139afc20efb5f17e203rederpj newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name);
3e6d7277b90d3011db832139afc20efb5f17e203rederpj newconf->provider = DAV_INHERIT_VALUE(parent, child, provider);
3e6d7277b90d3011db832139afc20efb5f17e203rederpj if (parent->provider_name != NULL) {
3e6d7277b90d3011db832139afc20efb5f17e203rederpj if (child->provider_name == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "\"DAV Off\" cannot be used to turn off a subtree "
e8f95a682820a599fe41b22977010636be5c2717jim "of a DAV-enabled location.");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (strcasecmp(child->provider_name,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener parent->provider_name) != 0) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener "A subtree cannot specify a different DAV provider "
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener "than its parent.");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
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,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener allow_depthinfinity);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
6683642c1e0032eeeed5f99e8c14880692ef84c5sf return newconf;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic const dav_provider *dav_get_provider(request_rec *r)
6683642c1e0032eeeed5f99e8c14880692ef84c5sf{
6683642c1e0032eeeed5f99e8c14880692ef84c5sf dav_dir_conf *conf;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
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
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* assert: conf->provider != NULL
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener (checked when conf->provider_name is set) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return conf->provider;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_locks *dav_get_lock_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return dav_get_provider(r)->locks;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return dav_get_provider(r)->propdb;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return dav_get_provider(r)->vsn;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_binding *dav_get_binding_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return dav_get_provider(r)->binding;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerconst dav_hooks_search *dav_get_search_hooks(request_rec *r)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return dav_get_provider(r)->search;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/*
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * Command handler for the DAV directive, which is TAKE1.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_dir_conf *conf = (dav_dir_conf *)config;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (strcasecmp(arg1, "on") == 0) {
0e05808dc59a321566303084c84b9826a4353cefrederpj conf->provider_name = DAV_DEFAULT_PROVIDER;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
b08925593f214f621161742925dcf074a8047e0acovener else if (strcasecmp(arg1, "off") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf->provider_name = NULL;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin conf->provider = NULL;
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf else {
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj conf->provider_name = apr_pstrdup(cmd->pool, arg1);
e8f95a682820a599fe41b22977010636be5c2717jim }
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes if (conf->provider_name != NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* lookup and cache the actual provider now */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes conf->provider = dav_lookup_provider(conf->provider_name);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (conf->provider == NULL) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* by the time they use it, the provider should be loaded and
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes registered with us. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_psprintf(cmd->pool,
ebe5305f8b22507374358f32b74d12fb50c05a25covener "Unknown DAV provider: %s",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes conf->provider_name);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return NULL;
513b324e774c559b579896df131fd7c8471ed529rederpj}
513b324e774c559b579896df131fd7c8471ed529rederpj
513b324e774c559b579896df131fd7c8471ed529rederpj/*
513b324e774c559b579896df131fd7c8471ed529rederpj * Command handler for the DAVDepthInfinity directive, which is FLAG.
513b324e774c559b579896df131fd7c8471ed529rederpj */
513b324e774c559b579896df131fd7c8471ed529rederpjstatic const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config,
513b324e774c559b579896df131fd7c8471ed529rederpj int arg)
513b324e774c559b579896df131fd7c8471ed529rederpj{
513b324e774c559b579896df131fd7c8471ed529rederpj dav_dir_conf *conf = (dav_dir_conf *)config;
513b324e774c559b579896df131fd7c8471ed529rederpj
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (arg)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf->allow_depthinfinity = DAV_ENABLED_ON;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf->allow_depthinfinity = DAV_ENABLED_OFF;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return NULL;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Command handler for DAVMinTimeout directive, which is TAKE1
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *arg1)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_dir_conf *conf = (dav_dir_conf *)config;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
9ad7b260be233be7d7b5576979825cac72e15498rederpj conf->locktimeout = atoi(arg1);
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (conf->locktimeout < 0)
9ad7b260be233be7d7b5576979825cac72e15498rederpj return "DAVMinTimeout requires a non-negative integer.";
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj return NULL;
9ad7b260be233be7d7b5576979825cac72e15498rederpj}
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj/*
9ad7b260be233be7d7b5576979825cac72e15498rederpj** dav_error_response()
9ad7b260be233be7d7b5576979825cac72e15498rederpj**
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**
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** ### this function is not logging any errors! (e.g. the body)
ebe5305f8b22507374358f32b74d12fb50c05a25covener*/
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic int dav_error_response(request_rec *r, int status, const char *body)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes r->status = status;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* ### I really don't think this is needed; gotta test */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin r->status_line = ap_get_status_line(status);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_set_content_type(r, "text/html");
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* begin the response now... */
ebe5305f8b22507374358f32b74d12fb50c05a25covener ap_rvputs(r,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes DAV_RESPONSE_BODY_1,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes r->status_line,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes DAV_RESPONSE_BODY_2,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes &r->status_line[4],
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes DAV_RESPONSE_BODY_3,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes body,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes DAV_RESPONSE_BODY_4,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_psignature("<hr />\n", r),
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes DAV_RESPONSE_BODY_5,
b08925593f214f621161742925dcf074a8047e0acovener NULL);
b08925593f214f621161742925dcf074a8047e0acovener
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* the response has been sent. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /*
9ad7b260be233be7d7b5576979825cac72e15498rederpj * ### Use of DONE obviates logging..!
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
128a5d93141a86e3afa151e921035a07297c9833rederpj return DONE;
9ad7b260be233be7d7b5576979825cac72e15498rederpj}
9ad7b260be233be7d7b5576979825cac72e15498rederpj
128a5d93141a86e3afa151e921035a07297c9833rederpj
128a5d93141a86e3afa151e921035a07297c9833rederpj/*
9ad7b260be233be7d7b5576979825cac72e15498rederpj * Send a "standardized" error response based on the error's namespace & tag
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
9ad7b260be233be7d7b5576979825cac72e15498rederpjstatic int dav_error_response_tag(request_rec *r,
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_error *err)
128a5d93141a86e3afa151e921035a07297c9833rederpj{
9ad7b260be233be7d7b5576979825cac72e15498rederpj r->status = err->status;
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ab21648975dff7e1b680daf8aea627227ba28f7trawick /* ### I really don't think this is needed; gotta test */
9ad7b260be233be7d7b5576979825cac72e15498rederpj r->status_line = ap_get_status_line(err->status);
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
9ad7b260be233be7d7b5576979825cac72e15498rederpj
87587593f1a53030e840acc0dec6cc881022ea40covener ap_rputs(DAV_XML_HEADER DEBUG_CR
87587593f1a53030e840acc0dec6cc881022ea40covener "<D:error xmlns:D=\"DAV:\"", r);
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (err->desc != NULL) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* ### should move this namespace somewhere (with the others!) */
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_rputs(" xmlns:m=\"http://apache.org/dav/xmlns\"", r);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (err->namespace != NULL) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_rprintf(r,
9ad7b260be233be7d7b5576979825cac72e15498rederpj " xmlns:C=\"%s\">" DEBUG_CR
9ad7b260be233be7d7b5576979825cac72e15498rederpj "<C:%s/>" DEBUG_CR,
9ad7b260be233be7d7b5576979825cac72e15498rederpj err->namespace, err->tagname);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj else {
9ab21648975dff7e1b680daf8aea627227ba28f7trawick ap_rprintf(r,
9ad7b260be233be7d7b5576979825cac72e15498rederpj ">" DEBUG_CR
9ad7b260be233be7d7b5576979825cac72e15498rederpj "<D:%s/>" DEBUG_CR, err->tagname);
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* here's our mod_dav specific tag: */
7add8f7fb048534390571801b7794f71cd9e127abnicholes if (err->desc != NULL) {
7add8f7fb048534390571801b7794f71cd9e127abnicholes ap_rprintf(r,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "<m:human-readable errcode=\"%d\">" DEBUG_CR
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "%s" DEBUG_CR
7add8f7fb048534390571801b7794f71cd9e127abnicholes "</m:human-readable>" DEBUG_CR,
7add8f7fb048534390571801b7794f71cd9e127abnicholes err->error_id,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_xml_quote_string(r->pool, err->desc, 0));
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_rputs("</D:error>" DEBUG_CR, r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* the response has been sent. */
7add8f7fb048534390571801b7794f71cd9e127abnicholes /*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * ### Use of DONE obviates logging..!
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return DONE;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/*
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.
7add8f7fb048534390571801b7794f71cd9e127abnicholes */
7add8f7fb048534390571801b7794f71cd9e127abnicholesstatic const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
141e1368614dc7564e1627671361b01b4869b491bnicholes{
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes const char *e_uri = ap_escape_uri(p, uri);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* check the easy case... */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (ap_strchr_c(e_uri, '&') == NULL)
e8f95a682820a599fe41b22977010636be5c2717jim return e_uri;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
ebe5305f8b22507374358f32b74d12fb50c05a25covener /* there was a '&', so more work is needed... sigh. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Note: this is a teeny bit of overkill since we know there are no
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * '<' or '>' characters, but who cares.
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_xml_quote_string(p, e_uri, 0);
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes}
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic void dav_send_multistatus(request_rec *r, int status,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_response *first,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_array_header_t *namespaces)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf{
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Set the correct status and Content-Type */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf r->status = status;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Send the headers and actual multistatus response now... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_rputs(DAV_XML_HEADER DEBUG_CR
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "<D:multistatus xmlns:D=\"DAV:\"", r);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (namespaces != NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf int i;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf for (i = namespaces->nelts; i--; ) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_rprintf(r, " xmlns:ns%d=\"%s\"", i,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf APR_XML_GET_URI_ITEM(namespaces, i));
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
e8f95a682820a599fe41b22977010636be5c2717jim /* ap_rputc('>', r); */
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs(">" DEBUG_CR, r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (; first != NULL; first = first->next) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf apr_text *t;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (first->propresult.xmlns == NULL) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs("<D:response>", r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf else {
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs("<D:response", r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (t = first->propresult.xmlns; t; t = t->next) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs(t->text, r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputc('>', r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs(DEBUG_CR "<D:href>", r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs(dav_xml_escape_uri(r->pool, first->href), r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs("</D:href>" DEBUG_CR, r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (first->propresult.propstats == NULL) {
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 */
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rprintf(r,
7dbf29be626018bc389ef94c1846aeac4b72633bsf "<D:status>HTTP/1.1 %s</D:status>" DEBUG_CR,
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_get_status_line(first->status));
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf else {
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* assume this includes <propstat> and is quoted properly */
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (t = first->propresult.propstats; t; t = t->next) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_rputs(t->text, r);
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (first->desc != NULL) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * We supply the description, so we know it doesn't have to
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * have any escaping/encoding applied to it.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_rputs("<D:responsedescription>", r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_rputs(first->desc, r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_rputs("</D:responsedescription>" DEBUG_CR, r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_rputs("</D:response>" DEBUG_CR, r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_rputs("</D:multistatus>" DEBUG_CR, r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * dav_log_err()
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes *
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Write error information to the log.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic void dav_log_err(request_rec *r, dav_error *err, int level)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_error *errscan;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
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 if (errscan->desc == NULL)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf continue;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (errscan->save_errno != 0) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes errno = errscan->save_errno;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes errscan->desc, errscan->status, errscan->error_id);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, level, 0, r,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "%s [%d, #%d]",
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf errscan->desc, errscan->status, errscan->error_id);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf}
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
7dbf29be626018bc389ef94c1846aeac4b72633bsf/*
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * dav_handle_err()
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Handle the standard error processing. <err> must be non-NULL.
e8f95a682820a599fe41b22977010636be5c2717jim *
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
7dbf29be626018bc389ef94c1846aeac4b72633bsf */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic int dav_handle_err(request_rec *r, dav_error *err,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_response *response)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf{
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* log the errors */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_log_err(r, err, APLOG_ERR);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (response == NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_error *stackerr = err;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* our error messages are safe; tell Apache this */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(r->notes, "verbose-error-to", "*");
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
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. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf while (stackerr != NULL && stackerr->tagname == NULL)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf stackerr = stackerr->prev;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (stackerr != NULL && stackerr->tagname != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_error_response_tag(r, stackerr);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return err->status;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the multistatus and tell Apache the request/response is DONE. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_send_multistatus(r, err->status, response, NULL);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return DONE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int replaced)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
54d22ed1c429b903b029bbd62621f11a9e286137minfrin const char *body;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (locn == NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin locn = r->uri;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* did the target resource already exist? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (replaced) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default message */
e8f95a682820a599fe41b22977010636be5c2717jim return HTTP_NO_CONTENT;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
8a03cd420b800a2428f49f4617293de9b2387b20jorton
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Per HTTP/1.1, S10.2.2: add a Location header to contain the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * URI that was created. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
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
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
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 what, ap_escape_html(r->pool, locn));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_error_response(r, HTTP_CREATED, body);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin}
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* ### move to dav_util? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrinint dav_get_depth(request_rec *r, int def_depth)
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener{
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener const char *depth = apr_table_get(r->headers_in, "Depth");
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener if (depth == NULL) {
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener return def_depth;
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (strcasecmp(depth, "infinity") == 0) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return DAV_INFINITY;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else if (strcmp(depth, "0") == 0) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return 0;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(depth, "1") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The caller will return an HTTP_BAD_REQUEST. This will augment the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message that Apache provides. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
e8f95a682820a599fe41b22977010636be5c2717jim "An invalid Depth header was specified.");
e8f95a682820a599fe41b22977010636be5c2717jim return -1;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jimstatic int dav_get_overwrite(request_rec *r)
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe{
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe const char *overwrite = apr_table_get(r->headers_in, "Overwrite");
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe
f0f6f1b90ab582896f8a7d56d85bd62a55e57d90covener if (overwrite == NULL) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return 1; /* default is "T" */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
560fd0658902ab57754616c172d8953e69fc4722bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
e8f95a682820a599fe41b22977010636be5c2717jim return 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
9ad7b260be233be7d7b5576979825cac72e15498rederpj if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
9ad7b260be233be7d7b5576979825cac72e15498rederpj return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The caller will return an HTTP_BAD_REQUEST. This will augment the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message that Apache provides. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "An invalid Overwrite header was specified.");
560fd0658902ab57754616c172d8953e69fc4722bnicholes return -1;
560fd0658902ab57754616c172d8953e69fc4722bnicholes}
560fd0658902ab57754616c172d8953e69fc4722bnicholes
560fd0658902ab57754616c172d8953e69fc4722bnicholes/* resolve a request URI to a resource descriptor.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If label_allowed != 0, then allow the request target to be altered by
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a Label: header.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
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.
e8f95a682820a599fe41b22977010636be5c2717jim */
e8f95a682820a599fe41b22977010636be5c2717jimstatic dav_error *dav_get_resource(request_rec *r, int label_allowed,
e8f95a682820a599fe41b22977010636be5c2717jim int use_checked_in, dav_resource **res_p)
e8f95a682820a599fe41b22977010636be5c2717jim{
e8f95a682820a599fe41b22977010636be5c2717jim dav_dir_conf *conf;
e8f95a682820a599fe41b22977010636be5c2717jim const char *label = NULL;
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener dav_error *err;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if the request target can be overridden, get any target selector */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (label_allowed) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes label = apr_table_get(r->headers_in, "label");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conf = ap_get_module_config(r->per_dir_config, &dav_module);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* assert: conf->provider != NULL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resolve the resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*conf->provider->repos->get_resource)(r, conf->dir,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes label, use_checked_in,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes res_p);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_push_error(r->pool, err->status, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Could not fetch resource information.", err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return err;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Note: this shouldn't happen, but just be sure... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*res_p == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */
e8f95a682820a599fe41b22977010636be5c2717jim return dav_new_error(r->pool, HTTP_NOT_FOUND, 0,
560fd0658902ab57754616c172d8953e69fc4722bnicholes apr_psprintf(r->pool,
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener "The provider did not define a "
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "resource for %s.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_escape_html(r->pool, r->uri)));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_add_vary_header(r, r, *res_p);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (hooks == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *lockdb = NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
0e05808dc59a321566303084c84b9826a4353cefrederpj /* open the thing lazily */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (*hooks->open_lockdb)(r, ro, 0, lockdb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic int dav_parse_range(request_rec *r,
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_off_t *range_start, apr_off_t *range_end)
ebe5305f8b22507374358f32b74d12fb50c05a25covener{
ebe5305f8b22507374358f32b74d12fb50c05a25covener const char *range_c;
ebe5305f8b22507374358f32b74d12fb50c05a25covener char *range;
ebe5305f8b22507374358f32b74d12fb50c05a25covener char *dash;
ebe5305f8b22507374358f32b74d12fb50c05a25covener char *slash;
ebe5305f8b22507374358f32b74d12fb50c05a25covener
ebe5305f8b22507374358f32b74d12fb50c05a25covener range_c = apr_table_get(r->headers_in, "content-range");
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (range_c == NULL)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return 0;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener range = apr_pstrdup(r->pool, range_c);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (strncasecmp(range, "bytes ", 6) != 0
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || (dash = ap_strchr(range, '-')) == NULL
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || (slash = ap_strchr(range, '/')) == NULL) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* malformed header. ignore it (per S14.16 of RFC2616) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return 0;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
0e05808dc59a321566303084c84b9826a4353cefrederpj *dash = *slash = '\0';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener *range_start = apr_atoi64(range + 6);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *range_end = apr_atoi64(dash + 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*range_end < *range_start
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener || (slash[1] != '*' && apr_atoi64(slash + 1) <= *range_end)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* invalid range. ignore it (per S14.16 of RFC2616) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* we now have a valid range */
9ad7b260be233be7d7b5576979825cac72e15498rederpj return 1;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin}
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* handle the GET method */
54d22ed1c429b903b029bbd62621f11a9e286137minfrinstatic int dav_method_get(request_rec *r)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin{
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_resource *resource;
560fd0658902ab57754616c172d8953e69fc4722bnicholes dav_error *err;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
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 */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &resource);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resource->exists) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_NOT_FOUND;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* set up the HTTP headers for the response */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_push_error(r->pool, err->status, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Unable to set up HTTP headers.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (r->header_only) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return DONE;
e8f95a682820a599fe41b22977010636be5c2717jim }
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* okay... time to deliver the content */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*resource->hooks->deliver)(resource,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->output_filters)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_push_error(r->pool, err->status, 0,
e8f95a682820a599fe41b22977010636be5c2717jim "Unable to deliver content.",
e8f95a682820a599fe41b22977010636be5c2717jim err);
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim return DONE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* validate resource on POST, then pass it off to the default handler */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int dav_method_post(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_resource *resource;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_error *err;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
e8f95a682820a599fe41b22977010636be5c2717jim /* Ask repository module to resolve the resource */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &resource);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Note: depth == 0. Implies no need for a multistatus response. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return DECLINED;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the PUT method */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int dav_method_put(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_resource *resource;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int resource_state;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_auto_version_info av_info;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *body;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_error *err;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_error *err2;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int result;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_stream_mode mode;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_stream *stream;
e8f95a682820a599fe41b22977010636be5c2717jim dav_response *multi_response;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int has_range;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_off_t range_start;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_off_t range_end;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return result;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Ask repository module to resolve the resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
e8f95a682820a599fe41b22977010636be5c2717jim &resource);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If not a file or collection resource, PUT not allowed */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (resource->type != DAV_RESOURCE_TYPE_REGULAR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && resource->type != DAV_RESOURCE_TYPE_WORKING) {
43c3e6a4b559b76b750c245ee95e2782c15b4296jim body = apr_psprintf(r->pool,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Cannot create resource %s with PUT.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_escape_html(r->pool, r->uri));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_error_response(r, HTTP_CONFLICT, body);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
43c3e6a4b559b76b750c245ee95e2782c15b4296jim /* Cannot PUT a collection */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (resource->collection) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_error_response(r, HTTP_CONFLICT,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Cannot PUT to a collection.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener }
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf resource_state = dav_get_resource_state(r, resource);
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /*
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 *
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 */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf resource_state == DAV_RESOURCE_NULL ?
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf DAV_VALIDATE_PARENT :
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### add a higher-level description? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_handle_err(r, err, multi_response);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* make sure the resource can be modified (if versioning repository) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_auto_checkout(r, resource,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 0 /* not parent_only */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &av_info)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* truncate and rewrite the file unless we see a Content-Range */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes mode = DAV_MODE_WRITE_TRUNC;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes has_range = dav_parse_range(r, &range_start, &range_end);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (has_range) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes mode = DAV_MODE_WRITE_SEEKABLE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Create the new file in the repository */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*resource->hooks->open_stream)(resource, mode,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &stream)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### assuming FORBIDDEN is probably not quite right... */
e8f95a682820a599fe41b22977010636be5c2717jim err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_psprintf(r->pool,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Unable to PUT new contents for %s.",
e8f95a682820a599fe41b22977010636be5c2717jim ap_escape_html(r->pool, r->uri)),
e8f95a682820a599fe41b22977010636be5c2717jim err);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err == NULL && has_range) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* a range was provided. seek to the start */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->seek_stream)(stream, range_start);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ap_should_client_block(r)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *buffer = apr_palloc(r->pool, DAV_READ_BLOCKSIZE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes long len;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
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.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem while ((len = ap_get_client_block(r, buffer,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_READ_BLOCKSIZE)) > 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err == NULL) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe /* write whatever we read, until we see an error */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe err = (*resource->hooks->write_stream)(stream,
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe buffer, len);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### what happens if we read more/less than the amount
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### specified in the Content-Range? eek...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (len == -1) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /*
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Error reading request body. This has precedence over
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * prior errors.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "An error occurred while reading the "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "request body.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = (*resource->hooks->close_stream)(stream,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err == NULL /* commit */);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err2 != NULL && err == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* no error during the write, but we hit one at close. use it. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = err2;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
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)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (err == NULL) {
e8f95a682820a599fe41b22977010636be5c2717jim resource->exists = 1;
e8f95a682820a599fe41b22977010636be5c2717jim }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
e8f95a682820a599fe41b22977010636be5c2717jim /* restore modifiability of resources back to what they were */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, resource, err != NULL /* undo if error */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 0 /*unlock*/, &av_info);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* check for errors now */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err2 != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* just log a warning */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_push_error(r->pool, err->status, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The PUT was successful, but there "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "was a problem automatically checking in "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "the resource or its parent collection.",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_log_err(r, err2, APLOG_WARNING);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### place the Content-Type and Content-Language into the propdb */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (locks_hooks != NULL) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj dav_lockdb *lockdb;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* The file creation was successful, but the locking failed. */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj err = dav_push_error(r->pool, err->status, 0,
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 err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* notify lock system that we have created/replaced a resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_notify_created(r, lockdb, resource, resource_state, 0);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj (*locks_hooks->close_lockdb)(lockdb);
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The file creation was successful, but the locking failed. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_push_error(r->pool, err->status, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The file was PUT successfully, but there "
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener "was a problem updating its lock "
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener "information.",
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener err);
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener return dav_handle_err(r, err, NULL);
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf}
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf/* ### move this to dav_util? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfDAV_DECLARE(void) dav_add_response(dav_walk_resource *wres,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf int status, dav_get_props_result *propstats)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf{
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_response *resp;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* just drop some data into an dav_response */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resp = apr_pcalloc(wres->pool, sizeof(*resp));
e8f95a682820a599fe41b22977010636be5c2717jim resp->href = apr_pstrdup(wres->pool, wres->resource->uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resp->status = status;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (propstats) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resp->propresult = *propstats;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resp->next = wres->response;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes wres->response = resp;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj}
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the DELETE method */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowestatic int dav_method_delete(request_rec *r)
e8f95a682820a599fe41b22977010636be5c2717jim{
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_resource *resource;
e8f95a682820a599fe41b22977010636be5c2717jim dav_auto_version_info av_info;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_error *err;
e8f95a682820a599fe41b22977010636be5c2717jim dav_error *err2;
e8f95a682820a599fe41b22977010636be5c2717jim dav_response *multi_response;
e8f95a682820a599fe41b22977010636be5c2717jim int result;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe int depth;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* We don't use the request body right now, so torch it. */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((result = ap_discard_request_body(r)) != OK) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return result;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Ask repository module to resolve the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem &resource);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (err != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resource->exists) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_NOT_FOUND;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes depth = dav_get_depth(r, DAV_INFINITY);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (resource->collection && depth != DAV_INFINITY) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This supplies additional information for the default message. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth must be \"infinity\" for DELETE of a collection.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_BAD_REQUEST;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resource->collection && depth == 1) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This supplies additional information for the default message. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth of \"1\" is not allowed for DELETE.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_BAD_REQUEST;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /*
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 **
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** Note that a failure on the resource itself does not generate a
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** multistatus response -- only internal members/collections.
8869662bb1a4078297020e94ae5e928626d877c6rederpj */
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((err = dav_validate_request(r, resource, depth, NULL,
8869662bb1a4078297020e94ae5e928626d877c6rederpj &multi_response,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem DAV_VALIDATE_PARENT
8869662bb1a4078297020e94ae5e928626d877c6rederpj | DAV_VALIDATE_USE_424, NULL)) != NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj err = dav_push_error(r->pool, err->status, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_psprintf(r->pool,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "Could not DELETE %s due to a failed "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "precondition (e.g. locks).",
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_escape_html(r->pool, r->uri)),
8869662bb1a4078297020e94ae5e928626d877c6rederpj err);
8869662bb1a4078297020e94ae5e928626d877c6rederpj return dav_handle_err(r, err, multi_response);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
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 */
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((result = dav_unlock(r, resource, NULL)) != OK) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj return result;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* if versioned resource, make sure parent is checked out */
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
8869662bb1a4078297020e94ae5e928626d877c6rederpj &av_info)) != NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### add a higher-level description? */
8869662bb1a4078297020e94ae5e928626d877c6rederpj return dav_handle_err(r, err, NULL);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* try to remove the resource */
8869662bb1a4078297020e94ae5e928626d877c6rederpj err = (*resource->hooks->remove_resource)(resource, &multi_response);
6733d943c9e8d0f27dd077a04037e8c49eb090ffcovener
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* restore writability of parent back to what it was */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
8869662bb1a4078297020e94ae5e928626d877c6rederpj 0 /*unlock*/, &av_info);
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* check for errors now */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (err != NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf err = dav_push_error(r->pool, err->status, 0,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_psprintf(r->pool,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Could not DELETE %s.",
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_escape_html(r->pool, r->uri)),
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf err);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_handle_err(r, err, multi_response);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (err2 != NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* just log a warning */
8869662bb1a4078297020e94ae5e928626d877c6rederpj err = dav_push_error(r->pool, err2->status, 0,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "The DELETE was successful, but there "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "was a problem automatically checking in "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "the parent collection.",
8869662bb1a4078297020e94ae5e928626d877c6rederpj err2);
8869662bb1a4078297020e94ae5e928626d877c6rederpj dav_log_err(r, err, APLOG_WARNING);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* Apache will supply a default error for this. */
8869662bb1a4078297020e94ae5e928626d877c6rederpj return HTTP_NO_CONTENT;
8869662bb1a4078297020e94ae5e928626d877c6rederpj}
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj/* generate DAV:supported-method-set OPTIONS response */
8869662bb1a4078297020e94ae5e928626d877c6rederpjstatic dav_error *dav_gen_supported_methods(request_rec *r,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const apr_xml_elem *elem,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const apr_table_t *methods,
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_text_header *body)
8869662bb1a4078297020e94ae5e928626d877c6rederpj{
8869662bb1a4078297020e94ae5e928626d877c6rederpj const apr_array_header_t *arr;
8869662bb1a4078297020e94ae5e928626d877c6rederpj const apr_table_entry_t *elts;
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_xml_elem *child;
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_xml_attr *attr;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem char *s;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int i;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_text_append(r->pool, body, "<D:supported-method-set>" DEBUG_CR);
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (elem->first_child == NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* show all supported methods */
8869662bb1a4078297020e94ae5e928626d877c6rederpj arr = apr_table_elts(methods);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem elts = (const apr_table_entry_t *)arr->elts;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem for (i = 0; i < arr->nelts; ++i) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (elts[i].key == NULL)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem continue;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem s = apr_psprintf(r->pool,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "<D:supported-method D:name=\"%s\"/>"
8869662bb1a4078297020e94ae5e928626d877c6rederpj DEBUG_CR,
8869662bb1a4078297020e94ae5e928626d877c6rederpj elts[i].key);
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_text_append(r->pool, body, s);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj else {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* check for support of specific methods */
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (child = elem->first_child; child != NULL; child = child->next) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (child->ns == APR_XML_NS_DAV_ID
8869662bb1a4078297020e94ae5e928626d877c6rederpj && strcmp(child->name, "supported-method") == 0) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *name = NULL;
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* go through attributes to find method name */
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (attr = child->attr; attr != NULL; attr = attr->next) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (attr->ns == APR_XML_NS_DAV_ID
8869662bb1a4078297020e94ae5e928626d877c6rederpj && strcmp(attr->name, "name") == 0)
8869662bb1a4078297020e94ae5e928626d877c6rederpj name = attr->value;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (name == NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "A DAV:supported-method element "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "does not have a \"name\" attribute");
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* see if method is supported */
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (apr_table_get(methods, name) != NULL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj s = apr_psprintf(r->pool,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "<D:supported-method D:name=\"%s\"/>"
8869662bb1a4078297020e94ae5e928626d877c6rederpj DEBUG_CR,
8869662bb1a4078297020e94ae5e928626d877c6rederpj name);
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_text_append(r->pool, body, s);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_text_append(r->pool, body, "</D:supported-method-set>" DEBUG_CR);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return NULL;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem}
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* generate DAV:supported-live-property-set OPTIONS response */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic dav_error *dav_gen_supported_live_props(request_rec *r,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj const dav_resource *resource,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj const apr_xml_elem *elem,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_text_header *body)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem{
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_lockdb *lockdb;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_propdb *propdb;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_xml_elem *child;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_xml_attr *attr;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_error *err;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
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 return dav_push_error(r->pool, err->status, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "The lock database could not be opened, "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "preventing the reporting of supported lock "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "properties.",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* open the property database (readonly) for the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((err = dav_open_propdb(r, lockdb, resource, 1, NULL,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem &propdb)) != NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (lockdb != NULL)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem (*lockdb->hooks->close_lockdb)(lockdb);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return dav_push_error(r->pool, err->status, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "The property database could not be opened, "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "preventing report of supported properties.",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_text_append(r->pool, body, "<D:supported-live-property-set>" DEBUG_CR);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (elem->first_child == NULL) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* show all supported live properties */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem body->last->next = props.propstats;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem while (body->last->next != NULL)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem body->last = body->last->next;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj else {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* check for support of specific live property */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj for (child = elem->first_child; child != NULL; child = child->next) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj if (child->ns == APR_XML_NS_DAV_ID
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj && strcmp(child->name, "supported-live-property") == 0) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj const char *name = NULL;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj const char *nmspace = NULL;
0e05808dc59a321566303084c84b9826a4353cefrederpj
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg /* go through attributes to find name and namespace */
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg for (attr = child->attr; attr != NULL; attr = attr->next) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj if (attr->ns == APR_XML_NS_DAV_ID) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj if (strcmp(attr->name, "name") == 0)
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj name = attr->value;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj else if (strcmp(attr->name, "namespace") == 0)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem nmspace = attr->value;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (name == NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "A DAV:supported-live-property "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "element does not have a \"name\" "
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj "attribute");
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj break;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* default namespace to DAV: */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (nmspace == NULL)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem nmspace = "DAV:";
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* check for support of property */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_get_liveprop_supported(propdb, nmspace, name, body);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_append(r->pool, body, "</D:supported-live-property-set>" DEBUG_CR);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_close_propdb(propdb);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (lockdb != NULL)
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj (*lockdb->hooks->close_lockdb)(lockdb);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj return err;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj}
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* generate DAV:supported-report-set OPTIONS response */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic dav_error *dav_gen_supported_reports(request_rec *r,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const dav_resource *resource,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const apr_xml_elem *elem,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_hooks_vsn *vsn_hooks,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_header *body)
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj{
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_xml_elem *child;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_xml_attr *attr;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_error *err;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj char *s;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_append(r->pool, body, "<D:supported-report-set>" DEBUG_CR);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (vsn_hooks != NULL) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_report_elem *reports;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const dav_report_elem *rp;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return dav_push_error(r->pool, err->status, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "DAV:supported-report-set could not be "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "determined due to a problem fetching the "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "available reports for this resource.",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (reports != NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj if (elem->first_child == NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* show all supported reports */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (rp = reports; rp->nmspace != NULL; ++rp) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Note: we presume reports->namespace is
0e05808dc59a321566303084c84b9826a4353cefrederpj * properly XML/URL quoted */
0e05808dc59a321566303084c84b9826a4353cefrederpj s = apr_psprintf(r->pool,
0e05808dc59a321566303084c84b9826a4353cefrederpj "<D:supported-report D:name=\"%s\" "
0e05808dc59a321566303084c84b9826a4353cefrederpj "D:namespace=\"%s\"/>" DEBUG_CR,
0e05808dc59a321566303084c84b9826a4353cefrederpj rp->name, rp->nmspace);
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_text_append(r->pool, body, s);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj else {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* check for support of specific report */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (child = elem->first_child; child != NULL; child = child->next) {
0e05808dc59a321566303084c84b9826a4353cefrederpj if (child->ns == APR_XML_NS_DAV_ID
0e05808dc59a321566303084c84b9826a4353cefrederpj && strcmp(child->name, "supported-report") == 0) {
0e05808dc59a321566303084c84b9826a4353cefrederpj const char *name = NULL;
0e05808dc59a321566303084c84b9826a4353cefrederpj const char *nmspace = NULL;
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj /* go through attributes to find name and namespace */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (attr = child->attr; attr != NULL; attr = attr->next) {
0e05808dc59a321566303084c84b9826a4353cefrederpj if (attr->ns == APR_XML_NS_DAV_ID) {
0e05808dc59a321566303084c84b9826a4353cefrederpj if (strcmp(attr->name, "name") == 0)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj name = attr->value;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj else if (strcmp(attr->name, "namespace") == 0)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj nmspace = attr->value;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (name == NULL) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "A DAV:supported-report element "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "does not have a \"name\" attribute");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* default namespace to DAV: */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (nmspace == NULL)
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj nmspace = "DAV:";
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem for (rp = reports; rp->nmspace != NULL; ++rp) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (strcmp(name, rp->name) == 0
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj && strcmp(nmspace, rp->nmspace) == 0) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Note: we presume reports->nmspace is
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * properly XML/URL quoted
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem s = apr_psprintf(r->pool,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "<D:supported-report "
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "D:name=\"%s\" "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "D:namespace=\"%s\"/>"
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj DEBUG_CR,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj rp->name, rp->nmspace);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_append(r->pool, body, s);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj break;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR);
0e05808dc59a321566303084c84b9826a4353cefrederpj return NULL;
0e05808dc59a321566303084c84b9826a4353cefrederpj}
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj/* handle the SEARCH method */
0e05808dc59a321566303084c84b9826a4353cefrederpjstatic int dav_method_search(request_rec *r)
0e05808dc59a321566303084c84b9826a4353cefrederpj{
0e05808dc59a321566303084c84b9826a4353cefrederpj const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
0e05808dc59a321566303084c84b9826a4353cefrederpj dav_resource *resource;
0e05808dc59a321566303084c84b9826a4353cefrederpj dav_error *err;
0e05808dc59a321566303084c84b9826a4353cefrederpj dav_response *multi_status;
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj /* If no search provider, decline the request */
0e05808dc59a321566303084c84b9826a4353cefrederpj if (search_hooks == NULL)
0e05808dc59a321566303084c84b9826a4353cefrederpj return DECLINED;
0e05808dc59a321566303084c84b9826a4353cefrederpj
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.
40a1aee60a66f7c8dbd0835fdd4f09334e12fc15rpluem */
0e05808dc59a321566303084c84b9826a4353cefrederpj err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
0e05808dc59a321566303084c84b9826a4353cefrederpj &resource);
40a1aee60a66f7c8dbd0835fdd4f09334e12fc15rpluem if (err != NULL)
0e05808dc59a321566303084c84b9826a4353cefrederpj return dav_handle_err(r, err, NULL);
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (!resource->exists) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Apache will supply a default error for this. */
0e05808dc59a321566303084c84b9826a4353cefrederpj return HTTP_NOT_FOUND;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj /* set up the HTTP headers for the response */
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj err = dav_push_error(r->pool, err->status, 0,
0e05808dc59a321566303084c84b9826a4353cefrederpj "Unable to set up HTTP headers.",
0e05808dc59a321566303084c84b9826a4353cefrederpj err);
0e05808dc59a321566303084c84b9826a4353cefrederpj return dav_handle_err(r, err, NULL);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (r->header_only) {
0e05808dc59a321566303084c84b9826a4353cefrederpj return DONE;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj /* okay... time to search the content */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Let's validate XML and process walk function
0e05808dc59a321566303084c84b9826a4353cefrederpj * in the hook function
0e05808dc59a321566303084c84b9826a4353cefrederpj */
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((err = (*search_hooks->search_resource)(r, &multi_status)) != NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* ### add a higher-level description? */
0e05808dc59a321566303084c84b9826a4353cefrederpj return dav_handle_err(r, err, NULL);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* We have results in multi_status */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Should I pass namespace?? */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return DONE;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem}
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/* handle the OPTIONS method */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpjstatic int dav_method_options(request_rec *r)
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj{
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 dav_resource *resource;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const char *dav_level;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem char *allow;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem char *s;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const apr_array_header_t *arr;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const apr_table_entry_t *elts;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_table_t *methods = apr_table_make(r->pool, 12);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_text_header vsn_options = { 0 };
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_text_header body = { 0 };
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_text *t;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int text_size;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int result;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int i;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_array_header_t *uri_ary;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_xml_doc *doc;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const apr_xml_elem *elem;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_error *err;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* resolve the resource */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem &resource);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (err != NULL)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return dav_handle_err(r, err, NULL);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* parse any request body */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((result = ap_xml_parse_input(r, &doc)) != OK) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj return result;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* note: doc == NULL if no request body */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (doc && !dav_validate_root(doc, "options")) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "The \"options\" element was not found.");
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj return HTTP_BAD_REQUEST;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* determine which providers are available */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj dav_level = "1";
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe if (locks_hooks != NULL) {
e8f95a682820a599fe41b22977010636be5c2717jim dav_level = "1,2";
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe if (binding_hooks != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes /* ###
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 * ###
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
f05787953018140838ad51456c86c965d6a86267jim apr_table_setn(r->headers_out, "DAV", dav_level);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f05787953018140838ad51456c86c965d6a86267jim /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If there is a versioning provider, generate DAV headers
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for versioning options.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
e8f95a682820a599fe41b22977010636be5c2717jim if (vsn_hooks != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (*vsn_hooks->get_vsn_options)(r->pool, &vsn_options);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (t = vsn_options.first; t != NULL; t = t->next)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(r->headers_out, "DAV", t->text);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim /*
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes uri_ary = apr_array_make(r->pool, 5, sizeof(const char *));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_run_gather_propsets(uri_ary);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0; i < uri_ary->nelts; ++i) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (((char **)uri_ary->elts)[i] != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(r->headers_out, "DAV", ((char **)uri_ary->elts)[i]);
e8f95a682820a599fe41b22977010636be5c2717jim }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* this tells MSFT products to skip looking for FrontPage extensions */
e8f95a682820a599fe41b22977010636be5c2717jim apr_table_setn(r->headers_out, "MS-Author-Via", "DAV");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
e8f95a682820a599fe41b22977010636be5c2717jim * Determine which methods are allowed on the resource.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Three cases: resource is null (3), is lock-null (7.4), or exists.
e8f95a682820a599fe41b22977010636be5c2717jim *
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "OPTIONS", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim /* ### take into account resource type */
e8f95a682820a599fe41b22977010636be5c2717jim switch (dav_get_resource_state(r, resource))
e8f95a682820a599fe41b22977010636be5c2717jim {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe case DAV_RESOURCE_EXISTS:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resource exists */
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener apr_table_addn(methods, "GET", "");
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener apr_table_addn(methods, "HEAD", "");
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener apr_table_addn(methods, "POST", "");
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener apr_table_addn(methods, "DELETE", "");
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener apr_table_addn(methods, "TRACE", "");
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener apr_table_addn(methods, "PROPFIND", "");
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener apr_table_addn(methods, "PROPPATCH", "");
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener apr_table_addn(methods, "COPY", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "MOVE", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resource->collection)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "PUT", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (locks_hooks != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "LOCK", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "UNLOCK", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case DAV_RESOURCE_LOCK_NULL:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* resource is lock-null. */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_table_addn(methods, "MKCOL", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "PROPFIND", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "PUT", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (locks_hooks != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "LOCK", "");
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes apr_table_addn(methods, "UNLOCK", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener case DAV_RESOURCE_NULL:
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* resource is null. */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener apr_table_addn(methods, "MKCOL", "");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_table_addn(methods, "PUT", "");
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (locks_hooks != NULL)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "LOCK", "");
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes default:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### internal error! */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a versioning provider, add versioning methods */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (vsn_hooks != NULL) {
e8f95a682820a599fe41b22977010636be5c2717jim if (!resource->exists) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((*vsn_hooks->versionable)(resource))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "VERSION-CONTROL", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (vsn_hooks->can_be_workspace != NULL
e8f95a682820a599fe41b22977010636be5c2717jim && (*vsn_hooks->can_be_workspace)(resource))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "MKWORKSPACE", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (vsn_hooks->can_be_activity != NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && (*vsn_hooks->can_be_activity)(resource))
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_table_addn(methods, "MKACTIVITY", "");
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (!resource->versioned) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((*vsn_hooks->versionable)(resource))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "VERSION-CONTROL", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (resource->working) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "CHECKIN", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we might not support this DeltaV option */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "UNCHECKOUT", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (vsn_hooks->add_label != NULL) {
e8f95a682820a599fe41b22977010636be5c2717jim apr_table_addn(methods, "CHECKOUT", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "LABEL", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "CHECKOUT", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a bindings provider, see if resource is bindable */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (binding_hooks != NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && (*binding_hooks->is_bindable)(resource)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "BIND", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is a search provider, set SEARCH in option */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (search_hooks != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_addn(methods, "SEARCH", "");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* Generate the Allow header */
7dbf29be626018bc389ef94c1846aeac4b72633bsf arr = apr_table_elts(methods);
7dbf29be626018bc389ef94c1846aeac4b72633bsf elts = (const apr_table_entry_t *)arr->elts;
7dbf29be626018bc389ef94c1846aeac4b72633bsf text_size = 0;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* first, compute total length */
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (i = 0; i < arr->nelts; ++i) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (elts[i].key == NULL)
7dbf29be626018bc389ef94c1846aeac4b72633bsf continue;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* add 1 for comma or null */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes text_size += strlen(elts[i].key) + 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes s = allow = apr_palloc(r->pool, text_size);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (i = 0; i < arr->nelts; ++i) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (elts[i].key == NULL)
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes continue;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (s != allow)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *s++ = ',';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes strcpy(s, elts[i].key);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes s += strlen(s);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_table_setn(r->headers_out, "Allow", allow);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If there is search set_option_head function, set head */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* DASL: <DAV:basicsearch>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DASL: <http://foo.bar.com/syntax1>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DASL: <http://akuma.com/syntax2>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (search_hooks != NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && *search_hooks->set_option_head != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*search_hooks->set_option_head)(r)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if there was no request body, then there is no response body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (doc == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_set_content_length(r, 0);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### this sends a Content-Type. the default OPTIONS does not. */
e8f95a682820a599fe41b22977010636be5c2717jim
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 return DONE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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 int core_option = 0;
e8f95a682820a599fe41b22977010636be5c2717jim dav_error *err = NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (elem->ns == APR_XML_NS_DAV_ID) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (strcmp(elem->name, "supported-method-set") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_gen_supported_methods(r, elem, methods, &body);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes core_option = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(elem->name, "supported-live-property-set") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_gen_supported_live_props(r, resource, elem, &body);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes core_option = 1;
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(elem->name, "supported-report-set") == 0) {
e8f95a682820a599fe41b22977010636be5c2717jim err = dav_gen_supported_reports(r, resource, elem, vsn_hooks, &body);
e8f95a682820a599fe41b22977010636be5c2717jim core_option = 1;
e8f95a682820a599fe41b22977010636be5c2717jim }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (err != NULL)
e8f95a682820a599fe41b22977010636be5c2717jim return dav_handle_err(r, err, NULL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* if unrecognized option, pass to versioning provider */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (!core_option) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((err = (*vsn_hooks->get_option)(resource, elem, &body))
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return dav_handle_err(r, err, NULL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the options response */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->status = HTTP_OK;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send the headers and response body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_rputs(DAV_XML_HEADER DEBUG_CR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (t = body.first; t != NULL; t = t->next)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_rputs(t->text, r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_rputs("</D:options-response>" DEBUG_CR, r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we've sent everything necessary to the client. */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return DONE;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes}
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesstatic void dav_cache_badprops(dav_walker_ctx *ctx)
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes{
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes const apr_xml_elem *elem;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_text_header hdr = { 0 };
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe
e8f95a682820a599fe41b22977010636be5c2717jim /* just return if we built the thing already */
e8f95a682820a599fe41b22977010636be5c2717jim if (ctx->propstat_404 != NULL) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes apr_text_append(ctx->w.pool, &hdr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "<D:propstat>" DEBUG_CR
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "<D:prop>" DEBUG_CR);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes elem = dav_find_child(ctx->doc->root, "prop");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes for (elem = elem->first_child; elem; elem = elem->next) {
f05787953018140838ad51456c86c965d6a86267jim apr_text_append(ctx->w.pool, &hdr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_xml_empty_elem(ctx->w.pool, elem));
f05787953018140838ad51456c86c965d6a86267jim }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_text_append(ctx->w.pool, &hdr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "</D:prop>" DEBUG_CR
e8f95a682820a599fe41b22977010636be5c2717jim "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "</D:propstat>" DEBUG_CR);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx->propstat_404 = hdr.first;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes}
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesstatic dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype)
e8f95a682820a599fe41b22977010636be5c2717jim{
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_walker_ctx *ctx = wres->walk_ctx;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_error *err;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_propdb *propdb;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_get_props_result propstats = { 0 };
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /*
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.
e8f95a682820a599fe41b22977010636be5c2717jim **
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ** Note: we cast to lose the "const". The propdb won't try to change
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ** the resource, however, since we are opening readonly.
e8f95a682820a599fe41b22977010636be5c2717jim */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
e8f95a682820a599fe41b22977010636be5c2717jim if (err != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### do something with err! */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_get_props_result badprops = { 0 };
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* some props were expected on this collection/resource */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_cache_badprops(ctx);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes badprops.propstats = ctx->propstat_404;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_add_response(wres, 0, &badprops);
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener }
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener else {
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener /* no props on this collection/resource */
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener dav_add_response(wres, HTTP_OK, NULL);
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener }
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener return NULL;
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener }
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener /* ### what to do about closing the propdb on server failure? */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes propstats = dav_get_props(propdb, ctx->doc);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_prop_insert what = ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ? DAV_PROP_INSERT_VALUE
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes : DAV_PROP_INSERT_NAME;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes propstats = dav_get_allprops(propdb, what);
e8f95a682820a599fe41b22977010636be5c2717jim }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_close_propdb(propdb);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_add_response(wres, 0, &propstats);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return NULL;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes}
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes/* handle the PROPFIND method */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesstatic int dav_method_propfind(request_rec *r)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes{
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes dav_resource *resource;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes int depth;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes dav_error *err;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes int result;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_xml_doc *doc;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener const apr_xml_elem *child;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener dav_walker_ctx ctx = { { 0 } };
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener dav_response *multi_status;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* Ask repository module to resolve the resource */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes &resource);
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes if (err != NULL)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return dav_handle_err(r, err, NULL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* Apache will supply a default error for this. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return HTTP_NOT_FOUND;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* dav_get_depth() supplies additional information for the
e8f95a682820a599fe41b22977010636be5c2717jim * default message. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return HTTP_BAD_REQUEST;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (depth == DAV_INFINITY && resource->collection) {
e8f95a682820a599fe41b22977010636be5c2717jim dav_dir_conf *conf;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes &dav_module);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* default is to DISALLOW these requests */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (conf->allow_depthinfinity != DAV_ENABLED_ON) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return dav_error_response(r, HTTP_FORBIDDEN,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_psprintf(r->pool,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "PROPFIND requests with a "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "Depth of \"infinity\" are "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "not allowed for %s.",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_escape_html(r->pool,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes r->uri)));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
490046d2a164ad86cc63bd789f32eaed663d239abnicholes if ((result = ap_xml_parse_input(r, &doc)) != OK) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return result;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* note: doc == NULL if no request body */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (doc && !dav_validate_root(doc, "propfind")) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* This supplies additional information for the default message. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "The \"propfind\" element was not found.");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return HTTP_BAD_REQUEST;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### validate that only one of these three elements is present */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (doc == NULL
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes || (child = dav_find_child(doc->root, "allprop")) != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* note: no request body implies allprop */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.propfind_type = DAV_PROPFIND_IS_ALLPROP;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim else if ((child = dav_find_child(doc->root, "propname")) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ctx.propfind_type = DAV_PROPFIND_IS_PROPNAME;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else if ((child = dav_find_child(doc->root, "prop")) != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.propfind_type = DAV_PROPFIND_IS_PROP;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* "propfind" element must have one of the above three children */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* This supplies additional information for the default message. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
e8f95a682820a599fe41b22977010636be5c2717jim "The \"propfind\" element does not contain one of "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "the required child elements (the specific command).");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return HTTP_BAD_REQUEST;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.func = dav_propfind_walker;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.walk_ctx = &ctx;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.pool = r->pool;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.w.root = resource;
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ctx.doc = doc;
e8f95a682820a599fe41b22977010636be5c2717jim ctx.r = r;
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim /* ### should open read-only */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = dav_open_lockdb(r, 0, &ctx.w.lockdb)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_push_error(r->pool, err->status, 0,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "The lock database could not be opened, "
e8f95a682820a599fe41b22977010636be5c2717jim "preventing access to the various lock "
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "properties for the PROPFIND.",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes err);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return dav_handle_err(r, err, NULL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (ctx.w.lockdb != NULL) {
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes /* if we have a lock database, then we can walk locknull resources */
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL;
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes }
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
0c8aa496e9d7676ff8101783398f17c0da1900f7bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (ctx.w.lockdb != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (err != NULL) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* ### add a higher-level description? */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return dav_handle_err(r, err, NULL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* return a 207 (Multi-Status) response now. */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ctx.propstat_404 != NULL) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes doc->namespaces);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* the response has been sent. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return DONE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_text * dav_failed_proppatch(apr_pool_t *p,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_array_header_t *prop_ctx)
e8f95a682820a599fe41b22977010636be5c2717jim{
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_text_header hdr = { 0 };
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int i = prop_ctx->nelts;
e8f95a682820a599fe41b22977010636be5c2717jim dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts;
e8f95a682820a599fe41b22977010636be5c2717jim dav_error *err424_set = NULL;
43c3e6a4b559b76b750c245ee95e2782c15b4296jim dav_error *err424_delete = NULL;
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes const char *s;
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes /* ### might be nice to sort by status code and description */
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes for ( ; i-- > 0; ++ctx ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_append(p, &hdr,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:propstat>" DEBUG_CR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:prop>");
e8f95a682820a599fe41b22977010636be5c2717jim apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_append(p, &hdr, "</D:prop>" DEBUG_CR);
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ctx->err == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* nothing was assigned here yet, so make it a 424 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ctx->operation == DAV_PROP_OP_SET) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err424_set == NULL)
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.");
e8f95a682820a599fe41b22977010636be5c2717jim ctx->err = err424_set;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes else if (ctx->operation == DAV_PROP_OP_DELETE) {
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes if (err424_delete == NULL)
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 "errors.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ctx->err = err424_delete;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes s = apr_psprintf(p,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:status>"
e8f95a682820a599fe41b22977010636be5c2717jim "HTTP/1.1 %d (status)"
e8f95a682820a599fe41b22977010636be5c2717jim "</D:status>" DEBUG_CR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ctx->err->status);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_append(p, &hdr, s);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we should use compute_desc if necessary... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ctx->err->desc != NULL) {
e8f95a682820a599fe41b22977010636be5c2717jim apr_text_append(p, &hdr, "<D:responsedescription>" DEBUG_CR);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_text_append(p, &hdr, ctx->err->desc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_append(p, &hdr, "</D:responsedescription>" DEBUG_CR);
e8f95a682820a599fe41b22977010636be5c2717jim }
e8f95a682820a599fe41b22977010636be5c2717jim
43c3e6a4b559b76b750c245ee95e2782c15b4296jim apr_text_append(p, &hdr, "</D:propstat>" DEBUG_CR);
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes }
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes return hdr.first;
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes}
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_text_header hdr = { 0 };
e8f95a682820a599fe41b22977010636be5c2717jim int i = prop_ctx->nelts;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### we probably need to revise the way we assemble the response...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ### this code assumes everything will return status==200.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_text_append(p, &hdr,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:propstat>" DEBUG_CR
e8f95a682820a599fe41b22977010636be5c2717jim "<D:prop>" DEBUG_CR);
e8f95a682820a599fe41b22977010636be5c2717jim
43c3e6a4b559b76b750c245ee95e2782c15b4296jim for ( ; i-- > 0; ++ctx ) {
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes apr_text_append(p, &hdr,
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes "</D:prop>" DEBUG_CR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "</D:propstat>" DEBUG_CR);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return hdr.first;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jimstatic void dav_prop_log_errors(dav_prop_ctx *ctx)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem{
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_log_err(ctx->r, ctx->err, APLOG_ERR);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Call <func> for each context. This can stop when an error occurs, or
e8f95a682820a599fe41b22977010636be5c2717jim * simply iterate through the whole list.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Returns 1 if an error occurs (and the iteration is aborted). Returns 0
e8f95a682820a599fe41b22977010636be5c2717jim * if all elements are processed.
e8f95a682820a599fe41b22977010636be5c2717jim *
43c3e6a4b559b76b750c245ee95e2782c15b4296jim * If <reverse> is true (non-zero), then the list is traversed in
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes * reverse order.
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes */
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholesstatic int dav_process_ctx_list(void (*func)(dav_prop_ctx *ctx),
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes apr_array_header_t *ctx_list, int stop_on_error,
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes int reverse)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int i = ctx_list->nelts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_prop_ctx *ctx = (dav_prop_ctx *)ctx_list->elts;
e8f95a682820a599fe41b22977010636be5c2717jim
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (reverse)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ctx += i;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (i--) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (reverse)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes --ctx;
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe (*func)(ctx);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (stop_on_error && DAV_PROP_CTX_HAS_ERR(*ctx)) {
e8f95a682820a599fe41b22977010636be5c2717jim return 1;
e8f95a682820a599fe41b22977010636be5c2717jim }
43c3e6a4b559b76b750c245ee95e2782c15b4296jim
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes if (!reverse)
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes ++ctx;
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes }
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes return 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* handle the PROPPATCH method */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int dav_method_proppatch(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_error *err;
e8f95a682820a599fe41b22977010636be5c2717jim dav_resource *resource;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int result;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_xml_doc *doc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_xml_elem *child;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_propdb *propdb;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int failure = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_response resp = { 0 };
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_text *propstat_text;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_array_header_t *ctx_list;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_prop_ctx *ctx;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_version_info av_info;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Ask repository module to resolve the resource */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin &resource);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (err != NULL)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
88adce5ec0da39b41450ce1d5a77659168097e0cjorton if (!resource->exists) {
88adce5ec0da39b41450ce1d5a77659168097e0cjorton /* Apache will supply a default error for this. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return HTTP_NOT_FOUND;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((result = ap_xml_parse_input(r, &doc)) != OK) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return result;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* note: doc == NULL if no request body */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (doc == NULL || !dav_validate_root(doc, "propertyupdate")) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "The request body does not contain "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "a \"propertyupdate\" element.");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return HTTP_BAD_REQUEST;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
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 DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure the resource can be modified (if versioning repository) */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((err = dav_auto_checkout(r, resource,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin 0 /* not parent_only */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin &av_info)) != NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes }
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes if ((err = dav_open_propdb(r, NULL, resource, 0, doc->namespaces,
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes &propdb)) != NULL) {
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* undo any auto-checkout */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_psprintf(r->pool,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not open the property "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "database for %s.",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_escape_html(r->pool, r->uri)),
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### what to do about closing the propdb on server failure? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### validate "live" properties */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* set up an array to hold property operation contexts */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx_list = apr_array_make(r->pool, 10, sizeof(dav_prop_ctx));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* do a first pass to ensure that all "remove" properties exist */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin for (child = doc->root->first_child; child; child = child->next) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin int is_remove;
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes apr_xml_elem *prop_group;
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes apr_xml_elem *one_prop;
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* Ignore children that are not set/remove */
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes if (child->ns != APR_XML_NS_DAV_ID
54d22ed1c429b903b029bbd62621f11a9e286137minfrin || (!(is_remove = strcmp(child->name, "remove") == 0)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin && strcmp(child->name, "set") != 0)) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin continue;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure that a "prop" child exists for set/remove */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((prop_group = dav_find_child(child, "prop")) == NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_close_propdb(propdb);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* undo any auto-checkout */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "A \"prop\" element is missing inside "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "the propertyupdate command.");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return HTTP_BAD_REQUEST;
e8f95a682820a599fe41b22977010636be5c2717jim }
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim for (one_prop = prop_group->first_child; one_prop;
e8f95a682820a599fe41b22977010636be5c2717jim one_prop = one_prop->next) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ctx = (dav_prop_ctx *)apr_array_push(ctx_list);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx->propdb = propdb;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx->operation = is_remove ? DAV_PROP_OP_DELETE : DAV_PROP_OP_SET;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ctx->prop = one_prop;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes ctx->r = r; /* for later use by dav_prop_log_errors() */
1223ef8a85a044b5e3a8df29391a66530153aefcbnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_prop_validate(ctx);
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes if ( DAV_PROP_CTX_HAS_ERR(*ctx) ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes failure = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### should test that we found at least one set/remove */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* execute all of the operations */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (!failure && dav_process_ctx_list(dav_prop_exec, ctx_list, 1, 0)) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin failure = 1;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* generate a failure/success response */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (failure) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_rollback, ctx_list, 0, 1);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin propstat_text = dav_failed_proppatch(r->pool, ctx_list);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_commit, ctx_list, 0, 0);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin propstat_text = dav_success_proppatch(r->pool, ctx_list);
796e4a7141265d8ed7036e4628161c6eafb2a789jorton }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure this gets closed! */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_close_propdb(propdb);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes /* complete any auto-versioning */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_checkin(r, resource, failure, 0 /*unlock*/, &av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* log any errors that occurred */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (void)dav_process_ctx_list(dav_prop_log_errors, ctx_list, 0, 0);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin resp.href = resource->uri;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### should probably use something new to pass along this text... */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin resp.propresult.propstats = propstat_text;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
e8f95a682820a599fe41b22977010636be5c2717jim dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces);
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* the response has been sent. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return DONE;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin}
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrinstatic int process_mkcol_body(request_rec *r)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin{
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
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
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* make sure to set the Apache request fields properly. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin r->read_body = REQUEST_NO_BODY;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin r->read_chunked = 0;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin r->remaining = 0;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (tenc) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (strcasecmp(tenc, "chunked")) {
e8f95a682820a599fe41b22977010636be5c2717jim /* Use this instead of Apache's default error string */
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
e8f95a682820a599fe41b22977010636be5c2717jim "Unknown Transfer-Encoding %s", tenc);
e8f95a682820a599fe41b22977010636be5c2717jim return HTTP_NOT_IMPLEMENTED;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener r->read_chunked = 1;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else if (lenp) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin const char *pos = lenp;
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin while (apr_isdigit(*pos) || apr_isspace(*pos)) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ++pos;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (*pos != '\0') {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This supplies additional information for the default message. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener "Invalid Content-Length %s", lenp);
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener return HTTP_BAD_REQUEST;
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener }
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe r->remaining = apr_atoi64(lenp);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (r->read_chunked || r->remaining > 0) {
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholes /* ### log something? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default error for this. */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return HTTP_UNSUPPORTED_MEDIA_TYPE;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener /*
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Get rid of the body. this will call ap_setup_client_block(), but
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * our copy above has already verified its work.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return ap_discard_request_body(r);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin}
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin/* handle the MKCOL method */
54d22ed1c429b903b029bbd62621f11a9e286137minfrinstatic int dav_method_mkcol(request_rec *r)
796e4a7141265d8ed7036e4628161c6eafb2a789jorton{
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_resource *resource;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin int resource_state;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_auto_version_info av_info;
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener dav_error *err;
e8f95a682820a599fe41b22977010636be5c2717jim dav_error *err2;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin int result;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_dir_conf *conf;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_response *multi_status;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* handle the request body */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### this may move lower once we start processing bodies */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((result = process_mkcol_body(r)) != OK) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return result;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe &dav_module);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Ask repository module to resolve the resource */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin &resource);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (err != NULL)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (resource->exists) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* oops. something was already there! */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Apache will supply a default error for this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### we should provide a specific error message! */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_METHOD_NOT_ALLOWED;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
e8f95a682820a599fe41b22977010636be5c2717jim resource_state = dav_get_resource_state(r, resource);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /*
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Check If-Headers and existing locks.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin *
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 *
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
796e4a7141265d8ed7036e4628161c6eafb2a789jorton if ((err = dav_validate_request(r, resource, 0, NULL, &multi_status,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin resource_state == DAV_RESOURCE_NULL ?
54d22ed1c429b903b029bbd62621f11a9e286137minfrin DAV_VALIDATE_PARENT :
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, multi_status);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* if versioned resource, make sure parent is checked out */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe &av_info)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* ### add a higher-level description? */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return dav_handle_err(r, err, NULL);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* try to create the collection */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin resource->collection = 1;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = (*resource->hooks->create_collection)(resource);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* restore modifiability of parent back to what it was */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 0 /*unlock*/, &av_info);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim /* check for errors now */
e8f95a682820a599fe41b22977010636be5c2717jim if (err != NULL) {
141e1368614dc7564e1627671361b01b4869b491bnicholes return dav_handle_err(r, err, NULL);
141e1368614dc7564e1627671361b01b4869b491bnicholes }
141e1368614dc7564e1627671361b01b4869b491bnicholes if (err2 != NULL) {
141e1368614dc7564e1627671361b01b4869b491bnicholes /* just log a warning */
141e1368614dc7564e1627671361b01b4869b491bnicholes err = dav_push_error(r->pool, err->status, 0,
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "The MKCOL was successful, but there "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "was a problem automatically checking in "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "the parent collection.",
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes err2);
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes dav_log_err(r, err, APLOG_WARNING);
141e1368614dc7564e1627671361b01b4869b491bnicholes }
796e4a7141265d8ed7036e4628161c6eafb2a789jorton
e8f95a682820a599fe41b22977010636be5c2717jim if (locks_hooks != NULL) {
141e1368614dc7564e1627671361b01b4869b491bnicholes dav_lockdb *lockdb;
141e1368614dc7564e1627671361b01b4869b491bnicholes
141e1368614dc7564e1627671361b01b4869b491bnicholes if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
141e1368614dc7564e1627671361b01b4869b491bnicholes /* The directory creation was successful, but the locking failed. */
141e1368614dc7564e1627671361b01b4869b491bnicholes err = dav_push_error(r->pool, err->status, 0,
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 err);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return dav_handle_err(r, err, NULL);
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes }
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj
e8f95a682820a599fe41b22977010636be5c2717jim /* notify lock system that we have created/replaced a resource */
e8f95a682820a599fe41b22977010636be5c2717jim err = dav_notify_created(r, lockdb, resource, resource_state, 0);
43c3e6a4b559b76b750c245ee95e2782c15b4296jim
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj (*locks_hooks->close_lockdb)(lockdb);
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes if (err != NULL) {
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes /* The dir creation was successful, but the locking failed. */
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes err = dav_push_error(r->pool, err->status, 0,
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "The MKCOL was successful, but there "
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes "was a problem updating its lock "
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes "information.",
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes err);
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes return dav_handle_err(r, err, NULL);
e8f95a682820a599fe41b22977010636be5c2717jim }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes /* return an appropriate response (HTTP_CREATED) */
4990e910dd8574b9b40beda0cf1aaa72334d6837bnicholes return dav_created(r, NULL, "Collection", 0);
d0fb19f6ddefe0d1b3c94eee44776a848ab0690drpluem}
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
1c9fe70e77b36d36ae34997fe25fe47beacf8709bnicholes/* handle the COPY and MOVE methods */
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholesstatic int dav_method_copymove(request_rec *r, int is_move)
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes{
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes dav_resource *resource;
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes dav_resource *resnew;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_auto_version_info src_av_info = { 0 };
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_auto_version_info dst_av_info = { 0 };
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *body;
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *dest;
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_error *err;
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_error *err2;
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_error *err3;
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_response *multi_response;
cb304b0c01e893dc2c24ee83ca382d8a6861d0e4trawick dav_lookup_result lookup;
128a5d93141a86e3afa151e921035a07297c9833rederpj int is_dir;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int overwrite;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int depth;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int result;
9ad7b260be233be7d7b5576979825cac72e15498rederpj dav_lockdb *lockdb;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int replace_dest;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int resnew_state;
0f60998368b493f90120180a93fc2e1e74490872covener
0f60998368b493f90120180a93fc2e1e74490872covener /* Ask repository module to resolve the resource */
0f60998368b493f90120180a93fc2e1e74490872covener err = dav_get_resource(r, !is_move /* label_allowed */,
0f60998368b493f90120180a93fc2e1e74490872covener 0 /* use_checked_in */, &resource);
0f60998368b493f90120180a93fc2e1e74490872covener if (err != NULL)
0f60998368b493f90120180a93fc2e1e74490872covener return dav_handle_err(r, err, NULL);
0f60998368b493f90120180a93fc2e1e74490872covener
0f60998368b493f90120180a93fc2e1e74490872covener if (!resource->exists) {
0f60998368b493f90120180a93fc2e1e74490872covener /* Apache will supply a default error for this. */
0f60998368b493f90120180a93fc2e1e74490872covener return HTTP_NOT_FOUND;
0f60998368b493f90120180a93fc2e1e74490872covener }
0f60998368b493f90120180a93fc2e1e74490872covener
0f60998368b493f90120180a93fc2e1e74490872covener /* If not a file or collection resource, COPY/MOVE not allowed */
0f60998368b493f90120180a93fc2e1e74490872covener /* ### allow COPY/MOVE of DeltaV resource types */
0f60998368b493f90120180a93fc2e1e74490872covener if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
0f60998368b493f90120180a93fc2e1e74490872covener body = apr_psprintf(r->pool,
0f60998368b493f90120180a93fc2e1e74490872covener "Cannot COPY/MOVE resource %s.",
0f60998368b493f90120180a93fc2e1e74490872covener ap_escape_html(r->pool, r->uri));
0f60998368b493f90120180a93fc2e1e74490872covener return dav_error_response(r, HTTP_METHOD_NOT_ALLOWED, body);
0f60998368b493f90120180a93fc2e1e74490872covener }
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* get the destination URI */
9ad7b260be233be7d7b5576979825cac72e15498rederpj dest = apr_table_get(r->headers_in, "Destination");
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (dest == NULL) {
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");
9ad7b260be233be7d7b5576979825cac72e15498rederpj
67c5e190a7b84528b8895d7ef7be81712d206805covener if (nscp_host != NULL && nscp_path != NULL)
67c5e190a7b84528b8895d7ef7be81712d206805covener dest = apr_psprintf(r->pool, "http://%s%s", nscp_host, nscp_path);
67c5e190a7b84528b8895d7ef7be81712d206805covener }
67c5e190a7b84528b8895d7ef7be81712d206805covener if (dest == NULL) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* This supplies additional information for the default message. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
9ad7b260be233be7d7b5576979825cac72e15498rederpj "The request is missing a Destination header.");
9ad7b260be233be7d7b5576979825cac72e15498rederpj return HTTP_BAD_REQUEST;
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (lookup.rnew == NULL) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (lookup.err.status == HTTP_BAD_REQUEST) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* This supplies additional information for the default message. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
128a5d93141a86e3afa151e921035a07297c9833rederpj lookup.err.desc);
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener return HTTP_BAD_REQUEST;
128a5d93141a86e3afa151e921035a07297c9833rederpj }
87587593f1a53030e840acc0dec6cc881022ea40covener
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* ### this assumes that dav_lookup_uri() only generates a status
9ad7b260be233be7d7b5576979825cac72e15498rederpj * ### that Apache can provide a status line for!! */
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj return dav_error_response(r, lookup.err.status, lookup.err.desc);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (lookup.rnew->status != HTTP_OK) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### how best to report this... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_error_response(r, lookup.rnew->status,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Destination URI had an error.");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Resolve destination resource */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf 0 /* use_checked_in */, &resnew);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (err != NULL)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_handle_err(r, err, NULL);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* are the two resources handled by the same repository? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (resource->hooks != resnew->hooks) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### this message exposes some backend config, but screw it... */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_error_response(r, HTTP_BAD_GATEWAY,
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 }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* get and parse the overwrite header value */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if ((overwrite = dav_get_overwrite(r)) < 0) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* dav_get_overwrite() supplies additional information for the
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * default message. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return HTTP_BAD_REQUEST;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* quick failure test: if dest exists and overwrite is false. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (resnew->exists && !overwrite) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Supply some text for the error response body. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return dav_error_response(r, HTTP_PRECONDITION_FAILED,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Destination is not empty and "
b6ce9b03bd0e4d37b21bc430f922a470cc2645d7rpluem "Overwrite is not \"T\"");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
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 return dav_error_response(r, HTTP_FORBIDDEN,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Source and Destination URIs are the same.");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf is_dir = resource->collection;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* get and parse the Depth header value. "0" and "infinity" are legal. */
9ad7b260be233be7d7b5576979825cac72e15498rederpj if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe /* dav_get_depth() supplies additional information for the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * default message. */
e8f95a682820a599fe41b22977010636be5c2717jim return HTTP_BAD_REQUEST;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (depth == 1) {
a0b44ec81b32ffb946537d4e43e1c3a3f7594137gregames /* This supplies additional information for the default message. */
1233ffe2092021833c2a642f1017d6c332075469gregames ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1233ffe2092021833c2a642f1017d6c332075469gregames "Depth must be \"0\" or \"infinity\" for COPY or MOVE.");
a0b44ec81b32ffb946537d4e43e1c3a3f7594137gregames return HTTP_BAD_REQUEST;
490046d2a164ad86cc63bd789f32eaed663d239abnicholes }
490046d2a164ad86cc63bd789f32eaed663d239abnicholes if (is_move && is_dir && depth != DAV_INFINITY) {
490046d2a164ad86cc63bd789f32eaed663d239abnicholes /* This supplies additional information for the default message. */
490046d2a164ad86cc63bd789f32eaed663d239abnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Depth must be \"infinity\" when moving a collection.");
ecc6e723b804fb4b8f858910eff3f88242ec56fasf return HTTP_BAD_REQUEST;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
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 *
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.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf *
141e1368614dc7564e1627671361b01b4869b491bnicholes * If a problem occurs with the Request-URI itself, then a plain error
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * (rather than a multistatus) will be returned.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (is_move
54d22ed1c429b903b029bbd62621f11a9e286137minfrin && (err = dav_validate_request(r, resource, depth, NULL,
f2386b627177c7a80d38fed6ec0aed3c086909c1covener &multi_response,
f2386b627177c7a80d38fed6ec0aed3c086909c1covener DAV_VALIDATE_PARENT
f2386b627177c7a80d38fed6ec0aed3c086909c1covener | DAV_VALIDATE_USE_424,
e8f95a682820a599fe41b22977010636be5c2717jim NULL)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_push_error(r->pool, err->status, 0,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_psprintf(r->pool,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not MOVE %s due to a failed "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "precondition on the source "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "(e.g. locks).",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ap_escape_html(r->pool, r->uri)),
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes err);
490046d2a164ad86cc63bd789f32eaed663d239abnicholes return dav_handle_err(r, err, multi_response);
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes }
490046d2a164ad86cc63bd789f32eaed663d239abnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /*
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 *
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)
9ab5933c174cb21de69e8305f80544cbe7ed2a7ccovener */
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes if ((err = dav_validate_request(lookup.rnew, resnew, DAV_INFINITY, NULL,
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes &multi_response,
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes DAV_VALIDATE_PARENT
e8f95a682820a599fe41b22977010636be5c2717jim | DAV_VALIDATE_USE_424, NULL)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe err = dav_push_error(r->pool, err->status, 0,
e8f95a682820a599fe41b22977010636be5c2717jim apr_psprintf(r->pool,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Could not MOVE/COPY %s due to a "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "failed precondition on the "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "destination (e.g. locks).",
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes ap_escape_html(r->pool, r->uri)),
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes err);
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes return dav_handle_err(r, err, multi_response);
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes }
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes if (is_dir
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes && depth == DAV_INFINITY
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes && (*resource->hooks->is_parent_resource)(resource, resnew)) {
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes /* Supply some text for the error response body. */
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes return dav_error_response(r, HTTP_FORBIDDEN,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "Source collection contains the "
cbbfa8f4222ecc7b2e0f16db3032d0118d6a0accbnicholes "Destination.");
0f60998368b493f90120180a93fc2e1e74490872covener
9c247afacdbb56fa794715f2ac218eb1cae39fe8bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (is_dir
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Supply some text for the error response body. */
e8f95a682820a599fe41b22977010636be5c2717jim return dav_error_response(r, HTTP_FORBIDDEN,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Destination collection contains the Source "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "and Overwrite has been specified.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### for now, we don't need anything in the body */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((result = ap_discard_request_body(r)) != OK) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return result;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* ### add a higher-level description? */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick return dav_handle_err(r, err, NULL);
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick }
43997561b2302d13dee973998e77743a3ddd2374trawick
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /* remove any locks from the old resources */
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick /*
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 *
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 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (is_move && lockdb != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### this is wrong! it blasts direct locks on parent resources */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### pass lockdb! */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (void)dav_unlock(r, resource, NULL);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* if this is a move, then the source parent collection will be modified */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (is_move) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &src_av_info)) != NULL) {
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes if (lockdb != NULL)
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes (*lockdb->hooks->close_lockdb)(lockdb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Remember the initial state of the destination, so the lock system
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * can be notified as to how it changed.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes resnew_state = dav_get_resource_state(lookup.rnew, resnew);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resnew->exists)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes replace_dest = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (is_move || !resource->versioned)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes replace_dest = 1;
e8f95a682820a599fe41b22977010636be5c2717jim else if (resource->type != resnew->type)
e8f95a682820a599fe41b22977010636be5c2717jim replace_dest = 1;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe else if ((resource->collection == 0) != (resnew->collection == 0))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes replace_dest = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes replace_dest = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If the destination must be created or replaced,
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton * make sure the parent collection is writable
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!resnew->exists || replace_dest) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = dav_auto_checkout(r, resnew, 1 /*parent_only*/,
024e70e05386a6367eb45d0d1cc406764520ff4cwrowe &dst_av_info)) != NULL) {
43997561b2302d13dee973998e77743a3ddd2374trawick /* could not make destination writable:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if move, restore state of source parent
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (is_move) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (void)dav_auto_checkin(r, NULL, 1 /* undo */,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes 0 /*unlock*/, &src_av_info);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (lockdb != NULL)
e8f95a682820a599fe41b22977010636be5c2717jim (*lockdb->hooks->close_lockdb)(lockdb);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
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.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (src_av_info.parent_resource != NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && dst_av_info.parent_resource != NULL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && (*src_av_info.parent_resource->hooks->is_same_resource)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (src_av_info.parent_resource, dst_av_info.parent_resource)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dst_av_info.parent_resource = src_av_info.parent_resource;
e8f95a682820a599fe41b22977010636be5c2717jim }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* If destination is being replaced, remove it first
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (we know Ovewrite must be TRUE). Then try to copy/move the resource.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
e8f95a682820a599fe41b22977010636be5c2717jim if (replace_dest)
e8f95a682820a599fe41b22977010636be5c2717jim err = (*resnew->hooks->remove_resource)(resnew, &multi_response);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (err == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (is_move)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->move_resource)(resource, resnew,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &multi_response);
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton else
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*resource->hooks->copy_resource)(resource, resnew, depth,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &multi_response);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim /* perform any auto-versioning cleanup */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin 0 /*unlock*/, &dst_av_info);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (is_move) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin 0 /*unlock*/, &src_av_info);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim else
e8f95a682820a599fe41b22977010636be5c2717jim err3 = NULL;
e8f95a682820a599fe41b22977010636be5c2717jim
d5cff0d8e871bf2528aadd8736fb50dc044b1e6dbnicholes /* check for error from remove/copy/move operations */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (err != NULL) {
ebe5305f8b22507374358f32b74d12fb50c05a25covener if (lockdb != NULL)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin (*lockdb->hooks->close_lockdb)(lockdb);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin err = dav_push_error(r->pool, err->status, 0,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_psprintf(r->pool,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "Could not MOVE/COPY %s.",
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton ap_escape_html(r->pool, r->uri)),
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_handle_err(r, err, multi_response);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
e8f95a682820a599fe41b22977010636be5c2717jim /* check for errors from auto-versioning */
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton if (err2 != NULL) {
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton /* just log a warning */
e70cf415769ad0b3704e98b3f6da38e916ff7228jorton err = dav_push_error(r->pool, err2->status, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The MOVE/COPY was successful, but there was a "
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes "problem automatically checking in the "
f7edd56768a46a01ae8b43c712c9eeef40e37f59bnicholes "source parent collection.",
f7edd56768a46a01ae8b43c712c9eeef40e37f59bnicholes err2);
f7edd56768a46a01ae8b43c712c9eeef40e37f59bnicholes dav_log_err(r, err, APLOG_WARNING);
57e892abdf632bb9224c6ae6a715d863242a00f3fuankg }
0f60998368b493f90120180a93fc2e1e74490872covener if (err3 != NULL) {
0f60998368b493f90120180a93fc2e1e74490872covener /* just log a warning */
0f60998368b493f90120180a93fc2e1e74490872covener err = dav_push_error(r->pool, err3->status, 0,
0f60998368b493f90120180a93fc2e1e74490872covener "The MOVE/COPY was successful, but there was a "
0f60998368b493f90120180a93fc2e1e74490872covener "problem automatically checking in the "
0f60998368b493f90120180a93fc2e1e74490872covener "destination or its parent collection.",
0f60998368b493f90120180a93fc2e1e74490872covener err3);
0f60998368b493f90120180a93fc2e1e74490872covener dav_log_err(r, err, APLOG_WARNING);
57e892abdf632bb9224c6ae6a715d863242a00f3fuankg }
0f60998368b493f90120180a93fc2e1e74490872covener
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* propagate any indirect locks at the target */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (lockdb != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* notify lock system that we have created/replaced a resource */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_notify_created(r, lockdb, resnew, resnew_state, depth);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim (*lockdb->hooks->close_lockdb)(lockdb);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton if (err != NULL) {
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton /* The move/copy was successful, but the locking failed. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = dav_push_error(r->pool, err->status, 0,
e8f95a682820a599fe41b22977010636be5c2717jim "The MOVE/COPY was successful, but there "
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick "was a problem updating the lock "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "information.",
af6d8b02b2fd4ea9a0f6bfb95940d6075030e9a7minfrin err);
41774018aa66ddb54ce7fd8fe049ccf3b3f7262aminfrin return dav_handle_err(r, err, NULL);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
43997561b2302d13dee973998e77743a3ddd2374trawick }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_created(r, lookup.rnew->uri, "Destination",
e025b9c2dbc3e2873142a775c37336a75ead222bjorton resnew_state == DAV_RESOURCE_EXISTS);
e8f95a682820a599fe41b22977010636be5c2717jim}
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe/* dav_method_lock: Handler to implement the DAV LOCK method
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Returns appropriate HTTP_* response.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe */
e8f95a682820a599fe41b22977010636be5c2717jimstatic int dav_method_lock(request_rec *r)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe{
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_error *err;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_resource *resource;
e8f95a682820a599fe41b22977010636be5c2717jim const dav_hooks_locks *locks_hooks;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe int result;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe int depth;
023ab66b169a239c82d6c36410ab43fe63561d11covener int new_lock_request = 0;
023ab66b169a239c82d6c36410ab43fe63561d11covener apr_xml_doc *doc;
023ab66b169a239c82d6c36410ab43fe63561d11covener dav_lock *lock;
e8f95a682820a599fe41b22977010636be5c2717jim dav_response *multi_response = NULL;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe dav_lockdb *lockdb;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe int resource_state;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* If no locks provider, decline the request */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe locks_hooks = DAV_GET_HOOKS_LOCKS(r);
e8f95a682820a599fe41b22977010636be5c2717jim if (locks_hooks == NULL)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return DECLINED;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
023ab66b169a239c82d6c36410ab43fe63561d11covener if ((result = ap_xml_parse_input(r, &doc)) != OK)
023ab66b169a239c82d6c36410ab43fe63561d11covener return result;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
e8f95a682820a599fe41b22977010636be5c2717jim depth = dav_get_depth(r, DAV_INFINITY);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (depth != 0 && depth != DAV_INFINITY) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "Depth must be 0 or \"infinity\" for LOCK.");
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe return HTTP_BAD_REQUEST;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* Ask repository module to resolve the resource */
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj &resource);
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj if (err != NULL)
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj return dav_handle_err(r, err, NULL);
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj /*
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj * Open writable. Unless an error occurs, we'll be
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj * writing into the database.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener /* ### add a higher-level description? */
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj return dav_handle_err(r, err, NULL);
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj }
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj if (doc != NULL) {
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj if ((err = dav_lock_parse_lockinfo(r, resource, lockdb, doc,
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj &lock)) != NULL) {
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj /* ### add a higher-level description to err? */
c99be08e59d6c21cdc4aa79f645feec41e157b09rederpj goto error;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim new_lock_request = 1;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe lock->auth_user = apr_pstrdup(r->pool, r->user);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
e8f95a682820a599fe41b22977010636be5c2717jim resource_state = dav_get_resource_state(r, resource);
141e1368614dc7564e1627671361b01b4869b491bnicholes
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /*
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Check If-Headers and existing locks.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem *
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 */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response,
0894cd17fe3f614bf01dbf84f1414756bd5a34c3bnicholes (resource_state == DAV_RESOURCE_NULL
9ad7b260be233be7d7b5576979825cac72e15498rederpj ? DAV_VALIDATE_PARENT
9ad7b260be233be7d7b5576979825cac72e15498rederpj : DAV_VALIDATE_RESOURCE)
9ad7b260be233be7d7b5576979825cac72e15498rederpj | (new_lock_request ? lock->scope : 0)
9ad7b260be233be7d7b5576979825cac72e15498rederpj | DAV_VALIDATE_ADD_LD,
9ad7b260be233be7d7b5576979825cac72e15498rederpj lockdb)) != OK) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj err = dav_push_error(r->pool, err->status, 0,
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_psprintf(r->pool,
87587593f1a53030e840acc0dec6cc881022ea40covener "Could not LOCK %s due to a failed "
9ad7b260be233be7d7b5576979825cac72e15498rederpj "precondition (e.g. other locks).",
0f60998368b493f90120180a93fc2e1e74490872covener ap_escape_html(r->pool, r->uri)),
0f60998368b493f90120180a93fc2e1e74490872covener err);
0f60998368b493f90120180a93fc2e1e74490872covener goto error;
0f60998368b493f90120180a93fc2e1e74490872covener }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (new_lock_request == 0) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf dav_locktoken_list *ltl;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /*
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 */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes if ((err = dav_get_locktoken_list(r, &ltl)) != NULL) {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes err = dav_push_error(r->pool, err->status, 0,
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes apr_psprintf(r->pool,
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "The lock refresh for %s failed "
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "because no lock tokens were "
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "specified in an \"If:\" "
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes "header.",
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes ap_escape_html(r->pool, r->uri)),
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj err);
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes goto error;
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((err = (*locks_hooks->refresh_locks)(lockdb, resource, ltl,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_get_timeout(r),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &lock)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### add a higher-level description to err? */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe goto error;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
9ad7b260be233be7d7b5576979825cac72e15498rederpj } else {
f05787953018140838ad51456c86c965d6a86267jim /* New lock request */
f05787953018140838ad51456c86c965d6a86267jim char *locktoken_txt;
f05787953018140838ad51456c86c965d6a86267jim dav_dir_conf *conf;
f05787953018140838ad51456c86c965d6a86267jim
f05787953018140838ad51456c86c965d6a86267jim conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes &dav_module);
/* apply lower bound (if any) from DAVMinTimeout directive */
if (lock->timeout != DAV_TIMEOUT_INFINITE
&& lock->timeout < time(NULL) + conf->locktimeout)
lock->timeout = time(NULL) + conf->locktimeout;
err = dav_add_lock(r, resource, lockdb, lock, &multi_response);
if (err != NULL) {
/* ### add a higher-level description to err? */
goto error;
}
locktoken_txt = apr_pstrcat(r->pool, "<",
(*locks_hooks->format_locktoken)(r->pool,
lock->locktoken),
">", NULL);
apr_table_set(r->headers_out, "Lock-Token", locktoken_txt);
}
(*locks_hooks->close_lockdb)(lockdb);
r->status = HTTP_OK;
ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r);
if (lock == NULL)
ap_rputs("<D:lockdiscovery/>" DEBUG_CR, r);
else {
ap_rprintf(r,
"<D:lockdiscovery>" DEBUG_CR
"%s" DEBUG_CR
"</D:lockdiscovery>" DEBUG_CR,
dav_lock_get_activelock(r, lock, NULL));
}
ap_rputs("</D:prop>", r);
/* the response has been sent. */
return DONE;
error:
(*locks_hooks->close_lockdb)(lockdb);
return dav_handle_err(r, err, multi_response);
}
/* dav_method_unlock: Handler to implement the DAV UNLOCK method
* Returns appropriate HTTP_* response.
*/
static int dav_method_unlock(request_rec *r)
{
dav_error *err;
dav_resource *resource;
const dav_hooks_locks *locks_hooks;
int result;
const char *const_locktoken_txt;
char *locktoken_txt;
dav_locktoken *locktoken = NULL;
int resource_state;
dav_response *multi_response;
/* If no locks provider, decline the request */
locks_hooks = DAV_GET_HOOKS_LOCKS(r);
if (locks_hooks == NULL)
return DECLINED;
if ((const_locktoken_txt = apr_table_get(r->headers_in,
"Lock-Token")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Unlock failed (%s): "
"No Lock-Token specified in header", r->filename);
return HTTP_BAD_REQUEST;
}
locktoken_txt = apr_pstrdup(r->pool, const_locktoken_txt);
if (locktoken_txt[0] != '<') {
/* ### should provide more specifics... */
return HTTP_BAD_REQUEST;
}
locktoken_txt++;
if (locktoken_txt[strlen(locktoken_txt) - 1] != '>') {
/* ### should provide more specifics... */
return HTTP_BAD_REQUEST;
}
locktoken_txt[strlen(locktoken_txt) - 1] = '\0';
if ((err = (*locks_hooks->parse_locktoken)(r->pool, locktoken_txt,
&locktoken)) != NULL) {
err = dav_push_error(r->pool, HTTP_BAD_REQUEST, 0,
apr_psprintf(r->pool,
"The UNLOCK on %s failed -- an "
"invalid lock token was specified "
"in the \"If:\" header.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
resource_state = dav_get_resource_state(r, resource);
/*
* Check If-Headers and existing locks.
*
* Note: depth == 0 normally requires no multistatus response. However,
* if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
* other than the Request-URI, thereby requiring a multistatus.
*
* If the resource is a locknull resource, then the UNLOCK will affect
* the parent collection (much like a delete). For that case, we must
* validate the parent resource's conditions.
*/
if ((err = dav_validate_request(r, resource, 0, locktoken,
&multi_response,
resource_state == DAV_RESOURCE_LOCK_NULL
? DAV_VALIDATE_PARENT
: DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, multi_response);
}
/* ### RFC 2518 s. 8.11: If this resource is locked by locktoken,
* _all_ resources locked by locktoken are released. It does not say
* resource has to be the root of an infinte lock. Thus, an UNLOCK
* on any part of an infinte lock will remove the lock on all resources.
*
* For us, if r->filename represents an indirect lock (part of an infinity lock),
* we must actually perform an UNLOCK on the direct lock for this resource.
*/
if ((result = dav_unlock(r, resource, locktoken)) != OK) {
return result;
}
return HTTP_NO_CONTENT;
}
static int dav_method_vsn_control(request_rec *r)
{
dav_resource *resource;
int resource_state;
dav_auto_version_info av_info;
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
apr_xml_doc *doc;
const char *target = NULL;
int result;
/* if no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
/* ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
/* remember the pre-creation resource state */
resource_state = dav_get_resource_state(r, resource);
/* parse the request body (may be a version-control element) */
if ((result = ap_xml_parse_input(r, &doc)) != OK) {
return result;
}
/* note: doc == NULL if no request body */
if (doc != NULL) {
const apr_xml_elem *child;
apr_size_t tsize;
if (!dav_validate_root(doc, "version-control")) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body does not contain "
"a \"version-control\" element.");
return HTTP_BAD_REQUEST;
}
/* get the version URI */
if ((child = dav_find_child(doc->root, "version")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The \"version-control\" element does not contain "
"a \"version\" element.");
return HTTP_BAD_REQUEST;
}
if ((child = dav_find_child(child, "href")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The \"version\" element does not contain "
"an \"href\" element.");
return HTTP_BAD_REQUEST;
}
/* get version URI */
apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
&target, &tsize);
if (tsize == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"An \"href\" element does not contain a URI.");
return HTTP_BAD_REQUEST;
}
}
/* Check request preconditions */
/* ### need a general mechanism for reporting precondition violations
* ### (should be returning XML document for 403/409 responses)
*/
/* if not versioning existing resource, must specify version to select */
if (!resource->exists && target == NULL) {
err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
"<DAV:initial-version-required/>");
return dav_handle_err(r, err, NULL);
}
else if (resource->exists) {
/* cannot add resource to existing version history */
if (target != NULL) {
err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
"<DAV:cannot-add-to-existing-history/>");
return dav_handle_err(r, err, NULL);
}
/* resource must be unversioned and versionable, or version selector */
if (resource->type != DAV_RESOURCE_TYPE_REGULAR
|| (!resource->versioned && !(vsn_hooks->versionable)(resource))) {
err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
"<DAV:must-be-versionable/>");
return dav_handle_err(r, err, NULL);
}
/* the DeltaV spec says if resource is a version selector,
* then VERSION-CONTROL is a no-op
*/
if (resource->versioned) {
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* no body */
ap_set_content_length(r, 0);
return DONE;
}
}
/* Check If-Headers and existing locks */
/* Note: depth == 0. Implies no need for a multistatus response. */
if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
resource_state == DAV_RESOURCE_NULL ?
DAV_VALIDATE_PARENT :
DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
return dav_handle_err(r, err, NULL);
}
/* if in versioned collection, make sure parent is checked out */
if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
&av_info)) != NULL) {
return dav_handle_err(r, err, NULL);
}
/* attempt to version-control the resource */
if ((err = (*vsn_hooks->vsn_control)(resource, target)) != NULL) {
dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not VERSION-CONTROL resource %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* revert writability of parent directory */
err = dav_auto_checkin(r, resource, 0 /*undo*/, 0 /*unlock*/, &av_info);
if (err != NULL) {
/* just log a warning */
err = dav_push_error(r->pool, err->status, 0,
"The VERSION-CONTROL was successful, but there "
"was a problem automatically checking in "
"the parent collection.",
err);
dav_log_err(r, err, APLOG_WARNING);
}
/* if the resource is lockable, let lock system know of new resource */
if (locks_hooks != NULL
&& (*locks_hooks->get_supportedlock)(resource) != NULL) {
dav_lockdb *lockdb;
if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
/* The resource creation was successful, but the locking failed. */
err = dav_push_error(r->pool, err->status, 0,
"The VERSION-CONTROL was successful, but there "
"was a problem opening the lock database "
"which prevents inheriting locks from the "
"parent resources.",
err);
return dav_handle_err(r, err, NULL);
}
/* notify lock system that we have created/replaced a resource */
err = dav_notify_created(r, lockdb, resource, resource_state, 0);
(*locks_hooks->close_lockdb)(lockdb);
if (err != NULL) {
/* The dir creation was successful, but the locking failed. */
err = dav_push_error(r->pool, err->status, 0,
"The VERSION-CONTROL was successful, but there "
"was a problem updating its lock "
"information.",
err);
return dav_handle_err(r, err, NULL);
}
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* return an appropriate response (HTTP_CREATED) */
return dav_created(r, resource->uri, "Version selector", 0 /*replaced*/);
}
/* handle the CHECKOUT method */
static int dav_method_checkout(request_rec *r)
{
dav_resource *resource;
dav_resource *working_resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
apr_xml_doc *doc;
int apply_to_vsn = 0;
int is_unreserved = 0;
int is_fork_ok = 0;
int create_activity = 0;
apr_array_header_t *activities = NULL;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
if ((result = ap_xml_parse_input(r, &doc)) != OK)
return result;
if (doc != NULL) {
const apr_xml_elem *aset;
if (!dav_validate_root(doc, "checkout")) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body, if present, must be a "
"DAV:checkout element.");
return HTTP_BAD_REQUEST;
}
if (dav_find_child(doc->root, "apply-to-version") != NULL) {
if (apr_table_get(r->headers_in, "label") != NULL) {
/* ### we want generic 403/409 XML reporting here */
/* ### DAV:must-not-have-label-and-apply-to-version */
return dav_error_response(r, HTTP_CONFLICT,
"DAV:apply-to-version cannot be "
"used in conjunction with a "
"Label header.");
}
apply_to_vsn = 1;
}
is_unreserved = dav_find_child(doc->root, "unreserved") != NULL;
is_fork_ok = dav_find_child(doc->root, "fork-ok") != NULL;
if ((aset = dav_find_child(doc->root, "activity-set")) != NULL) {
if (dav_find_child(aset, "new") != NULL) {
create_activity = 1;
}
else {
const apr_xml_elem *child = aset->first_child;
activities = apr_array_make(r->pool, 1, sizeof(const char *));
for (; child != NULL; child = child->next) {
if (child->ns == APR_XML_NS_DAV_ID
&& strcmp(child->name, "href") == 0) {
const char *href;
href = dav_xml_get_cdata(child, r->pool,
1 /* strip_white */);
*(const char **)apr_array_push(activities) = href;
}
}
if (activities->nelts == 0) {
/* no href's is a DTD violation:
<!ELEMENT activity-set (href+ | new)>
*/
/* This supplies additional info for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Within the DAV:activity-set element, the "
"DAV:new element must be used, or at least "
"one DAV:href must be specified.");
return HTTP_BAD_REQUEST;
}
}
}
}
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 1 /*label_allowed*/, apply_to_vsn, &resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* Check the state of the resource: must be a file or collection,
* must be versioned, and must not already be checked out.
*/
if (resource->type != DAV_RESOURCE_TYPE_REGULAR
&& resource->type != DAV_RESOURCE_TYPE_VERSION) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot checkout this type of resource.");
}
if (!resource->versioned) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot checkout unversioned resource.");
}
if (resource->working) {
return dav_error_response(r, HTTP_CONFLICT,
"The resource is already checked out to the workspace.");
}
/* ### do lock checks, once behavior is defined */
/* Do the checkout */
if ((err = (*vsn_hooks->checkout)(resource, 0 /*auto_checkout*/,
is_unreserved, is_fork_ok,
create_activity, activities,
&working_resource)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not CHECKOUT resource %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* if no working resource created, return OK,
* else return CREATED with working resource URL in Location header
*/
if (working_resource == NULL) {
/* no body */
ap_set_content_length(r, 0);
return DONE;
}
return dav_created(r, working_resource->uri, "Checked-out resource", 0);
}
/* handle the UNCHECKOUT method */
static int dav_method_uncheckout(request_rec *r)
{
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
if ((result = ap_discard_request_body(r)) != OK) {
return result;
}
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* Check the state of the resource: must be a file or collection,
* must be versioned, and must be checked out.
*/
if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot uncheckout this type of resource.");
}
if (!resource->versioned) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot uncheckout unversioned resource.");
}
if (!resource->working) {
return dav_error_response(r, HTTP_CONFLICT,
"The resource is not checked out to the workspace.");
}
/* ### do lock checks, once behavior is defined */
/* Do the uncheckout */
if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not UNCHECKOUT resource %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* no body */
ap_set_content_length(r, 0);
return DONE;
}
/* handle the CHECKIN method */
static int dav_method_checkin(request_rec *r)
{
dav_resource *resource;
dav_resource *new_version;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
apr_xml_doc *doc;
int keep_checked_out = 0;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
if ((result = ap_xml_parse_input(r, &doc)) != OK)
return result;
if (doc != NULL) {
if (!dav_validate_root(doc, "checkin")) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body, if present, must be a "
"DAV:checkin element.");
return HTTP_BAD_REQUEST;
}
keep_checked_out = dav_find_child(doc->root, "keep-checked-out") != NULL;
}
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* Check the state of the resource: must be a file or collection,
* must be versioned, and must be checked out.
*/
if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot checkin this type of resource.");
}
if (!resource->versioned) {
return dav_error_response(r, HTTP_CONFLICT,
"Cannot checkin unversioned resource.");
}
if (!resource->working) {
return dav_error_response(r, HTTP_CONFLICT,
"The resource is not checked out.");
}
/* ### do lock checks, once behavior is defined */
/* Do the checkin */
if ((err = (*vsn_hooks->checkin)(resource, keep_checked_out, &new_version))
!= NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
apr_psprintf(r->pool,
"Could not CHECKIN resource %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
return dav_created(r, new_version->uri, "Version", 0);
}
static int dav_method_update(request_rec *r)
{
dav_resource *resource;
dav_resource *version = NULL;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
apr_xml_doc *doc;
apr_xml_elem *child;
int is_label = 0;
int depth;
int result;
apr_size_t tsize;
const char *target;
dav_response *multi_response;
dav_error *err;
dav_lookup_result lookup;
/* If no versioning provider, or UPDATE not supported,
* decline the request */
if (vsn_hooks == NULL || vsn_hooks->update == NULL)
return DECLINED;
if ((depth = dav_get_depth(r, 0)) < 0) {
/* dav_get_depth() supplies additional information for the
* default message. */
return HTTP_BAD_REQUEST;
}
/* parse the request body */
if ((result = ap_xml_parse_input(r, &doc)) != OK) {
return result;
}
if (doc == NULL || !dav_validate_root(doc, "update")) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body does not contain "
"an \"update\" element.");
return HTTP_BAD_REQUEST;
}
/* check for label-name or version element, but not both */
if ((child = dav_find_child(doc->root, "label-name")) != NULL)
is_label = 1;
else if ((child = dav_find_child(doc->root, "version")) != NULL) {
/* get the href element */
if ((child = dav_find_child(child, "href")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The version element does not contain "
"an \"href\" element.");
return HTTP_BAD_REQUEST;
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The \"update\" element does not contain "
"a \"label-name\" or \"version\" element.");
return HTTP_BAD_REQUEST;
}
/* a depth greater than zero is only allowed for a label */
if (!is_label && depth != 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Depth must be zero for UPDATE with a version");
return HTTP_BAD_REQUEST;
}
/* get the target value (a label or a version URI) */
apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
&target, &tsize);
if (tsize == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"A \"label-name\" or \"href\" element does not contain "
"any content.");
return HTTP_BAD_REQUEST;
}
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* ### need a general mechanism for reporting precondition violations
* ### (should be returning XML document for 403/409 responses)
*/
if (resource->type != DAV_RESOURCE_TYPE_REGULAR
|| !resource->versioned || resource->working) {
return dav_error_response(r, HTTP_CONFLICT,
"<DAV:must-be-checked-in-version-controlled-resource>");
}
/* if target is a version, resolve the version resource */
/* ### dav_lookup_uri only allows absolute URIs; is that OK? */
if (!is_label) {
lookup = dav_lookup_uri(target, r, 0 /* must_be_absolute */);
if (lookup.rnew == NULL) {
if (lookup.err.status == HTTP_BAD_REQUEST) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
lookup.err.desc);
return HTTP_BAD_REQUEST;
}
/* ### this assumes that dav_lookup_uri() only generates a status
* ### that Apache can provide a status line for!! */
return dav_error_response(r, lookup.err.status, lookup.err.desc);
}
if (lookup.rnew->status != HTTP_OK) {
/* ### how best to report this... */
return dav_error_response(r, lookup.rnew->status,
"Version URI had an error.");
}
/* resolve version resource */
err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
0 /* use_checked_in */, &version);
if (err != NULL)
return dav_handle_err(r, err, NULL);
/* NULL out target, since we're using a version resource */
target = NULL;
}
/* do the UPDATE operation */
err = (*vsn_hooks->update)(resource, version, target, depth, &multi_response);
if (err != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not UPDATE %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* no body */
ap_set_content_length(r, 0);
return DONE;
}
/* context maintained during LABEL treewalk */
typedef struct dav_label_walker_ctx
{
/* input: */
dav_walk_params w;
/* label being manipulated */
const char *label;
/* label operation */
int label_op;
#define DAV_LABEL_ADD 1
#define DAV_LABEL_SET 2
#define DAV_LABEL_REMOVE 3
/* version provider hooks */
const dav_hooks_vsn *vsn_hooks;
} dav_label_walker_ctx;
static dav_error * dav_label_walker(dav_walk_resource *wres, int calltype)
{
dav_label_walker_ctx *ctx = wres->walk_ctx;
dav_error *err = NULL;
/* Check the state of the resource: must be a version or
* non-checkedout version selector
*/
/* ### need a general mechanism for reporting precondition violations
* ### (should be returning XML document for 403/409 responses)
*/
if (wres->resource->type != DAV_RESOURCE_TYPE_VERSION &&
(wres->resource->type != DAV_RESOURCE_TYPE_REGULAR
|| !wres->resource->versioned)) {
err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0,
"<DAV:must-be-version-or-version-selector/>");
}
else if (wres->resource->working) {
err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0,
"<DAV:must-not-be-checked-out/>");
}
else {
/* do the label operation */
if (ctx->label_op == DAV_LABEL_REMOVE)
err = (*ctx->vsn_hooks->remove_label)(wres->resource, ctx->label);
else
err = (*ctx->vsn_hooks->add_label)(wres->resource, ctx->label,
ctx->label_op == DAV_LABEL_SET);
}
if (err != NULL) {
/* ### need utility routine to add response with description? */
dav_add_response(wres, err->status, NULL);
wres->response->desc = err->desc;
}
return NULL;
}
static int dav_method_label(request_rec *r)
{
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
apr_xml_doc *doc;
apr_xml_elem *child;
int depth;
int result;
apr_size_t tsize;
dav_error *err;
dav_label_walker_ctx ctx = { { 0 } };
dav_response *multi_status;
/* If no versioning provider, or the provider doesn't support
* labels, decline the request */
if (vsn_hooks == NULL || vsn_hooks->add_label == NULL)
return DECLINED;
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
if ((depth = dav_get_depth(r, 0)) < 0) {
/* dav_get_depth() supplies additional information for the
* default message. */
return HTTP_BAD_REQUEST;
}
/* parse the request body */
if ((result = ap_xml_parse_input(r, &doc)) != OK) {
return result;
}
if (doc == NULL || !dav_validate_root(doc, "label")) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body does not contain "
"a \"label\" element.");
return HTTP_BAD_REQUEST;
}
/* check for add, set, or remove element */
if ((child = dav_find_child(doc->root, "add")) != NULL) {
ctx.label_op = DAV_LABEL_ADD;
}
else if ((child = dav_find_child(doc->root, "set")) != NULL) {
ctx.label_op = DAV_LABEL_SET;
}
else if ((child = dav_find_child(doc->root, "remove")) != NULL) {
ctx.label_op = DAV_LABEL_REMOVE;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The \"label\" element does not contain "
"an \"add\", \"set\", or \"remove\" element.");
return HTTP_BAD_REQUEST;
}
/* get the label string */
if ((child = dav_find_child(child, "label-name")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The label command element does not contain "
"a \"label-name\" element.");
return HTTP_BAD_REQUEST;
}
apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
&ctx.label, &tsize);
if (tsize == 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"A \"label-name\" element does not contain "
"a label name.");
return HTTP_BAD_REQUEST;
}
/* do the label operation walk */
ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
ctx.w.func = dav_label_walker;
ctx.w.walk_ctx = &ctx;
ctx.w.pool = r->pool;
ctx.w.root = resource;
ctx.vsn_hooks = vsn_hooks;
err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
if (err != NULL) {
/* some sort of error occurred which terminated the walk */
err = dav_push_error(r->pool, err->status, 0,
"The LABEL operation was terminated prematurely.",
err);
return dav_handle_err(r, err, multi_status);
}
if (multi_status != NULL) {
/* One or more resources had errors. If depth was zero, convert
* response to simple error, else make sure there is an
* overall error to pass to dav_handle_err()
*/
if (depth == 0) {
err = dav_new_error(r->pool, multi_status->status, 0, multi_status->desc);
multi_status = NULL;
}
else {
err = dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
"Errors occurred during the LABEL operation.");
}
return dav_handle_err(r, err, multi_status);
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* no body */
ap_set_content_length(r, 0);
return DONE;
}
static int dav_method_report(request_rec *r)
{
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
int result;
int label_allowed;
apr_xml_doc *doc;
dav_error *err;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
if ((result = ap_xml_parse_input(r, &doc)) != OK)
return result;
if (doc == NULL) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body must specify a report.");
return HTTP_BAD_REQUEST;
}
/* Ask repository module to resolve the resource.
* First determine whether a Target-Selector header is allowed
* for this report.
*/
label_allowed = (*vsn_hooks->report_label_header_allowed)(doc);
err = dav_get_resource(r, label_allowed, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* set up defaults for the report response */
r->status = HTTP_OK;
ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
/* run report hook */
if ((err = (*vsn_hooks->deliver_report)(r, resource, doc,
r->output_filters)) != NULL) {
/* NOTE: we're assuming that the provider has not generated any
content yet! */
return dav_handle_err(r, err, NULL);
}
return DONE;
}
static int dav_method_make_workspace(request_rec *r)
{
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
apr_xml_doc *doc;
int result;
/* if no versioning provider, or the provider does not support workspaces,
* decline the request
*/
if (vsn_hooks == NULL || vsn_hooks->make_workspace == NULL)
return DECLINED;
/* ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
/* parse the request body (must be a mkworkspace element) */
if ((result = ap_xml_parse_input(r, &doc)) != OK) {
return result;
}
if (doc == NULL
|| !dav_validate_root(doc, "mkworkspace")) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body does not contain "
"a \"mkworkspace\" element.");
return HTTP_BAD_REQUEST;
}
/* Check request preconditions */
/* ### need a general mechanism for reporting precondition violations
* ### (should be returning XML document for 403/409 responses)
*/
/* resource must not already exist */
if (resource->exists) {
err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
"<DAV:resource-must-be-null/>");
return dav_handle_err(r, err, NULL);
}
/* ### what about locking? */
/* attempt to create the workspace */
if ((err = (*vsn_hooks->make_workspace)(resource, doc)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not create workspace %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* return an appropriate response (HTTP_CREATED) */
return dav_created(r, resource->uri, "Workspace", 0 /*replaced*/);
}
static int dav_method_make_activity(request_rec *r)
{
dav_resource *resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
/* if no versioning provider, or the provider does not support activities,
* decline the request
*/
if (vsn_hooks == NULL || vsn_hooks->make_activity == NULL)
return DECLINED;
/* ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
/* MKACTIVITY does not have a defined request body. */
if ((result = ap_discard_request_body(r)) != OK) {
return result;
}
/* Check request preconditions */
/* ### need a general mechanism for reporting precondition violations
* ### (should be returning XML document for 403/409 responses)
*/
/* resource must not already exist */
if (resource->exists) {
err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
"<DAV:resource-must-be-null/>");
return dav_handle_err(r, err, NULL);
}
/* ### what about locking? */
/* attempt to create the activity */
if ((err = (*vsn_hooks->make_activity)(resource)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not create activity %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* set the Cache-Control header, per the spec */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* return an appropriate response (HTTP_CREATED) */
return dav_created(r, resource->uri, "Activity", 0 /*replaced*/);
}
static int dav_method_baseline_control(request_rec *r)
{
/* ### */
return HTTP_METHOD_NOT_ALLOWED;
}
static int dav_method_merge(request_rec *r)
{
dav_resource *resource;
dav_resource *source_resource;
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
dav_error *err;
int result;
apr_xml_doc *doc;
apr_xml_elem *source_elem;
apr_xml_elem *href_elem;
apr_xml_elem *prop_elem;
const char *source;
int no_auto_merge;
int no_checkout;
dav_lookup_result lookup;
/* If no versioning provider, decline the request */
if (vsn_hooks == NULL)
return DECLINED;
if ((result = ap_xml_parse_input(r, &doc)) != OK)
return result;
if (doc == NULL || !dav_validate_root(doc, "merge")) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request body must be present and must be a "
"DAV:merge element.");
return HTTP_BAD_REQUEST;
}
if ((source_elem = dav_find_child(doc->root, "source")) == NULL) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The DAV:merge element must contain a DAV:source "
"element.");
return HTTP_BAD_REQUEST;
}
if ((href_elem = dav_find_child(source_elem, "href")) == NULL) {
/* This supplies additional information for the default msg. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The DAV:source element must contain a DAV:href "
"element.");
return HTTP_BAD_REQUEST;
}
source = dav_xml_get_cdata(href_elem, r->pool, 1 /* strip_white */);
/* get a subrequest for the source, so that we can get a dav_resource
for that source. */
lookup = dav_lookup_uri(source, r, 0 /* must_be_absolute */);
if (lookup.rnew == NULL) {
if (lookup.err.status == HTTP_BAD_REQUEST) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
lookup.err.desc);
return HTTP_BAD_REQUEST;
}
/* ### this assumes that dav_lookup_uri() only generates a status
* ### that Apache can provide a status line for!! */
return dav_error_response(r, lookup.err.status, lookup.err.desc);
}
if (lookup.rnew->status != HTTP_OK) {
/* ### how best to report this... */
return dav_error_response(r, lookup.rnew->status,
"Merge source URI had an error.");
}
err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
0 /* use_checked_in */, &source_resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
no_auto_merge = dav_find_child(doc->root, "no-auto-merge") != NULL;
no_checkout = dav_find_child(doc->root, "no-checkout") != NULL;
prop_elem = dav_find_child(doc->root, "prop");
/* ### check RFC. I believe the DAV:merge element may contain any
### element also allowed within DAV:checkout. need to extract them
### here, and pass them along.
### if so, then refactor the CHECKOUT method handling so we can reuse
### the code. maybe create a structure to hold CHECKOUT parameters
### which can be passed to the checkout() and merge() hooks. */
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* ### check the source and target resources flags/types */
/* ### do lock checks, once behavior is defined */
/* set the Cache-Control header, per the spec */
/* ### correct? */
apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
/* Initialize these values for a standard MERGE response. If the MERGE
is going to do something different (i.e. an error), then it must
return a dav_error, and we'll reset these values properly. */
r->status = HTTP_OK;
ap_set_content_type(r, "text/xml");
/* ### should we do any preliminary response generation? probably not,
### because we may have an error, thus demanding something else in
### the response body. */
/* Do the merge, including any response generation. */
if ((err = (*vsn_hooks->merge)(resource, source_resource,
no_auto_merge, no_checkout,
prop_elem,
r->output_filters)) != NULL) {
/* ### is err->status the right error here? */
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not MERGE resource \"%s\" "
"into \"%s\".",
ap_escape_html(r->pool, source),
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* the response was fully generated by the merge() hook. */
/* ### urk. does this prevent logging? need to check... */
return DONE;
}
static int dav_method_bind(request_rec *r)
{
dav_resource *resource;
dav_resource *binding;
dav_auto_version_info av_info;
const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r);
const char *dest;
dav_error *err;
dav_error *err2;
dav_response *multi_response = NULL;
dav_lookup_result lookup;
int overwrite;
/* If no bindings provider, decline the request */
if (binding_hooks == NULL)
return DECLINED;
/* Ask repository module to resolve the resource */
err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* get the destination URI */
dest = apr_table_get(r->headers_in, "Destination");
if (dest == NULL) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"The request is missing a Destination header.");
return HTTP_BAD_REQUEST;
}
lookup = dav_lookup_uri(dest, r, 0 /* must_be_absolute */);
if (lookup.rnew == NULL) {
if (lookup.err.status == HTTP_BAD_REQUEST) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
lookup.err.desc);
return HTTP_BAD_REQUEST;
}
else if (lookup.err.status == HTTP_BAD_GATEWAY) {
/* ### Bindings protocol draft 02 says to return 507
* ### (Cross Server Binding Forbidden); Apache already defines 507
* ### as HTTP_INSUFFICIENT_STORAGE. So, for now, we'll return
* ### HTTP_FORBIDDEN
*/
return dav_error_response(r, HTTP_FORBIDDEN,
"Cross server bindings are not "
"allowed by this server.");
}
/* ### this assumes that dav_lookup_uri() only generates a status
* ### that Apache can provide a status line for!! */
return dav_error_response(r, lookup.err.status, lookup.err.desc);
}
if (lookup.rnew->status != HTTP_OK) {
/* ### how best to report this... */
return dav_error_response(r, lookup.rnew->status,
"Destination URI had an error.");
}
/* resolve binding resource */
err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
0 /* use_checked_in */, &binding);
if (err != NULL)
return dav_handle_err(r, err, NULL);
/* are the two resources handled by the same repository? */
if (resource->hooks != binding->hooks) {
/* ### this message exposes some backend config, but screw it... */
return dav_error_response(r, HTTP_BAD_GATEWAY,
"Destination URI is handled by a "
"different repository than the source URI. "
"BIND between repositories is not possible.");
}
/* get and parse the overwrite header value */
if ((overwrite = dav_get_overwrite(r)) < 0) {
/* dav_get_overwrite() supplies additional information for the
* default message. */
return HTTP_BAD_REQUEST;
}
/* quick failure test: if dest exists and overwrite is false. */
if (binding->exists && !overwrite) {
return dav_error_response(r, HTTP_PRECONDITION_FAILED,
"Destination is not empty and "
"Overwrite is not \"T\"");
}
/* are the source and destination the same? */
if ((*resource->hooks->is_same_resource)(resource, binding)) {
return dav_error_response(r, HTTP_FORBIDDEN,
"Source and Destination URIs are the same.");
}
/*
* Check If-Headers and existing locks for destination. Note that we
* use depth==infinity since the target (hierarchy) will be deleted
* before the move/copy is completed.
*
* Note that we are overwriting the target, which implies a DELETE, so
* we are subject to the error/response rules as a DELETE. Namely, we
* will return a 424 error if any of the validations fail.
* (see dav_method_delete() for more information)
*/
if ((err = dav_validate_request(lookup.rnew, binding, DAV_INFINITY, NULL,
&multi_response,
DAV_VALIDATE_PARENT
| DAV_VALIDATE_USE_424, NULL)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not BIND %s due to a "
"failed precondition on the "
"destination (e.g. locks).",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
/* guard against creating circular bindings */
if (resource->collection
&& (*resource->hooks->is_parent_resource)(resource, binding)) {
return dav_error_response(r, HTTP_FORBIDDEN,
"Source collection contains the Destination.");
}
if (resource->collection
&& (*resource->hooks->is_parent_resource)(binding, resource)) {
/* The destination must exist (since it contains the source), and
* a condition above implies Overwrite==T. Obviously, we cannot
* delete the Destination before the BIND, as that would
* delete the Source.
*/
return dav_error_response(r, HTTP_FORBIDDEN,
"Destination collection contains the Source and "
"Overwrite has been specified.");
}
/* prepare the destination collection for modification */
if ((err = dav_auto_checkout(r, binding, 1 /* parent_only */,
&av_info)) != NULL) {
/* could not make destination writable */
return dav_handle_err(r, err, NULL);
}
/* If target exists, remove it first (we know Ovewrite must be TRUE).
* Then try to bind to the resource.
*/
if (binding->exists)
err = (*resource->hooks->remove_resource)(binding, &multi_response);
if (err == NULL) {
err = (*binding_hooks->bind_resource)(resource, binding);
}
/* restore parent collection states */
err2 = dav_auto_checkin(r, NULL,
err != NULL /* undo if error */,
0 /* unlock */, &av_info);
/* check for error from remove/bind operations */
if (err != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not BIND %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
/* check for errors from reverting writability */
if (err2 != NULL) {
/* just log a warning */
err = dav_push_error(r->pool, err2->status, 0,
"The BIND was successful, but there was a "
"problem automatically checking in the "
"source parent collection.",
err2);
dav_log_err(r, err, APLOG_WARNING);
}
/* return an appropriate response (HTTP_CREATED) */
/* ### spec doesn't say what happens when destination was replaced */
return dav_created(r, lookup.rnew->uri, "Binding", 0);
}
/*
* Response handler for DAV resources
*/
static int dav_handler(request_rec *r)
{
dav_dir_conf *conf;
if (strcmp(r->handler, "dav-handler")) {
return DECLINED;
}
/* quickly ignore any HTTP/0.9 requests */
if (r->assbackwards) {
return DECLINED;
}
/* ### do we need to do anything with r->proxyreq ?? */
conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
&dav_module);
/*
* Set up the methods mask, since that's one of the reasons this handler
* gets called, and lower-level things may need the info.
*
* First, set the mask to the methods we handle directly. Since by
* definition we own our managed space, we unconditionally set
* the r->allowed field rather than ORing our values with anything
* any other module may have put in there.
*
* These are the HTTP-defined methods that we handle directly.
*/
r->allowed = 0
| (AP_METHOD_BIT << M_GET)
| (AP_METHOD_BIT << M_PUT)
| (AP_METHOD_BIT << M_DELETE)
| (AP_METHOD_BIT << M_OPTIONS)
| (AP_METHOD_BIT << M_INVALID);
/*
* These are the DAV methods we handle.
*/
r->allowed |= 0
| (AP_METHOD_BIT << M_COPY)
| (AP_METHOD_BIT << M_LOCK)
| (AP_METHOD_BIT << M_UNLOCK)
| (AP_METHOD_BIT << M_MKCOL)
| (AP_METHOD_BIT << M_MOVE)
| (AP_METHOD_BIT << M_PROPFIND)
| (AP_METHOD_BIT << M_PROPPATCH);
/*
* These are methods that we don't handle directly, but let the
* server's default handler do for us as our agent.
*/
r->allowed |= 0
| (AP_METHOD_BIT << M_POST);
/* ### hrm. if we return HTTP_METHOD_NOT_ALLOWED, then an Allow header
* ### is sent; it will need the other allowed states; since the default
* ### handler is not called on error, then it doesn't add the other
* ### allowed states, so we must
*/
/* ### we might need to refine this for just where we return the error.
* ### also, there is the issue with other methods (see ISSUES)
*/
/* ### more work necessary, now that we have M_foo for DAV methods */
/* dispatch the appropriate method handler */
if (r->method_number == M_GET) {
return dav_method_get(r);
}
if (r->method_number == M_PUT) {
return dav_method_put(r);
}
if (r->method_number == M_POST) {
return dav_method_post(r);
}
if (r->method_number == M_DELETE) {
return dav_method_delete(r);
}
if (r->method_number == M_OPTIONS) {
return dav_method_options(r);
}
if (r->method_number == M_PROPFIND) {
return dav_method_propfind(r);
}
if (r->method_number == M_PROPPATCH) {
return dav_method_proppatch(r);
}
if (r->method_number == M_MKCOL) {
return dav_method_mkcol(r);
}
if (r->method_number == M_COPY) {
return dav_method_copymove(r, DAV_DO_COPY);
}
if (r->method_number == M_MOVE) {
return dav_method_copymove(r, DAV_DO_MOVE);
}
if (r->method_number == M_LOCK) {
return dav_method_lock(r);
}
if (r->method_number == M_UNLOCK) {
return dav_method_unlock(r);
}
if (r->method_number == M_VERSION_CONTROL) {
return dav_method_vsn_control(r);
}
if (r->method_number == M_CHECKOUT) {
return dav_method_checkout(r);
}
if (r->method_number == M_UNCHECKOUT) {
return dav_method_uncheckout(r);
}
if (r->method_number == M_CHECKIN) {
return dav_method_checkin(r);
}
if (r->method_number == M_UPDATE) {
return dav_method_update(r);
}
if (r->method_number == M_LABEL) {
return dav_method_label(r);
}
if (r->method_number == M_REPORT) {
return dav_method_report(r);
}
if (r->method_number == M_MKWORKSPACE) {
return dav_method_make_workspace(r);
}
if (r->method_number == M_MKACTIVITY) {
return dav_method_make_activity(r);
}
if (r->method_number == M_BASELINE_CONTROL) {
return dav_method_baseline_control(r);
}
if (r->method_number == M_MERGE) {
return dav_method_merge(r);
}
if (r->method_number == dav_methods[DAV_M_BIND]) {
return dav_method_bind(r);
}
/* DASL method */
if (r->method_number == dav_methods[DAV_M_SEARCH]) {
return dav_method_search(r);
}
/* ### add'l methods for Advanced Collections, ACLs */
return DECLINED;
}
static int dav_type_checker(request_rec *r)
{
dav_dir_conf *conf;
conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
&dav_module);
/* if DAV is not enabled, then we've got nothing to do */
if (conf->provider == NULL) {
return DECLINED;
}
if (r->method_number == M_GET) {
/*
* ### need some work to pull Content-Type and Content-Language
* ### from the property database.
*/
/*
* If the repository hasn't indicated that it will handle the
* GET method, then just punt.
*
* ### this isn't quite right... taking over the response can break
* ### things like mod_negotiation. need to look into this some more.
*/
if (!conf->provider->repos->handle_get) {
return DECLINED;
}
}
/* ### we should (instead) trap the ones that we DO understand */
/* ### the handler DOES handle POST, so we need to fix one of these */
if (r->method_number != M_POST) {
/*
* ### anything else to do here? could another module and/or
* ### config option "take over" the handler here? i.e. how do
* ### we lock down this hierarchy so that we are the ultimate
* ### arbiter? (or do we simply depend on the administrator
* ### to avoid conflicting configurations?)
*
* ### I think the OK stops running type-checkers. need to look.
*/
r->handler = "dav-handler";
return OK;
}
return DECLINED;
}
static void register_hooks(apr_pool_t *p)
{
ap_hook_handler(dav_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(dav_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_type_checker(dav_type_checker, NULL, NULL, APR_HOOK_FIRST);
dav_hook_find_liveprop(dav_core_find_liveprop, NULL, NULL, APR_HOOK_LAST);
dav_hook_insert_all_liveprops(dav_core_insert_all_liveprops,
NULL, NULL, APR_HOOK_MIDDLE);
dav_core_register_uris(p);
}
/*---------------------------------------------------------------------------
*
* Configuration info for the module
*/
static const command_rec dav_cmds[] =
{
/* per directory/location */
AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF,
"specify the DAV provider for a directory or location"),
/* per directory/location, or per server */
AP_INIT_TAKE1("DAVMinTimeout", dav_cmd_davmintimeout, NULL,
ACCESS_CONF|RSRC_CONF,
"specify minimum allowed timeout"),
/* per directory/location, or per server */
AP_INIT_FLAG("DAVDepthInfinity", dav_cmd_davdepthinfinity, NULL,
ACCESS_CONF|RSRC_CONF,
"allow Depth infinity PROPFIND requests"),
{ NULL }
};
module DAV_DECLARE_DATA dav_module =
{
STANDARD20_MODULE_STUFF,
dav_create_dir_config, /* dir config creater */
dav_merge_dir_config, /* dir merger --- default is to override */
dav_create_server_config, /* server config */
dav_merge_server_config, /* merge server config */
dav_cmds, /* command table */
register_hooks, /* register hooks */
};
APR_HOOK_STRUCT(
APR_HOOK_LINK(gather_propsets)
APR_HOOK_LINK(find_liveprop)
APR_HOOK_LINK(insert_all_liveprops)
)
APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, gather_propsets,
(apr_array_header_t *uris),
(uris))
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dav, DAV, int, find_liveprop,
(const dav_resource *resource,
const char *ns_uri, const char *name,
const dav_hooks_liveprop **hooks),
(resource, ns_uri, name, hooks), 0)
APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, insert_all_liveprops,
(request_rec *r, const dav_resource *resource,
dav_prop_insert what, apr_text_header *phdr),
(r, resource, what, phdr))