mod_dav.c revision f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbda
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* ====================================================================
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * The Apache Software License, Version 1.1
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Copyright (c) 2000 The Apache Software Foundation. All rights
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * reserved.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Redistribution and use in source and binary forms, with or without
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * modification, are permitted provided that the following conditions
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * are met:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 1. Redistributions of source code must retain the above copyright
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * notice, this list of conditions and the following disclaimer.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 2. Redistributions in binary form must reproduce the above copyright
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * notice, this list of conditions and the following disclaimer in
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * the documentation and/or other materials provided with the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * distribution.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 3. The end-user documentation included with the redistribution,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * if any, must include the following acknowledgment:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * "This product includes software developed by the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Apache Software Foundation (http://www.apache.org/)."
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Alternately, this acknowledgment may appear in the software itself,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * if and wherever such third-party acknowledgments normally appear.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 4. The names "Apache" and "Apache Software Foundation" must
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * not be used to endorse or promote products derived from this
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * software without prior written permission. For written
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * permission, please contact apache@apache.org.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 5. Products derived from this software may not be called "Apache",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * nor may "Apache" appear in their name, without prior written
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * permission of the Apache Software Foundation.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * SUCH DAMAGE.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ====================================================================
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb *
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * This software consists of voluntary contributions made by many
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * individuals on behalf of the Apache Software Foundation. For more
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * information on the Apache Software Foundation, please see
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * <http://www.apache.org/>.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** DAV extension module for Apache 2.0.*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** This module is repository-independent. It depends on hooks provided by a
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** repository implementation.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** APACHE ISSUES:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - within a DAV hierarchy, if an unknown method is used and we default
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** to Apache's implementation, it sends back an OPTIONS with the wrong
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** set of methods -- there is NO HOOK for us.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - process_mkcol_body() had to dup code from ap_setup_client_block().
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - it would be nice to get status lines from Apache for arbitrary
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** status codes
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - it would be nice to be able to extend Apache's set of response
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** codes so that it doesn't return 500 when an unknown code is placed
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** into r->status.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - http_vhost functions should apply "const" to their params
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** DESIGN NOTES:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - For PROPFIND, we batch up the entire response in memory before
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** sending it. We may want to reorganize around sending the information
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** as we suck it in from the propdb. Alternatively, we should at least
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** generate a total Content-Length if we're going to buffer in memory
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** so that we can keep the connection open.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb*/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "httpd.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_config.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_core.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_log.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_main.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_protocol.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "http_request.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "util_script.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "mod_dav.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#include "dav_opaquelock.h"
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbenum {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_ENABLED_UNSET = 0,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_ENABLED_OFF,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_ENABLED_ON
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb};
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* per-dir configuration */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbtypedef struct {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int enabled;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *dir;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int locktimeout;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int handle_get; /* cached from repository hook structure */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int allow_depthinfinity;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb long limit_xml_body;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_table_t *d_params; /* per-directory DAV config parameters */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb struct dav_dyn_mod_ctx *dmc;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dyn_hooks propdb;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dyn_hooks locks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dyn_hooks *liveprop;
c3e342e5b0b9fea6617ee16d2da02c3ef2108126dougm dav_dyn_hooks repository;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dyn_hooks vsn;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb} dav_dir_conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* per-server configuration */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbtypedef struct {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *lockdb_path; /* lock database path */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb uuid_state st; /* UUID state for opaquelocktoken */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb} dav_server_conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#define DAV_INHERIT_VALUE(parent, child, field) \
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ((child)->field ? (child)->field : (parent)->field)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* LimitXMLRequestBody handling */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#define DAV_LIMIT_UNSET ((long) -1)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb#define DAV_DEFAULT_LIMIT_XML_BODY ((size_t)1000000)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* forward-declare for use in configuration lookup */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbextern module MODULE_VAR_EXPORT dav_module;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* copy a module's providers into our per-directory configuration state */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void dav_copy_providers(ap_pool_t *p, const char *name, dav_dir_conf *conf)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_dyn_module *mod;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_dyn_provider *provider;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dyn_hooks hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb void *ctx;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb mod = dav_find_module(name);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### if NULL? need to error out somehow... */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Set hooks for any providers in the module */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ctx = dav_prepare_scan(p, mod);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (ctx == NULL) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### how to signal an error? */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe while (!dav_scan_providers(ctx, &provider, &hooks)) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe switch (provider->type) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_PROPDB:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->propdb = hooks;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_LOCKS:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->locks = hooks;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_QUERY_GRAMMAR:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### not yet defined */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
2f1949bb0e3c209db94c8d521cba7380b9d11421trawick
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_ACL:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### not yet defined */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
2f1949bb0e3c209db94c8d521cba7380b9d11421trawick
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_VSN:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->vsn = hooks;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe case DAV_DYN_TYPE_REPOSITORY:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->repository = hooks;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->handle_get = DAV_AS_HOOKS_REPOSITORY(&hooks)->handle_get;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
2f1949bb0e3c209db94c8d521cba7380b9d11421trawick case DAV_DYN_TYPE_LIVEPROP:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe dav_dyn_hooks *ddh = ap_palloc(p, sizeof(*ddh));
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
2f1949bb0e3c209db94c8d521cba7380b9d11421trawick *ddh = hooks;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ddh->next = conf->liveprop;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe conf->liveprop = ddh;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe default:
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### need to error out somehow... */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe break;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void dav_init_handler(ap_pool_t *p, ap_pool_t *plog, ap_pool_t *ptemp,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb server_rec *s)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* DBG0("dav_init_handler"); */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_add_version_component(p, "DAV/" DAV_VERSION);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_process_builtin_modules(p);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void *dav_create_server_config(ap_pool_t *p, server_rec *s)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *newconf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf = (dav_server_conf *) ap_pcalloc(p, sizeof(*newconf));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->lockdb_path = NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_create_uuid_state(&newconf->st);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return newconf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void *dav_merge_server_config(ap_pool_t *p, void *base, void *overrides)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *parent = base;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *child = overrides;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *newconf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf = (dav_server_conf *) ap_pcalloc(p, sizeof(*newconf));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->lockdb_path = DAV_INHERIT_VALUE(parent, child, lockdb_path);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb memcpy(&newconf->st, &child->st, sizeof(newconf->st));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return newconf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void *dav_create_dir_config(ap_pool_t *p, char *dir)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* NOTE: dir==NULL creates the default per-dir config */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = (dav_dir_conf *) ap_pcalloc(p, sizeof(*conf));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->dir = ap_pstrdup(p, dir);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->d_params = ap_make_table(p, 1);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->limit_xml_body = DAV_LIMIT_UNSET;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* DBG1("dav_create_dir_config: %08lx", (long)conf); */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Locate the appropriate module (NULL == default) and copy the module's
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** providers' hooks into our configuration state.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_copy_providers(p, NULL, conf);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void *dav_merge_dir_config(ap_pool_t *p, void *base, void *overrides)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *parent = base;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *child = overrides;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *newconf = (dav_dir_conf *) ap_pcalloc(p, sizeof(*newconf));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb (long)newconf, (long)base, (long)overrides); */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->enabled = DAV_INHERIT_VALUE(parent, child, enabled);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->dir = DAV_INHERIT_VALUE(parent, child, dir);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb allow_depthinfinity);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->limit_xml_body != DAV_LIMIT_UNSET)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->limit_xml_body = child->limit_xml_body;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->limit_xml_body = parent->limit_xml_body;
4ca6cbe768b4e0917ac0b76333c26a7d5396d454trawick
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->d_params = ap_copy_table(p, parent->d_params);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_overlap_tables(newconf->d_params, child->d_params,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb AP_OVERLAP_TABLES_SET);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->propdb.hooks != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->propdb = child->propdb;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->propdb = parent->propdb;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->locks.hooks != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->locks = child->locks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->locks = parent->locks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->vsn.hooks != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->vsn = child->vsn;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->vsn = parent->vsn;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->repository.hooks != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->repository = child->repository;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->repository = parent->repository;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->handle_get =
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->repository.hooks != NULL
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb && DAV_AS_HOOKS_REPOSITORY(&newconf->repository)->handle_get;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (child->liveprop != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->liveprop = child->liveprop;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb newconf->liveprop = parent->liveprop;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return newconf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbuuid_state *dav_get_uuid_state(const request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = ap_get_module_config(r->server->module_config, &dav_module);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return &conf->st;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbconst char *dav_get_lockdb_path(const request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = ap_get_module_config(r->server->module_config, &dav_module);
b29f87f4b6c6886a04dccc296177a7033f70dfedtrawick return conf->lockdb_path;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbap_table_t *dav_get_dir_params(const request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = ap_get_module_config(r->per_dir_config, &dav_module);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return conf->d_params;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbsize_t dav_get_limit_xml_body(const request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = ap_get_module_config(r->per_dir_config, &dav_module);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (conf->limit_xml_body == DAV_LIMIT_UNSET)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return DAV_DEFAULT_LIMIT_XML_BODY;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return (size_t)conf->limit_xml_body;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbconst dav_dyn_hooks *dav_get_provider_hooks(request_rec *r, int provider_type)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_dyn_hooks *hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb static const dav_dyn_hooks null_hooks = { { 0 } };
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Call repository hook to resolve resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &dav_module);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb switch (provider_type) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_PROPDB:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &conf->propdb;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_LOCKS:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &conf->locks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_QUERY_GRAMMAR:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### not yet defined */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &null_hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_ACL:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### not yet defined */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &null_hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_VSN:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &conf->vsn;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_REPOSITORY:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &conf->repository;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb case DAV_DYN_TYPE_LIVEPROP:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = conf->liveprop;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb default:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* unknown provider type */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb hooks = &null_hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return hooks;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Command handler for the DAV directive, which is FLAG.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic const char *dav_cmd_dav(cmd_parms *cmd, void *config, int arg)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf = (dav_dir_conf *) config;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (arg)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->enabled = DAV_ENABLED_ON;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->enabled = DAV_ENABLED_OFF;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Command handler for the DAVDepthInfinity directive, which is FLAG.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int arg)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf = (dav_dir_conf *) config;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (arg)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->allow_depthinfinity = DAV_ENABLED_ON;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->allow_depthinfinity = DAV_ENABLED_OFF;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Command handler for the DAVLockDB directive, which is TAKE1
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic const char *dav_cmd_davlockdb(cmd_parms *cmd, void *config, char *arg1)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_server_conf *conf;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf = (dav_server_conf *) ap_get_module_config(cmd->server->module_config,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &dav_module);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb arg1 = ap_os_canonical_filename(cmd->pool, arg1);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->lockdb_path = ap_server_root_relative(cmd->pool, arg1);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Command handler for DAVMinTimeout directive, which is TAKE1
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb char *arg1)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_dir_conf *conf = (dav_dir_conf *) config;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb conf->locktimeout = atoi(arg1);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (conf->locktimeout < 0)
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe return "DAVMinTimeout requires a non-negative integer.";
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Command handler for DAVParam directive, which is TAKE2
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe */
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowestatic const char *dav_cmd_davparam(cmd_parms *cmd, void *config,
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe char *arg1, char *arg2)
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe{
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe dav_dir_conf *conf = (dav_dir_conf *) config;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe ap_table_set(conf->d_params, arg1, arg2);
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe return NULL;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe}
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe * Command handler for LimitXMLRequestBody directive, which is TAKE1
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe */
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowestatic const char *dav_cmd_limitxmlrequestbody(cmd_parms *cmd, void *config,
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe char *arg1)
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe{
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe dav_dir_conf *conf = (dav_dir_conf *) config;
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe conf->limit_xml_body = atol(arg1);
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe if (conf->limit_xml_body < 0)
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe return "LimitXMLRequestBody requires a non-negative integer.";
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe return NULL;
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe}
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe/*
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe** dav_error_response()
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe**
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe** Send a nice response back to the user. In most cases, Apache doesn't
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe** allow us to provide details in the body about what happened. This
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe** function allows us to completely specify the response body.
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe*/
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowestatic int dav_error_response(request_rec *r, int status, const char *body)
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe{
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe r->status = status;
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe r->content_type = "text/html";
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe /* since we're returning DONE, ensure the request body is consumed. */
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe (void) ap_discard_request_body(r);
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
580786e253bbe2fa462fdb24af47e52e1ef3dd83wrowe /* begin the response now... */
580786e253bbe2fa462fdb24af47e52e1ef3dd83wrowe ap_send_http_header(r);
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe
6fed20de38221f6f8a60c0ab1d907f1173c443f4wrowe ap_rvputs(r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_RESPONSE_BODY_1,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb r->status_line,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_RESPONSE_BODY_2,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &r->status_line[4],
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_RESPONSE_BODY_3,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(body, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(ap_psignature("\n<P><HR>\n", r), r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(DAV_RESPONSE_BODY_4, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* the response has been sent. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ### Use of DONE obviates logging..!
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return DONE;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** Apache's URI escaping does not replace '&' since that is a valid character
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** in a URI (to form a query section). We must explicitly handle it so that
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** we can embed the URI into an XML document.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb*/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic const char *dav_xml_escape_uri(ap_pool_t *p, const char *uri)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *e_uri = ap_escape_uri(p, uri);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* check the easy case... */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (strchr(e_uri, '&') == NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return e_uri;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* more work needed... sigh. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Note: this is a teeny bit of overkill since we know there are no
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** '<' or '>' characters, but who cares.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_quote_string(p, e_uri, 0);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void dav_send_multistatus(request_rec *r, int status,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_response *first,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_array_header_t *namespaces)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Set the correct status and Content-Type */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe r->status = status;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe r->content_type = DAV_XML_CONTENT_TYPE;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Send all of the headers now */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe ap_send_http_header(r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Send the actual multistatus response now... */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(DAV_XML_HEADER DEBUG_CR
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "<D:multistatus xmlns:D=\"DAV:\"", r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (namespaces != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int i;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb for (i = namespaces->nelts; i--; ) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rprintf(r, " xmlns:ns%d=\"%s\"", i,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_GET_URI_ITEM(namespaces, i));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ap_rputc('>', r); */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe ap_rputs(">" DEBUG_CR, r);
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb for (; first != NULL; first = first->next) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_text *t;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (first->propresult.xmlns == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("<D:response>", r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("<D:response", r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb for (t = first->propresult.xmlns; t; t = t->next) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(t->text, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputc('>', r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(DEBUG_CR "<D:href>", r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(dav_xml_escape_uri(r->pool, first->href), r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("</D:href>" DEBUG_CR, r);
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe if (first->propresult.propstats == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### it would be nice to get a status line from Apache */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rprintf(r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "<D:status>HTTP/1.1 %d status text goes here</D:status>"
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe DEBUG_CR, first->status);
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe }
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe else {
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe /* assume this includes <propstat> and is quoted properly */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe for (t = first->propresult.propstats; t; t = t->next) {
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe ap_rputs(t->text, r);
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe }
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (first->desc != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** We supply the description, so we know it doesn't have to
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** have any escaping/encoding applied to it.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("<D:responsedescription>", r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs(first->desc, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("</D:responsedescription>" DEBUG_CR, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("</D:response>" DEBUG_CR, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_rputs("</D:multistatus>" DEBUG_CR, r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** dav_log_err()
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe** Write error information to the log.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb*/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic void dav_log_err(request_rec *r, dav_error *err, int level)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *errscan;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Log the errors */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### should have a directive to log the first or all */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb for (errscan = err; errscan != NULL; errscan = errscan->prev) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (errscan->desc == NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb continue;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (errscan->save_errno != 0) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb errno = errscan->save_errno;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb errscan->desc, errscan->status, errscan->error_id);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_rerror(APLOG_MARK, level | APLOG_NOERRNO, 0, r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "%s [%d, #%d]",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb errscan->desc, errscan->status, errscan->error_id);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** dav_handle_err()
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** Handle the standard error processing. <err> must be non-NULL.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb**
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** <response> is set by the following:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - dav_validate_request()
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - dav_add_lock()
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - repos_hooks->remove_resource
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - repos_hooks->move_resource
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb** - repos_hooks->copy_resource
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb*/
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int dav_handle_err(request_rec *r, dav_error *err,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_response *response)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* log the errors */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_log_err(r, err, APLOG_ERR);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (response == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* our error messages are safe; tell Apache this */
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe ap_table_setn(r->notes, "verbose-error-to", "*");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return err->status;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* since we're returning DONE, ensure the request body is consumed. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb (void) ap_discard_request_body(r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* send the multistatus and tell Apache the request/response is DONE. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_send_multistatus(r, err->status, response, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return DONE;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* handy function for return values of methods that (may) create things */
8aefbd756763807188d2e3ce336a8680e4893066wrowestatic int dav_created(request_rec *r, request_rec *rnew,
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_resource *res, const char *what,
8aefbd756763807188d2e3ce336a8680e4893066wrowe int replaced)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe const char *body;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (rnew == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe rnew = r;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* did the target resource already exist? */
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (replaced) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Apache will supply a default message */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_NO_CONTENT;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Per HTTP/1.1, S10.2.2: add a Location header to contain the
8aefbd756763807188d2e3ce336a8680e4893066wrowe * URI that was created. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### rnew->uri does not contain an absoluteURI. S14.30 states that
8aefbd756763807188d2e3ce336a8680e4893066wrowe * ### the Location header requires an absoluteURI. where to get it? */
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### disable until we get the right value */
8aefbd756763807188d2e3ce336a8680e4893066wrowe#if 0
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_table_setn(r->headers_out, "Location", rnew->uri);
8aefbd756763807188d2e3ce336a8680e4893066wrowe#endif
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
8aefbd756763807188d2e3ce336a8680e4893066wrowe * we must manufacture the entire response. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe body = ap_psprintf(r->pool, "%s %s has been created.",
8aefbd756763807188d2e3ce336a8680e4893066wrowe what,
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_escape_html(rnew->pool, rnew->uri));
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_error_response(r, HTTP_CREATED, body);
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe/* ### move to dav_util? */
8aefbd756763807188d2e3ce336a8680e4893066wroweint dav_get_depth(request_rec *r, int def_depth)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe const char *depth = ap_table_get(r->headers_in, "Depth");
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (depth == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return def_depth;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (strcasecmp(depth, "infinity") == 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return DAV_INFINITY;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else if (strcmp(depth, "0") == 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 0;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else if (strcmp(depth, "1") == 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 1;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* The caller will return an HTTP_BAD_REQUEST. This will augment the
8aefbd756763807188d2e3ce336a8680e4893066wrowe * default message that Apache provides. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "An invalid Depth header was specified.");
8aefbd756763807188d2e3ce336a8680e4893066wrowe return -1;
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowestatic int dav_get_overwrite(request_rec *r)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe const char *overwrite = ap_table_get(r->headers_in, "Overwrite");
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (overwrite == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 1; /* default is "T" */
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 0;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe return 1;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* The caller will return an HTTP_BAD_REQUEST. This will augment the
8aefbd756763807188d2e3ce336a8680e4893066wrowe * default message that Apache provides. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe "An invalid Overwrite header was specified.");
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe return -1;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe}
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe/* resolve a request URI to a resource descriptor */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowestatic int dav_get_resource(request_rec *r, dav_resource **res_p)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_dir_conf *conf;
8aefbd756763807188d2e3ce336a8680e4893066wrowe const dav_hooks_repository *repos_hooks;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Call repository hook to resolve resource */
8aefbd756763807188d2e3ce336a8680e4893066wrowe conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
8aefbd756763807188d2e3ce336a8680e4893066wrowe &dav_module);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe repos_hooks = DAV_AS_HOOKS_REPOSITORY(&conf->repository);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (repos_hooks == NULL || repos_hooks->get_resource == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### this should happen at startup rather than per-request */
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "No %s has been configured.",
8aefbd756763807188d2e3ce336a8680e4893066wrowe repos_hooks == NULL
8aefbd756763807188d2e3ce336a8680e4893066wrowe ? "repository module"
8aefbd756763807188d2e3ce336a8680e4893066wrowe : "GET handler");
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_INTERNAL_SERVER_ERROR;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe *res_p = (*repos_hooks->get_resource)(r, conf->dir,
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_get_target_selector(r));
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (*res_p == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Apache will supply a default error for this. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_NOT_FOUND;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe return OK;
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowestatic dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (hooks == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe *lockdb = NULL;
8aefbd756763807188d2e3ce336a8680e4893066wrowe return NULL;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe /* open the thing lazily */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return (*hooks->open_lockdb)(r, ro, 0, lockdb);
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowestatic int dav_parse_range(request_rec *r,
8aefbd756763807188d2e3ce336a8680e4893066wrowe off_t *range_start, off_t *range_end)
8aefbd756763807188d2e3ce336a8680e4893066wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe const char *range;
8aefbd756763807188d2e3ce336a8680e4893066wrowe char *dash;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe char *slash;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe range = ap_table_get(r->headers_in, "content-range");
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (range == NULL)
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 0;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe range = ap_pstrdup(r->pool, range);
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe if (strncasecmp(range, "bytes ", 6) != 0
8aefbd756763807188d2e3ce336a8680e4893066wrowe || (dash = strchr(range, '-')) == NULL
8aefbd756763807188d2e3ce336a8680e4893066wrowe || (slash = strchr(range, '/')) == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* malformed header. ignore it (per S14.16 of RFC2616) */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return 0;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe *dash = *slash = '\0';
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe *range_start = atol(range + 6);
8aefbd756763807188d2e3ce336a8680e4893066wrowe *range_end = atol(dash + 1);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (*range_end < *range_start
8aefbd756763807188d2e3ce336a8680e4893066wrowe || (slash[1] != '*' && atol(slash + 1) <= *range_end)) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* invalid range. ignore it (per S14.16 of RFC2616) */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe return 0;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe }
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe /* we now have a valid range */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe return 1;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe}
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe/* handle the GET method */
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowestatic int dav_method_get(request_rec *r)
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe{
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_resource *resource;
8aefbd756763807188d2e3ce336a8680e4893066wrowe int result;
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe /* This method should only be called when the resource is not
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe * visible to Apache. We will fetch the resource from the repository,
4fca95918a9c0ae93593806544b425d0adc2fcc3wrowe * then create a subrequest for Apache to handle.
8aefbd756763807188d2e3ce336a8680e4893066wrowe */
8aefbd756763807188d2e3ce336a8680e4893066wrowe result = dav_get_resource(r, &resource);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (result != OK)
8aefbd756763807188d2e3ce336a8680e4893066wrowe return result;
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (!resource->exists) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Apache will supply a default error for this. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_NOT_FOUND;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Check resource type */
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (resource->type != DAV_RESOURCE_TYPE_REGULAR &&
8aefbd756763807188d2e3ce336a8680e4893066wrowe resource->type != DAV_RESOURCE_TYPE_REVISION) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_error_response(r, HTTP_CONFLICT,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "Cannot GET this type of resource.");
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* Cannot handle GET of a collection from a repository */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (resource->collection) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return dav_error_response(r, HTTP_CONFLICT,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe "No default response to GET for a "
8aefbd756763807188d2e3ce336a8680e4893066wrowe "collection.");
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /*
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** We can use two different approaches for a GET.
8aefbd756763807188d2e3ce336a8680e4893066wrowe **
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** 1) get_pathname will return a pathname to a file which should be
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** sent to the client. If the repository provides this, then we
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** use it.
8aefbd756763807188d2e3ce336a8680e4893066wrowe **
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** This is the best alternative since it allows us to do a sub-
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** request on the file, which gives the Apache framework a chance
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** to deal with negotiation, MIME types, or whatever.
8aefbd756763807188d2e3ce336a8680e4893066wrowe **
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** 2) open_stream and read_stream.
8aefbd756763807188d2e3ce336a8680e4893066wrowe */
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (resource->hooks->get_pathname != NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe const char *pathname;
8aefbd756763807188d2e3ce336a8680e4893066wrowe void *fhandle;
8aefbd756763807188d2e3ce336a8680e4893066wrowe request_rec *new_req;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Ask repository for copy of file */
8aefbd756763807188d2e3ce336a8680e4893066wrowe pathname = (*resource->hooks->get_pathname)(resource, &fhandle);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (pathname == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_NOT_FOUND;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Convert to canonical filename, so Apache detects component
8aefbd756763807188d2e3ce336a8680e4893066wrowe * separators (on Windows, it only looks for '/', not '\')
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe pathname = ap_os_case_canonical_filename(r->pool, pathname);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Create a sub-request with the new filename */
8aefbd756763807188d2e3ce336a8680e4893066wrowe new_req = ap_sub_req_lookup_file(pathname, r);
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (new_req == NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe (*resource->hooks->free_file)(fhandle);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return HTTP_INTERNAL_SERVER_ERROR;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* This may be a HEAD request */
8aefbd756763807188d2e3ce336a8680e4893066wrowe new_req->header_only = r->header_only;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### this enables header generation */
8aefbd756763807188d2e3ce336a8680e4893066wrowe new_req->assbackwards = 0;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Run the sub-request */
8aefbd756763807188d2e3ce336a8680e4893066wrowe result = ap_run_sub_req(new_req);
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_destroy_sub_req(new_req);
b29f87f4b6c6886a04dccc296177a7033f70dfedtrawick
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* Free resources */
b29f87f4b6c6886a04dccc296177a7033f70dfedtrawick (*resource->hooks->free_file)(fhandle);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe return result;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_stream_mode mode;
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_stream *stream;
8aefbd756763807188d2e3ce336a8680e4893066wrowe dav_error *err;
8aefbd756763807188d2e3ce336a8680e4893066wrowe void *buffer;
8aefbd756763807188d2e3ce336a8680e4893066wrowe int has_range;
8aefbd756763807188d2e3ce336a8680e4893066wrowe off_t range_start;
8aefbd756763807188d2e3ce336a8680e4893066wrowe off_t range_end;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* set up the HTTP headers for the response */
8aefbd756763807188d2e3ce336a8680e4893066wrowe if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe err = dav_push_error(r->pool, err->status, 0,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "Unable to set up HTTP headers.",
8aefbd756763807188d2e3ce336a8680e4893066wrowe err);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_handle_err(r, err, NULL);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* use plain READ mode unless we see a Content-Range */
8aefbd756763807188d2e3ce336a8680e4893066wrowe mode = DAV_MODE_READ;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* process the Content-Range header (if present) */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe has_range = dav_parse_range(r, &range_start, &range_end);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (has_range) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* use a read mode which is seekable */
8aefbd756763807188d2e3ce336a8680e4893066wrowe mode = DAV_MODE_READ_SEEKABLE;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* prep the output */
8aefbd756763807188d2e3ce336a8680e4893066wrowe r->status = HTTP_PARTIAL_CONTENT;
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_table_setn(r->headers_out,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "Content-Range",
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_psprintf(r->pool, "bytes %ld-%ld/*",
8aefbd756763807188d2e3ce336a8680e4893066wrowe range_start, range_end));
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_set_content_length(r, range_end - range_start + 1);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (r->header_only) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_send_http_header(r);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return DONE;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if ((err = (*resource->hooks->open_stream)(resource, mode,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe &stream)) != NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### assuming FORBIDDEN is probably not quite right... */
8aefbd756763807188d2e3ce336a8680e4893066wrowe err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ap_psprintf(r->pool,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "Unable to GET contents for %s.",
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_escape_html(r->pool, r->uri)),
8aefbd756763807188d2e3ce336a8680e4893066wrowe err);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_handle_err(r, err, NULL);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (has_range
8aefbd756763807188d2e3ce336a8680e4893066wrowe && (err = (*resource->hooks->seek_stream)(stream,
8aefbd756763807188d2e3ce336a8680e4893066wrowe range_start)) != NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe err = dav_push_error(r->pool, err->status, 0,
8aefbd756763807188d2e3ce336a8680e4893066wrowe "Could not seek to beginning of the "
8aefbd756763807188d2e3ce336a8680e4893066wrowe "specified Content-Range.", err);
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_handle_err(r, err, NULL);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* all set. send the headers now. */
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_send_http_header(r);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe buffer = ap_palloc(r->pool, DAV_READ_BLOCKSIZE);
8aefbd756763807188d2e3ce336a8680e4893066wrowe while (1) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe size_t amt;
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (!has_range)
8aefbd756763807188d2e3ce336a8680e4893066wrowe amt = DAV_READ_BLOCKSIZE;
8aefbd756763807188d2e3ce336a8680e4893066wrowe else if ((range_end - range_start + 1) > DAV_READ_BLOCKSIZE)
8aefbd756763807188d2e3ce336a8680e4893066wrowe amt = DAV_READ_BLOCKSIZE;
8aefbd756763807188d2e3ce336a8680e4893066wrowe else {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* note: range_end - range_start is an ssize_t */
8aefbd756763807188d2e3ce336a8680e4893066wrowe amt = (size_t)(range_end - range_start + 1);
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if ((err = (*resource->hooks->read_stream)(stream, buffer,
8aefbd756763807188d2e3ce336a8680e4893066wrowe &amt)) != NULL) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe break;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (amt == 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* no more content */
8aefbd756763807188d2e3ce336a8680e4893066wrowe break;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (ap_rwrite(buffer, amt, r) < 0) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* ### what to do with this error? */
8aefbd756763807188d2e3ce336a8680e4893066wrowe break;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (has_range) {
8aefbd756763807188d2e3ce336a8680e4893066wrowe range_start += amt;
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (range_start > range_end)
8aefbd756763807188d2e3ce336a8680e4893066wrowe break;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe if (err != NULL)
8aefbd756763807188d2e3ce336a8680e4893066wrowe return dav_handle_err(r, err, NULL);
8aefbd756763807188d2e3ce336a8680e4893066wrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /*
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** ### range_start should equal range_end+1. if it doesn't, then
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** ### we did not send enough data to the client. the client will
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** ### hang (and timeout) waiting for the data.
8aefbd756763807188d2e3ce336a8680e4893066wrowe **
8aefbd756763807188d2e3ce336a8680e4893066wrowe ** ### what to do? abort the connection?
8aefbd756763807188d2e3ce336a8680e4893066wrowe */
8aefbd756763807188d2e3ce336a8680e4893066wrowe return DONE;
8aefbd756763807188d2e3ce336a8680e4893066wrowe }
8aefbd756763807188d2e3ce336a8680e4893066wrowe
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* NOTREACHED */
8aefbd756763807188d2e3ce336a8680e4893066wrowe}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* validate resource on POST, then pass it off to the default handler */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int dav_method_post(request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_resource *resource;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *err;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Ask repository module to resolve the resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb result = dav_get_resource(r, &resource);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (result != OK) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Note: depth == 0. Implies no need for a multistatus response. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### add a higher-level description? */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_handle_err(r, err, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return DECLINED;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* handle the PUT method */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int dav_method_put(request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_resource *resource;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int resource_state;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_resource *resource_parent;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const char *body;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *err;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *err2;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int resource_existed = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int resource_was_writable = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int parent_was_writable = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_stream_mode mode;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_stream *stream;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_response *multi_response;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int has_range;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb off_t range_start;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb off_t range_end;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Ask repository module to resolve the resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb result = dav_get_resource(r, &resource);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (result != OK) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* If not a file or collection resource, PUT not allowed */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb body = ap_psprintf(r->pool,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Cannot create resource %s with PUT.",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_escape_html(r->pool, r->uri));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_error_response(r, HTTP_CONFLICT, body);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Cannot PUT a collection */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (resource->collection) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_error_response(r, HTTP_CONFLICT,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Cannot PUT to a collection.");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb resource_state = dav_get_resource_state(r, resource);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Note: depth == 0 normally requires no multistatus response. However,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** other than the Request-URI, thereby requiring a multistatus.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb **
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** If the resource does not exist (DAV_RESOURCE_NULL), then we must
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** check the resource *and* its parent. If the resource exists or is
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** a locknull resource, then we check only the resource.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((err = dav_validate_request(r, resource, 0, NULL, &multi_response,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb resource_state == DAV_RESOURCE_NULL ?
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_VALIDATE_PARENT :
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### add a higher-level description? */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_handle_err(r, err, multi_response);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* make sure the resource can be modified (if versioning repository) */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((err = dav_ensure_resource_writable(r, resource,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb 0 /* not parent_only */,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &resource_parent,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &resource_existed,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &resource_was_writable,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &parent_was_writable)) != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### add a higher-level description? */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_handle_err(r, err, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* truncate and rewrite the file unless we see a Content-Range */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb mode = DAV_MODE_WRITE_TRUNC;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb has_range = dav_parse_range(r, &range_start, &range_end);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (has_range) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb mode = DAV_MODE_WRITE_SEEKABLE;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Create the new file in the repository */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((err = (*resource->hooks->open_stream)(resource, mode,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &stream)) != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### assuming FORBIDDEN is probably not quite right... */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_psprintf(r->pool,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Unable to PUT new contents for %s.",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_escape_html(r->pool, r->uri)),
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (err == NULL && has_range) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* a range was provided. seek to the start */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = (*resource->hooks->seek_stream)(stream, range_start);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (err == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (ap_should_client_block(r)) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb char *buffer = ap_palloc(r->pool, DAV_READ_BLOCKSIZE);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb long len;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Once we start reading the request, then we must read the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** whole darn thing. ap_discard_request_body() won't do anything
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** for a partially-read request.
8aefbd756763807188d2e3ce336a8680e4893066wrowe */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb while ((len = ap_get_client_block(r, buffer,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_READ_BLOCKSIZE)) > 0) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (err == NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* write whatever we read, until we see an error */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = (*resource->hooks->write_stream)(stream,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb buffer, len);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** ### what happens if we read more/less than the amount
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** ### specified in the Content-Range? eek...
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (len == -1) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Error reading request body. This has precedence over
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** prior errors.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "An error occurred while reading the "
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "request body.");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err2 = (*resource->hooks->close_stream)(stream,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe err == NULL /* commit */);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (err2 != NULL && err == NULL) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe /* no error during the write, but we hit one at close. use it. */
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe err = err2;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe /*
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe ** Ensure that we think the resource exists now.
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe ** ### eek. if an error occurred during the write and we did not commit,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe ** ### then the resource might NOT exist (e.g. dav_fs_repos.c)
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe */
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (err == NULL) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe resource->exists = 1;
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe /* restore modifiability of resources back to what they were */
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe err2 = dav_revert_resource_writability(r, resource, resource_parent,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe err != NULL /* undo if error */,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe resource_existed,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe resource_was_writable,
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe parent_was_writable);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe /* check for errors now */
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (err != NULL) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe return dav_handle_err(r, err, NULL);
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe }
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe if (err2 != NULL) {
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe /* just log a warning */
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe err2 = dav_push_error(r->pool, err->status, 0,
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "The PUT was successful, but there "
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "was a problem reverting the writability of "
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "the resource or its parent collection.",
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe err2);
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe dav_log_err(r, err2, APLOG_WARNING);
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe }
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe /* ### place the Content-Type and Content-Language into the propdb */
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe if (locks_hooks != NULL) {
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe dav_lockdb *lockdb;
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe /* The file creation was successful, but the locking failed. */
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe err = dav_push_error(r->pool, err->status, 0,
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "The file was PUT successfully, but there "
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "was a problem opening the lock database "
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "which prevents inheriting locks from the "
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe "parent resources.",
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe err);
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe return dav_handle_err(r, err, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* notify lock system that we have created/replaced a resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = dav_notify_created(r, lockdb, resource, resource_state, 0);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb (*locks_hooks->close_lockdb)(lockdb);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (err != NULL) {
4ca6cbe768b4e0917ac0b76333c26a7d5396d454trawick /* The file creation was successful, but the locking failed. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = dav_push_error(r->pool, err->status, 0,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "The file was PUT successfully, but there "
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "was a problem updating its lock "
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "information.",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_handle_err(r, err, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_created(r, NULL, resource, "Resource", resource_existed);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* ### move this to dav_util? */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbvoid dav_add_response(dav_walker_ctx *ctx, const char *href, int status,
48d2edbfb84e5559b5da0f8d614ccab805cc67a8rbb dav_get_props_result *propstats)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_response *resp;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* just drop some data into an dav_response */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb resp = ap_pcalloc(ctx->pool, sizeof(*resp));
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe resp->href = ap_pstrdup(ctx->pool, href);
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe resp->status = status;
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe if (propstats) {
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe resp->propresult = *propstats;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe resp->next = ctx->response;
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe ctx->response = resp;
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe}
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe
1b839c67d5c0e4b1f22b44a4217f9860b420d47cwrowe/* handle the DELETE method */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int dav_method_delete(request_rec *r)
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe{
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe dav_resource *resource;
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb dav_resource *resource_parent = NULL;
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb dav_error *err;
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb dav_error *err2;
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb dav_response *multi_response;
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb const char *body;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int depth;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int parent_was_writable = 0;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* We don't use the request body right now, so torch it. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((result = ap_discard_request_body(r)) != OK) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Ask repository module to resolve the resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb result = dav_get_resource(r, &resource);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (result != OK)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (!resource->exists) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Apache will supply a default error for this. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return HTTP_NOT_FOUND;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* 2518 says that depth must be infinity only for collections.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * For non-collections, depth is ignored, unless it is an illegal value (1).
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb depth = dav_get_depth(r, DAV_INFINITY);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (resource->collection && depth != DAV_INFINITY) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* This supplies additional information for the default message. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Depth must be \"infinity\" for DELETE of a collection.");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return HTTP_BAD_REQUEST;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (!resource->collection && depth == 1) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* This supplies additional information for the default message. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Depth of \"1\" is not allowed for DELETE.");
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return HTTP_BAD_REQUEST;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* Check for valid resource type */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### allow DAV_RESOURCE_TYPE_REVISION with All-Bindings header */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (resource->type != DAV_RESOURCE_TYPE_REGULAR &&
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb resource->type != DAV_RESOURCE_TYPE_WORKSPACE) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb body = ap_psprintf(r->pool,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb "Cannot delete resource %s.",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_escape_html(r->pool, r->uri));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return dav_error_response(r, HTTP_CONFLICT, body);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** If any resources fail the lock/If: conditions, then we must fail
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** the delete. Each of the failing resources will be listed within
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** a DAV:multistatus body, wrapped into a 424 response.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb **
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Note that a failure on the resource itself does not generate a
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** multistatus response -- only internal members/collections.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if ((err = dav_validate_request(r, resource, depth, NULL,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb &multi_response,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb DAV_VALIDATE_PARENT
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb | DAV_VALIDATE_USE_424, NULL)) != NULL) {
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe err = dav_push_error(r->pool, err->status, 0,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe ap_psprintf(r->pool,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe "Could not DELETE %s due to a failed "
117026201e6d8fe7d82416b8a7324830f5a87292wrowe "precondition (e.g. locks).",
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe ap_escape_html(r->pool, r->uri)),
117026201e6d8fe7d82416b8a7324830f5a87292wrowe err);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return dav_handle_err(r, err, multi_response);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe }
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those
117026201e6d8fe7d82416b8a7324830f5a87292wrowe * locked by the token(s) in the if_header.
117026201e6d8fe7d82416b8a7324830f5a87292wrowe */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if ((result = dav_unlock(r, resource, NULL)) != OK) {
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return result;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe }
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* if versioned resource, make sure parent is checked out */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if ((err = dav_ensure_resource_writable(r, resource, 1 /* parent_only */,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe &resource_parent,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe NULL, NULL,
55eb5bb774cfb861542b827fbf4c30e6efbbfc44wrowe &parent_was_writable)) != NULL) {
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* ### add a higher-level description? */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return dav_handle_err(r, err, NULL);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe }
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* try to remove the resource */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe err = (*resource->hooks->remove_resource)(resource, &multi_response);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* restore writability of parent back to what it was */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe err2 = dav_revert_resource_writability(r, NULL, resource_parent,
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe err != NULL /* undo if error */,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe 0, 0, parent_was_writable);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
e7505ba54ac56ae30e4e250f912f3dbaf92ca45fwrowe /* check for errors now */
e7505ba54ac56ae30e4e250f912f3dbaf92ca45fwrowe if (err != NULL) {
e7505ba54ac56ae30e4e250f912f3dbaf92ca45fwrowe err = dav_push_error(r->pool, err->status, 0,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe ap_psprintf(r->pool,
117026201e6d8fe7d82416b8a7324830f5a87292wrowe "Could not DELETE %s.",
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ap_escape_html(r->pool, r->uri)),
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe err);
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe return dav_handle_err(r, err, multi_response);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe if (err2 != NULL) {
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe /* just log a warning */
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe err = dav_push_error(r->pool, err2->status, 0,
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe "The DELETE was successful, but there "
beda1fb2f11c52ca4612460a5d5ba47398143efbwrowe "was a problem reverting the writability of "
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe "its parent collection.",
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe err2);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe dav_log_err(r, err, APLOG_WARNING);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* Apache will supply a default error for this. */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return HTTP_NO_CONTENT;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe}
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe/* handle the OPTIONS method */
117026201e6d8fe7d82416b8a7324830f5a87292wrowestatic int dav_method_options(request_rec *r)
117026201e6d8fe7d82416b8a7324830f5a87292wrowe{
efa1a34b0a7785fc72863eff175b0cfc1ecb0e38wrowe const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe dav_resource *resource;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const char *options;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const char *dav_level;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const char *vsn_level;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe int result;
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const dav_dir_conf *conf;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe const dav_dyn_hooks *lp;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* per HTTP/1.1 S9.2, we can discard this body */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if ((result = ap_discard_request_body(r)) != OK) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe return result;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* no body */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe ap_set_content_length(r, 0);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe /* resolve the resource */
117026201e6d8fe7d82416b8a7324830f5a87292wrowe result = dav_get_resource(r, &resource);
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if (result != OK)
117026201e6d8fe7d82416b8a7324830f5a87292wrowe return result;
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe /* determine which providers are available */
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe dav_level = "1";
117026201e6d8fe7d82416b8a7324830f5a87292wrowe vsn_level = NULL;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if (locks_hooks != NULL) {
117026201e6d8fe7d82416b8a7324830f5a87292wrowe dav_level = "1,2";
117026201e6d8fe7d82416b8a7324830f5a87292wrowe }
117026201e6d8fe7d82416b8a7324830f5a87292wrowe if (vsn_hooks != NULL) {
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe vsn_level = (*vsn_hooks->get_vsn_header)();
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe }
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe /*
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe ** Iterate through the live property providers; add their URIs to
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe ** the dav_level string.
650ac07cba9ab3ad9bdeda50b78c278442604814wrowe */
650ac07cba9ab3ad9bdeda50b78c278442604814wrowe conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
650ac07cba9ab3ad9bdeda50b78c278442604814wrowe &dav_module);
650ac07cba9ab3ad9bdeda50b78c278442604814wrowe for (lp = conf->liveprop; lp != NULL; lp = lp->next) {
117026201e6d8fe7d82416b8a7324830f5a87292wrowe const char *uri = DAV_AS_HOOKS_LIVEPROP(lp)->propset_uri;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (uri != NULL)
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe dav_level = ap_pstrcat(r->pool, dav_level, ",<", uri, ">", NULL);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* this tells MSFT products to skip looking for FrontPage extensions */
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe ap_table_setn(r->headers_out, "MS-Author-Via", "DAV");
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe /*
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe ** Three cases: resource is null (3), is lock-null (7.4), or exists.
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe **
117026201e6d8fe7d82416b8a7324830f5a87292wrowe ** All cases support OPTIONS and LOCK.
117026201e6d8fe7d82416b8a7324830f5a87292wrowe ** (Lock-) null resources also support MKCOL and PUT.
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe ** Lock-null support PROPFIND and UNLOCK.
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe ** Existing resources support lots of stuff.
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### take into account resource type */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb switch (dav_get_resource_state(r, resource))
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb {
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe case DAV_RESOURCE_EXISTS:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* resource exists */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (resource->collection) {
1b839c67d5c0e4b1f22b44a4217f9860b420d47cwrowe options = ap_pstrcat(r->pool,
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb "OPTIONS, "
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe "GET, HEAD, POST, DELETE, TRACE, "
e68544ae924174ca227ede8e2e722cefa00ea0d3wrowe "PROPFIND, PROPPATCH, COPY, MOVE",
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe locks_hooks != NULL ? ", LOCK, UNLOCK" : "",
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe NULL);
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe }
b67fb549910fa0faf4cdd8aeaf9aeab51d4b6a92wrowe else {
b45c1c292ff1fa635004ae81fa691f8cb3cdda85rbb /* files also support PUT */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb options = ap_pstrcat(r->pool,
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe "OPTIONS, "
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe "GET, HEAD, POST, DELETE, TRACE, "
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe "PROPFIND, PROPPATCH, COPY, MOVE, PUT",
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe locks_hooks != NULL ? ", LOCK, UNLOCK" : "",
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe NULL);
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe }
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe break;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe case DAV_RESOURCE_LOCK_NULL:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* resource is lock-null. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb options = ap_pstrcat(r->pool, "OPTIONS, MKCOL, PUT, PROPFIND",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb locks_hooks != NULL ? ", LOCK, UNLOCK" : "",
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe NULL);
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe break;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe case DAV_RESOURCE_NULL:
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe /* resource is null. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb options = ap_pstrcat(r->pool, "OPTIONS, MKCOL, PUT",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb locks_hooks != NULL ? ", LOCK" : "",
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe NULL);
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe break;
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe
5bb29f57ae0184d2b3c1cdf35132f8ceb011f882wrowe default:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### internal error! */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb options = "OPTIONS";
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb break;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* If there is a versioning provider, add versioning options */
e16c4a220d3410c6f3424e7f6b12f3cd5455dddejwoolley if (vsn_hooks != NULL) {
e16c4a220d3410c6f3424e7f6b12f3cd5455dddejwoolley const char *vsn_options = NULL;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### take into account resource type */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (!resource->exists) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if ((*vsn_hooks->versionable)(resource))
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe vsn_options = ", MKRESOURCE";
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe else if (!resource->versioned) {
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if ((*vsn_hooks->versionable)(resource))
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe vsn_options = ", CHECKIN";
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe else if (resource->working)
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe vsn_options = ", CHECKIN, UNCHECKOUT";
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe else
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe vsn_options = ", CHECKOUT";
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (vsn_options != NULL)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb options = ap_pstrcat(r->pool, options, vsn_options, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_table_setn(r->headers_out, "Allow", options);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ap_table_setn(r->headers_out, "DAV", dav_level);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe if (vsn_level != NULL)
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ap_table_setn(r->headers_out, "Versioning", vsn_level);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### this will send a Content-Type. the default OPTIONS does not. */
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ap_send_http_header(r);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* ### the default (ap_send_http_options) returns OK, but I believe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * ### that is because it is the default handler and nothing else
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ### will run after the thing. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* we've sent everything necessary to the client. */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return DONE;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowestatic void dav_cache_badprops(dav_walker_ctx *ctx)
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_xml_elem *elem;
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe dav_text_header hdr = { 0 };
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* just return if we built the thing already */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (ctx->propstat_404 != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return;
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe }
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe dav_text_append(ctx->pool, &hdr,
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe "<D:propstat>" DEBUG_CR
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe "<D:prop>" DEBUG_CR);
650ac07cba9ab3ad9bdeda50b78c278442604814wrowe
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe elem = dav_find_child(ctx->doc->root, "prop");
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe for (elem = elem->first_child; elem; elem = elem->next) {
73fbb0a2e9cb209173d6c319c57260cbf29c8cc7wrowe dav_text_append(ctx->pool, &hdr, dav_empty_elem(ctx->pool, elem));
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe dav_text_append(ctx->pool, &hdr,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe "</D:prop>" DEBUG_CR
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe "</D:propstat>" DEBUG_CR);
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe ctx->propstat_404 = hdr.first;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic dav_error * dav_propfind_walker(dav_walker_ctx *ctx, int calltype)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *err;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_propdb *propdb;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_get_props_result propstats = { 0 };
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /*
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** dav_get_allprops() does not need to do namespace translation,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** we're okay.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb **
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** Note: we cast to lose the "const". The propdb won't try to change
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ** the resource, however, since we are opening readonly.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb err = dav_open_propdb(ctx->r, ctx->lockdb,
1067418d9ed9ed9daeb3ca4f74e72db810c49833wrowe (dav_resource *)ctx->resource, 1,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (err != NULL) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### do something with err! */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_get_props_result badprops = { 0 };
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* some props were expected on this collection/resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_cache_badprops(ctx);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb badprops.propstats = ctx->propstat_404;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_add_response(ctx, ctx->uri.buf, 0, &badprops);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* no props on this collection/resource */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_add_response(ctx, ctx->uri.buf, HTTP_OK, NULL);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb /* ### what to do about closing the propdb on server failure? */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb propstats = dav_get_props(propdb, ctx->doc);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb else {
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb propstats = dav_get_allprops(propdb,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb }
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_close_propdb(propdb);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_add_response(ctx, ctx->uri.buf, 0, &propstats);
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb return NULL;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb}
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* handle the PROPFIND method */
b38846b15c8891c6dec44dcc4f96ca40721bf663rbbstatic int dav_method_propfind(request_rec *r)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb{
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_resource *resource;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int depth;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_error *err;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb int result;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_xml_doc *doc;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb const dav_xml_elem *child;
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb dav_walker_ctx ctx = { 0 };
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) {
/* dav_get_depth() supplies additional information for the
* default message. */
return HTTP_BAD_REQUEST;
}
if (depth == DAV_INFINITY) {
dav_dir_conf *conf;
conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
&dav_module);
/* default is to DISALLOW these requests */
if (conf->allow_depthinfinity != DAV_ENABLED_ON) {
return dav_error_response(r, HTTP_FORBIDDEN,
ap_psprintf(r->pool,
"PROPFIND requests with a "
"Depth of \"infinity\" are "
"not allowed for %s.",
ap_escape_html(r->pool,
r->uri)));
}
}
if ((result = dav_parse_input(r, &doc)) != OK) {
return result;
}
/* note: doc == NULL if no request body */
if (doc && !dav_validate_root(doc, "propfind")) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"The \"propfind\" element was not found.");
return HTTP_BAD_REQUEST;
}
/* ### validate that only one of these three elements is present */
if (doc == NULL
|| (child = dav_find_child(doc->root, "allprop")) != NULL) {
/* note: no request body implies allprop */
ctx.propfind_type = DAV_PROPFIND_IS_ALLPROP;
}
else if ((child = dav_find_child(doc->root, "propname")) != NULL) {
ctx.propfind_type = DAV_PROPFIND_IS_PROPNAME;
}
else if ((child = dav_find_child(doc->root, "prop")) != NULL) {
ctx.propfind_type = DAV_PROPFIND_IS_PROP;
}
else {
/* "propfind" element must have one of the above three children */
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"The \"propfind\" element does not contain one of "
"the required child elements (the specific command).");
return HTTP_BAD_REQUEST;
}
ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_AUTH;
ctx.func = dav_propfind_walker;
ctx.pool = r->pool;
ctx.doc = doc;
ctx.r = r;
ctx.resource = resource;
dav_buffer_init(r->pool, &ctx.uri, r->uri);
/* ### should open read-only */
if ((err = dav_open_lockdb(r, 0, &ctx.lockdb)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
"The lock database could not be opened, "
"preventing access to the various lock "
"properties for the PROPFIND.",
err);
return dav_handle_err(r, err, NULL);
}
if (ctx.lockdb != NULL) {
/* if we have a lock database, then we can walk locknull resources */
ctx.walk_type |= DAV_WALKTYPE_LOCKNULL;
}
err = (*resource->hooks->walk)(&ctx, depth);
if (ctx.lockdb != NULL) {
(*ctx.lockdb->hooks->close_lockdb)(ctx.lockdb);
}
if (err != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* return a 207 (Multi-Status) response now. */
/* if a 404 was generated for an HREF, then we need to spit out the
* doc's namespaces for use by the 404. Note that <response> elements
* will override these ns0, ns1, etc, but NOT within the <response>
* scope for the badprops. */
/* NOTE: propstat_404 != NULL implies doc != NULL */
if (ctx.propstat_404 != NULL) {
dav_send_multistatus(r, HTTP_MULTI_STATUS, ctx.response,
doc->namespaces);
}
else {
dav_send_multistatus(r, HTTP_MULTI_STATUS, ctx.response, NULL);
}
/* the response has been sent. */
return DONE;
}
static dav_text * dav_failed_proppatch(ap_pool_t *p,
ap_array_header_t *prop_ctx)
{
dav_text_header hdr = { 0 };
int i = prop_ctx->nelts;
dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts;
dav_error *err424_set = NULL;
dav_error *err424_delete = NULL;
const char *s;
/* ### might be nice to sort by status code and description */
for ( ; i-- > 0; ++ctx ) {
dav_text_append(p, &hdr,
"<D:propstat>" DEBUG_CR
"<D:prop>");
dav_text_append(p, &hdr, dav_empty_elem(p, ctx->prop));
dav_text_append(p, &hdr, "</D:prop>" DEBUG_CR);
if (ctx->err == NULL) {
/* nothing was assigned here yet, so make it a 424 */
if (ctx->operation == DAV_PROP_OP_SET) {
if (err424_set == NULL)
err424_set = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0,
"Attempted DAV:set operation "
"could not be completed due "
"to other errors.");
ctx->err = err424_set;
}
else if (ctx->operation == DAV_PROP_OP_DELETE) {
if (err424_delete == NULL)
err424_delete = dav_new_error(p, HTTP_FAILED_DEPENDENCY, 0,
"Attempted DAV:remove "
"operation could not be "
"completed due to other "
"errors.");
ctx->err = err424_delete;
}
}
s = ap_psprintf(p,
"<D:status>"
"HTTP/1.1 %d (status)"
"</D:status>" DEBUG_CR,
ctx->err->status);
dav_text_append(p, &hdr, s);
/* ### we should use compute_desc if necessary... */
if (ctx->err->desc != NULL) {
dav_text_append(p, &hdr, "<D:responsedescription>" DEBUG_CR);
dav_text_append(p, &hdr, ctx->err->desc);
dav_text_append(p, &hdr, "</D:responsedescription>" DEBUG_CR);
}
dav_text_append(p, &hdr, "</D:propstat>" DEBUG_CR);
}
return hdr.first;
}
static dav_text * dav_success_proppatch(ap_pool_t *p, ap_array_header_t *prop_ctx)
{
dav_text_header hdr = { 0 };
int i = prop_ctx->nelts;
dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts;
/*
** ### we probably need to revise the way we assemble the response...
** ### this code assumes everything will return status==200.
*/
dav_text_append(p, &hdr,
"<D:propstat>" DEBUG_CR
"<D:prop>" DEBUG_CR);
for ( ; i-- > 0; ++ctx ) {
dav_text_append(p, &hdr, dav_empty_elem(p, ctx->prop));
}
dav_text_append(p, &hdr,
"</D:prop>" DEBUG_CR
"<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
"</D:propstat>" DEBUG_CR);
return hdr.first;
}
static void dav_prop_log_errors(dav_prop_ctx *ctx)
{
dav_log_err(ctx->r, ctx->err, APLOG_ERR);
}
/*
** Call <func> for each context. This can stop when an error occurs, or
** simply iterate through the whole list.
**
** Returns 1 if an error occurs (and the iteration is aborted). Returns 0
** if all elements are processed.
**
** If <reverse> is true (non-zero), then the list is traversed in
** reverse order.
*/
static int dav_process_ctx_list(void (*func)(dav_prop_ctx *ctx),
ap_array_header_t *ctx_list, int stop_on_error,
int reverse)
{
int i = ctx_list->nelts;
dav_prop_ctx *ctx = (dav_prop_ctx *)ctx_list->elts;
if (reverse)
ctx += i;
while (i--) {
if (reverse)
--ctx;
(*func)(ctx);
if (stop_on_error && DAV_PROP_CTX_HAS_ERR(*ctx)) {
return 1;
}
if (!reverse)
++ctx;
}
return 0;
}
/* handle the PROPPATCH method */
static int dav_method_proppatch(request_rec *r)
{
dav_error *err;
dav_resource *resource;
int result;
dav_xml_doc *doc;
dav_xml_elem *child;
dav_propdb *propdb;
int failure = 0;
dav_response resp = { 0 };
dav_text *propstat_text;
ap_array_header_t *ctx_list;
dav_prop_ctx *ctx;
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
if ((result = dav_parse_input(r, &doc)) != OK) {
return result;
}
/* note: doc == NULL if no request body */
if (doc == NULL || !dav_validate_root(doc, "propertyupdate")) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"The request body does not contain "
"a \"propertyupdate\" element.");
return HTTP_BAD_REQUEST;
}
/* 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,
DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
if ((err = dav_open_propdb(r, NULL, resource, 0, doc->namespaces,
&propdb)) != NULL) {
err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
ap_psprintf(r->pool,
"Could not open the property "
"database for %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, NULL);
}
/* ### what to do about closing the propdb on server failure? */
/* ### validate "live" properties */
/* set up an array to hold property operation contexts */
ctx_list = ap_make_array(r->pool, 10, sizeof(dav_prop_ctx));
/* do a first pass to ensure that all "remove" properties exist */
for (child = doc->root->first_child; child; child = child->next) {
int is_remove;
dav_xml_elem *prop_group;
dav_xml_elem *one_prop;
/* Ignore children that are not set/remove */
if (child->ns != DAV_NS_DAV_ID
|| (!(is_remove = strcmp(child->name, "remove") == 0)
&& strcmp(child->name, "set") != 0)) {
continue;
}
/* make sure that a "prop" child exists for set/remove */
if ((prop_group = dav_find_child(child, "prop")) == NULL) {
dav_close_propdb(propdb);
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"A \"prop\" element is missing inside "
"the propertyupdate command.");
return HTTP_BAD_REQUEST;
}
for (one_prop = prop_group->first_child; one_prop;
one_prop = one_prop->next) {
ctx = (dav_prop_ctx *)ap_push_array(ctx_list);
ctx->propdb = propdb;
ctx->operation = is_remove ? DAV_PROP_OP_DELETE : DAV_PROP_OP_SET;
ctx->prop = one_prop;
ctx->r = r; /* for later use by dav_prop_log_errors() */
dav_prop_validate(ctx);
if ( DAV_PROP_CTX_HAS_ERR(*ctx) ) {
failure = 1;
}
}
}
/* ### should test that we found at least one set/remove */
/* execute all of the operations */
if (!failure && dav_process_ctx_list(dav_prop_exec, ctx_list, 1, 0)) {
failure = 1;
}
/* generate a failure/success response */
if (failure) {
(void)dav_process_ctx_list(dav_prop_rollback, ctx_list, 0, 1);
propstat_text = dav_failed_proppatch(r->pool, ctx_list);
}
else {
(void)dav_process_ctx_list(dav_prop_commit, ctx_list, 0, 0);
propstat_text = dav_success_proppatch(r->pool, ctx_list);
}
/* make sure this gets closed! */
dav_close_propdb(propdb);
/* log any errors that occurred */
(void)dav_process_ctx_list(dav_prop_log_errors, ctx_list, 0, 0);
resp.href = resource->uri;
/* ### should probably use something new to pass along this text... */
resp.propresult.propstats = propstat_text;
dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces);
/* the response has been sent. */
return DONE;
}
static int process_mkcol_body(request_rec *r)
{
/* This is snarfed from ap_setup_client_block(). We could get pretty
* close to this behavior by passing REQUEST_NO_BODY, but we need to
* return HTTP_UNSUPPORTED_MEDIA_TYPE (while ap_setup_client_block
* returns HTTP_REQUEST_ENTITY_TOO_LARGE). */
const char *tenc = ap_table_get(r->headers_in, "Transfer-Encoding");
const char *lenp = ap_table_get(r->headers_in, "Content-Length");
/* make sure to set the Apache request fields properly. */
r->read_body = REQUEST_NO_BODY;
r->read_chunked = 0;
r->remaining = 0;
if (tenc) {
if (strcasecmp(tenc, "chunked")) {
/* Use this instead of Apache's default error string */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Unknown Transfer-Encoding %s", tenc);
return HTTP_NOT_IMPLEMENTED;
}
r->read_chunked = 1;
}
else if (lenp) {
const char *pos = lenp;
while (ap_isdigit(*pos) || ap_isspace(*pos)) {
++pos;
}
if (*pos != '\0') {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Invalid Content-Length %s", lenp);
return HTTP_BAD_REQUEST;
}
r->remaining = atol(lenp);
}
if (r->read_chunked || r->remaining > 0) {
/* ### log something? */
/* Apache will supply a default error for this. */
return HTTP_UNSUPPORTED_MEDIA_TYPE;
}
/*
** Get rid of the body. this will call ap_setup_client_block(), but
** our copy above has already verified its work.
*/
return ap_discard_request_body(r);
}
/* handle the MKCOL method */
static int dav_method_mkcol(request_rec *r)
{
dav_resource *resource;
int resource_state;
dav_resource *resource_parent;
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
dav_error *err;
dav_error *err2;
int result;
dav_dir_conf *conf;
int parent_was_writable = 0;
dav_response *multi_status;
/* handle the request body */
/* ### this may move lower once we start processing bodies */
if ((result = process_mkcol_body(r)) != OK) {
return result;
}
conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
&dav_module);
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
if (resource->exists) {
/* oops. something was already there! */
/* Apache will supply a default error for this. */
/* ### we should provide a specific error message! */
return HTTP_METHOD_NOT_ALLOWED;
}
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 does not exist (DAV_RESOURCE_NULL), then we must
** check the resource *and* its parent. If the resource exists or is
** a locknull resource, then we check only the resource.
*/
if ((err = dav_validate_request(r, resource, 0, NULL, &multi_status,
resource_state == DAV_RESOURCE_NULL ?
DAV_VALIDATE_PARENT :
DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, multi_status);
}
/* if versioned resource, make sure parent is checked out */
if ((err = dav_ensure_resource_writable(r, resource, 1 /* parent_only */,
&resource_parent,
NULL, NULL,
&parent_was_writable)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* try to create the collection */
resource->collection = 1;
err = (*resource->hooks->create_collection)(r->pool, resource);
/* restore modifiability of parent back to what it was */
err2 = dav_revert_resource_writability(r, NULL, resource_parent,
err != NULL /* undo if error */,
0, 0, parent_was_writable);
/* check for errors now */
if (err != NULL) {
return dav_handle_err(r, err, NULL);
}
if (err2 != NULL) {
/* just log a warning */
err = dav_push_error(r->pool, err->status, 0,
"The MKCOL was successful, but there "
"was a problem reverting the writability of "
"its parent collection.",
err2);
dav_log_err(r, err, APLOG_WARNING);
}
if (locks_hooks != NULL) {
dav_lockdb *lockdb;
if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
/* The directory creation was successful, but the locking failed. */
err = dav_push_error(r->pool, err->status, 0,
"The MKCOL 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 MKCOL was successful, but there "
"was a problem updating its lock "
"information.",
err);
return dav_handle_err(r, err, NULL);
}
}
/* return an appropriate response (HTTP_CREATED) */
return dav_created(r, NULL, resource, "Collection", 0);
}
/* handle the COPY and MOVE methods */
static int dav_method_copymove(request_rec *r, int is_move)
{
dav_resource *resource;
dav_resource *resource_parent = NULL;
dav_resource *resnew;
dav_resource *resnew_parent = NULL;
const char *body;
const char *dest;
dav_error *err;
dav_error *err2;
dav_error *err3;
dav_response *multi_response;
dav_lookup_result lookup;
int is_dir;
int overwrite;
int depth;
int result;
dav_lockdb *lockdb;
int replaced;
int src_parent_was_writable = 0;
int dst_parent_was_writable = 0;
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* If not a file or collection resource, COPY/MOVE not allowed */
if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
body = ap_psprintf(r->pool,
"Cannot COPY/MOVE resource %s.",
ap_escape_html(r->pool, r->uri));
return dav_error_response(r, HTTP_METHOD_NOT_ALLOWED, body);
}
/* get the destination URI */
dest = ap_table_get(r->headers_in, "Destination");
if (dest == NULL) {
/* Look in headers provided by Netscape's Roaming Profiles */
const char *nscp_host = ap_table_get(r->headers_in, "Host");
const char *nscp_path = ap_table_get(r->headers_in, "New-uri");
if (nscp_host != NULL && nscp_path != NULL)
dest = ap_psprintf(r->pool, "http://%s%s", nscp_host, nscp_path);
}
if (dest == NULL) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"The request is missing a Destination header.");
return HTTP_BAD_REQUEST;
}
lookup = dav_lookup_uri(dest, r);
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 | APLOG_NOERRNO, 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,
"Destination URI had an error.");
}
/* Resolve destination resource */
result = dav_get_resource(lookup.rnew, &resnew);
if (result != OK)
return result;
/* are the two resources handled by the same repository? */
if (resource->hooks != resnew->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. "
"MOVE or COPY 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 (resnew->exists && !overwrite) {
/* Supply some text for the error response body. */
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, resnew)) {
/* Supply some text for the error response body. */
return dav_error_response(r, HTTP_FORBIDDEN,
"Source and Destination URIs are the same.");
}
is_dir = resource->collection;
/* get and parse the Depth header value. "0" and "infinity" are legal. */
if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) {
/* dav_get_depth() supplies additional information for the
* default message. */
return HTTP_BAD_REQUEST;
}
if (depth == 1) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Depth must be \"0\" or \"infinity\" for COPY or MOVE.");
return HTTP_BAD_REQUEST;
}
if (is_move && is_dir && depth != DAV_INFINITY) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Depth must be \"infinity\" when moving a collection.");
return HTTP_BAD_REQUEST;
}
/*
** Check If-Headers and existing locks for each resource in the source
** if we are performing a MOVE. We will return a 424 response with a
** DAV:multistatus body. The multistatus responses will contain the
** information about any resource that fails the validation.
**
** We check the parent resource, too, since this is a MOVE. Moving the
** resource effectively removes it from the parent collection, so we
** must ensure that we have met the appropriate conditions.
**
** If a problem occurs with the Request-URI itself, then a plain error
** (rather than a multistatus) will be returned.
*/
if (is_move
&& (err = dav_validate_request(r, resource, depth, NULL,
&multi_response,
DAV_VALIDATE_PARENT
| DAV_VALIDATE_USE_424,
NULL)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
ap_psprintf(r->pool,
"Could not MOVE %s due to a failed "
"precondition on the source "
"(e.g. locks).",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
/*
** 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, resnew, DAV_INFINITY, NULL,
&multi_response,
DAV_VALIDATE_PARENT
| DAV_VALIDATE_USE_424, NULL)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
ap_psprintf(r->pool,
"Could not MOVE/COPY %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);
}
if (is_dir
&& depth == DAV_INFINITY
&& (*resource->hooks->is_parent_resource)(resource, resnew)) {
/* Supply some text for the error response body. */
return dav_error_response(r, HTTP_FORBIDDEN,
"Source collection contains the "
"Destination.");
}
if (is_dir
&& (*resnew->hooks->is_parent_resource)(resnew, 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 MOVE/COPY, as that would
* delete the Source.
*/
/* Supply some text for the error response body. */
return dav_error_response(r, HTTP_FORBIDDEN,
"Destination collection contains the Source "
"and Overwrite has been specified.");
}
/* ### for now, we don't need anything in the body */
if ((result = ap_discard_request_body(r)) != OK) {
return result;
}
if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* remove any locks from the old resources */
/*
** ### this is Yet Another Traversal. if we do a rename(), then we
** ### really don't have to do this in some cases since the inode
** ### values will remain constant across the move. but we can't
** ### know that fact from outside the provider :-(
**
** ### note that we now have a problem atomicity in the move/copy
** ### since a failure after this would have removed locks (technically,
** ### this is okay to do, but really...)
*/
if (is_move && lockdb != NULL) {
/* ### this is wrong! it blasts direct locks on parent resources */
/* ### pass lockdb! */
(void)dav_unlock(r, resource, NULL);
}
/* remember whether target resource existed */
replaced = resnew->exists;
/* if this is a move, then the source parent collection will be modified */
if (is_move) {
if ((err = dav_ensure_resource_writable(r, resource,
1 /* parent_only */,
&resource_parent,
NULL, NULL,
&src_parent_was_writable)) != NULL) {
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
}
/* prepare the destination collection for modification */
if ((err = dav_ensure_resource_writable(r, resnew, 1 /* parent_only */,
&resnew_parent,
NULL, NULL,
&dst_parent_was_writable)) != NULL) {
/* could not make destination writable:
* if move, restore state of source parent
*/
if (is_move) {
(void) dav_revert_resource_writability(r, NULL, resource_parent,
1 /* undo */,
0, 0,
src_parent_was_writable);
}
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* If source and destination parents are the same, then
* use the same object, so status updates to one are reflected
* in the other.
*/
if (resource_parent != NULL
&& (*resource_parent->hooks->is_same_resource)(resource_parent,
resnew_parent))
resnew_parent = resource_parent;
/* New resource will be same kind as source */
resnew->collection = resource->collection;
/* If target exists, remove it first (we know Ovewrite must be TRUE).
* Then try to copy/move the resource.
*/
if (resnew->exists)
err = (*resnew->hooks->remove_resource)(resnew, &multi_response);
if (err == NULL) {
if (is_move)
err = (*resource->hooks->move_resource)(resource, resnew,
&multi_response);
else
err = (*resource->hooks->copy_resource)(resource, resnew, depth,
&multi_response);
}
/* restore parent collection states */
err2 = dav_revert_resource_writability(r, NULL, resnew_parent,
err != NULL /* undo if error */,
0, 0, dst_parent_was_writable);
if (is_move) {
err3 = dav_revert_resource_writability(r, NULL, resource_parent,
err != NULL /* undo if error */,
0, 0, src_parent_was_writable);
}
else
err3 = NULL;
/* check for error from remove/copy/move operations */
if (err != NULL) {
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
err = dav_push_error(r->pool, err->status, 0,
ap_psprintf(r->pool,
"Could not MOVE/COPY %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 MOVE/COPY was successful, but there was a "
"problem reverting the writability of the "
"source parent collection.",
err2);
dav_log_err(r, err, APLOG_WARNING);
}
if (err3 != NULL) {
/* just log a warning */
err = dav_push_error(r->pool, err3->status, 0,
"The MOVE/COPY was successful, but there was a "
"problem reverting the writability of the "
"destination parent collection.",
err3);
dav_log_err(r, err, APLOG_WARNING);
}
/* propagate any indirect locks at the target */
if (lockdb != NULL) {
int resource_state = dav_get_resource_state(lookup.rnew, resnew);
/* notify lock system that we have created/replaced a resource */
err = dav_notify_created(r, lockdb, resnew, resource_state, depth);
(*lockdb->hooks->close_lockdb)(lockdb);
if (err != NULL) {
/* The move/copy was successful, but the locking failed. */
err = dav_push_error(r->pool, err->status, 0,
"The MOVE/COPY was successful, but there "
"was a problem updating the lock "
"information.",
err);
return dav_handle_err(r, err, NULL);
}
}
/* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
return dav_created(r, lookup.rnew, resnew, "Destination", replaced);
}
/* dav_method_lock: Handler to implement the DAV LOCK method
** Returns appropriate HTTP_* response.
*/
static int dav_method_lock(request_rec *r)
{
dav_error *err;
dav_resource *resource;
const dav_hooks_locks *locks_hooks;
int result;
int depth;
int new_lock_request = 0;
dav_xml_doc *doc = NULL;
dav_lock *lock;
dav_response *multi_response = NULL;
dav_lockdb *lockdb;
int resource_state;
/* If no locks provider, decline the request */
locks_hooks = DAV_GET_HOOKS_LOCKS(r);
if (locks_hooks == NULL)
return DECLINED;
if ((result = dav_parse_input(r, &doc)) != OK)
return result;
depth = dav_get_depth(r, DAV_INFINITY);
if (depth != 0 && depth != DAV_INFINITY) {
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Depth must be 0 or \"infinity\" for LOCK.");
return HTTP_BAD_REQUEST;
}
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
/*
** Open writable. Unless an error occurs, we'll be
** writing into the database.
*/
if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
if (doc != NULL) {
if ((err = dav_lock_parse_lockinfo(r, resource, lockdb, doc,
&lock)) != NULL) {
/* ### add a higher-level description to err? */
goto error;
}
new_lock_request = 1;
lock->auth_user = ap_pstrdup(r->pool, r->user);
}
resource_state = dav_get_resource_state(r, resource);
/*
** Check If-Headers and existing locks.
**
** If this will create a locknull resource, then the LOCK will affect
** the parent collection (much like a PUT/MKCOL). For that case, we must
** validate the parent resource's conditions.
*/
if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response,
(resource_state == DAV_RESOURCE_NULL
? DAV_VALIDATE_PARENT
: DAV_VALIDATE_RESOURCE)
| (new_lock_request ? lock->scope : 0)
| DAV_VALIDATE_ADD_LD,
lockdb)) != OK) {
err = dav_push_error(r->pool, err->status, 0,
ap_psprintf(r->pool,
"Could not LOCK %s due to a failed "
"precondition (e.g. other locks).",
ap_escape_html(r->pool, r->uri)),
err);
goto error;
}
if (new_lock_request == 0) {
dav_locktoken_list *ltl;
/*
** Refresh request
** ### Assumption: We can renew multiple locks on the same resource
** ### at once. First harvest all the positive lock-tokens given in
** ### the If header. Then modify the lock entries for this resource
** ### with the new Timeout val.
*/
if ((err = dav_get_locktoken_list(r, &ltl)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
ap_psprintf(r->pool,
"The lock refresh for %s failed "
"because no lock tokens were "
"specified in an \"If:\" "
"header.",
ap_escape_html(r->pool, r->uri)),
err);
goto error;
}
if ((err = (*locks_hooks->refresh_locks)(lockdb, resource, ltl,
dav_get_timeout(r),
&lock)) != NULL) {
/* ### add a higher-level description to err? */
goto error;
}
} else {
/* New lock request */
char *locktoken_txt;
dav_dir_conf *conf;
conf = (dav_dir_conf *) ap_get_module_config(r->per_dir_config,
&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 = ap_pstrcat(r->pool, "<",
(*locks_hooks->format_locktoken)(r->pool, lock->locktoken),
">", NULL);
ap_table_set(r->headers_out, "Lock-Token", locktoken_txt);
}
(*locks_hooks->close_lockdb)(lockdb);
r->status = HTTP_OK;
r->content_type = DAV_XML_CONTENT_TYPE;
ap_send_http_header(r);
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 = ap_table_get(r->headers_in, "Lock-Token")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Unlock failed (%s): No Lock-Token specified in header", r->filename);
return HTTP_BAD_REQUEST;
}
locktoken_txt = ap_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,
ap_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 */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
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;
}
/* handle the SEARCH method from DASL */
static int dav_method_search(request_rec *r)
{
/* ### we know this method, but we won't allow it yet */
/* Apache will supply a default error for this. */
return HTTP_METHOD_NOT_ALLOWED;
/* Do some error checking, like if the querygrammar is
* supported by the content type, and then pass the
* request on to the appropriate query module.
*/
}
/* handle the CHECKOUT method */
static int dav_method_checkout(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;
/* ### eventually check body for DAV:checkin-policy */
if ((result = ap_discard_request_body(r)) != OK) {
return result;
}
/* Ask repository module to resolve the resource */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
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) {
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)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
ap_psprintf(r->pool,
"Could not CHECKOUT 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);
ap_send_http_header(r);
return DONE;
}
/* 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 */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
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,
ap_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);
ap_send_http_header(r);
return DONE;
}
/* handle the CHECKIN method */
static int dav_method_checkin(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 */
result = dav_get_resource(r, &resource);
if (result != OK)
return result;
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 to the workspace.");
}
/* ### do lock checks, once behavior is defined */
/* Do the checkin */
if ((err = (*vsn_hooks->checkin)(resource)) != NULL) {
err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
ap_psprintf(r->pool,
"Could not CHECKIN 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);
ap_send_http_header(r);
return DONE;
}
/*
* Response handler for DAV resources
*/
static int dav_handler(request_rec *r)
{
dav_dir_conf *conf;
/* 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
| (1 << M_GET)
| (1 << M_PUT)
| (1 << M_DELETE)
| (1 << M_OPTIONS)
| (1 << M_INVALID);
/*
* These are the DAV methods we handle.
*/
r->allowed |= 0
| (1 << M_COPY)
| (1 << M_LOCK)
| (1 << M_UNLOCK)
| (1 << M_MKCOL)
| (1 << M_MOVE)
| (1 << M_PROPFIND)
| (1 << 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
| (1 << 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);
}
/*
* NOTE: When Apache moves creates defines for the add'l DAV methods,
* then it will no longer use M_INVALID. This code must be
* updated each time Apache adds method defines.
*/
if (r->method_number != M_INVALID) {
return DECLINED;
}
if (!strcmp(r->method, "SEARCH")) {
return dav_method_search(r);
}
if (!strcmp(r->method, "CHECKOUT")) {
return dav_method_checkout(r);
}
if (!strcmp(r->method, "UNCHECKOUT")) {
return dav_method_uncheckout(r);
}
if (!strcmp(r->method, "CHECKIN")) {
return dav_method_checkin(r);
}
#if 0
if (!strcmp(r->method, "MKRESOURCE")) {
return dav_method_mkresource(r);
}
if (!strcmp(r->method, "REPORT")) {
return dav_method_report(r);
}
#endif
/* ### add'l methods for Advanced Collections, ACLs, DASL */
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->enabled != DAV_ENABLED_ON) {
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->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(void)
{
ap_hook_post_config(dav_init_handler, NULL, NULL, AP_HOOK_MIDDLE);
ap_hook_type_checker(dav_type_checker, NULL, NULL, AP_HOOK_MIDDLE);
}
/*---------------------------------------------------------------------------
**
** Configuration info for the module
*/
static const command_rec dav_cmds[] =
{
{
"DAV",
dav_cmd_dav,
NULL,
ACCESS_CONF, /* per directory/location */
FLAG,
"turn DAV on/off for a directory or location"
},
{
"DAVLockDB",
dav_cmd_davlockdb,
NULL,
RSRC_CONF, /* per server */
TAKE1,
"specify a lock database"
},
{
"DAVMinTimeout",
dav_cmd_davmintimeout,
NULL,
ACCESS_CONF|RSRC_CONF, /* per directory/location, or per server */
TAKE1,
"specify minimum allowed timeout"
},
{
"DAVDepthInfinity",
dav_cmd_davdepthinfinity,
NULL,
ACCESS_CONF|RSRC_CONF, /* per directory/location, or per server */
FLAG,
"allow Depth infinity PROPFIND requests"
},
{
"DAVParam",
dav_cmd_davparam,
NULL,
ACCESS_CONF|RSRC_CONF, /* per directory/location, or per server */
TAKE2,
"DAVParam <parameter name> <parameter value>"
},
{
"LimitXMLRequestBody",
dav_cmd_limitxmlrequestbody,
NULL,
ACCESS_CONF|RSRC_CONF, /* per directory/location, or per server */
TAKE1,
"Limit (in bytes) on maximum size of an XML-based request body"
},
{ NULL }
};
static const handler_rec dav_handlers[] =
{
{"dav-handler", dav_handler},
{ NULL }
};
module MODULE_VAR_EXPORT 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 */
dav_handlers, /* handlers */
register_hooks, /* register hooks */
};