summaryrefslogtreecommitdiffstats
path: root/rubbos/app/httpd-2.0.64/modules/dav/main
diff options
context:
space:
mode:
authorhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
committerhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
commitc0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch)
tree5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/httpd-2.0.64/modules/dav/main
parentb6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff)
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2 Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/dav/main')
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/.deps0
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/Makefile8
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/Makefile.in3
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/NWGNUmakefile268
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/config5.m422
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/dav.imp64
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/liveprop.c140
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.c4834
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.dsp164
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.h2420
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/modules.mk3
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/props.c1116
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/providers.c33
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/std_liveprop.c194
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/util.c2021
-rw-r--r--rubbos/app/httpd-2.0.64/modules/dav/main/util_lock.c791
16 files changed, 0 insertions, 12081 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/.deps b/rubbos/app/httpd-2.0.64/modules/dav/main/.deps
deleted file mode 100644
index e69de29b..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/.deps
+++ /dev/null
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile b/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile
deleted file mode 100644
index 509e3634..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-top_srcdir = /bottlenecks/rubbos/app/httpd-2.0.64
-top_builddir = /bottlenecks/rubbos/app/httpd-2.0.64
-srcdir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/main
-builddir = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/main
-VPATH = /bottlenecks/rubbos/app/httpd-2.0.64/modules/dav/main
-# a modules Makefile has no explicit targets -- they will be defined by
-# whatever modules are enabled. just grab special.mk to deal with this.
-include $(top_srcdir)/build/special.mk
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile.in b/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile.in
deleted file mode 100644
index 7c5c149d..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/Makefile.in
+++ /dev/null
@@ -1,3 +0,0 @@
-# a modules Makefile has no explicit targets -- they will be defined by
-# whatever modules are enabled. just grab special.mk to deal with this.
-include $(top_srcdir)/build/special.mk
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/NWGNUmakefile b/rubbos/app/httpd-2.0.64/modules/dav/main/NWGNUmakefile
deleted file mode 100644
index 8546d6a3..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/NWGNUmakefile
+++ /dev/null
@@ -1,268 +0,0 @@
-#
-# Declare the sub-directories to be built here
-#
-
-SUBDIRS = \
- $(EOLIST)
-
-#
-# Get the 'head' of the build environment. This includes default targets and
-# paths to tools
-#
-
-include $(AP_WORK)\build\NWGNUhead.inc
-
-#
-# build this level's files
-#
-# Make sure all needed macro's are defined
-#
-
-#
-# These directories will be at the beginning of the include list, followed by
-# INCDIRS
-#
-XINCDIRS += \
- $(APR)/include \
- $(APRUTIL)/include \
- $(AP_WORK)/include \
- $(AP_WORK)/server/mpm/NetWare \
- $(NWOS) \
- $(EOLIST)
-
-#
-# These flags will come after CFLAGS
-#
-XCFLAGS += \
- $(EOLIST)
-
-#
-# These defines will come after DEFINES
-#
-XDEFINES += \
- $(EOLIST)
-
-#
-# These flags will be added to the link.opt file
-#
-XLFLAGS += \
- $(EOLIST)
-
-#
-# These values will be appended to the correct variables based on the value of
-# RELEASE
-#
-ifeq "$(RELEASE)" "debug"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "noopt"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-ifeq "$(RELEASE)" "release"
-XINCDIRS += \
- $(EOLIST)
-
-XCFLAGS += \
- $(EOLIST)
-
-XDEFINES += \
- $(EOLIST)
-
-XLFLAGS += \
- $(EOLIST)
-endif
-
-#
-# These are used by the link target if an NLM is being generated
-# This is used by the link 'name' directive to name the nlm. If left blank
-# TARGET_nlm (see below) will be used.
-#
-NLM_NAME = mod_DAV
-
-#
-# This is used by the link '-desc ' directive.
-# If left blank, NLM_NAME will be used.
-#
-NLM_DESCRIPTION = Apache $(VERSION_STR) DAV module
-
-#
-# This is used by the '-threadname' directive. If left blank,
-# NLM_NAME Thread will be used.
-#
-NLM_THREAD_NAME = mod_DAV
-
-#
-# If this is specified, it will override VERSION value in
-# $(AP_WORK)\build\NWGNUenvironment.inc
-#
-NLM_VERSION =
-
-#
-# If this is specified, it will override the default of 64K
-#
-NLM_STACK_SIZE = 65536
-
-
-#
-# If this is specified it will be used by the link '-entry' directive
-#
-NLM_ENTRY_SYM = _LibCPrelude
-
-#
-# If this is specified it will be used by the link '-exit' directive
-#
-NLM_EXIT_SYM = _LibCPostlude
-
-#
-# If this is specified it will be used by the link '-check' directive
-#
-NLM_CHECK_SYM =
-
-#
-# If this is specified it will be used by the link '-flags' directive
-#
-NLM_FLAGS = AUTOUNLOAD, PSEUDOPREEMPTION
-
-#
-# If this is specified it will be linked in with the XDCData option in the def
-# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
-# by setting APACHE_UNIPROC in the environment
-#
-XDCDATA =
-
-#
-# Declare all target files (you must add your files here)
-#
-
-#
-# If there is an NLM target, put it here
-#
-TARGET_nlm = \
- $(OBJDIR)/mod_dav.nlm \
- $(EOLIST)
-
-#
-# If there is an LIB target, put it here
-#
-TARGET_lib = \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the NLM target above.
-# Paths must all use the '/' character
-#
-FILES_nlm_objs = \
- $(OBJDIR)/mod_dav.o \
- $(OBJDIR)/props.o \
- $(OBJDIR)/util.o \
- $(OBJDIR)/util_lock.o \
- $(OBJDIR)/liveprop.o \
- $(OBJDIR)/providers.o \
- $(OBJDIR)/std_liveprop.o \
- $(EOLIST)
-
-#
-# These are the LIB files needed to create the NLM target above.
-# These will be added as a library command in the link.opt file.
-#
-FILES_nlm_libs = \
- libcpre.o \
- $(EOLIST)
-
-#
-# These are the modules that the above NLM target depends on to load.
-# These will be added as a module command in the link.opt file.
-#
-FILES_nlm_modules = \
- Apache2 \
- Libc \
- $(EOLIST)
-
-#
-# If the nlm has a msg file, put it's path here
-#
-FILE_nlm_msg =
-
-#
-# If the nlm has a hlp file put it's path here
-#
-FILE_nlm_hlp =
-
-#
-# If this is specified, it will override $(NWOS)\copyright.txt.
-#
-FILE_nlm_copyright =
-
-#
-# Any additional imports go here
-#
-FILES_nlm_Ximports = \
- @libc.imp \
- @$(APR)/aprlib.imp \
- @httpd.imp \
- $(EOLIST)
-
-#
-# Any symbols exported to here
-#
-FILES_nlm_exports = \
- dav_module \
- @dav.imp \
- $(EOLIST)
-
-#
-# These are the OBJ files needed to create the LIB target above.
-# Paths must all use the '/' character
-#
-FILES_lib_objs = \
- $(EOLIST)
-
-#
-# implement targets and dependancies (leave this section alone)
-#
-
-libs :: $(OBJDIR) $(TARGET_lib)
-
-nlms :: libs $(TARGET_nlm)
-
-#
-# Updated this target to create necessary directories and copy files to the
-# correct place. (See $(AP_WORK)\build\NWGNUhead.inc for examples)
-#
-install :: nlms FORCE
- copy $(OBJDIR)\mod_dav.nlm $(INSTALL)\Apache2\modules\*.*
-
-#
-# Any specialized rules here
-#
-
-#
-# Include the 'tail' makefile that has targets that depend on variables defined
-# in this makefile
-#
-
-include $(AP_WORK)\build\NWGNUtail.inc
-
-
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/config5.m4 b/rubbos/app/httpd-2.0.64/modules/dav/main/config5.m4
deleted file mode 100644
index fa2eee47..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/config5.m4
+++ /dev/null
@@ -1,22 +0,0 @@
-dnl modules enabled in this directory by default
-
-APACHE_MODPATH_INIT(dav/main)
-
-dav_objects="mod_dav.lo props.lo util.lo util_lock.lo liveprop.lo providers.lo std_liveprop.lo"
-
-if test "$enable_http" = "no"; then
- dav_enable=no
-else
- dav_enable=most
-fi
-
-APACHE_MODULE(dav, WebDAV protocol handling, $dav_objects, , $dav_enable)
-
-if test "$dav_enable" != "no" -o "$enable_dav" != "no"; then
- apache_need_expat=yes
-
- APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
-fi
-
-
-APACHE_MODPATH_FINISH
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/dav.imp b/rubbos/app/httpd-2.0.64/modules/dav/main/dav.imp
deleted file mode 100644
index 88b306da..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/dav.imp
+++ /dev/null
@@ -1,64 +0,0 @@
-
- (mod_dav)
- dav_add_all_liveprop_xmlns,
- dav_add_lock,
- dav_add_response,
- dav_add_vary_header,
- dav_auto_checkin,
- dav_auto_checkout,
- dav_buffer_append,
- dav_buffer_init,
- dav_buffer_place,
- dav_buffer_place_mem,
- dav_check_bufsize,
- dav_close_propdb,
- dav_core_find_liveprop,
- dav_core_insert_all_liveprops,
- dav_core_register_uris,
- dav_do_find_liveprop,
- dav_find_child,
- dav_get_allprops,
- dav_get_binding_hooks,
- dav_get_depth,
- dav_get_liveprop_info,
- dav_get_liveprop_ns_count,
- dav_get_liveprop_ns_index,
- dav_get_liveprop_supported,
- dav_get_lock_hooks,
- dav_get_locktoken_list,
- dav_get_propdb_hooks,
- dav_get_props,
- dav_get_resource_state,
- dav_get_search_hooks,
- dav_get_timeout,
- dav_get_vsn_hooks,
- dav_hook_find_liveprop,
- dav_hook_gather_propsets,
- dav_hook_insert_all_liveprops,
- dav_lock_get_activelock,
- dav_lock_parse_lockinfo,
- dav_lock_query,
- dav_lookup_provider,
- dav_lookup_uri,
- dav_new_error,
- dav_new_error_tag,
- dav_notify_created,
- dav_open_propdb,
- dav_prop_commit,
- dav_prop_exec,
- dav_prop_rollback,
- dav_prop_validate,
- dav_push_error,
- dav_register_liveprop_group,
- dav_register_provider,
- dav_set_bufsize,
- dav_unlock,
- dav_validate_request,
- dav_validate_root,
- dav_xml_get_cdata,
- dav_xmlns_add,
- dav_xmlns_add_uri,
- dav_xmlns_create,
- dav_xmlns_generate,
- dav_xmlns_get_prefix,
- dav_xmlns_get_uri
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/liveprop.c b/rubbos/app/httpd-2.0.64/modules/dav/main/liveprop.c
deleted file mode 100644
index 88461a80..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/liveprop.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "apr_pools.h"
-#include "apr_hash.h"
-#include "apr_errno.h"
-#include "apr_strings.h"
-#include "util_xml.h" /* for apr_text_header */
-#include "mod_dav.h"
-
-
-static apr_hash_t *dav_liveprop_uris = NULL;
-static int dav_liveprop_count = 0;
-
-
-static apr_status_t dav_cleanup_liveprops(void *ctx)
-{
- dav_liveprop_uris = NULL;
- dav_liveprop_count = 0;
- return APR_SUCCESS;
-}
-
-static void dav_register_liveprop_namespace(apr_pool_t *p, const char *uri)
-{
- int value;
-
- if (dav_liveprop_uris == NULL) {
- dav_liveprop_uris = apr_hash_make(p);
- apr_pool_cleanup_register(p, NULL, dav_cleanup_liveprops, apr_pool_cleanup_null);
- }
-
- value = (int)apr_hash_get(dav_liveprop_uris, uri, APR_HASH_KEY_STRING);
- if (value != 0) {
- /* already registered */
- return;
- }
-
- /* start at 1, and count up */
- apr_hash_set(dav_liveprop_uris, uri, APR_HASH_KEY_STRING,
- (void *)++dav_liveprop_count);
-}
-
-DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri)
-{
- return (int)apr_hash_get(dav_liveprop_uris, uri, APR_HASH_KEY_STRING);
-}
-
-DAV_DECLARE(int) dav_get_liveprop_ns_count(void)
-{
- return dav_liveprop_count;
-}
-
-DAV_DECLARE(void) dav_add_all_liveprop_xmlns(apr_pool_t *p,
- apr_text_header *phdr)
-{
- apr_hash_index_t *idx = apr_hash_first(p, dav_liveprop_uris);
-
- for ( ; idx != NULL; idx = apr_hash_next(idx) ) {
- const void *key;
- void *val;
- const char *s;
-
- apr_hash_this(idx, &key, NULL, &val);
-
- s = apr_psprintf(p, " xmlns:lp%d=\"%s\"", (int)val, (const char *)key);
- apr_text_append(p, phdr, s);
- }
-}
-
-DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name,
- const dav_liveprop_group *group,
- const dav_hooks_liveprop **hooks)
-{
- const char * const *uris = group->namespace_uris;
- const dav_liveprop_spec *scan;
- int ns;
-
- /* first: locate the namespace in the namespace table */
- for (ns = 0; uris[ns] != NULL; ++ns)
- if (strcmp(ns_uri, uris[ns]) == 0)
- break;
- if (uris[ns] == NULL) {
- /* not our property (the namespace matched none of ours) */
- return 0;
- }
-
- /* second: look for the property in the liveprop specs */
- for (scan = group->specs; scan->name != NULL; ++scan)
- if (ns == scan->ns && strcmp(name, scan->name) == 0) {
- *hooks = group->hooks;
- return scan->propid;
- }
-
- /* not our property (same namespace, but no matching prop name) */
- return 0;
-}
-
-DAV_DECLARE(int) dav_get_liveprop_info(int propid,
- const dav_liveprop_group *group,
- const dav_liveprop_spec **info)
-{
- const dav_liveprop_spec *scan;
-
- for (scan = group->specs; scan->name != NULL; ++scan) {
- if (scan->propid == propid) {
- *info = scan;
-
- /* map the provider-local NS into a global NS index */
- return dav_get_liveprop_ns_index(group->namespace_uris[scan->ns]);
- }
- }
-
- /* assert: should not reach this point */
- *info = NULL;
- return 0;
-}
-
-DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *p,
- const dav_liveprop_group *group)
-{
- /* register the namespace URIs */
- const char * const * uris = group->namespace_uris;
-
- for ( ; *uris != NULL; ++uris) {
- dav_register_liveprop_namespace(p, *uris);
- }
-}
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.c b/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.c
deleted file mode 100644
index 3d3b47bb..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.c
+++ /dev/null
@@ -1,4834 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * DAV extension module for Apache 2.0.*
- *
- * This module is repository-independent. It depends on hooks provided by a
- * repository implementation.
- *
- * APACHE ISSUES:
- * - within a DAV hierarchy, if an unknown method is used and we default
- * to Apache's implementation, it sends back an OPTIONS with the wrong
- * set of methods -- there is NO HOOK for us.
- * therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED
- * and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).
- * - process_mkcol_body() had to dup code from ap_setup_client_block().
- * - it would be nice to get status lines from Apache for arbitrary
- * status codes
- * - it would be nice to be able to extend Apache's set of response
- * codes so that it doesn't return 500 when an unknown code is placed
- * into r->status.
- * - http_vhost functions should apply "const" to their params
- *
- * DESIGN NOTES:
- * - For PROPFIND, we batch up the entire response in memory before
- * sending it. We may want to reorganize around sending the information
- * as we suck it in from the propdb. Alternatively, we should at least
- * generate a total Content-Length if we're going to buffer in memory
- * so that we can keep the connection open.
- */
-
-#include "apr_strings.h"
-#include "apr_lib.h" /* for apr_is* */
-
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-#include "httpd.h"
-#include "http_config.h"
-#include "http_core.h"
-#include "http_log.h"
-#include "http_main.h"
-#include "http_protocol.h"
-#include "http_request.h"
-#include "util_script.h"
-
-#include "mod_dav.h"
-
-
-/* ### what is the best way to set this? */
-#define DAV_DEFAULT_PROVIDER "filesystem"
-
-/* used to denote that mod_dav will be handling this request */
-#define DAV_HANDLER_NAME "dav-handler"
-
-enum {
- DAV_ENABLED_UNSET = 0,
- DAV_ENABLED_OFF,
- DAV_ENABLED_ON
-};
-
-/* per-dir configuration */
-typedef struct {
- const char *provider_name;
- const dav_provider *provider;
- const char *dir;
- int locktimeout;
- int allow_depthinfinity;
-
-} dav_dir_conf;
-
-/* per-server configuration */
-typedef struct {
- int unused;
-
-} dav_server_conf;
-
-#define DAV_INHERIT_VALUE(parent, child, field) \
- ((child)->field ? (child)->field : (parent)->field)
-
-
-/* forward-declare for use in configuration lookup */
-extern module DAV_DECLARE_DATA dav_module;
-
-/* DAV methods */
-enum {
- DAV_M_BIND = 0,
- DAV_M_SEARCH,
- DAV_M_LAST
-};
-static int dav_methods[DAV_M_LAST];
-
-
-static int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
- server_rec *s)
-{
- /* DBG0("dav_init_handler"); */
-
- /* Register DAV methods */
- dav_methods[DAV_M_BIND] = ap_method_register(p, "BIND");
- dav_methods[DAV_M_SEARCH] = ap_method_register(p, "SEARCH");
-
- ap_add_version_component(p, "DAV/2");
-
- return OK;
-}
-
-static void *dav_create_server_config(apr_pool_t *p, server_rec *s)
-{
- dav_server_conf *newconf;
-
- newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
-
- /* ### this isn't used at the moment... */
-
- return newconf;
-}
-
-static void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides)
-{
-#if 0
- dav_server_conf *child = overrides;
-#endif
- dav_server_conf *newconf;
-
- newconf = (dav_server_conf *)apr_pcalloc(p, sizeof(*newconf));
-
- /* ### nothing to merge right now... */
-
- return newconf;
-}
-
-static void *dav_create_dir_config(apr_pool_t *p, char *dir)
-{
- /* NOTE: dir==NULL creates the default per-dir config */
-
- dav_dir_conf *conf;
-
- conf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*conf));
-
- /* clean up the directory to remove any trailing slash */
- if (dir != NULL) {
- char *d;
- apr_size_t l;
-
- d = apr_pstrdup(p, dir);
- l = strlen(d);
- if (l > 1 && d[l - 1] == '/')
- d[l - 1] = '\0';
- conf->dir = d;
- }
-
- return conf;
-}
-
-static void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
-{
- dav_dir_conf *parent = base;
- dav_dir_conf *child = overrides;
- dav_dir_conf *newconf = (dav_dir_conf *)apr_pcalloc(p, sizeof(*newconf));
-
- /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx",
- (long)newconf, (long)base, (long)overrides); */
-
- newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name);
- newconf->provider = DAV_INHERIT_VALUE(parent, child, provider);
- if (parent->provider_name != NULL) {
- if (child->provider_name == NULL) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
- "\"DAV Off\" cannot be used to turn off a subtree "
- "of a DAV-enabled location.");
- }
- else if (strcasecmp(child->provider_name,
- parent->provider_name) != 0) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
- "A subtree cannot specify a different DAV provider "
- "than its parent.");
- }
- }
-
- newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout);
- newconf->dir = DAV_INHERIT_VALUE(parent, child, dir);
- newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child,
- allow_depthinfinity);
-
- return newconf;
-}
-
-static const dav_provider *dav_get_provider(request_rec *r)
-{
- dav_dir_conf *conf;
-
- conf = ap_get_module_config(r->per_dir_config, &dav_module);
- /* assert: conf->provider_name != NULL
- (otherwise, DAV is disabled, and we wouldn't be here) */
-
- /* assert: conf->provider != NULL
- (checked when conf->provider_name is set) */
- return conf->provider;
-}
-
-DAV_DECLARE(const dav_hooks_locks *) dav_get_lock_hooks(request_rec *r)
-{
- return dav_get_provider(r)->locks;
-}
-
-DAV_DECLARE(const dav_hooks_propdb *) dav_get_propdb_hooks(request_rec *r)
-{
- return dav_get_provider(r)->propdb;
-}
-
-DAV_DECLARE(const dav_hooks_vsn *) dav_get_vsn_hooks(request_rec *r)
-{
- return dav_get_provider(r)->vsn;
-}
-
-DAV_DECLARE(const dav_hooks_binding *) dav_get_binding_hooks(request_rec *r)
-{
- return dav_get_provider(r)->binding;
-}
-
-DAV_DECLARE(const dav_hooks_search *) dav_get_search_hooks(request_rec *r)
-{
- return dav_get_provider(r)->search;
-}
-
-/*
- * Command handler for the DAV directive, which is TAKE1.
- */
-static const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1)
-{
- dav_dir_conf *conf = (dav_dir_conf *)config;
-
- if (strcasecmp(arg1, "on") == 0) {
- conf->provider_name = DAV_DEFAULT_PROVIDER;
- }
- else if (strcasecmp(arg1, "off") == 0) {
- conf->provider_name = NULL;
- conf->provider = NULL;
- }
- else {
- conf->provider_name = apr_pstrdup(cmd->pool, arg1);
- }
-
- if (conf->provider_name != NULL) {
- /* lookup and cache the actual provider now */
- conf->provider = dav_lookup_provider(conf->provider_name);
-
- if (conf->provider == NULL) {
- /* by the time they use it, the provider should be loaded and
- registered with us. */
- return apr_psprintf(cmd->pool,
- "Unknown DAV provider: %s",
- conf->provider_name);
- }
- }
-
- return NULL;
-}
-
-/*
- * Command handler for the DAVDepthInfinity directive, which is FLAG.
- */
-static const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config,
- int arg)
-{
- dav_dir_conf *conf = (dav_dir_conf *)config;
-
- if (arg)
- conf->allow_depthinfinity = DAV_ENABLED_ON;
- else
- conf->allow_depthinfinity = DAV_ENABLED_OFF;
- return NULL;
-}
-
-/*
- * Command handler for DAVMinTimeout directive, which is TAKE1
- */
-static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config,
- const char *arg1)
-{
- dav_dir_conf *conf = (dav_dir_conf *)config;
-
- conf->locktimeout = atoi(arg1);
- if (conf->locktimeout < 0)
- return "DAVMinTimeout requires a non-negative integer.";
-
- return NULL;
-}
-
-/*
-** dav_error_response()
-**
-** Send a nice response back to the user. In most cases, Apache doesn't
-** allow us to provide details in the body about what happened. This
-** function allows us to completely specify the response body.
-**
-** ### this function is not logging any errors! (e.g. the body)
-*/
-static int dav_error_response(request_rec *r, int status, const char *body)
-{
- r->status = status;
-
- /* ### I really don't think this is needed; gotta test */
- r->status_line = ap_get_status_line(status);
-
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
-
- /* begin the response now... */
- ap_rvputs(r,
- DAV_RESPONSE_BODY_1,
- r->status_line,
- DAV_RESPONSE_BODY_2,
- &r->status_line[4],
- DAV_RESPONSE_BODY_3,
- body,
- DAV_RESPONSE_BODY_4,
- ap_psignature("<hr />\n", r),
- DAV_RESPONSE_BODY_5,
- NULL);
-
- /* the response has been sent. */
- /*
- * ### Use of DONE obviates logging..!
- */
- return DONE;
-}
-
-
-/*
- * Send a "standardized" error response based on the error's namespace & tag
- */
-static int dav_error_response_tag(request_rec *r,
- dav_error *err)
-{
- r->status = err->status;
-
- /* ### I really don't think this is needed; gotta test */
- r->status_line = ap_get_status_line(err->status);
-
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
-
- ap_rputs(DAV_XML_HEADER DEBUG_CR
- "<D:error xmlns:D=\"DAV:\"", r);
-
- if (err->desc != NULL) {
- /* ### should move this namespace somewhere (with the others!) */
- ap_rputs(" xmlns:m=\"http://apache.org/dav/xmlns\"", r);
- }
-
- if (err->namespace != NULL) {
- ap_rprintf(r,
- " xmlns:C=\"%s\">" DEBUG_CR
- "<C:%s/>" DEBUG_CR,
- err->namespace, err->tagname);
- }
- else {
- ap_rprintf(r,
- ">" DEBUG_CR
- "<D:%s/>" DEBUG_CR, err->tagname);
- }
-
- /* here's our mod_dav specific tag: */
- if (err->desc != NULL) {
- ap_rprintf(r,
- "<m:human-readable errcode=\"%d\">" DEBUG_CR
- "%s" DEBUG_CR
- "</m:human-readable>" DEBUG_CR,
- err->error_id,
- apr_xml_quote_string(r->pool, err->desc, 0));
- }
-
- ap_rputs("</D:error>" DEBUG_CR, r);
-
- /* the response has been sent. */
- /*
- * ### Use of DONE obviates logging..!
- */
- return DONE;
-}
-
-
-/*
- * Apache's URI escaping does not replace '&' since that is a valid character
- * in a URI (to form a query section). We must explicitly handle it so that
- * we can embed the URI into an XML document.
- */
-static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
-{
- const char *e_uri = ap_escape_uri(p, uri);
-
- /* check the easy case... */
- if (ap_strchr_c(e_uri, '&') == NULL)
- return e_uri;
-
- /* there was a '&', so more work is needed... sigh. */
-
- /*
- * Note: this is a teeny bit of overkill since we know there are no
- * '<' or '>' characters, but who cares.
- */
- return apr_xml_quote_string(p, e_uri, 0);
-}
-
-
-/* Write a complete RESPONSE object out as a <DAV:repsonse> xml
- element. Data is sent into brigade BB, which is auto-flushed into
- OUTPUT filter stack. Use POOL for any temporary allocations.
-
- [Presumably the <multistatus> tag has already been written; this
- routine is shared by dav_send_multistatus and dav_stream_response.]
-*/
-static void dav_send_one_response(dav_response *response,
- apr_bucket_brigade *bb,
- ap_filter_t *output,
- apr_pool_t *pool)
-{
- apr_text *t = NULL;
-
- if (response->propresult.xmlns == NULL) {
- ap_fputs(output, bb, "<D:response>");
- }
- else {
- ap_fputs(output, bb, "<D:response");
- for (t = response->propresult.xmlns; t; t = t->next) {
- ap_fputs(output, bb, t->text);
- }
- ap_fputc(output, bb, '>');
- }
-
- ap_fputstrs(output, bb,
- DEBUG_CR "<D:href>",
- dav_xml_escape_uri(pool, response->href),
- "</D:href>" DEBUG_CR,
- NULL);
-
- if (response->propresult.propstats == NULL) {
- /* use the Status-Line text from Apache. Note, this will
- * default to 500 Internal Server Error if first->status
- * is not a known (or valid) status code.
- */
- ap_fputstrs(output, bb,
- "<D:status>HTTP/1.1 ",
- ap_get_status_line(response->status),
- "</D:status>" DEBUG_CR,
- NULL);
- }
- else {
- /* assume this includes <propstat> and is quoted properly */
- for (t = response->propresult.propstats; t; t = t->next) {
- ap_fputs(output, bb, t->text);
- }
- }
-
- if (response->desc != NULL) {
- /*
- * We supply the description, so we know it doesn't have to
- * have any escaping/encoding applied to it.
- */
- ap_fputstrs(output, bb,
- "<D:responsedescription>",
- response->desc,
- "</D:responsedescription>" DEBUG_CR,
- NULL);
- }
-
- ap_fputs(output, bb, "</D:response>" DEBUG_CR);
-}
-
-
-/* Factorized helper function: prep request_rec R for a multistatus
- response and write <multistatus> tag into BB, destined for
- R->output_filters. Use xml NAMESPACES in initial tag, if
- non-NULL. */
-static void dav_begin_multistatus(apr_bucket_brigade *bb,
- request_rec *r, int status,
- apr_array_header_t *namespaces)
-{
- /* Set the correct status and Content-Type */
- r->status = status;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
-
- /* Send the headers and actual multistatus response now... */
- ap_fputs(r->output_filters, bb, DAV_XML_HEADER DEBUG_CR
- "<D:multistatus xmlns:D=\"DAV:\"");
-
- if (namespaces != NULL) {
- int i;
-
- for (i = namespaces->nelts; i--; ) {
- ap_fprintf(r->output_filters, bb, " xmlns:ns%d=\"%s\"", i,
- APR_XML_GET_URI_ITEM(namespaces, i));
- }
- }
-
- ap_fputs(r->output_filters, bb, ">" DEBUG_CR);
-}
-
-/* Finish a multistatus response started by dav_begin_multistatus: */
-static apr_status_t dav_finish_multistatus(request_rec *r,
- apr_bucket_brigade *bb)
-{
- apr_bucket *b;
-
- ap_fputs(r->output_filters, bb, "</D:multistatus>" DEBUG_CR);
-
- /* indicate the end of the response body */
- b = apr_bucket_eos_create(r->connection->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, b);
-
- /* deliver whatever might be remaining in the brigade */
- return ap_pass_brigade(r->output_filters, bb);
-}
-
-static void dav_send_multistatus(request_rec *r, int status,
- dav_response *first,
- apr_array_header_t *namespaces)
-{
- apr_pool_t *subpool;
- apr_bucket_brigade *bb = apr_brigade_create(r->pool,
- r->connection->bucket_alloc);
-
- dav_begin_multistatus(bb, r, status, namespaces);
-
- apr_pool_create(&subpool, r->pool);
-
- for (; first != NULL; first = first->next) {
- apr_pool_clear(subpool);
- dav_send_one_response(first, bb, r->output_filters, subpool);
- }
- apr_pool_destroy(subpool);
-
- dav_finish_multistatus(r, bb);
-}
-
-/*
- * dav_log_err()
- *
- * Write error information to the log.
- */
-static void dav_log_err(request_rec *r, dav_error *err, int level)
-{
- dav_error *errscan;
-
- /* Log the errors */
- /* ### should have a directive to log the first or all */
- for (errscan = err; errscan != NULL; errscan = errscan->prev) {
- if (errscan->desc == NULL)
- continue;
-
- if (errscan->save_errno != 0) {
- errno = errscan->save_errno;
- ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
- errscan->desc, errscan->status, errscan->error_id);
- }
- else {
- ap_log_rerror(APLOG_MARK, level, 0, r,
- "%s [%d, #%d]",
- errscan->desc, errscan->status, errscan->error_id);
- }
- }
-}
-
-/*
- * dav_handle_err()
- *
- * Handle the standard error processing. <err> must be non-NULL.
- *
- * <response> is set by the following:
- * - dav_validate_request()
- * - dav_add_lock()
- * - repos_hooks->remove_resource
- * - repos_hooks->move_resource
- * - repos_hooks->copy_resource
- * - vsn_hooks->update
- */
-static int dav_handle_err(request_rec *r, dav_error *err,
- dav_response *response)
-{
- /* log the errors */
- dav_log_err(r, err, APLOG_ERR);
-
- if (response == NULL) {
- dav_error *stackerr = err;
-
- /* our error messages are safe; tell Apache this */
- apr_table_setn(r->notes, "verbose-error-to", "*");
-
- /* Didn't get a multistatus response passed in, but we still
- might be able to generate a standard <D:error> response.
- Search the error stack for an errortag. */
- while (stackerr != NULL && stackerr->tagname == NULL)
- stackerr = stackerr->prev;
-
- if (stackerr != NULL && stackerr->tagname != NULL)
- return dav_error_response_tag(r, stackerr);
-
- return err->status;
- }
-
- /* send the multistatus and tell Apache the request/response is DONE. */
- dav_send_multistatus(r, err->status, response, NULL);
- return DONE;
-}
-
-/* handy function for return values of methods that (may) create things */
-static int dav_created(request_rec *r, const char *locn, const char *what,
- int replaced)
-{
- const char *body;
-
- if (locn == NULL) {
- locn = r->uri;
- }
-
- /* did the target resource already exist? */
- if (replaced) {
- /* Apache will supply a default message */
- return HTTP_NO_CONTENT;
- }
-
- /* Per HTTP/1.1, S10.2.2: add a Location header to contain the
- * URI that was created. */
-
- /* Convert locn to an absolute URI, and return in Location header */
- apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r));
-
- /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
-
- /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
- * we must manufacture the entire response. */
- body = apr_psprintf(r->pool, "%s %s has been created.",
- what, ap_escape_html(r->pool, locn));
- return dav_error_response(r, HTTP_CREATED, body);
-}
-
-/* ### move to dav_util? */
-DAV_DECLARE(int) dav_get_depth(request_rec *r, int def_depth)
-{
- const char *depth = apr_table_get(r->headers_in, "Depth");
-
- if (depth == NULL) {
- return def_depth;
- }
-
- if (strcasecmp(depth, "infinity") == 0) {
- return DAV_INFINITY;
- }
- else if (strcmp(depth, "0") == 0) {
- return 0;
- }
- else if (strcmp(depth, "1") == 0) {
- return 1;
- }
-
- /* The caller will return an HTTP_BAD_REQUEST. This will augment the
- * default message that Apache provides. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "An invalid Depth header was specified.");
- return -1;
-}
-
-static int dav_get_overwrite(request_rec *r)
-{
- const char *overwrite = apr_table_get(r->headers_in, "Overwrite");
-
- if (overwrite == NULL) {
- return 1; /* default is "T" */
- }
-
- if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
- return 0;
- }
-
- if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
- return 1;
- }
-
- /* The caller will return an HTTP_BAD_REQUEST. This will augment the
- * default message that Apache provides. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "An invalid Overwrite header was specified.");
- return -1;
-}
-
-/* resolve a request URI to a resource descriptor.
- *
- * If label_allowed != 0, then allow the request target to be altered by
- * a Label: header.
- *
- * If use_checked_in is true, then the repository provider should return
- * the resource identified by the DAV:checked-in property of the resource
- * identified by the Request-URI.
- */
-static dav_error *dav_get_resource(request_rec *r, int label_allowed,
- int use_checked_in, dav_resource **res_p)
-{
- dav_dir_conf *conf;
- const char *label = NULL;
- dav_error *err;
-
- /* if the request target can be overridden, get any target selector */
- if (label_allowed) {
- label = apr_table_get(r->headers_in, "label");
- }
-
- conf = ap_get_module_config(r->per_dir_config, &dav_module);
- /* assert: conf->provider != NULL */
-
- /* resolve the resource */
- err = (*conf->provider->repos->get_resource)(r, conf->dir,
- label, use_checked_in,
- res_p);
- if (err != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- "Could not fetch resource information.", err);
- return err;
- }
-
- /* Note: this shouldn't happen, but just be sure... */
- if (*res_p == NULL) {
- /* ### maybe use HTTP_INTERNAL_SERVER_ERROR */
- return dav_new_error(r->pool, HTTP_NOT_FOUND, 0,
- apr_psprintf(r->pool,
- "The provider did not define a "
- "resource for %s.",
- ap_escape_html(r->pool, r->uri)));
- }
-
- /* ### hmm. this doesn't feel like the right place or thing to do */
- /* if there were any input headers requiring a Vary header in the response,
- * add it now */
- dav_add_vary_header(r, r, *res_p);
-
- return NULL;
-}
-
-static dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
-{
- const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
-
- if (hooks == NULL) {
- *lockdb = NULL;
- return NULL;
- }
-
- /* open the thing lazily */
- return (*hooks->open_lockdb)(r, ro, 0, lockdb);
-}
-
-static int dav_parse_range(request_rec *r,
- apr_off_t *range_start, apr_off_t *range_end)
-{
- const char *range_c;
- char *range;
- char *dash;
- char *slash;
-
- range_c = apr_table_get(r->headers_in, "content-range");
- if (range_c == NULL)
- return 0;
-
- range = apr_pstrdup(r->pool, range_c);
- if (strncasecmp(range, "bytes ", 6) != 0
- || (dash = ap_strchr(range, '-')) == NULL
- || (slash = ap_strchr(range, '/')) == NULL) {
- /* malformed header. ignore it (per S14.16 of RFC2616) */
- return 0;
- }
-
- *dash = *slash = '\0';
-
- *range_start = apr_atoi64(range + 6);
- *range_end = apr_atoi64(dash + 1);
-
- if (*range_end < *range_start
- || (slash[1] != '*' && apr_atoi64(slash + 1) <= *range_end)) {
- /* invalid range. ignore it (per S14.16 of RFC2616) */
- return 0;
- }
-
- /* we now have a valid range */
- return 1;
-}
-
-/* handle the GET method */
-static int dav_method_get(request_rec *r)
-{
- dav_resource *resource;
- dav_error *err;
-
- /* This method should only be called when the resource is not
- * visible to Apache. We will fetch the resource from the repository,
- * then create a subrequest for Apache to handle.
- */
- err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* set up the HTTP headers for the response */
- if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- "Unable to set up HTTP headers.",
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- if (r->header_only) {
- return DONE;
- }
-
- /* okay... time to deliver the content */
- if ((err = (*resource->hooks->deliver)(resource,
- r->output_filters)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- "Unable to deliver content.",
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- return DONE;
-}
-
-/* validate resource/locks on POST, then pass to the default handler */
-static int dav_method_post(request_rec *r)
-{
- dav_resource *resource;
- dav_error *err;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* 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);
- }
-
- return DECLINED;
-}
-
-/* handle the PUT method */
-static int dav_method_put(request_rec *r)
-{
- dav_resource *resource;
- int resource_state;
- dav_auto_version_info av_info;
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- const char *body;
- dav_error *err;
- dav_error *err2;
- dav_stream_mode mode;
- dav_stream *stream;
- dav_response *multi_response;
- int has_range;
- apr_off_t range_start;
- apr_off_t range_end;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* If not a file or collection resource, PUT not allowed */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR
- && resource->type != DAV_RESOURCE_TYPE_WORKING) {
- body = apr_psprintf(r->pool,
- "Cannot create resource %s with PUT.",
- ap_escape_html(r->pool, r->uri));
- return dav_error_response(r, HTTP_CONFLICT, body);
- }
-
- /* Cannot PUT a collection */
- if (resource->collection) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot PUT to a collection.");
-
- }
-
- resource_state = dav_get_resource_state(r, resource);
-
- /*
- * 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_response,
- 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_response);
- }
-
- /* make sure the resource can be modified (if versioning repository) */
- if ((err = dav_auto_checkout(r, resource,
- 0 /* not parent_only */,
- &av_info)) != NULL) {
- /* ### add a higher-level description? */
- return dav_handle_err(r, err, NULL);
- }
-
- /* truncate and rewrite the file unless we see a Content-Range */
- mode = DAV_MODE_WRITE_TRUNC;
-
- has_range = dav_parse_range(r, &range_start, &range_end);
- if (has_range) {
- mode = DAV_MODE_WRITE_SEEKABLE;
- }
-
- /* Create the new file in the repository */
- if ((err = (*resource->hooks->open_stream)(resource, mode,
- &stream)) != NULL) {
- /* ### assuming FORBIDDEN is probably not quite right... */
- err = dav_push_error(r->pool, HTTP_FORBIDDEN, 0,
- apr_psprintf(r->pool,
- "Unable to PUT new contents for %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- }
-
- if (err == NULL && has_range) {
- /* a range was provided. seek to the start */
- err = (*resource->hooks->seek_stream)(stream, range_start);
- }
-
- if (err == NULL) {
- apr_bucket_brigade *bb;
- apr_bucket *b;
- int seen_eos = 0;
-
- bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
-
- do {
- apr_status_t rc;
-
- rc = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
- APR_BLOCK_READ, DAV_READ_BLOCKSIZE);
-
- if (rc != APR_SUCCESS) {
- err = dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not get next bucket brigade");
- break;
- }
-
- for (b = APR_BRIGADE_FIRST(bb);
- b != APR_BRIGADE_SENTINEL(bb);
- b = APR_BUCKET_NEXT(b))
- {
- const char *data;
- apr_size_t len;
-
- if (APR_BUCKET_IS_EOS(b)) {
- seen_eos = 1;
- break;
- }
-
- if (APR_BUCKET_IS_METADATA(b)) {
- continue;
- }
-
- rc = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (rc != APR_SUCCESS) {
- err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
- "An error occurred while reading "
- "the request body.");
- break;
- }
-
- if (err == NULL) {
- /* write whatever we read, until we see an error */
- err = (*resource->hooks->write_stream)(stream, data, len);
- }
- }
-
- apr_brigade_cleanup(bb);
- } while (!seen_eos);
-
- apr_brigade_destroy(bb);
-
- err2 = (*resource->hooks->close_stream)(stream,
- err == NULL /* commit */);
- if (err2 != NULL && err == NULL) {
- /* no error during the write, but we hit one at close. use it. */
- err = err2;
- }
- }
-
- /*
- * Ensure that we think the resource exists now.
- * ### eek. if an error occurred during the write and we did not commit,
- * ### then the resource might NOT exist (e.g. dav_fs_repos.c)
- */
- if (err == NULL) {
- resource->exists = 1;
- }
-
- /* restore modifiability of resources back to what they were */
- err2 = dav_auto_checkin(r, resource, err != NULL /* undo if error */,
- 0 /*unlock*/, &av_info);
-
- /* check for errors now */
- if (err != NULL) {
- return dav_handle_err(r, err, NULL);
- }
-
- if (err2 != NULL) {
- /* just log a warning */
- err2 = dav_push_error(r->pool, err2->status, 0,
- "The PUT was successful, but there "
- "was a problem automatically checking in "
- "the resource or its parent collection.",
- err2);
- dav_log_err(r, err2, APLOG_WARNING);
- }
-
- /* ### place the Content-Type and Content-Language into the propdb */
-
- if (locks_hooks != NULL) {
- dav_lockdb *lockdb;
-
- if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
- /* The file creation was successful, but the locking failed. */
- err = dav_push_error(r->pool, err->status, 0,
- "The file was PUT successfully, 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 file creation was successful, but the locking failed. */
- err = dav_push_error(r->pool, err->status, 0,
- "The file was PUT successfully, but there "
- "was a problem updating its lock "
- "information.",
- err);
- return dav_handle_err(r, err, NULL);
- }
- }
-
- /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */
-
- /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */
- return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS);
-}
-
-
-/* Use POOL to temporarily construct a dav_response object (from WRES
- STATUS, and PROPSTATS) and stream it via WRES's ctx->brigade. */
-static void dav_stream_response(dav_walk_resource *wres,
- int status,
- dav_get_props_result *propstats,
- apr_pool_t *pool)
-{
- dav_response resp = { 0 };
- dav_walker_ctx *ctx = wres->walk_ctx;
-
- resp.href = wres->resource->uri;
- resp.status = status;
- if (propstats) {
- resp.propresult = *propstats;
- }
-
- dav_send_one_response(&resp, ctx->bb, ctx->r->output_filters, pool);
-}
-
-
-/* ### move this to dav_util? */
-DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres,
- int status, dav_get_props_result *propstats)
-{
- dav_response *resp;
-
- /* just drop some data into an dav_response */
- resp = apr_pcalloc(wres->pool, sizeof(*resp));
- resp->href = apr_pstrdup(wres->pool, wres->resource->uri);
- resp->status = status;
- if (propstats) {
- resp->propresult = *propstats;
- }
-
- resp->next = wres->response;
- wres->response = resp;
-}
-
-
-/* handle the DELETE method */
-static int dav_method_delete(request_rec *r)
-{
- dav_resource *resource;
- dav_auto_version_info av_info;
- dav_error *err;
- dav_error *err2;
- dav_response *multi_response;
- int result;
- int depth;
-
- /* We don't use the request body right now, so torch it. */
- if ((result = ap_discard_request_body(r)) != OK) {
- return result;
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* 2518 says that depth must be infinity only for collections.
- * For non-collections, depth is ignored, unless it is an illegal value (1).
- */
- depth = dav_get_depth(r, DAV_INFINITY);
-
- if (resource->collection && depth != DAV_INFINITY) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Depth must be \"infinity\" for DELETE of a collection.");
- return HTTP_BAD_REQUEST;
- }
-
- if (!resource->collection && depth == 1) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Depth of \"1\" is not allowed for DELETE.");
- return HTTP_BAD_REQUEST;
- }
-
- /*
- ** If any resources fail the lock/If: conditions, then we must fail
- ** the delete. Each of the failing resources will be listed within
- ** a DAV:multistatus body, wrapped into a 424 response.
- **
- ** Note that a failure on the resource itself does not generate a
- ** multistatus response -- only internal members/collections.
- */
- if ((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,
- apr_psprintf(r->pool,
- "Could not DELETE %s due to a failed "
- "precondition (e.g. locks).",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, multi_response);
- }
-
- /* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those
- * locked by the token(s) in the if_header.
- */
- if ((result = dav_unlock(r, resource, NULL)) != OK) {
- return result;
- }
-
- /* if versioned resource, make sure parent is checked out */
- if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
- &av_info)) != NULL) {
- /* ### add a higher-level description? */
- return dav_handle_err(r, err, NULL);
- }
-
- /* try to remove the resource */
- err = (*resource->hooks->remove_resource)(resource, &multi_response);
-
- /* restore writability of parent back to what it was */
- err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
- 0 /*unlock*/, &av_info);
-
- /* check for errors now */
- if (err != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not DELETE %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, multi_response);
- }
- if (err2 != NULL) {
- /* just log a warning */
- err = dav_push_error(r->pool, err2->status, 0,
- "The DELETE was successful, but there "
- "was a problem automatically checking in "
- "the parent collection.",
- err2);
- dav_log_err(r, err, APLOG_WARNING);
- }
-
- /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */
-
- /* Apache will supply a default error for this. */
- return HTTP_NO_CONTENT;
-}
-
-/* generate DAV:supported-method-set OPTIONS response */
-static dav_error *dav_gen_supported_methods(request_rec *r,
- const apr_xml_elem *elem,
- const apr_table_t *methods,
- apr_text_header *body)
-{
- const apr_array_header_t *arr;
- const apr_table_entry_t *elts;
- apr_xml_elem *child;
- apr_xml_attr *attr;
- char *s;
- int i;
-
- apr_text_append(r->pool, body, "<D:supported-method-set>" DEBUG_CR);
-
- if (elem->first_child == NULL) {
- /* show all supported methods */
- arr = apr_table_elts(methods);
- elts = (const apr_table_entry_t *)arr->elts;
-
- for (i = 0; i < arr->nelts; ++i) {
- if (elts[i].key == NULL)
- continue;
-
- s = apr_psprintf(r->pool,
- "<D:supported-method D:name=\"%s\"/>"
- DEBUG_CR,
- elts[i].key);
- apr_text_append(r->pool, body, s);
- }
- }
- else {
- /* check for support of specific methods */
- for (child = elem->first_child; child != NULL; child = child->next) {
- if (child->ns == APR_XML_NS_DAV_ID
- && strcmp(child->name, "supported-method") == 0) {
- const char *name = NULL;
-
- /* go through attributes to find method name */
- for (attr = child->attr; attr != NULL; attr = attr->next) {
- if (attr->ns == APR_XML_NS_DAV_ID
- && strcmp(attr->name, "name") == 0)
- name = attr->value;
- }
-
- if (name == NULL) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
- "A DAV:supported-method element "
- "does not have a \"name\" attribute");
- }
-
- /* see if method is supported */
- if (apr_table_get(methods, name) != NULL) {
- s = apr_psprintf(r->pool,
- "<D:supported-method D:name=\"%s\"/>"
- DEBUG_CR,
- name);
- apr_text_append(r->pool, body, s);
- }
- }
- }
- }
-
- apr_text_append(r->pool, body, "</D:supported-method-set>" DEBUG_CR);
- return NULL;
-}
-
-/* generate DAV:supported-live-property-set OPTIONS response */
-static dav_error *dav_gen_supported_live_props(request_rec *r,
- const dav_resource *resource,
- const apr_xml_elem *elem,
- apr_text_header *body)
-{
- dav_lockdb *lockdb;
- dav_propdb *propdb;
- apr_xml_elem *child;
- apr_xml_attr *attr;
- dav_error *err;
-
- /* open lock database, to report on supported lock properties */
- /* ### should open read-only */
- if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
- return dav_push_error(r->pool, err->status, 0,
- "The lock database could not be opened, "
- "preventing the reporting of supported lock "
- "properties.",
- err);
- }
-
- /* open the property database (readonly) for the resource */
- if ((err = dav_open_propdb(r, lockdb, resource, 1, NULL,
- &propdb)) != NULL) {
- if (lockdb != NULL)
- (*lockdb->hooks->close_lockdb)(lockdb);
-
- return dav_push_error(r->pool, err->status, 0,
- "The property database could not be opened, "
- "preventing report of supported properties.",
- err);
- }
-
- apr_text_append(r->pool, body, "<D:supported-live-property-set>" DEBUG_CR);
-
- if (elem->first_child == NULL) {
- /* show all supported live properties */
- dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED);
- body->last->next = props.propstats;
- while (body->last->next != NULL)
- body->last = body->last->next;
- }
- else {
- /* check for support of specific live property */
- for (child = elem->first_child; child != NULL; child = child->next) {
- if (child->ns == APR_XML_NS_DAV_ID
- && strcmp(child->name, "supported-live-property") == 0) {
- const char *name = NULL;
- const char *nmspace = NULL;
-
- /* go through attributes to find name and namespace */
- for (attr = child->attr; attr != NULL; attr = attr->next) {
- if (attr->ns == APR_XML_NS_DAV_ID) {
- if (strcmp(attr->name, "name") == 0)
- name = attr->value;
- else if (strcmp(attr->name, "namespace") == 0)
- nmspace = attr->value;
- }
- }
-
- if (name == NULL) {
- err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
- "A DAV:supported-live-property "
- "element does not have a \"name\" "
- "attribute");
- break;
- }
-
- /* default namespace to DAV: */
- if (nmspace == NULL)
- nmspace = "DAV:";
-
- /* check for support of property */
- dav_get_liveprop_supported(propdb, nmspace, name, body);
- }
- }
- }
-
- apr_text_append(r->pool, body, "</D:supported-live-property-set>" DEBUG_CR);
-
- dav_close_propdb(propdb);
-
- if (lockdb != NULL)
- (*lockdb->hooks->close_lockdb)(lockdb);
-
- return err;
-}
-
-/* generate DAV:supported-report-set OPTIONS response */
-static dav_error *dav_gen_supported_reports(request_rec *r,
- const dav_resource *resource,
- const apr_xml_elem *elem,
- const dav_hooks_vsn *vsn_hooks,
- apr_text_header *body)
-{
- apr_xml_elem *child;
- apr_xml_attr *attr;
- dav_error *err;
- char *s;
-
- apr_text_append(r->pool, body, "<D:supported-report-set>" DEBUG_CR);
-
- if (vsn_hooks != NULL) {
- const dav_report_elem *reports;
- const dav_report_elem *rp;
-
- if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) {
- return dav_push_error(r->pool, err->status, 0,
- "DAV:supported-report-set could not be "
- "determined due to a problem fetching the "
- "available reports for this resource.",
- err);
- }
-
- if (reports != NULL) {
- if (elem->first_child == NULL) {
- /* show all supported reports */
- for (rp = reports; rp->nmspace != NULL; ++rp) {
- /* Note: we presume reports->namespace is
- * properly XML/URL quoted */
- s = apr_psprintf(r->pool,
- "<D:supported-report D:name=\"%s\" "
- "D:namespace=\"%s\"/>" DEBUG_CR,
- rp->name, rp->nmspace);
- apr_text_append(r->pool, body, s);
- }
- }
- else {
- /* check for support of specific report */
- for (child = elem->first_child; child != NULL; child = child->next) {
- if (child->ns == APR_XML_NS_DAV_ID
- && strcmp(child->name, "supported-report") == 0) {
- const char *name = NULL;
- const char *nmspace = NULL;
-
- /* go through attributes to find name and namespace */
- for (attr = child->attr; attr != NULL; attr = attr->next) {
- if (attr->ns == APR_XML_NS_DAV_ID) {
- if (strcmp(attr->name, "name") == 0)
- name = attr->value;
- else if (strcmp(attr->name, "namespace") == 0)
- nmspace = attr->value;
- }
- }
-
- if (name == NULL) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
- "A DAV:supported-report element "
- "does not have a \"name\" attribute");
- }
-
- /* default namespace to DAV: */
- if (nmspace == NULL)
- nmspace = "DAV:";
-
- for (rp = reports; rp->nmspace != NULL; ++rp) {
- if (strcmp(name, rp->name) == 0
- && strcmp(nmspace, rp->nmspace) == 0) {
- /* Note: we presume reports->nmspace is
- * properly XML/URL quoted
- */
- s = apr_psprintf(r->pool,
- "<D:supported-report "
- "D:name=\"%s\" "
- "D:namespace=\"%s\"/>"
- DEBUG_CR,
- rp->name, rp->nmspace);
- apr_text_append(r->pool, body, s);
- break;
- }
- }
- }
- }
- }
- }
- }
-
- apr_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR);
- return NULL;
-}
-
-
-/* handle the SEARCH method */
-static int dav_method_search(request_rec *r)
-{
- const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
- dav_resource *resource;
- dav_error *err;
- dav_response *multi_status;
-
- /* If no search provider, decline the request */
- if (search_hooks == NULL)
- return DECLINED;
-
- /* This method should only be called when the resource is not
- * visible to Apache. We will fetch the resource from the repository,
- * then create a subrequest for Apache to handle.
- */
- err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* set up the HTTP headers for the response */
- if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- "Unable to set up HTTP headers.",
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- if (r->header_only) {
- return DONE;
- }
-
- /* okay... time to search the content */
- /* Let's validate XML and process walk function
- * in the hook function
- */
- if ((err = (*search_hooks->search_resource)(r, &multi_status)) != NULL) {
- /* ### add a higher-level description? */
- return dav_handle_err(r, err, NULL);
- }
-
- /* We have results in multi_status */
- /* Should I pass namespace?? */
- dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL);
-
- return DONE;
-}
-
-
-/* handle the OPTIONS method */
-static int dav_method_options(request_rec *r)
-{
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r);
- const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
- dav_resource *resource;
- const char *dav_level;
- char *allow;
- char *s;
- const apr_array_header_t *arr;
- const apr_table_entry_t *elts;
- apr_table_t *methods = apr_table_make(r->pool, 12);
- apr_text_header vsn_options = { 0 };
- apr_text_header body = { 0 };
- apr_text *t;
- int text_size;
- int result;
- int i;
- apr_array_header_t *uri_ary;
- apr_xml_doc *doc;
- const apr_xml_elem *elem;
- dav_error *err;
-
- /* resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* parse any request body */
- if ((result = ap_xml_parse_input(r, &doc)) != OK) {
- return result;
- }
- /* note: doc == NULL if no request body */
-
- if (doc && !dav_validate_root(doc, "options")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The \"options\" element was not found.");
- return HTTP_BAD_REQUEST;
- }
-
- /* determine which providers are available */
- dav_level = "1";
-
- if (locks_hooks != NULL) {
- dav_level = "1,2";
- }
-
- if (binding_hooks != NULL)
- dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL);
-
- /* ###
- * MSFT Web Folders chokes if length of DAV header value > 63 characters!
- * To workaround that, we use separate DAV headers for versioning and
- * live prop provider namespace URIs.
- * ###
- */
- apr_table_setn(r->headers_out, "DAV", dav_level);
-
- /*
- * If there is a versioning provider, generate DAV headers
- * for versioning options.
- */
- if (vsn_hooks != NULL) {
- (*vsn_hooks->get_vsn_options)(r->pool, &vsn_options);
-
- for (t = vsn_options.first; t != NULL; t = t->next)
- apr_table_addn(r->headers_out, "DAV", t->text);
- }
-
- /*
- * Gather property set URIs from all the liveprop providers,
- * and generate a separate DAV header for each URI, to avoid
- * problems with long header lengths.
- */
- uri_ary = apr_array_make(r->pool, 5, sizeof(const char *));
- dav_run_gather_propsets(uri_ary);
- for (i = 0; i < uri_ary->nelts; ++i) {
- if (((char **)uri_ary->elts)[i] != NULL)
- apr_table_addn(r->headers_out, "DAV", ((char **)uri_ary->elts)[i]);
- }
-
- /* this tells MSFT products to skip looking for FrontPage extensions */
- apr_table_setn(r->headers_out, "MS-Author-Via", "DAV");
-
- /*
- * Determine which methods are allowed on the resource.
- * Three cases: resource is null (3), is lock-null (7.4), or exists.
- *
- * All cases support OPTIONS, and if there is a lock provider, LOCK.
- * (Lock-) null resources also support MKCOL and PUT.
- * Lock-null supports PROPFIND and UNLOCK.
- * Existing resources support lots of stuff.
- */
-
- apr_table_addn(methods, "OPTIONS", "");
-
- /* ### take into account resource type */
- switch (dav_get_resource_state(r, resource))
- {
- case DAV_RESOURCE_EXISTS:
- /* resource exists */
- apr_table_addn(methods, "GET", "");
- apr_table_addn(methods, "HEAD", "");
- apr_table_addn(methods, "POST", "");
- apr_table_addn(methods, "DELETE", "");
- apr_table_addn(methods, "TRACE", "");
- apr_table_addn(methods, "PROPFIND", "");
- apr_table_addn(methods, "PROPPATCH", "");
- apr_table_addn(methods, "COPY", "");
- apr_table_addn(methods, "MOVE", "");
-
- if (!resource->collection)
- apr_table_addn(methods, "PUT", "");
-
- if (locks_hooks != NULL) {
- apr_table_addn(methods, "LOCK", "");
- apr_table_addn(methods, "UNLOCK", "");
- }
-
- break;
-
- case DAV_RESOURCE_LOCK_NULL:
- /* resource is lock-null. */
- apr_table_addn(methods, "MKCOL", "");
- apr_table_addn(methods, "PROPFIND", "");
- apr_table_addn(methods, "PUT", "");
-
- if (locks_hooks != NULL) {
- apr_table_addn(methods, "LOCK", "");
- apr_table_addn(methods, "UNLOCK", "");
- }
-
- break;
-
- case DAV_RESOURCE_NULL:
- /* resource is null. */
- apr_table_addn(methods, "MKCOL", "");
- apr_table_addn(methods, "PUT", "");
-
- if (locks_hooks != NULL)
- apr_table_addn(methods, "LOCK", "");
-
- break;
-
- default:
- /* ### internal error! */
- break;
- }
-
- /* If there is a versioning provider, add versioning methods */
- if (vsn_hooks != NULL) {
- if (!resource->exists) {
- if ((*vsn_hooks->versionable)(resource))
- apr_table_addn(methods, "VERSION-CONTROL", "");
-
- if (vsn_hooks->can_be_workspace != NULL
- && (*vsn_hooks->can_be_workspace)(resource))
- apr_table_addn(methods, "MKWORKSPACE", "");
-
- if (vsn_hooks->can_be_activity != NULL
- && (*vsn_hooks->can_be_activity)(resource))
- apr_table_addn(methods, "MKACTIVITY", "");
- }
- else if (!resource->versioned) {
- if ((*vsn_hooks->versionable)(resource))
- apr_table_addn(methods, "VERSION-CONTROL", "");
- }
- else if (resource->working) {
- apr_table_addn(methods, "CHECKIN", "");
-
- /* ### we might not support this DeltaV option */
- apr_table_addn(methods, "UNCHECKOUT", "");
- }
- else if (vsn_hooks->add_label != NULL) {
- apr_table_addn(methods, "CHECKOUT", "");
- apr_table_addn(methods, "LABEL", "");
- }
- else {
- apr_table_addn(methods, "CHECKOUT", "");
- }
- }
-
- /* If there is a bindings provider, see if resource is bindable */
- if (binding_hooks != NULL
- && (*binding_hooks->is_bindable)(resource)) {
- apr_table_addn(methods, "BIND", "");
- }
-
- /* If there is a search provider, set SEARCH in option */
- if (search_hooks != NULL) {
- apr_table_addn(methods, "SEARCH", "");
- }
-
- /* Generate the Allow header */
- arr = apr_table_elts(methods);
- elts = (const apr_table_entry_t *)arr->elts;
- text_size = 0;
-
- /* first, compute total length */
- for (i = 0; i < arr->nelts; ++i) {
- if (elts[i].key == NULL)
- continue;
-
- /* add 1 for comma or null */
- text_size += strlen(elts[i].key) + 1;
- }
-
- s = allow = apr_palloc(r->pool, text_size);
-
- for (i = 0; i < arr->nelts; ++i) {
- if (elts[i].key == NULL)
- continue;
-
- if (s != allow)
- *s++ = ',';
-
- strcpy(s, elts[i].key);
- s += strlen(s);
- }
-
- apr_table_setn(r->headers_out, "Allow", allow);
-
-
- /* If there is search set_option_head function, set head */
- /* DASL: <DAV:basicsearch>
- * DASL: <http://foo.bar.com/syntax1>
- * DASL: <http://akuma.com/syntax2>
- */
- if (search_hooks != NULL
- && *search_hooks->set_option_head != NULL) {
- if ((err = (*search_hooks->set_option_head)(r)) != NULL) {
- return dav_handle_err(r, err, NULL);
- }
- }
-
- /* if there was no request body, then there is no response body */
- if (doc == NULL) {
- ap_set_content_length(r, 0);
-
- /* ### this sends a Content-Type. the default OPTIONS does not. */
-
- /* ### the default (ap_send_http_options) returns OK, but I believe
- * ### that is because it is the default handler and nothing else
- * ### will run after the thing. */
- return DONE;
- }
-
- /* handle each options request */
- for (elem = doc->root->first_child; elem != NULL; elem = elem->next) {
- /* check for something we recognize first */
- int core_option = 0;
- dav_error *err = NULL;
-
- if (elem->ns == APR_XML_NS_DAV_ID) {
- if (strcmp(elem->name, "supported-method-set") == 0) {
- err = dav_gen_supported_methods(r, elem, methods, &body);
- core_option = 1;
- }
- else if (strcmp(elem->name, "supported-live-property-set") == 0) {
- err = dav_gen_supported_live_props(r, resource, elem, &body);
- core_option = 1;
- }
- else if (strcmp(elem->name, "supported-report-set") == 0) {
- err = dav_gen_supported_reports(r, resource, elem, vsn_hooks, &body);
- core_option = 1;
- }
- }
-
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* if unrecognized option, pass to versioning provider */
- if (!core_option && vsn_hooks != NULL) {
- if ((err = (*vsn_hooks->get_option)(resource, elem, &body))
- != NULL) {
- return dav_handle_err(r, err, NULL);
- }
- }
- }
-
- /* send the options response */
- r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
-
- /* send the headers and response body */
- ap_rputs(DAV_XML_HEADER DEBUG_CR
- "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r);
-
- for (t = body.first; t != NULL; t = t->next)
- ap_rputs(t->text, r);
-
- ap_rputs("</D:options-response>" DEBUG_CR, r);
-
- /* we've sent everything necessary to the client. */
- return DONE;
-}
-
-static void dav_cache_badprops(dav_walker_ctx *ctx)
-{
- const apr_xml_elem *elem;
- apr_text_header hdr = { 0 };
-
- /* just return if we built the thing already */
- if (ctx->propstat_404 != NULL) {
- return;
- }
-
- apr_text_append(ctx->w.pool, &hdr,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" DEBUG_CR);
-
- elem = dav_find_child(ctx->doc->root, "prop");
- for (elem = elem->first_child; elem; elem = elem->next) {
- apr_text_append(ctx->w.pool, &hdr,
- apr_xml_empty_elem(ctx->w.pool, elem));
- }
-
- apr_text_append(ctx->w.pool, &hdr,
- "</D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
- "</D:propstat>" DEBUG_CR);
-
- ctx->propstat_404 = hdr.first;
-}
-
-static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype)
-{
- dav_walker_ctx *ctx = wres->walk_ctx;
- dav_error *err;
- dav_propdb *propdb;
- dav_get_props_result propstats = { 0 };
-
- /*
- ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since
- ** dav_get_allprops() does not need to do namespace translation,
- ** we're okay.
- **
- ** Note: we cast to lose the "const". The propdb won't try to change
- ** the resource, however, since we are opening readonly.
- */
- err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1,
- ctx->doc ? ctx->doc->namespaces : NULL, &propdb);
- if (err != NULL) {
- /* ### do something with err! */
-
- if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
- dav_get_props_result badprops = { 0 };
-
- /* some props were expected on this collection/resource */
- dav_cache_badprops(ctx);
- badprops.propstats = ctx->propstat_404;
- dav_stream_response(wres, 0, &badprops, ctx->scratchpool);
- }
- else {
- /* no props on this collection/resource */
- dav_stream_response(wres, HTTP_OK, NULL, ctx->scratchpool);
- }
-
- apr_pool_clear(ctx->scratchpool);
- return NULL;
- }
- /* ### what to do about closing the propdb on server failure? */
-
- if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) {
- propstats = dav_get_props(propdb, ctx->doc);
- }
- else {
- dav_prop_insert what = ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP
- ? DAV_PROP_INSERT_VALUE
- : DAV_PROP_INSERT_NAME;
- propstats = dav_get_allprops(propdb, what);
- }
- dav_close_propdb(propdb);
-
- dav_stream_response(wres, 0, &propstats, ctx->scratchpool);
-
- /* at this point, ctx->scratchpool has been used to stream a
- single response. this function fully controls the pool, and
- thus has the right to clear it for the next iteration of this
- callback. */
- apr_pool_clear(ctx->scratchpool);
-
- return NULL;
-}
-
-/* handle the PROPFIND method */
-static int dav_method_propfind(request_rec *r)
-{
- dav_resource *resource;
- int depth;
- dav_error *err;
- int result;
- apr_xml_doc *doc;
- const apr_xml_elem *child;
- dav_walker_ctx ctx = { { 0 } };
- dav_response *multi_status;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (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 && resource->collection) {
- 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,
- apr_psprintf(r->pool,
- "PROPFIND requests with a "
- "Depth of \"infinity\" are "
- "not allowed for %s.",
- ap_escape_html(r->pool,
- r->uri)));
- }
- }
-
- if ((result = ap_xml_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, 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, 0, r,
- "The \"propfind\" element does not contain one of "
- "the required child elements (the specific command).");
- return HTTP_BAD_REQUEST;
- }
-
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH;
- ctx.w.func = dav_propfind_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = resource;
-
- ctx.doc = doc;
- ctx.r = r;
- ctx.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- apr_pool_create(&ctx.scratchpool, r->pool);
-
- /* ### should open read-only */
- if ((err = dav_open_lockdb(r, 0, &ctx.w.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.w.lockdb != NULL) {
- /* if we have a lock database, then we can walk locknull resources */
- ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL;
- }
-
- /* send <multistatus> tag, with all doc->namespaces attached. */
-
- /* NOTE: we *cannot* leave out the doc's namespaces from the
- initial <multistatus> tag. if a 404 was generated for an HREF,
- then we need to spit out the doc's namespaces for use by the
- 404. Note that <response> elements will override these ns0,
- ns1, etc, but NOT within the <response> scope for the
- badprops. */
- dav_begin_multistatus(ctx.bb, r, HTTP_MULTI_STATUS,
- doc ? doc->namespaces : NULL);
-
- /* Have the provider walk the resource. */
- err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
-
- if (ctx.w.lockdb != NULL) {
- (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb);
- }
-
- if (err != NULL) {
- /* If an error occurred during the resource walk, there's
- basically nothing we can do but abort the connection and
- log an error. This is one of the limitations of HTTP; it
- needs to "know" the entire status of the response before
- generating it, which is just impossible in these streamy
- response situations. */
- err = dav_push_error(r->pool, err->status, 0,
- "Provider encountered an error while streaming"
- " a multistatus PROPFIND response.", err);
- dav_log_err(r, err, APLOG_ERR);
- r->connection->aborted = 1;
- return DONE;
- }
-
- dav_finish_multistatus(r, ctx.bb);
- ap_filter_flush(ctx.bb, r->output_filters);
-
- /* the response has been sent. */
- return DONE;
-}
-
-static apr_text * dav_failed_proppatch(apr_pool_t *p,
- apr_array_header_t *prop_ctx)
-{
- apr_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 ) {
- apr_text_append(p, &hdr,
- "<D:propstat>" DEBUG_CR
- "<D:prop>");
- apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
- apr_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 = apr_psprintf(p,
- "<D:status>"
- "HTTP/1.1 %d (status)"
- "</D:status>" DEBUG_CR,
- ctx->err->status);
- apr_text_append(p, &hdr, s);
-
- /* ### we should use compute_desc if necessary... */
- if (ctx->err->desc != NULL) {
- apr_text_append(p, &hdr, "<D:responsedescription>" DEBUG_CR);
- apr_text_append(p, &hdr, ctx->err->desc);
- apr_text_append(p, &hdr, "</D:responsedescription>" DEBUG_CR);
- }
-
- apr_text_append(p, &hdr, "</D:propstat>" DEBUG_CR);
- }
-
- return hdr.first;
-}
-
-static apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx)
-{
- apr_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.
- */
-
- apr_text_append(p, &hdr,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" DEBUG_CR);
-
- for ( ; i-- > 0; ++ctx ) {
- apr_text_append(p, &hdr, apr_xml_empty_elem(p, ctx->prop));
- }
-
- apr_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),
- apr_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;
- apr_xml_doc *doc;
- apr_xml_elem *child;
- dav_propdb *propdb;
- int failure = 0;
- dav_response resp = { 0 };
- apr_text *propstat_text;
- apr_array_header_t *ctx_list;
- dav_prop_ctx *ctx;
- dav_auto_version_info av_info;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- if ((result = ap_xml_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, 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);
- }
-
- /* make sure the resource can be modified (if versioning repository) */
- if ((err = dav_auto_checkout(r, resource,
- 0 /* not parent_only */,
- &av_info)) != 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) {
- /* undo any auto-checkout */
- dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
-
- err = dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_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 = apr_array_make(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;
- apr_xml_elem *prop_group;
- apr_xml_elem *one_prop;
-
- /* Ignore children that are not set/remove */
- if (child->ns != APR_XML_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);
-
- /* undo any auto-checkout */
- dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
-
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 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 *)apr_array_push(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);
-
- /* complete any auto-versioning */
- dav_auto_checkin(r, resource, failure, 0 /*unlock*/, &av_info);
-
- /* 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 = apr_table_get(r->headers_in, "Transfer-Encoding");
- const char *lenp = apr_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, 0, r,
- "Unknown Transfer-Encoding %s", tenc);
- return HTTP_NOT_IMPLEMENTED;
- }
-
- r->read_chunked = 1;
- }
- else if (lenp) {
- const char *pos = lenp;
-
- while (apr_isdigit(*pos) || apr_isspace(*pos)) {
- ++pos;
- }
-
- if (*pos != '\0') {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Invalid Content-Length %s", lenp);
- return HTTP_BAD_REQUEST;
- }
-
- r->remaining = apr_atoi64(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_auto_version_info av_info;
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- dav_error *err;
- dav_error *err2;
- int result;
- dav_dir_conf *conf;
- 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 */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (resource->exists) {
- /* 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_auto_checkout(r, resource, 1 /* parent_only */,
- &av_info)) != 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)(resource);
-
- /* restore modifiability of parent back to what it was */
- err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
- 0 /*unlock*/, &av_info);
-
- /* 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, err2->status, 0,
- "The MKCOL was successful, but there "
- "was a problem automatically checking in "
- "the 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, "Collection", 0);
-}
-
-/* handle the COPY and MOVE methods */
-static int dav_method_copymove(request_rec *r, int is_move)
-{
- dav_resource *resource;
- dav_resource *resnew;
- dav_auto_version_info src_av_info = { 0 };
- dav_auto_version_info dst_av_info = { 0 };
- 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 replace_dest;
- int resnew_state;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, !is_move /* label_allowed */,
- 0 /* use_checked_in */, &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* If not a file or collection resource, COPY/MOVE not allowed */
- /* ### allow COPY/MOVE of DeltaV resource types */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
- body = apr_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 = apr_table_get(r->headers_in, "Destination");
- if (dest == NULL) {
- /* Look in headers provided by Netscape's Roaming Profiles */
- const char *nscp_host = apr_table_get(r->headers_in, "Host");
- const char *nscp_path = apr_table_get(r->headers_in, "New-uri");
-
- if (nscp_host != NULL && nscp_path != NULL)
- dest = apr_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, 0, r,
- "The request is missing a Destination header.");
- return HTTP_BAD_REQUEST;
- }
-
- lookup = dav_lookup_uri(dest, r, 1 /* must_be_absolute */);
- if (lookup.rnew == NULL) {
- if (lookup.err.status == HTTP_BAD_REQUEST) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "%s", 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) {
- const char *auth = apr_table_get(lookup.rnew->err_headers_out,
- "WWW-Authenticate");
- if (lookup.rnew->status == HTTP_UNAUTHORIZED && auth != NULL) {
- /* propagate the WWW-Authorization header up from the
- * subreq so the client sees it. */
- apr_table_set(r->err_headers_out, "WWW-Authenticate",
- apr_pstrdup(r->pool, auth));
- }
-
- /* ### how best to report this... */
- return dav_error_response(r, lookup.rnew->status,
- "Destination URI had an error.");
- }
-
- /* Resolve destination resource */
- err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
- 0 /* use_checked_in */, &resnew);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* 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, 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, 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,
- apr_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,
- apr_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);
- }
-
- /* if this is a move, then the source parent collection will be modified */
- if (is_move) {
- if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
- &src_av_info)) != NULL) {
- if (lockdb != NULL)
- (*lockdb->hooks->close_lockdb)(lockdb);
-
- /* ### add a higher-level description? */
- return dav_handle_err(r, err, NULL);
- }
- }
-
- /*
- * Remember the initial state of the destination, so the lock system
- * can be notified as to how it changed.
- */
- resnew_state = dav_get_resource_state(lookup.rnew, resnew);
-
- /* In a MOVE operation, the destination is replaced by the source.
- * In a COPY operation, if the destination exists, is under version
- * control, and is the same resource type as the source,
- * then it should not be replaced, but modified to be a copy of
- * the source.
- */
- if (!resnew->exists)
- replace_dest = 0;
- else if (is_move || !resource->versioned)
- replace_dest = 1;
- else if (resource->type != resnew->type)
- replace_dest = 1;
- else if ((resource->collection == 0) != (resnew->collection == 0))
- replace_dest = 1;
- else
- replace_dest = 0;
-
- /* If the destination must be created or replaced,
- * make sure the parent collection is writable
- */
- if (!resnew->exists || replace_dest) {
- if ((err = dav_auto_checkout(r, resnew, 1 /*parent_only*/,
- &dst_av_info)) != NULL) {
- /* could not make destination writable:
- * if move, restore state of source parent
- */
- if (is_move) {
- (void)dav_auto_checkin(r, NULL, 1 /* undo */,
- 0 /*unlock*/, &src_av_info);
- }
-
- 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 resource object, so status updates to one are reflected
- * in the other, when doing auto-versioning. Otherwise,
- * we may try to checkin the parent twice.
- */
- if (src_av_info.parent_resource != NULL
- && dst_av_info.parent_resource != NULL
- && (*src_av_info.parent_resource->hooks->is_same_resource)
- (src_av_info.parent_resource, dst_av_info.parent_resource)) {
-
- dst_av_info.parent_resource = src_av_info.parent_resource;
- }
-
- /* If destination is being replaced, remove it first
- * (we know Ovewrite must be TRUE). Then try to copy/move the resource.
- */
- if (replace_dest)
- 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);
- }
-
- /* perform any auto-versioning cleanup */
- err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
- 0 /*unlock*/, &dst_av_info);
-
- if (is_move) {
- err3 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
- 0 /*unlock*/, &src_av_info);
- }
- 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,
- apr_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 auto-versioning */
- 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 automatically checking in 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 automatically checking in the "
- "destination or its parent collection.",
- err3);
- dav_log_err(r, err, APLOG_WARNING);
- }
-
- /* propagate any indirect locks at the target */
- if (lockdb != NULL) {
-
- /* notify lock system that we have created/replaced a resource */
- err = dav_notify_created(r, lockdb, resnew, resnew_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->uri, "Destination",
- resnew_state == DAV_RESOURCE_EXISTS);
-}
-
-/* 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;
- apr_xml_doc *doc;
- 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 = ap_xml_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, 0, r,
- "Depth must be 0 or \"infinity\" for LOCK.");
- return HTTP_BAD_REQUEST;
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /*
- * 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 = apr_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,
- apr_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,
- apr_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 = apr_pstrcat(r->pool, "<",
- (*locks_hooks->format_locktoken)(r->pool,
- lock->locktoken),
- ">", NULL);
-
- apr_table_set(r->headers_out, "Lock-Token", locktoken_txt);
- }
-
- (*locks_hooks->close_lockdb)(lockdb);
-
- r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
-
- ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r);
- if (lock == NULL)
- ap_rputs("<D:lockdiscovery/>" DEBUG_CR, r);
- else {
- ap_rprintf(r,
- "<D:lockdiscovery>" DEBUG_CR
- "%s" DEBUG_CR
- "</D:lockdiscovery>" DEBUG_CR,
- dav_lock_get_activelock(r, lock, NULL));
- }
- ap_rputs("</D:prop>", r);
-
- /* the response has been sent. */
- return DONE;
-
- error:
- (*locks_hooks->close_lockdb)(lockdb);
- return dav_handle_err(r, err, multi_response);
-}
-
-/* dav_method_unlock: Handler to implement the DAV UNLOCK method
- * Returns appropriate HTTP_* response.
- */
-static int dav_method_unlock(request_rec *r)
-{
- dav_error *err;
- dav_resource *resource;
- const dav_hooks_locks *locks_hooks;
- int result;
- const char *const_locktoken_txt;
- char *locktoken_txt;
- dav_locktoken *locktoken = NULL;
- int resource_state;
- dav_response *multi_response;
-
- /* If no locks provider, decline the request */
- locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- if (locks_hooks == NULL)
- return DECLINED;
-
- if ((const_locktoken_txt = apr_table_get(r->headers_in,
- "Lock-Token")) == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Unlock failed (%s): "
- "No Lock-Token specified in header", r->filename);
- return HTTP_BAD_REQUEST;
- }
-
- locktoken_txt = apr_pstrdup(r->pool, const_locktoken_txt);
- if (locktoken_txt[0] != '<') {
- /* ### should provide more specifics... */
- return HTTP_BAD_REQUEST;
- }
- locktoken_txt++;
-
- if (locktoken_txt[strlen(locktoken_txt) - 1] != '>') {
- /* ### should provide more specifics... */
- return HTTP_BAD_REQUEST;
- }
- locktoken_txt[strlen(locktoken_txt) - 1] = '\0';
-
- if ((err = (*locks_hooks->parse_locktoken)(r->pool, locktoken_txt,
- &locktoken)) != NULL) {
- err = dav_push_error(r->pool, HTTP_BAD_REQUEST, 0,
- apr_psprintf(r->pool,
- "The UNLOCK on %s failed -- an "
- "invalid lock token was specified "
- "in the \"If:\" header.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- resource_state = dav_get_resource_state(r, resource);
-
- /*
- * Check If-Headers and existing locks.
- *
- * Note: depth == 0 normally requires no multistatus response. However,
- * if we pass DAV_VALIDATE_PARENT, then we could get an error on a URI
- * other than the Request-URI, thereby requiring a multistatus.
- *
- * If the resource is a locknull resource, then the UNLOCK will affect
- * the parent collection (much like a delete). For that case, we must
- * validate the parent resource's conditions.
- */
- if ((err = dav_validate_request(r, resource, 0, locktoken,
- &multi_response,
- resource_state == DAV_RESOURCE_LOCK_NULL
- ? DAV_VALIDATE_PARENT
- : DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
- /* ### add a higher-level description? */
- return dav_handle_err(r, err, multi_response);
- }
-
- /* ### RFC 2518 s. 8.11: If this resource is locked by locktoken,
- * _all_ resources locked by locktoken are released. It does not say
- * resource has to be the root of an infinte lock. Thus, an UNLOCK
- * on any part of an infinte lock will remove the lock on all resources.
- *
- * For us, if r->filename represents an indirect lock (part of an infinity lock),
- * we must actually perform an UNLOCK on the direct lock for this resource.
- */
- if ((result = dav_unlock(r, resource, locktoken)) != OK) {
- return result;
- }
-
- return HTTP_NO_CONTENT;
-}
-
-static int dav_method_vsn_control(request_rec *r)
-{
- dav_resource *resource;
- int resource_state;
- dav_auto_version_info av_info;
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- apr_xml_doc *doc;
- const char *target = NULL;
- int result;
-
- /* if no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- /* ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* remember the pre-creation resource state */
- resource_state = dav_get_resource_state(r, resource);
-
- /* parse the request body (may be a version-control element) */
- if ((result = ap_xml_parse_input(r, &doc)) != OK) {
- return result;
- }
- /* note: doc == NULL if no request body */
-
- if (doc != NULL) {
- const apr_xml_elem *child;
- apr_size_t tsize;
-
- if (!dav_validate_root(doc, "version-control")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body does not contain "
- "a \"version-control\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* get the version URI */
- if ((child = dav_find_child(doc->root, "version")) == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The \"version-control\" element does not contain "
- "a \"version\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- if ((child = dav_find_child(child, "href")) == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The \"version\" element does not contain "
- "an \"href\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* get version URI */
- apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
- &target, &tsize);
- if (tsize == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "An \"href\" element does not contain a URI.");
- return HTTP_BAD_REQUEST;
- }
- }
-
- /* Check request preconditions */
-
- /* ### need a general mechanism for reporting precondition violations
- * ### (should be returning XML document for 403/409 responses)
- */
-
- /* if not versioning existing resource, must specify version to select */
- if (!resource->exists && target == NULL) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:initial-version-required/>");
- return dav_handle_err(r, err, NULL);
- }
- else if (resource->exists) {
- /* cannot add resource to existing version history */
- if (target != NULL) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:cannot-add-to-existing-history/>");
- return dav_handle_err(r, err, NULL);
- }
-
- /* resource must be unversioned and versionable, or version selector */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR
- || (!resource->versioned && !(vsn_hooks->versionable)(resource))) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:must-be-versionable/>");
- return dav_handle_err(r, err, NULL);
- }
-
- /* the DeltaV spec says if resource is a version selector,
- * then VERSION-CONTROL is a no-op
- */
- if (resource->versioned) {
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* no body */
- ap_set_content_length(r, 0);
-
- return DONE;
- }
- }
-
- /* Check If-Headers and existing locks */
- /* Note: depth == 0. Implies no need for a multistatus response. */
- if ((err = dav_validate_request(r, resource, 0, NULL, NULL,
- resource_state == DAV_RESOURCE_NULL ?
- DAV_VALIDATE_PARENT :
- DAV_VALIDATE_RESOURCE, NULL)) != NULL) {
- return dav_handle_err(r, err, NULL);
- }
-
- /* if in versioned collection, make sure parent is checked out */
- if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
- &av_info)) != NULL) {
- return dav_handle_err(r, err, NULL);
- }
-
- /* attempt to version-control the resource */
- if ((err = (*vsn_hooks->vsn_control)(resource, target)) != NULL) {
- dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, &av_info);
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Could not VERSION-CONTROL resource %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* revert writability of parent directory */
- err = dav_auto_checkin(r, resource, 0 /*undo*/, 0 /*unlock*/, &av_info);
- if (err != NULL) {
- /* just log a warning */
- err = dav_push_error(r->pool, err->status, 0,
- "The VERSION-CONTROL was successful, but there "
- "was a problem automatically checking in "
- "the parent collection.",
- err);
- dav_log_err(r, err, APLOG_WARNING);
- }
-
- /* if the resource is lockable, let lock system know of new resource */
- if (locks_hooks != NULL
- && (*locks_hooks->get_supportedlock)(resource) != NULL) {
- dav_lockdb *lockdb;
-
- if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
- /* The resource creation was successful, but the locking failed. */
- err = dav_push_error(r->pool, err->status, 0,
- "The VERSION-CONTROL was successful, but there "
- "was a problem opening the lock database "
- "which prevents inheriting locks from the "
- "parent resources.",
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* notify lock system that we have created/replaced a resource */
- err = dav_notify_created(r, lockdb, resource, resource_state, 0);
-
- (*locks_hooks->close_lockdb)(lockdb);
-
- if (err != NULL) {
- /* The dir creation was successful, but the locking failed. */
- err = dav_push_error(r->pool, err->status, 0,
- "The VERSION-CONTROL was successful, but there "
- "was a problem updating its lock "
- "information.",
- err);
- return dav_handle_err(r, err, NULL);
- }
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* return an appropriate response (HTTP_CREATED) */
- return dav_created(r, resource->uri, "Version selector", 0 /*replaced*/);
-}
-
-/* handle the CHECKOUT method */
-static int dav_method_checkout(request_rec *r)
-{
- dav_resource *resource;
- dav_resource *working_resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- int result;
- apr_xml_doc *doc;
- int apply_to_vsn = 0;
- int is_unreserved = 0;
- int is_fork_ok = 0;
- int create_activity = 0;
- apr_array_header_t *activities = NULL;
-
- /* If no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- if ((result = ap_xml_parse_input(r, &doc)) != OK)
- return result;
-
- if (doc != NULL) {
- const apr_xml_elem *aset;
-
- if (!dav_validate_root(doc, "checkout")) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body, if present, must be a "
- "DAV:checkout element.");
- return HTTP_BAD_REQUEST;
- }
-
- if (dav_find_child(doc->root, "apply-to-version") != NULL) {
- if (apr_table_get(r->headers_in, "label") != NULL) {
- /* ### we want generic 403/409 XML reporting here */
- /* ### DAV:must-not-have-label-and-apply-to-version */
- return dav_error_response(r, HTTP_CONFLICT,
- "DAV:apply-to-version cannot be "
- "used in conjunction with a "
- "Label header.");
- }
- apply_to_vsn = 1;
- }
-
- is_unreserved = dav_find_child(doc->root, "unreserved") != NULL;
- is_fork_ok = dav_find_child(doc->root, "fork-ok") != NULL;
-
- if ((aset = dav_find_child(doc->root, "activity-set")) != NULL) {
- if (dav_find_child(aset, "new") != NULL) {
- create_activity = 1;
- }
- else {
- const apr_xml_elem *child = aset->first_child;
-
- activities = apr_array_make(r->pool, 1, sizeof(const char *));
-
- for (; child != NULL; child = child->next) {
- if (child->ns == APR_XML_NS_DAV_ID
- && strcmp(child->name, "href") == 0) {
- const char *href;
-
- href = dav_xml_get_cdata(child, r->pool,
- 1 /* strip_white */);
- *(const char **)apr_array_push(activities) = href;
- }
- }
-
- if (activities->nelts == 0) {
- /* no href's is a DTD violation:
- <!ELEMENT activity-set (href+ | new)>
- */
-
- /* This supplies additional info for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Within the DAV:activity-set element, the "
- "DAV:new element must be used, or at least "
- "one DAV:href must be specified.");
- return HTTP_BAD_REQUEST;
- }
- }
- }
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 1 /*label_allowed*/, apply_to_vsn, &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* Check the state of the resource: must be a file or collection,
- * must be versioned, and must not already be checked out.
- */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR
- && resource->type != DAV_RESOURCE_TYPE_VERSION) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot checkout this type of resource.");
- }
-
- if (!resource->versioned) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot checkout unversioned resource.");
- }
-
- if (resource->working) {
- return dav_error_response(r, HTTP_CONFLICT,
- "The resource is already checked out to the workspace.");
- }
-
- /* ### do lock checks, once behavior is defined */
-
- /* Do the checkout */
- if ((err = (*vsn_hooks->checkout)(resource, 0 /*auto_checkout*/,
- is_unreserved, is_fork_ok,
- create_activity, activities,
- &working_resource)) != NULL) {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Could not CHECKOUT resource %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* if no working resource created, return OK,
- * else return CREATED with working resource URL in Location header
- */
- if (working_resource == NULL) {
- /* no body */
- ap_set_content_length(r, 0);
- return DONE;
- }
-
- return dav_created(r, working_resource->uri, "Checked-out resource", 0);
-}
-
-/* handle the UNCHECKOUT method */
-static int dav_method_uncheckout(request_rec *r)
-{
- dav_resource *resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- int result;
-
- /* If no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- if ((result = ap_discard_request_body(r)) != OK) {
- return result;
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* Check the state of the resource: must be a file or collection,
- * must be versioned, and must be checked out.
- */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot uncheckout this type of resource.");
- }
-
- if (!resource->versioned) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot uncheckout unversioned resource.");
- }
-
- if (!resource->working) {
- return dav_error_response(r, HTTP_CONFLICT,
- "The resource is not checked out to the workspace.");
- }
-
- /* ### do lock checks, once behavior is defined */
-
- /* Do the uncheckout */
- if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Could not UNCHECKOUT resource %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* no body */
- ap_set_content_length(r, 0);
-
- return DONE;
-}
-
-/* handle the CHECKIN method */
-static int dav_method_checkin(request_rec *r)
-{
- dav_resource *resource;
- dav_resource *new_version;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- int result;
- apr_xml_doc *doc;
- int keep_checked_out = 0;
-
- /* If no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- if ((result = ap_xml_parse_input(r, &doc)) != OK)
- return result;
-
- if (doc != NULL) {
- if (!dav_validate_root(doc, "checkin")) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body, if present, must be a "
- "DAV:checkin element.");
- return HTTP_BAD_REQUEST;
- }
-
- keep_checked_out = dav_find_child(doc->root, "keep-checked-out") != NULL;
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* Check the state of the resource: must be a file or collection,
- * must be versioned, and must be checked out.
- */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot checkin this type of resource.");
- }
-
- if (!resource->versioned) {
- return dav_error_response(r, HTTP_CONFLICT,
- "Cannot checkin unversioned resource.");
- }
-
- if (!resource->working) {
- return dav_error_response(r, HTTP_CONFLICT,
- "The resource is not checked out.");
- }
-
- /* ### do lock checks, once behavior is defined */
-
- /* Do the checkin */
- if ((err = (*vsn_hooks->checkin)(resource, keep_checked_out, &new_version))
- != NULL) {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Could not CHECKIN resource %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- return dav_created(r, new_version->uri, "Version", 0);
-}
-
-static int dav_method_update(request_rec *r)
-{
- dav_resource *resource;
- dav_resource *version = NULL;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- apr_xml_doc *doc;
- apr_xml_elem *child;
- int is_label = 0;
- int depth;
- int result;
- apr_size_t tsize;
- const char *target;
- dav_response *multi_response;
- dav_error *err;
- dav_lookup_result lookup;
-
- /* If no versioning provider, or UPDATE not supported,
- * decline the request */
- if (vsn_hooks == NULL || vsn_hooks->update == NULL)
- return DECLINED;
-
- if ((depth = dav_get_depth(r, 0)) < 0) {
- /* dav_get_depth() supplies additional information for the
- * default message. */
- return HTTP_BAD_REQUEST;
- }
-
- /* parse the request body */
- if ((result = ap_xml_parse_input(r, &doc)) != OK) {
- return result;
- }
-
- if (doc == NULL || !dav_validate_root(doc, "update")) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body does not contain "
- "an \"update\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* check for label-name or version element, but not both */
- if ((child = dav_find_child(doc->root, "label-name")) != NULL)
- is_label = 1;
- else if ((child = dav_find_child(doc->root, "version")) != NULL) {
- /* get the href element */
- if ((child = dav_find_child(child, "href")) == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The version element does not contain "
- "an \"href\" element.");
- return HTTP_BAD_REQUEST;
- }
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The \"update\" element does not contain "
- "a \"label-name\" or \"version\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* a depth greater than zero is only allowed for a label */
- if (!is_label && depth != 0) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Depth must be zero for UPDATE with a version");
- return HTTP_BAD_REQUEST;
- }
-
- /* get the target value (a label or a version URI) */
- apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
- &target, &tsize);
- if (tsize == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "A \"label-name\" or \"href\" element does not contain "
- "any content.");
- return HTTP_BAD_REQUEST;
- }
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* ### need a general mechanism for reporting precondition violations
- * ### (should be returning XML document for 403/409 responses)
- */
- if (resource->type != DAV_RESOURCE_TYPE_REGULAR
- || !resource->versioned || resource->working) {
- return dav_error_response(r, HTTP_CONFLICT,
- "<DAV:must-be-checked-in-version-controlled-resource>");
- }
-
- /* if target is a version, resolve the version resource */
- /* ### dav_lookup_uri only allows absolute URIs; is that OK? */
- if (!is_label) {
- lookup = dav_lookup_uri(target, r, 0 /* must_be_absolute */);
- if (lookup.rnew == NULL) {
- if (lookup.err.status == HTTP_BAD_REQUEST) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "%s", lookup.err.desc);
- return HTTP_BAD_REQUEST;
- }
-
- /* ### this assumes that dav_lookup_uri() only generates a status
- * ### that Apache can provide a status line for!! */
-
- return dav_error_response(r, lookup.err.status, lookup.err.desc);
- }
- if (lookup.rnew->status != HTTP_OK) {
- /* ### how best to report this... */
- return dav_error_response(r, lookup.rnew->status,
- "Version URI had an error.");
- }
-
- /* resolve version resource */
- err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
- 0 /* use_checked_in */, &version);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* NULL out target, since we're using a version resource */
- target = NULL;
- }
-
- /* do the UPDATE operation */
- err = (*vsn_hooks->update)(resource, version, target, depth, &multi_response);
-
- if (err != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not UPDATE %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, multi_response);
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* no body */
- ap_set_content_length(r, 0);
-
- return DONE;
-}
-
-/* context maintained during LABEL treewalk */
-typedef struct dav_label_walker_ctx
-{
- /* input: */
- dav_walk_params w;
-
- /* label being manipulated */
- const char *label;
-
- /* label operation */
- int label_op;
-#define DAV_LABEL_ADD 1
-#define DAV_LABEL_SET 2
-#define DAV_LABEL_REMOVE 3
-
- /* version provider hooks */
- const dav_hooks_vsn *vsn_hooks;
-
-} dav_label_walker_ctx;
-
-static dav_error * dav_label_walker(dav_walk_resource *wres, int calltype)
-{
- dav_label_walker_ctx *ctx = wres->walk_ctx;
- dav_error *err = NULL;
-
- /* Check the state of the resource: must be a version or
- * non-checkedout version selector
- */
- /* ### need a general mechanism for reporting precondition violations
- * ### (should be returning XML document for 403/409 responses)
- */
- if (wres->resource->type != DAV_RESOURCE_TYPE_VERSION &&
- (wres->resource->type != DAV_RESOURCE_TYPE_REGULAR
- || !wres->resource->versioned)) {
- err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0,
- "<DAV:must-be-version-or-version-selector/>");
- }
- else if (wres->resource->working) {
- err = dav_new_error(ctx->w.pool, HTTP_CONFLICT, 0,
- "<DAV:must-not-be-checked-out/>");
- }
- else {
- /* do the label operation */
- if (ctx->label_op == DAV_LABEL_REMOVE)
- err = (*ctx->vsn_hooks->remove_label)(wres->resource, ctx->label);
- else
- err = (*ctx->vsn_hooks->add_label)(wres->resource, ctx->label,
- ctx->label_op == DAV_LABEL_SET);
- }
-
- if (err != NULL) {
- /* ### need utility routine to add response with description? */
- dav_add_response(wres, err->status, NULL);
- wres->response->desc = err->desc;
- }
-
- return NULL;
-}
-
-static int dav_method_label(request_rec *r)
-{
- dav_resource *resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- apr_xml_doc *doc;
- apr_xml_elem *child;
- int depth;
- int result;
- apr_size_t tsize;
- dav_error *err;
- dav_label_walker_ctx ctx = { { 0 } };
- dav_response *multi_status;
-
- /* If no versioning provider, or the provider doesn't support
- * labels, decline the request */
- if (vsn_hooks == NULL || vsn_hooks->add_label == NULL)
- return DECLINED;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- if ((depth = dav_get_depth(r, 0)) < 0) {
- /* dav_get_depth() supplies additional information for the
- * default message. */
- return HTTP_BAD_REQUEST;
- }
-
- /* parse the request body */
- if ((result = ap_xml_parse_input(r, &doc)) != OK) {
- return result;
- }
-
- if (doc == NULL || !dav_validate_root(doc, "label")) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body does not contain "
- "a \"label\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* check for add, set, or remove element */
- if ((child = dav_find_child(doc->root, "add")) != NULL) {
- ctx.label_op = DAV_LABEL_ADD;
- }
- else if ((child = dav_find_child(doc->root, "set")) != NULL) {
- ctx.label_op = DAV_LABEL_SET;
- }
- else if ((child = dav_find_child(doc->root, "remove")) != NULL) {
- ctx.label_op = DAV_LABEL_REMOVE;
- }
- else {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The \"label\" element does not contain "
- "an \"add\", \"set\", or \"remove\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* get the label string */
- if ((child = dav_find_child(child, "label-name")) == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The label command element does not contain "
- "a \"label-name\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- apr_xml_to_text(r->pool, child, APR_XML_X2T_INNER, NULL, NULL,
- &ctx.label, &tsize);
- if (tsize == 0) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "A \"label-name\" element does not contain "
- "a label name.");
- return HTTP_BAD_REQUEST;
- }
-
- /* do the label operation walk */
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
- ctx.w.func = dav_label_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = resource;
- ctx.vsn_hooks = vsn_hooks;
-
- err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status);
-
- if (err != NULL) {
- /* some sort of error occurred which terminated the walk */
- err = dav_push_error(r->pool, err->status, 0,
- "The LABEL operation was terminated prematurely.",
- err);
- return dav_handle_err(r, err, multi_status);
- }
-
- if (multi_status != NULL) {
- /* One or more resources had errors. If depth was zero, convert
- * response to simple error, else make sure there is an
- * overall error to pass to dav_handle_err()
- */
- if (depth == 0) {
- err = dav_new_error(r->pool, multi_status->status, 0, multi_status->desc);
- multi_status = NULL;
- }
- else {
- err = dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
- "Errors occurred during the LABEL operation.");
- }
-
- return dav_handle_err(r, err, multi_status);
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* no body */
- ap_set_content_length(r, 0);
-
- return DONE;
-}
-
-static int dav_method_report(request_rec *r)
-{
- dav_resource *resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- int result;
- int label_allowed;
- apr_xml_doc *doc;
- dav_error *err;
-
- /* If no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- if ((result = ap_xml_parse_input(r, &doc)) != OK)
- return result;
- if (doc == NULL) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body must specify a report.");
- return HTTP_BAD_REQUEST;
- }
-
- /* Ask repository module to resolve the resource.
- * First determine whether a Target-Selector header is allowed
- * for this report.
- */
- label_allowed = (*vsn_hooks->report_label_header_allowed)(doc);
- err = dav_get_resource(r, label_allowed, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* set up defaults for the report response */
- r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
-
- /* run report hook */
- if ((err = (*vsn_hooks->deliver_report)(r, resource, doc,
- r->output_filters)) != NULL) {
- if (! r->sent_bodyct)
- /* No data has been sent to client yet; throw normal error. */
- return dav_handle_err(r, err, NULL);
-
- /* If an error occurred during the report delivery, there's
- basically nothing we can do but abort the connection and
- log an error. This is one of the limitations of HTTP; it
- needs to "know" the entire status of the response before
- generating it, which is just impossible in these streamy
- response situations. */
- err = dav_push_error(r->pool, err->status, 0,
- "Provider encountered an error while streaming"
- " a REPORT response.", err);
- dav_log_err(r, err, APLOG_ERR);
- r->connection->aborted = 1;
- return DONE;
- }
-
- return DONE;
-}
-
-static int dav_method_make_workspace(request_rec *r)
-{
- dav_resource *resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- apr_xml_doc *doc;
- int result;
-
- /* if no versioning provider, or the provider does not support workspaces,
- * decline the request
- */
- if (vsn_hooks == NULL || vsn_hooks->make_workspace == NULL)
- return DECLINED;
-
- /* ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* parse the request body (must be a mkworkspace element) */
- if ((result = ap_xml_parse_input(r, &doc)) != OK) {
- return result;
- }
-
- if (doc == NULL
- || !dav_validate_root(doc, "mkworkspace")) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body does not contain "
- "a \"mkworkspace\" element.");
- return HTTP_BAD_REQUEST;
- }
-
- /* Check request preconditions */
-
- /* ### need a general mechanism for reporting precondition violations
- * ### (should be returning XML document for 403/409 responses)
- */
-
- /* resource must not already exist */
- if (resource->exists) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:resource-must-be-null/>");
- return dav_handle_err(r, err, NULL);
- }
-
- /* ### what about locking? */
-
- /* attempt to create the workspace */
- if ((err = (*vsn_hooks->make_workspace)(resource, doc)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not create workspace %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* return an appropriate response (HTTP_CREATED) */
- return dav_created(r, resource->uri, "Workspace", 0 /*replaced*/);
-}
-
-static int dav_method_make_activity(request_rec *r)
-{
- dav_resource *resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- int result;
-
- /* if no versioning provider, or the provider does not support activities,
- * decline the request
- */
- if (vsn_hooks == NULL || vsn_hooks->make_activity == NULL)
- return DECLINED;
-
- /* ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* MKACTIVITY does not have a defined request body. */
- if ((result = ap_discard_request_body(r)) != OK) {
- return result;
- }
-
- /* Check request preconditions */
-
- /* ### need a general mechanism for reporting precondition violations
- * ### (should be returning XML document for 403/409 responses)
- */
-
- /* resource must not already exist */
- if (resource->exists) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:resource-must-be-null/>");
- return dav_handle_err(r, err, NULL);
- }
-
- /* the provider must say whether the resource can be created as
- an activity, i.e. whether the location is ok. */
- if (vsn_hooks->can_be_activity != NULL
- && !(*vsn_hooks->can_be_activity)(resource)) {
- err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0,
- "<DAV:activity-location-ok/>");
- return dav_handle_err(r, err, NULL);
- }
-
- /* ### what about locking? */
-
- /* attempt to create the activity */
- if ((err = (*vsn_hooks->make_activity)(resource)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not create activity %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* set the Cache-Control header, per the spec */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* return an appropriate response (HTTP_CREATED) */
- return dav_created(r, resource->uri, "Activity", 0 /*replaced*/);
-}
-
-static int dav_method_baseline_control(request_rec *r)
-{
- /* ### */
- return HTTP_METHOD_NOT_ALLOWED;
-}
-
-static int dav_method_merge(request_rec *r)
-{
- dav_resource *resource;
- dav_resource *source_resource;
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err;
- int result;
- apr_xml_doc *doc;
- apr_xml_elem *source_elem;
- apr_xml_elem *href_elem;
- apr_xml_elem *prop_elem;
- const char *source;
- int no_auto_merge;
- int no_checkout;
- dav_lookup_result lookup;
-
- /* If no versioning provider, decline the request */
- if (vsn_hooks == NULL)
- return DECLINED;
-
- if ((result = ap_xml_parse_input(r, &doc)) != OK)
- return result;
-
- if (doc == NULL || !dav_validate_root(doc, "merge")) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request body must be present and must be a "
- "DAV:merge element.");
- return HTTP_BAD_REQUEST;
- }
-
- if ((source_elem = dav_find_child(doc->root, "source")) == NULL) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The DAV:merge element must contain a DAV:source "
- "element.");
- return HTTP_BAD_REQUEST;
- }
- if ((href_elem = dav_find_child(source_elem, "href")) == NULL) {
- /* This supplies additional information for the default msg. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The DAV:source element must contain a DAV:href "
- "element.");
- return HTTP_BAD_REQUEST;
- }
- source = dav_xml_get_cdata(href_elem, r->pool, 1 /* strip_white */);
-
- /* get a subrequest for the source, so that we can get a dav_resource
- for that source. */
- lookup = dav_lookup_uri(source, r, 0 /* must_be_absolute */);
- if (lookup.rnew == NULL) {
- if (lookup.err.status == HTTP_BAD_REQUEST) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "%s", lookup.err.desc);
- return HTTP_BAD_REQUEST;
- }
-
- /* ### this assumes that dav_lookup_uri() only generates a status
- * ### that Apache can provide a status line for!! */
-
- return dav_error_response(r, lookup.err.status, lookup.err.desc);
- }
- if (lookup.rnew->status != HTTP_OK) {
- /* ### how best to report this... */
- return dav_error_response(r, lookup.rnew->status,
- "Merge source URI had an error.");
- }
- err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
- 0 /* use_checked_in */, &source_resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- no_auto_merge = dav_find_child(doc->root, "no-auto-merge") != NULL;
- no_checkout = dav_find_child(doc->root, "no-checkout") != NULL;
-
- prop_elem = dav_find_child(doc->root, "prop");
-
- /* ### check RFC. I believe the DAV:merge element may contain any
- ### element also allowed within DAV:checkout. need to extract them
- ### here, and pass them along.
- ### if so, then refactor the CHECKOUT method handling so we can reuse
- ### the code. maybe create a structure to hold CHECKOUT parameters
- ### which can be passed to the checkout() and merge() hooks. */
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* ### check the source and target resources flags/types */
-
- /* ### do lock checks, once behavior is defined */
-
- /* set the Cache-Control header, per the spec */
- /* ### correct? */
- apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
-
- /* Initialize these values for a standard MERGE response. If the MERGE
- is going to do something different (i.e. an error), then it must
- return a dav_error, and we'll reset these values properly. */
- r->status = HTTP_OK;
- ap_set_content_type(r, "text/xml");
-
- /* ### should we do any preliminary response generation? probably not,
- ### because we may have an error, thus demanding something else in
- ### the response body. */
-
- /* Do the merge, including any response generation. */
- if ((err = (*vsn_hooks->merge)(resource, source_resource,
- no_auto_merge, no_checkout,
- prop_elem,
- r->output_filters)) != NULL) {
- /* ### is err->status the right error here? */
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not MERGE resource \"%s\" "
- "into \"%s\".",
- ap_escape_html(r->pool, source),
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, NULL);
- }
-
- /* the response was fully generated by the merge() hook. */
- /* ### urk. does this prevent logging? need to check... */
- return DONE;
-}
-
-static int dav_method_bind(request_rec *r)
-{
- dav_resource *resource;
- dav_resource *binding;
- dav_auto_version_info av_info;
- const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r);
- const char *dest;
- dav_error *err;
- dav_error *err2;
- dav_response *multi_response = NULL;
- dav_lookup_result lookup;
- int overwrite;
-
- /* If no bindings provider, decline the request */
- if (binding_hooks == NULL)
- return DECLINED;
-
- /* Ask repository module to resolve the resource */
- err = dav_get_resource(r, 0 /* label_allowed */, 0 /* use_checked_in */,
- &resource);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- if (!resource->exists) {
- /* Apache will supply a default error for this. */
- return HTTP_NOT_FOUND;
- }
-
- /* get the destination URI */
- dest = apr_table_get(r->headers_in, "Destination");
- if (dest == NULL) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "The request is missing a Destination header.");
- return HTTP_BAD_REQUEST;
- }
-
- lookup = dav_lookup_uri(dest, r, 0 /* must_be_absolute */);
- if (lookup.rnew == NULL) {
- if (lookup.err.status == HTTP_BAD_REQUEST) {
- /* This supplies additional information for the default message. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "%s", lookup.err.desc);
- return HTTP_BAD_REQUEST;
- }
- else if (lookup.err.status == HTTP_BAD_GATEWAY) {
- /* ### Bindings protocol draft 02 says to return 507
- * ### (Cross Server Binding Forbidden); Apache already defines 507
- * ### as HTTP_INSUFFICIENT_STORAGE. So, for now, we'll return
- * ### HTTP_FORBIDDEN
- */
- return dav_error_response(r, HTTP_FORBIDDEN,
- "Cross server bindings are not "
- "allowed by this server.");
- }
-
- /* ### this assumes that dav_lookup_uri() only generates a status
- * ### that Apache can provide a status line for!! */
-
- return dav_error_response(r, lookup.err.status, lookup.err.desc);
- }
- if (lookup.rnew->status != HTTP_OK) {
- /* ### how best to report this... */
- return dav_error_response(r, lookup.rnew->status,
- "Destination URI had an error.");
- }
-
- /* resolve binding resource */
- err = dav_get_resource(lookup.rnew, 0 /* label_allowed */,
- 0 /* use_checked_in */, &binding);
- if (err != NULL)
- return dav_handle_err(r, err, NULL);
-
- /* are the two resources handled by the same repository? */
- if (resource->hooks != binding->hooks) {
- /* ### this message exposes some backend config, but screw it... */
- return dav_error_response(r, HTTP_BAD_GATEWAY,
- "Destination URI is handled by a "
- "different repository than the source URI. "
- "BIND between repositories is not possible.");
- }
-
- /* get and parse the overwrite header value */
- if ((overwrite = dav_get_overwrite(r)) < 0) {
- /* dav_get_overwrite() supplies additional information for the
- * default message. */
- return HTTP_BAD_REQUEST;
- }
-
- /* quick failure test: if dest exists and overwrite is false. */
- if (binding->exists && !overwrite) {
- return dav_error_response(r, HTTP_PRECONDITION_FAILED,
- "Destination is not empty and "
- "Overwrite is not \"T\"");
- }
-
- /* are the source and destination the same? */
- if ((*resource->hooks->is_same_resource)(resource, binding)) {
- return dav_error_response(r, HTTP_FORBIDDEN,
- "Source and Destination URIs are the same.");
- }
-
- /*
- * Check If-Headers and existing locks for destination. Note that we
- * use depth==infinity since the target (hierarchy) will be deleted
- * before the move/copy is completed.
- *
- * Note that we are overwriting the target, which implies a DELETE, so
- * we are subject to the error/response rules as a DELETE. Namely, we
- * will return a 424 error if any of the validations fail.
- * (see dav_method_delete() for more information)
- */
- if ((err = dav_validate_request(lookup.rnew, binding, DAV_INFINITY, NULL,
- &multi_response,
- DAV_VALIDATE_PARENT
- | DAV_VALIDATE_USE_424, NULL)) != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not BIND %s due to a "
- "failed precondition on the "
- "destination (e.g. locks).",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, multi_response);
- }
-
- /* guard against creating circular bindings */
- if (resource->collection
- && (*resource->hooks->is_parent_resource)(resource, binding)) {
- return dav_error_response(r, HTTP_FORBIDDEN,
- "Source collection contains the Destination.");
- }
- if (resource->collection
- && (*resource->hooks->is_parent_resource)(binding, resource)) {
- /* The destination must exist (since it contains the source), and
- * a condition above implies Overwrite==T. Obviously, we cannot
- * delete the Destination before the BIND, as that would
- * delete the Source.
- */
-
- return dav_error_response(r, HTTP_FORBIDDEN,
- "Destination collection contains the Source and "
- "Overwrite has been specified.");
- }
-
- /* prepare the destination collection for modification */
- if ((err = dav_auto_checkout(r, binding, 1 /* parent_only */,
- &av_info)) != NULL) {
- /* could not make destination writable */
- return dav_handle_err(r, err, NULL);
- }
-
- /* If target exists, remove it first (we know Ovewrite must be TRUE).
- * Then try to bind to the resource.
- */
- if (binding->exists)
- err = (*resource->hooks->remove_resource)(binding, &multi_response);
-
- if (err == NULL) {
- err = (*binding_hooks->bind_resource)(resource, binding);
- }
-
- /* restore parent collection states */
- err2 = dav_auto_checkin(r, NULL,
- err != NULL /* undo if error */,
- 0 /* unlock */, &av_info);
-
- /* check for error from remove/bind operations */
- if (err != NULL) {
- err = dav_push_error(r->pool, err->status, 0,
- apr_psprintf(r->pool,
- "Could not BIND %s.",
- ap_escape_html(r->pool, r->uri)),
- err);
- return dav_handle_err(r, err, multi_response);
- }
-
- /* check for errors from reverting writability */
- if (err2 != NULL) {
- /* just log a warning */
- err = dav_push_error(r->pool, err2->status, 0,
- "The BIND was successful, but there was a "
- "problem automatically checking in the "
- "source parent collection.",
- err2);
- dav_log_err(r, err, APLOG_WARNING);
- }
-
- /* return an appropriate response (HTTP_CREATED) */
- /* ### spec doesn't say what happens when destination was replaced */
- return dav_created(r, lookup.rnew->uri, "Binding", 0);
-}
-
-
-/*
- * Response handler for DAV resources
- */
-static int dav_handler(request_rec *r)
-{
- if (strcmp(r->handler, DAV_HANDLER_NAME) != 0)
- return DECLINED;
-
- /* Reject requests with an unescaped hash character, as these may
- * be more destructive than the user intended. */
- if (r->parsed_uri.fragment != NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "buggy client used un-escaped hash in Request-URI");
- return dav_error_response(r, HTTP_BAD_REQUEST,
- "The request was invalid: the URI included "
- "an un-escaped hash character");
- }
-
- /* ### do we need to do anything with r->proxyreq ?? */
-
- /*
- * ### anything else to do here? could another module and/or
- * ### config option "take over" the handler here? i.e. how do
- * ### we lock down this hierarchy so that we are the ultimate
- * ### arbiter? (or do we simply depend on the administrator
- * ### to avoid conflicting configurations?)
- */
-
- /*
- * Set up the methods mask, since that's one of the reasons this handler
- * gets called, and lower-level things may need the info.
- *
- * First, set the mask to the methods we handle directly. Since by
- * definition we own our managed space, we unconditionally set
- * the r->allowed field rather than ORing our values with anything
- * any other module may have put in there.
- *
- * These are the HTTP-defined methods that we handle directly.
- */
- r->allowed = 0
- | (AP_METHOD_BIT << M_GET)
- | (AP_METHOD_BIT << M_PUT)
- | (AP_METHOD_BIT << M_DELETE)
- | (AP_METHOD_BIT << M_OPTIONS)
- | (AP_METHOD_BIT << M_INVALID);
-
- /*
- * These are the DAV methods we handle.
- */
- r->allowed |= 0
- | (AP_METHOD_BIT << M_COPY)
- | (AP_METHOD_BIT << M_LOCK)
- | (AP_METHOD_BIT << M_UNLOCK)
- | (AP_METHOD_BIT << M_MKCOL)
- | (AP_METHOD_BIT << M_MOVE)
- | (AP_METHOD_BIT << M_PROPFIND)
- | (AP_METHOD_BIT << M_PROPPATCH);
-
- /*
- * These are methods that we don't handle directly, but let the
- * server's default handler do for us as our agent.
- */
- r->allowed |= 0
- | (AP_METHOD_BIT << M_POST);
-
- /* ### hrm. if we return HTTP_METHOD_NOT_ALLOWED, then an Allow header
- * ### is sent; it will need the other allowed states; since the default
- * ### handler is not called on error, then it doesn't add the other
- * ### allowed states, so we must
- */
-
- /* ### we might need to refine this for just where we return the error.
- * ### also, there is the issue with other methods (see ISSUES)
- */
-
- /* dispatch the appropriate method handler */
- if (r->method_number == M_GET) {
- return dav_method_get(r);
- }
-
- if (r->method_number == M_PUT) {
- return dav_method_put(r);
- }
-
- if (r->method_number == M_POST) {
- return dav_method_post(r);
- }
-
- if (r->method_number == M_DELETE) {
- return dav_method_delete(r);
- }
-
- if (r->method_number == M_OPTIONS) {
- return dav_method_options(r);
- }
-
- if (r->method_number == M_PROPFIND) {
- return dav_method_propfind(r);
- }
-
- if (r->method_number == M_PROPPATCH) {
- return dav_method_proppatch(r);
- }
-
- if (r->method_number == M_MKCOL) {
- return dav_method_mkcol(r);
- }
-
- if (r->method_number == M_COPY) {
- return dav_method_copymove(r, DAV_DO_COPY);
- }
-
- if (r->method_number == M_MOVE) {
- return dav_method_copymove(r, DAV_DO_MOVE);
- }
-
- if (r->method_number == M_LOCK) {
- return dav_method_lock(r);
- }
-
- if (r->method_number == M_UNLOCK) {
- return dav_method_unlock(r);
- }
-
- if (r->method_number == M_VERSION_CONTROL) {
- return dav_method_vsn_control(r);
- }
-
- if (r->method_number == M_CHECKOUT) {
- return dav_method_checkout(r);
- }
-
- if (r->method_number == M_UNCHECKOUT) {
- return dav_method_uncheckout(r);
- }
-
- if (r->method_number == M_CHECKIN) {
- return dav_method_checkin(r);
- }
-
- if (r->method_number == M_UPDATE) {
- return dav_method_update(r);
- }
-
- if (r->method_number == M_LABEL) {
- return dav_method_label(r);
- }
-
- if (r->method_number == M_REPORT) {
- return dav_method_report(r);
- }
-
- if (r->method_number == M_MKWORKSPACE) {
- return dav_method_make_workspace(r);
- }
-
- if (r->method_number == M_MKACTIVITY) {
- return dav_method_make_activity(r);
- }
-
- if (r->method_number == M_BASELINE_CONTROL) {
- return dav_method_baseline_control(r);
- }
-
- if (r->method_number == M_MERGE) {
- return dav_method_merge(r);
- }
-
- /* BIND method */
- if (r->method_number == dav_methods[DAV_M_BIND]) {
- return dav_method_bind(r);
- }
-
- /* DASL method */
- if (r->method_number == dav_methods[DAV_M_SEARCH]) {
- return dav_method_search(r);
- }
-
- /* ### add'l methods for Advanced Collections, ACLs */
-
- return DECLINED;
-}
-
-static int dav_fixups(request_rec *r)
-{
- dav_dir_conf *conf;
-
- /* quickly ignore any HTTP/0.9 requests which aren't subreqs. */
- if (r->assbackwards && !r->main) {
- return DECLINED;
- }
-
- conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config,
- &dav_module);
-
- /* if DAV is not enabled, then we've got nothing to do */
- if (conf->provider == NULL) {
- return DECLINED;
- }
-
- /* We are going to handle almost every request. In certain cases,
- the provider maps to the filesystem (thus, handle_get is
- FALSE), and core Apache will handle it. a For that case, we
- just return right away. */
- if (r->method_number == M_GET) {
- /*
- * ### need some work to pull Content-Type and Content-Language
- * ### from the property database.
- */
-
- /*
- * If the repository hasn't indicated that it will handle the
- * GET method, then just punt.
- *
- * ### this isn't quite right... taking over the response can break
- * ### things like mod_negotiation. need to look into this some more.
- */
- if (!conf->provider->repos->handle_get) {
- return DECLINED;
- }
- }
-
- /* ### this is wrong. We should only be setting the r->handler for the
- * requests that mod_dav knows about. If we set the handler for M_POST
- * requests, then CGI scripts that use POST will return the source for the
- * script. However, mod_dav DOES handle POST, so something else needs
- * to be fixed.
- */
- if (r->method_number != M_POST) {
-
- /* We are going to be handling the response for this resource. */
- r->handler = DAV_HANDLER_NAME;
- return OK;
- }
-
- return DECLINED;
-}
-
-static void register_hooks(apr_pool_t *p)
-{
- ap_hook_handler(dav_handler, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_post_config(dav_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_fixups(dav_fixups, NULL, NULL, APR_HOOK_MIDDLE);
-
- dav_hook_find_liveprop(dav_core_find_liveprop, NULL, NULL, APR_HOOK_LAST);
- dav_hook_insert_all_liveprops(dav_core_insert_all_liveprops,
- NULL, NULL, APR_HOOK_MIDDLE);
-
- dav_core_register_uris(p);
-}
-
-/*---------------------------------------------------------------------------
- *
- * Configuration info for the module
- */
-
-static const command_rec dav_cmds[] =
-{
- /* per directory/location */
- AP_INIT_TAKE1("DAV", dav_cmd_dav, NULL, ACCESS_CONF,
- "specify the DAV provider for a directory or location"),
-
- /* per directory/location, or per server */
- AP_INIT_TAKE1("DAVMinTimeout", dav_cmd_davmintimeout, NULL,
- ACCESS_CONF|RSRC_CONF,
- "specify minimum allowed timeout"),
-
- /* per directory/location, or per server */
- AP_INIT_FLAG("DAVDepthInfinity", dav_cmd_davdepthinfinity, NULL,
- ACCESS_CONF|RSRC_CONF,
- "allow Depth infinity PROPFIND requests"),
-
- { NULL }
-};
-
-module DAV_DECLARE_DATA dav_module =
-{
- STANDARD20_MODULE_STUFF,
- dav_create_dir_config, /* dir config creater */
- dav_merge_dir_config, /* dir merger --- default is to override */
- dav_create_server_config, /* server config */
- dav_merge_server_config, /* merge server config */
- dav_cmds, /* command table */
- register_hooks, /* register hooks */
-};
-
-APR_HOOK_STRUCT(
- APR_HOOK_LINK(gather_propsets)
- APR_HOOK_LINK(find_liveprop)
- APR_HOOK_LINK(insert_all_liveprops)
- )
-
-APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, gather_propsets,
- (apr_array_header_t *uris),
- (uris))
-
-APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dav, DAV, int, find_liveprop,
- (const dav_resource *resource,
- const char *ns_uri, const char *name,
- const dav_hooks_liveprop **hooks),
- (resource, ns_uri, name, hooks), 0)
-
-APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, insert_all_liveprops,
- (request_rec *r, const dav_resource *resource,
- dav_prop_insert what, apr_text_header *phdr),
- (r, resource, what, phdr))
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.dsp b/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.dsp
deleted file mode 100644
index 38972a11..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.dsp
+++ /dev/null
@@ -1,164 +0,0 @@
-# Microsoft Developer Studio Project File - Name="mod_dav" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=mod_dav - Win32 Release
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "mod_dav.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "mod_dav.mak" CFG="mod_dav - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "mod_dav - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "mod_dav - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "mod_dav - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
-# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "DAV_DECLARE_EXPORT" /Fd"Release\mod_dav_src" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /out:"Release/mod_dav.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav.so
-# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Release/mod_dav.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav.so /opt:ref
-
-!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
-# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../../include" /I "../../../srclib/apr/include" /I "../../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "DAV_DECLARE_EXPORT" /Fd"Debug\mod_dav_src" /FD /c
-# ADD BASE MTL /nologo /D "_DEBUG" /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_dav.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav.so
-# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:"Debug/mod_dav.so" /base:@..\..\..\os\win32\BaseAddr.ref,mod_dav.so
-
-!ENDIF
-
-# Begin Target
-
-# Name "mod_dav - Win32 Release"
-# Name "mod_dav - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
-# Begin Source File
-
-SOURCE=.\liveprop.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\mod_dav.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\props.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\providers.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\std_liveprop.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\util.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\util_lock.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
-# Begin Source File
-
-SOURCE=.\mod_dav.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\mod_dav.rc
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\build\win32\win32ver.awk
-
-!IF "$(CFG)" == "mod_dav - Win32 Release"
-
-# PROP Ignore_Default_Tool 1
-# Begin Custom Build - Creating Version Resource
-InputPath=..\..\..\build\win32\win32ver.awk
-
-".\mod_dav.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- awk -f ../../../build/win32/win32ver.awk mod_dav.so "dav_module for Apache" ../../../include/ap_release.h > .\mod_dav.rc
-
-# End Custom Build
-
-!ELSEIF "$(CFG)" == "mod_dav - Win32 Debug"
-
-# PROP Ignore_Default_Tool 1
-# Begin Custom Build - Creating Version Resource
-InputPath=..\..\..\build\win32\win32ver.awk
-
-".\mod_dav.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
- awk -f ../../../build/win32/win32ver.awk mod_dav.so "dav_module for Apache" ../../../include/ap_release.h > .\mod_dav.rc
-
-# End Custom Build
-
-!ENDIF
-
-# End Source File
-# End Target
-# End Project
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.h b/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.h
deleted file mode 100644
index 0fb9ac9b..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/mod_dav.h
+++ /dev/null
@@ -1,2420 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-** DAV extension module for Apache 2.0.*
-*/
-
-#ifndef _MOD_DAV_H_
-#define _MOD_DAV_H_
-
-#include "apr_hooks.h"
-#include "apr_hash.h"
-#include "apr_dbm.h"
-#include "apr_tables.h"
-
-#include "httpd.h"
-#include "util_filter.h"
-#include "util_xml.h"
-
-#include <limits.h> /* for INT_MAX */
-#include <time.h> /* for time_t */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#define DAV_VERSION AP_SERVER_BASEREVISION
-
-#define DAV_XML_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-#define DAV_XML_CONTENT_TYPE "text/xml; charset=\"utf-8\""
-
-#define DAV_READ_BLOCKSIZE 2048 /* used for reading input blocks */
-
-#define DAV_RESPONSE_BODY_1 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>"
-#define DAV_RESPONSE_BODY_2 "</title>\n</head><body>\n<h1>"
-#define DAV_RESPONSE_BODY_3 "</h1>\n<p>"
-#define DAV_RESPONSE_BODY_4 "</p>\n"
-#define DAV_RESPONSE_BODY_5 "</body></html>\n"
-
-#define DAV_DO_COPY 0
-#define DAV_DO_MOVE 1
-
-
-#if 1
-#define DAV_DEBUG 1
-#define DEBUG_CR "\n"
-#define DBG0(f) ap_log_error(APLOG_MARK, \
- APLOG_ERR, 0, NULL, (f))
-#define DBG1(f,a1) ap_log_error(APLOG_MARK, \
- APLOG_ERR, 0, NULL, f, a1)
-#define DBG2(f,a1,a2) ap_log_error(APLOG_MARK, \
- APLOG_ERR, 0, NULL, f, a1, a2)
-#define DBG3(f,a1,a2,a3) ap_log_error(APLOG_MARK, \
- APLOG_ERR, 0, NULL, f, a1, a2, a3)
-#else
-#undef DAV_DEBUG
-#define DEBUG_CR ""
-#endif
-
-#define DAV_INFINITY INT_MAX /* for the Depth: header */
-
-/* Create a set of DAV_DECLARE(type), DAV_DECLARE_NONSTD(type) and
- * DAV_DECLARE_DATA with appropriate export and import tags for the platform
- */
-#if !defined(WIN32)
-#define DAV_DECLARE(type) type
-#define DAV_DECLARE_NONSTD(type) type
-#define DAV_DECLARE_DATA
-#elif defined(DAV_DECLARE_STATIC)
-#define DAV_DECLARE(type) type __stdcall
-#define DAV_DECLARE_NONSTD(type) type
-#define DAV_DECLARE_DATA
-#elif defined(DAV_DECLARE_EXPORT)
-#define DAV_DECLARE(type) __declspec(dllexport) type __stdcall
-#define DAV_DECLARE_NONSTD(type) __declspec(dllexport) type
-#define DAV_DECLARE_DATA __declspec(dllexport)
-#else
-#define DAV_DECLARE(type) __declspec(dllimport) type __stdcall
-#define DAV_DECLARE_NONSTD(type) __declspec(dllimport) type
-#define DAV_DECLARE_DATA __declspec(dllimport)
-#endif
-
-/* --------------------------------------------------------------------
-**
-** ERROR MANAGEMENT
-*/
-
-/*
-** dav_error structure.
-**
-** In most cases, mod_dav uses a pointer to a dav_error structure. If the
-** pointer is NULL, then no error has occurred.
-**
-** In certain cases, a dav_error structure is directly used. In these cases,
-** a status value of 0 means that an error has not occurred.
-**
-** Note: this implies that status != 0 whenever an error occurs.
-**
-** The desc field is optional (it may be NULL). When NULL, it typically
-** implies that Apache has a proper description for the specified status.
-*/
-typedef struct dav_error {
- int status; /* suggested HTTP status (0 for no error) */
- int error_id; /* DAV-specific error ID */
- const char *desc; /* DAV:responsedescription and error log */
-
- int save_errno; /* copy of errno causing the error */
-
- const char *namespace; /* [optional] namespace of error */
- const char *tagname; /* name of error-tag */
-
- struct dav_error *prev; /* previous error (in stack) */
-
-} dav_error;
-
-/*
-** Create a new error structure. save_errno will be filled with the current
-** errno value.
-*/
-DAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status,
- int error_id, const char *desc);
-
-
-/*
-** Create a new error structure with tagname and (optional) namespace;
-** namespace may be NULL, which means "DAV:". save_errno will be
-** filled with the current errno value.
-*/
-DAV_DECLARE(dav_error*) dav_new_error_tag(apr_pool_t *p, int status,
- int error_id, const char *desc,
- const char *namespace,
- const char *tagname);
-
-
-/*
-** Push a new error description onto the stack of errors.
-**
-** This function is used to provide an additional description to an existing
-** error.
-**
-** <status> should contain the caller's view of what the current status is,
-** given the underlying error. If it doesn't have a better idea, then the
-** caller should pass prev->status.
-**
-** <error_id> can specify a new error_id since the topmost description has
-** changed.
-*/
-DAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status, int error_id,
- const char *desc, dav_error *prev);
-
-
-/* error ID values... */
-
-/* IF: header errors */
-#define DAV_ERR_IF_PARSE 100 /* general parsing error */
-#define DAV_ERR_IF_MULTIPLE_NOT 101 /* multiple "Not" found */
-#define DAV_ERR_IF_UNK_CHAR 102 /* unknown char in header */
-#define DAV_ERR_IF_ABSENT 103 /* no locktokens given */
-#define DAV_ERR_IF_TAGGED 104 /* in parsing tagged-list */
-#define DAV_ERR_IF_UNCLOSED_PAREN 105 /* in no-tagged-list */
-
-/* Prop DB errors */
-#define DAV_ERR_PROP_BAD_MAJOR 200 /* major version was wrong */
-#define DAV_ERR_PROP_READONLY 201 /* prop is read-only */
-#define DAV_ERR_PROP_NO_DATABASE 202 /* writable db not avail */
-#define DAV_ERR_PROP_NOT_FOUND 203 /* prop not found */
-#define DAV_ERR_PROP_BAD_LOCKDB 204 /* could not open lockdb */
-#define DAV_ERR_PROP_OPENING 205 /* problem opening propdb */
-#define DAV_ERR_PROP_EXEC 206 /* problem exec'ing patch */
-
-/* Predefined DB errors */
-/* ### any to define?? */
-
-/* Predefined locking system errors */
-#define DAV_ERR_LOCK_OPENDB 400 /* could not open lockdb */
-#define DAV_ERR_LOCK_NO_DB 401 /* no database defined */
-#define DAV_ERR_LOCK_CORRUPT_DB 402 /* DB is corrupt */
-#define DAV_ERR_LOCK_UNK_STATE_TOKEN 403 /* unknown State-token */
-#define DAV_ERR_LOCK_PARSE_TOKEN 404 /* bad opaquelocktoken */
-#define DAV_ERR_LOCK_SAVE_LOCK 405 /* err saving locks */
-
-/*
-** Some comments on Error ID values:
-**
-** The numbers do not necessarily need to be unique. Uniqueness simply means
-** that two errors that have not been predefined above can be distinguished
-** from each other. At the moment, mod_dav does not use this distinguishing
-** feature, but it could be used in the future to collapse <response> elements
-** into groups based on the error ID (and associated responsedescription).
-**
-** If a compute_desc is provided, then the error ID should be unique within
-** the context of the compute_desc function (so the function can figure out
-** what to filled into the desc).
-**
-** Basically, subsystems can ignore defining new error ID values if they want
-** to. The subsystems *do* need to return the predefined errors when
-** appropriate, so that mod_dav can figure out what to do. Subsystems can
-** simply leave the error ID field unfilled (zero) if there isn't an error
-** that must be placed there.
-*/
-
-
-/* --------------------------------------------------------------------
-**
-** HOOK STRUCTURES
-**
-** These are here for forward-declaration purposes. For more info, see
-** the section title "HOOK HANDLING" for more information, plus each
-** structure definition.
-*/
-
-/* forward-declare this structure */
-typedef struct dav_hooks_propdb dav_hooks_propdb;
-typedef struct dav_hooks_locks dav_hooks_locks;
-typedef struct dav_hooks_vsn dav_hooks_vsn;
-typedef struct dav_hooks_repository dav_hooks_repository;
-typedef struct dav_hooks_liveprop dav_hooks_liveprop;
-typedef struct dav_hooks_binding dav_hooks_binding;
-typedef struct dav_hooks_search dav_hooks_search;
-
-/* ### deprecated name */
-typedef dav_hooks_propdb dav_hooks_db;
-
-
-/* --------------------------------------------------------------------
-**
-** RESOURCE HANDLING
-*/
-
-/*
-** Resource Types:
-** The base protocol defines only file and collection resources.
-** The versioning protocol defines several additional resource types
-** to represent artifacts of a version control system.
-**
-** This enumeration identifies the type of URL used to identify the
-** resource. Since the same resource may have more than one type of
-** URL which can identify it, dav_resource_type cannot be used
-** alone to determine the type of the resource; attributes of the
-** dav_resource object must also be consulted.
-*/
-typedef enum {
- DAV_RESOURCE_TYPE_UNKNOWN,
-
- DAV_RESOURCE_TYPE_REGULAR, /* file or collection; could be
- * unversioned, or version selector,
- * or baseline selector */
-
- DAV_RESOURCE_TYPE_VERSION, /* version or baseline URL */
-
- DAV_RESOURCE_TYPE_HISTORY, /* version or baseline history URL */
-
- DAV_RESOURCE_TYPE_WORKING, /* working resource URL */
-
- DAV_RESOURCE_TYPE_WORKSPACE, /* workspace URL */
-
- DAV_RESOURCE_TYPE_ACTIVITY, /* activity URL */
-
- DAV_RESOURCE_TYPE_PRIVATE /* repository-private type */
-
-} dav_resource_type;
-
-/*
-** Opaque, repository-specific information for a resource.
-*/
-typedef struct dav_resource_private dav_resource_private;
-
-/*
-** Resource descriptor, generated by a repository provider.
-**
-** Note: the lock-null state is not explicitly represented here,
-** since it may be expensive to compute. Use dav_get_resource_state()
-** to determine whether a non-existent resource is a lock-null resource.
-**
-** A quick explanation of how the flags can apply to different resources:
-**
-** unversioned file or collection:
-** type = DAV_RESOURCE_TYPE_REGULAR
-** exists = ? (1 if exists)
-** collection = ? (1 if collection)
-** versioned = 0
-** baselined = 0
-** working = 0
-**
-** version-controlled resource or configuration:
-** type = DAV_RESOURCE_TYPE_REGULAR
-** exists = 1
-** collection = ? (1 if collection)
-** versioned = 1
-** baselined = ? (1 if configuration)
-** working = ? (1 if checked out)
-**
-** version/baseline history:
-** type = DAV_RESOURCE_TYPE_HISTORY
-** exists = 1
-** collection = 0
-** versioned = 0
-** baselined = 0
-** working = 0
-**
-** version/baseline:
-** type = DAV_RESOURCE_TYPE_VERSION
-** exists = 1
-** collection = ? (1 if collection)
-** versioned = 1
-** baselined = ? (1 if baseline)
-** working = 0
-**
-** working resource:
-** type = DAV_RESOURCE_TYPE_WORKING
-** exists = 1
-** collection = ? (1 if collection)
-** versioned = 1
-** baselined = 0
-** working = 1
-**
-** workspace:
-** type = DAV_RESOURCE_TYPE_WORKSPACE
-** exists = ? (1 if exists)
-** collection = 1
-** versioned = ? (1 if version-controlled)
-** baselined = ? (1 if baseline-controlled)
-** working = ? (1 if checked out)
-**
-** activity:
-** type = DAV_RESOURCE_TYPE_ACTIVITY
-** exists = ? (1 if exists)
-** collection = 0
-** versioned = 0
-** baselined = 0
-** working = 0
-*/
-typedef struct dav_resource {
- dav_resource_type type;
-
- int exists; /* 0 => null resource */
-
- int collection; /* 0 => file; can be 1 for
- * REGULAR, VERSION, and WORKING resources,
- * and is always 1 for WORKSPACE */
-
- int versioned; /* 0 => unversioned; can be 1 for
- * REGULAR and WORKSPACE resources,
- * and is always 1 for VERSION and WORKING */
-
- int baselined; /* 0 => not baselined; can be 1 for
- * REGULAR, VERSION, and WORKSPACE resources;
- * versioned == 1 when baselined == 1 */
-
- int working; /* 0 => not checked out; can be 1 for
- * REGULAR and WORKSPACE resources,
- * and is always 1 for WORKING */
-
- const char *uri; /* the URI for this resource */
-
- dav_resource_private *info; /* the provider's private info */
-
- const dav_hooks_repository *hooks; /* hooks used for this resource */
-
- /* When allocating items related specifically to this resource, the
- following pool should be used. Its lifetime will be at least as
- long as the dav_resource structure. */
- apr_pool_t *pool;
-
-} dav_resource;
-
-/*
-** Lock token type. Lock providers define the details of a lock token.
-** However, all providers are expected to at least be able to parse
-** the "opaquelocktoken" scheme, which is represented by a uuid_t.
-*/
-typedef struct dav_locktoken dav_locktoken;
-
-
-/* --------------------------------------------------------------------
-**
-** BUFFER HANDLING
-**
-** These buffers are used as a lightweight buffer reuse mechanism. Apache
-** provides sub-pool creation and destruction to much the same effect, but
-** the sub-pools are a bit more general and heavyweight than these buffers.
-*/
-
-/* buffer for reuse; can grow to accomodate needed size */
-typedef struct
-{
- apr_size_t alloc_len; /* how much has been allocated */
- apr_size_t cur_len; /* how much is currently being used */
- char *buf; /* buffer contents */
-} dav_buffer;
-#define DAV_BUFFER_MINSIZE 256 /* minimum size for buffer */
-#define DAV_BUFFER_PAD 64 /* amount of pad when growing */
-
-/* set the cur_len to the given size and ensure space is available */
-DAV_DECLARE(void) dav_set_bufsize(apr_pool_t *p, dav_buffer *pbuf,
- apr_size_t size);
-
-/* initialize a buffer and copy the specified (null-term'd) string into it */
-DAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf,
- const char *str);
-
-/* check that the buffer can accomodate <extra_needed> more bytes */
-DAV_DECLARE(void) dav_check_bufsize(apr_pool_t *p, dav_buffer *pbuf,
- apr_size_t extra_needed);
-
-/* append a string to the end of the buffer, adjust length */
-DAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf,
- const char *str);
-
-/* place a string on the end of the buffer, do NOT adjust length */
-DAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf,
- const char *str);
-
-/* place some memory on the end of a buffer; do NOT adjust length */
-DAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf,
- const void *mem, apr_size_t amt,
- apr_size_t pad);
-
-
-/* --------------------------------------------------------------------
-**
-** HANDY UTILITIES
-*/
-
-/* contains results from one of the getprop functions */
-typedef struct
-{
- apr_text * propstats; /* <propstat> element text */
- apr_text * xmlns; /* namespace decls for <response> elem */
-} dav_get_props_result;
-
-/* holds the contents of a <response> element */
-typedef struct dav_response
-{
- const char *href; /* always */
- const char *desc; /* optional description at <response> level */
-
- /* use status if propresult.propstats is NULL. */
- dav_get_props_result propresult;
-
- int status;
-
- struct dav_response *next;
-} dav_response;
-
-typedef struct
-{
- request_rec *rnew; /* new subrequest */
- dav_error err; /* potential error response */
-} dav_lookup_result;
-
-
-DAV_DECLARE(dav_lookup_result) dav_lookup_uri(const char *uri, request_rec *r,
- int must_be_absolute);
-
-/* defines type of property info a provider is to return */
-typedef enum {
- DAV_PROP_INSERT_NOTDEF, /* property is defined by this provider,
- but nothing was inserted because the
- (live) property is not defined for this
- resource (it may be present as a dead
- property). */
- DAV_PROP_INSERT_NOTSUPP, /* property is recognized by this provider,
- but it is not supported, and cannot be
- treated as a dead property */
- DAV_PROP_INSERT_NAME, /* a property name (empty elem) was
- inserted into the text block */
- DAV_PROP_INSERT_VALUE, /* a property name/value pair was inserted
- into the text block */
- DAV_PROP_INSERT_SUPPORTED /* a supported live property was added to
- the text block as a
- <DAV:supported-live-property> element */
-} dav_prop_insert;
-
-/* ### this stuff is private to dav/fs/repos.c; move it... */
-/* format a time string (buf must be at least DAV_TIMEBUF_SIZE chars) */
-#define DAV_STYLE_ISO8601 1
-#define DAV_STYLE_RFC822 2
-#define DAV_TIMEBUF_SIZE 30
-
-DAV_DECLARE(int) dav_get_depth(request_rec *r, int def_depth);
-
-DAV_DECLARE(int) dav_validate_root(const apr_xml_doc *doc,
- const char *tagname);
-DAV_DECLARE(apr_xml_elem *) dav_find_child(const apr_xml_elem *elem,
- const char *tagname);
-
-/* gather up all the CDATA into a single string */
-DAV_DECLARE(const char *) dav_xml_get_cdata(const apr_xml_elem *elem, apr_pool_t *pool,
- int strip_white);
-
-/*
-** XML namespace handling
-**
-** This structure tracks namespace declarations (xmlns:prefix="URI").
-** It maintains a one-to-many relationship of URIs-to-prefixes. In other
-** words, one URI may be defined by many prefixes, but any specific
-** prefix will specify only one URI.
-**
-** Prefixes using the "g###" pattern can be generated automatically if
-** the caller does not have specific prefix requirements.
-*/
-typedef struct {
- apr_pool_t *pool;
- apr_hash_t *uri_prefix; /* map URIs to an available prefix */
- apr_hash_t *prefix_uri; /* map all prefixes to their URIs */
- int count; /* counter for "g###" prefixes */
-} dav_xmlns_info;
-
-/* create an empty dav_xmlns_info structure */
-DAV_DECLARE(dav_xmlns_info *) dav_xmlns_create(apr_pool_t *pool);
-
-/* add a specific prefix/URI pair. the prefix/uri should have a lifetime
- at least that of xmlns->pool */
-DAV_DECLARE(void) dav_xmlns_add(dav_xmlns_info *xi,
- const char *prefix, const char *uri);
-
-/* add a URI (if not present); any prefix is acceptable and is returned.
- the uri should have a lifetime at least that xmlns->pool */
-DAV_DECLARE(const char *) dav_xmlns_add_uri(dav_xmlns_info *xi,
- const char *uri);
-
-/* return the URI for a specified prefix (or NULL if the prefix is unknown) */
-DAV_DECLARE(const char *) dav_xmlns_get_uri(dav_xmlns_info *xi,
- const char *prefix);
-
-/* return an available prefix for a specified URI (or NULL if the URI
- is unknown) */
-DAV_DECLARE(const char *) dav_xmlns_get_prefix(dav_xmlns_info *xi,
- const char *uri);
-
-/* generate xmlns declarations (appending into the given text) */
-DAV_DECLARE(void) dav_xmlns_generate(dav_xmlns_info *xi,
- apr_text_header *phdr);
-
-/* --------------------------------------------------------------------
-**
-** DAV PLUGINS
-*/
-
-/* ### docco ... */
-
-/*
-** dav_provider
-**
-** This structure wraps up all of the hooks that a mod_dav provider can
-** supply. The provider MUST supply <repos> and <propdb>. The rest are
-** optional and should contain NULL if that feature is not supplied.
-**
-** Note that a provider cannot pick and choose portions from various
-** underlying implementations (which was theoretically possible in
-** mod_dav 1.0). There are too many dependencies between a dav_resource
-** (defined by <repos>) and the other functionality.
-**
-** Live properties are not part of the dav_provider structure because they
-** are handled through the APR_HOOK interface (to allow for multiple liveprop
-** providers). The core always provides some properties, and then a given
-** provider will add more properties.
-**
-** Some providers may need to associate a context with the dav_provider
-** structure -- the ctx field is available for storing this context. Just
-** leave it NULL if it isn't required.
-*/
-typedef struct {
- const dav_hooks_repository *repos;
- const dav_hooks_propdb *propdb;
- const dav_hooks_locks *locks;
- const dav_hooks_vsn *vsn;
- const dav_hooks_binding *binding;
- const dav_hooks_search *search;
-
- void *ctx;
-} dav_provider;
-
-/*
-** gather_propsets: gather all live property propset-URIs
-**
-** The hook implementor should push one or more URIs into the specified
-** array. These URIs are returned in the DAV: header to let clients know
-** what sets of live properties are supported by the installation. mod_dav
-** will place open/close angle brackets around each value (much like
-** a Coded-URL); quotes and brackets should not be in the value.
-**
-** Example: http://apache.org/dav/props/
-**
-** (of course, use your own domain to ensure a unique value)
-*/
-APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, gather_propsets,
- (apr_array_header_t *uris))
-
-/*
-** find_liveprop: find a live property, returning a non-zero, unique,
-** opaque identifier.
-**
-** If the hook implementor determines the specified URI/name refers to
-** one of its properties, then it should fill in HOOKS and return a
-** non-zero value. The returned value is the "property ID" and will
-** be passed to the various liveprop hook functions.
-**
-** Return 0 if the property is not defined by the hook implementor.
-*/
-APR_DECLARE_EXTERNAL_HOOK(dav, DAV, int, find_liveprop,
- (const dav_resource *resource,
- const char *ns_uri, const char *name,
- const dav_hooks_liveprop **hooks))
-
-/*
-** insert_all_liveprops: insert all (known) live property names/values.
-**
-** The hook implementor should append XML text to PHDR, containing liveprop
-** names. If INSVALUE is true, then the property values should also be
-** inserted into the output XML stream.
-**
-** The liveprop provider should insert *all* known and *defined* live
-** properties on the specified resource. If a particular liveprop is
-** not defined for this resource, then it should not be inserted.
-*/
-APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, insert_all_liveprops,
- (request_rec *r, const dav_resource *resource,
- dav_prop_insert what, apr_text_header *phdr))
-
-DAV_DECLARE(const dav_hooks_locks *) dav_get_lock_hooks(request_rec *r);
-DAV_DECLARE(const dav_hooks_propdb *) dav_get_propdb_hooks(request_rec *r);
-DAV_DECLARE(const dav_hooks_vsn *) dav_get_vsn_hooks(request_rec *r);
-DAV_DECLARE(const dav_hooks_binding *) dav_get_binding_hooks(request_rec *r);
-DAV_DECLARE(const dav_hooks_search *) dav_get_search_hooks(request_rec *r);
-
-DAV_DECLARE(void) dav_register_provider(apr_pool_t *p, const char *name,
- const dav_provider *hooks);
-DAV_DECLARE(const dav_provider *) dav_lookup_provider(const char *name);
-
-
-/* ### deprecated */
-#define DAV_GET_HOOKS_PROPDB(r) dav_get_propdb_hooks(r)
-#define DAV_GET_HOOKS_LOCKS(r) dav_get_lock_hooks(r)
-#define DAV_GET_HOOKS_VSN(r) dav_get_vsn_hooks(r)
-#define DAV_GET_HOOKS_BINDING(r) dav_get_binding_hooks(r)
-#define DAV_GET_HOOKS_SEARCH(r) dav_get_search_hooks(r)
-
-
-/* --------------------------------------------------------------------
-**
-** IF HEADER PROCESSING
-**
-** Here is the definition of the If: header from RFC 2518, S9.4:
-**
-** If = "If" ":" (1*No-tag-list | 1*Tagged-list)
-** No-tag-list = List
-** Tagged-list = Resource 1*List
-** Resource = Coded-URL
-** List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")"
-** State-token = Coded-URL
-** Coded-URL = "<" absoluteURI ">" ; absoluteURI from RFC 2616
-**
-** List corresponds to dav_if_state_list. No-tag-list corresponds to
-** dav_if_header with uri==NULL. Tagged-list corresponds to a sequence of
-** dav_if_header structures with (duplicate) uri==Resource -- one
-** dav_if_header per state_list. A second Tagged-list will start a new
-** sequence of dav_if_header structures with the new URI.
-**
-** A summary of the semantics, mapped into our structures:
-** - Chained dav_if_headers: OR
-** - Chained dav_if_state_lists: AND
-** - NULL uri matches all resources
-*/
-
-typedef enum
-{
- dav_if_etag,
- dav_if_opaquelock
-} dav_if_state_type;
-
-typedef struct dav_if_state_list
-{
- dav_if_state_type type;
-
- int condition;
-#define DAV_IF_COND_NORMAL 0
-#define DAV_IF_COND_NOT 1 /* "Not" was applied */
-
- const char *etag;
- dav_locktoken *locktoken;
-
- struct dav_if_state_list *next;
-} dav_if_state_list;
-
-typedef struct dav_if_header
-{
- const char *uri;
- apr_size_t uri_len;
- struct dav_if_state_list *state;
- struct dav_if_header *next;
-
- int dummy_header; /* used internally by the lock/etag validation */
-} dav_if_header;
-
-typedef struct dav_locktoken_list
-{
- dav_locktoken *locktoken;
- struct dav_locktoken_list *next;
-} dav_locktoken_list;
-
-DAV_DECLARE(dav_error *) dav_get_locktoken_list(request_rec *r,
- dav_locktoken_list **ltl);
-
-
-/* --------------------------------------------------------------------
-**
-** LIVE PROPERTY HANDLING
-*/
-
-/* opaque type for PROPPATCH rollback information */
-typedef struct dav_liveprop_rollback dav_liveprop_rollback;
-
-struct dav_hooks_liveprop
-{
- /*
- ** Insert property information into a text block. The property to
- ** insert is identified by the propid value. The information to insert
- ** is identified by the "what" argument, as follows:
- ** DAV_PROP_INSERT_NAME
- ** property name, as an empty XML element
- ** DAV_PROP_INSERT_VALUE
- ** property name/value, as an XML element
- ** DAV_PROP_INSERT_SUPPORTED
- ** if the property is defined on the resource, then
- ** a DAV:supported-live-property element, as defined
- ** by the DeltaV extensions to RFC2518.
- **
- ** Providers should return DAV_PROP_INSERT_NOTDEF if the property is
- ** known and not defined for this resource, so should be handled as a
- ** dead property. If a provider recognizes, but does not support, a
- ** property, and does not want it handled as a dead property, it should
- ** return DAV_PROP_INSERT_NOTSUPP.
- **
- ** Returns one of DAV_PROP_INSERT_* based on what happened.
- **
- ** ### we may need more context... ie. the lock database
- */
- dav_prop_insert (*insert_prop)(const dav_resource *resource,
- int propid, dav_prop_insert what,
- apr_text_header *phdr);
-
- /*
- ** Determine whether a given property is writable.
- **
- ** ### we may want a different semantic. i.e. maybe it should be
- ** ### "can we write <value> into this property?"
- **
- ** Returns 1 if the live property can be written, 0 if read-only.
- */
- int (*is_writable)(const dav_resource *resource, int propid);
-
- /*
- ** This member defines the set of namespace URIs that the provider
- ** uses for its properties. When insert_all is called, it will be
- ** passed a list of integers that map from indices into this list
- ** to namespace IDs for output generation.
- **
- ** The last entry in this list should be a NULL value (sentinel).
- */
- const char * const * namespace_uris;
-
- /*
- ** ### this is not the final design. we want an open-ended way for
- ** ### liveprop providers to attach *new* properties. To this end,
- ** ### we'll have a "give me a list of the props you define", a way
- ** ### to check for a prop's existence, a way to validate a set/remove
- ** ### of a prop, and a way to execute/commit/rollback that change.
- */
-
- /*
- ** Validate that the live property can be assigned a value, and that
- ** the provided value is valid.
- **
- ** elem will point to the XML element that names the property. For
- ** example:
- ** <lp1:executable>T</lp1:executable>
- **
- ** The provider can access the cdata fields and the child elements
- ** to extract the relevant pieces.
- **
- ** operation is one of DAV_PROP_OP_SET or _DELETE.
- **
- ** The provider may return a value in *context which will be passed
- ** to each of the exec/commit/rollback functions. For example, this
- ** may contain an internal value which has been processed from the
- ** input element.
- **
- ** The provider must set defer_to_dead to true (non-zero) or false.
- ** If true, then the set/remove is deferred to the dead property
- ** database. Note: it will be set to zero on entry.
- */
- dav_error * (*patch_validate)(const dav_resource *resource,
- const apr_xml_elem *elem,
- int operation,
- void **context,
- int *defer_to_dead);
-
- /* ### doc... */
- dav_error * (*patch_exec)(const dav_resource *resource,
- const apr_xml_elem *elem,
- int operation,
- void *context,
- dav_liveprop_rollback **rollback_ctx);
-
- /* ### doc... */
- void (*patch_commit)(const dav_resource *resource,
- int operation,
- void *context,
- dav_liveprop_rollback *rollback_ctx);
-
- /* ### doc... */
- dav_error * (*patch_rollback)(const dav_resource *resource,
- int operation,
- void *context,
- dav_liveprop_rollback *rollback_ctx);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-};
-
-/*
-** dav_liveprop_spec: specify a live property
-**
-** This structure is used as a standard way to determine if a particular
-** property is a live property. Its use is not part of the mandated liveprop
-** interface, but can be used by liveprop providers in conjuction with the
-** utility routines below.
-**
-** spec->name == NULL is the defined end-sentinel for a list of specs.
-*/
-typedef struct {
- int ns; /* provider-local namespace index */
- const char *name; /* name of the property */
-
- int propid; /* provider-local property ID */
-
- int is_writable; /* is the property writable? */
-
-} dav_liveprop_spec;
-
-/*
-** dav_liveprop_group: specify a group of liveprops
-**
-** This structure specifies a group of live properties, their namespaces,
-** and how to handle them.
-*/
-typedef struct {
- const dav_liveprop_spec *specs;
- const char * const *namespace_uris;
- const dav_hooks_liveprop *hooks;
-
-} dav_liveprop_group;
-
-/* ### docco */
-DAV_DECLARE(int) dav_do_find_liveprop(const char *ns_uri, const char *name,
- const dav_liveprop_group *group,
- const dav_hooks_liveprop **hooks);
-
-/* ### docco */
-DAV_DECLARE(int) dav_get_liveprop_info(int propid,
- const dav_liveprop_group *group,
- const dav_liveprop_spec **info);
-
-/* ### docco */
-DAV_DECLARE(void) dav_register_liveprop_group(apr_pool_t *pool,
- const dav_liveprop_group *group);
-
-/* ### docco */
-DAV_DECLARE(int) dav_get_liveprop_ns_index(const char *uri);
-
-/* ### docco */
-DAV_DECLARE(int) dav_get_liveprop_ns_count(void);
-
-/* ### docco */
-DAV_DECLARE(void) dav_add_all_liveprop_xmlns(apr_pool_t *p,
- apr_text_header *phdr);
-
-/*
-** The following three functions are part of mod_dav's internal handling
-** for the core WebDAV properties. They are not part of mod_dav's API.
-*/
-DAV_DECLARE_NONSTD(int) dav_core_find_liveprop(
- const dav_resource *resource,
- const char *ns_uri,
- const char *name,
- const dav_hooks_liveprop **hooks);
-DAV_DECLARE_NONSTD(void) dav_core_insert_all_liveprops(
- request_rec *r,
- const dav_resource *resource,
- dav_prop_insert what,
- apr_text_header *phdr);
-DAV_DECLARE_NONSTD(void) dav_core_register_uris(apr_pool_t *p);
-
-
-/*
-** Standard WebDAV Property Identifiers
-**
-** A live property provider does not need to use these; they are simply
-** provided for convenience.
-**
-** Property identifiers need to be unique within a given provider, but not
-** *across* providers (note: this uniqueness constraint was different in
-** older versions of mod_dav).
-**
-** The identifiers start at 20000 to make it easier for providers to avoid
-** conflicts with the standard properties. The properties are arranged
-** alphabetically, and may be reordered from time to time (as properties
-** are introduced).
-**
-** NOTE: there is no problem with reordering (e.g. binary compat) since the
-** identifiers are only used within a given provider, which would pick up
-** the entire set of changes upon a recompile.
-*/
-enum {
- DAV_PROPID_BEGIN = 20000,
-
- /* Standard WebDAV properties (RFC 2518) */
- DAV_PROPID_creationdate,
- DAV_PROPID_displayname,
- DAV_PROPID_getcontentlanguage,
- DAV_PROPID_getcontentlength,
- DAV_PROPID_getcontenttype,
- DAV_PROPID_getetag,
- DAV_PROPID_getlastmodified,
- DAV_PROPID_lockdiscovery,
- DAV_PROPID_resourcetype,
- DAV_PROPID_source,
- DAV_PROPID_supportedlock,
-
- /* DeltaV properties (from the I-D (#14)) */
- DAV_PROPID_activity_checkout_set,
- DAV_PROPID_activity_set,
- DAV_PROPID_activity_version_set,
- DAV_PROPID_auto_merge_set,
- DAV_PROPID_auto_version,
- DAV_PROPID_baseline_collection,
- DAV_PROPID_baseline_controlled_collection,
- DAV_PROPID_baseline_controlled_collection_set,
- DAV_PROPID_checked_in,
- DAV_PROPID_checked_out,
- DAV_PROPID_checkin_fork,
- DAV_PROPID_checkout_fork,
- DAV_PROPID_checkout_set,
- DAV_PROPID_comment,
- DAV_PROPID_creator_displayname,
- DAV_PROPID_current_activity_set,
- DAV_PROPID_current_workspace_set,
- DAV_PROPID_default_variant,
- DAV_PROPID_eclipsed_set,
- DAV_PROPID_label_name_set,
- DAV_PROPID_merge_set,
- DAV_PROPID_precursor_set,
- DAV_PROPID_predecessor_set,
- DAV_PROPID_root_version,
- DAV_PROPID_subactivity_set,
- DAV_PROPID_subbaseline_set,
- DAV_PROPID_successor_set,
- DAV_PROPID_supported_method_set,
- DAV_PROPID_supported_live_property_set,
- DAV_PROPID_supported_report_set,
- DAV_PROPID_unreserved,
- DAV_PROPID_variant_set,
- DAV_PROPID_version_controlled_binding_set,
- DAV_PROPID_version_controlled_configuration,
- DAV_PROPID_version_history,
- DAV_PROPID_version_name,
- DAV_PROPID_workspace,
- DAV_PROPID_workspace_checkout_set,
-
- DAV_PROPID_END
-};
-
-/*
-** Property Identifier Registration
-**
-** At the moment, mod_dav requires live property providers to ensure that
-** each property returned has a unique value. For now, this is done through
-** central registration (there are no known providers other than the default,
-** so this remains manageable).
-**
-** WARNING: the TEST ranges should never be "shipped".
-*/
-#define DAV_PROPID_CORE 10000 /* ..10099. defined by mod_dav */
-#define DAV_PROPID_FS 10100 /* ..10299.
- mod_dav filesystem provider. */
-#define DAV_PROPID_TEST1 10300 /* ..10399 */
-#define DAV_PROPID_TEST2 10400 /* ..10499 */
-#define DAV_PROPID_TEST3 10500 /* ..10599 */
-/* Next: 10600 */
-
-
-/* --------------------------------------------------------------------
-**
-** DATABASE FUNCTIONS
-*/
-
-typedef struct dav_db dav_db;
-typedef struct dav_namespace_map dav_namespace_map;
-typedef struct dav_deadprop_rollback dav_deadprop_rollback;
-
-typedef struct {
- const char *ns; /* "" signals "no namespace" */
- const char *name;
-} dav_prop_name;
-
-/* hook functions to enable pluggable databases */
-struct dav_hooks_propdb
-{
- dav_error * (*open)(apr_pool_t *p, const dav_resource *resource, int ro,
- dav_db **pdb);
- void (*close)(dav_db *db);
-
- /*
- ** In bulk, define any namespaces that the values and their name
- ** elements may need.
- **
- ** Note: sometimes mod_dav will defer calling this until output_value
- ** returns found==1. If the output process needs the dav_xmlns_info
- ** filled for its work, then it will need to fill it on demand rather
- ** than depending upon this hook to fill in the structure.
- **
- ** Note: this will *always* be called during an output sequence. Thus,
- ** the provider may rely solely on using this to fill the xmlns info.
- */
- dav_error * (*define_namespaces)(dav_db *db, dav_xmlns_info *xi);
-
- /*
- ** Output the value from the database (i.e. add an element name and
- ** the value into *phdr). Set *found based on whether the name/value
- ** was found in the propdb.
- **
- ** Note: it is NOT an error for the key/value pair to not exist.
- **
- ** The dav_xmlns_info passed to define_namespaces() is also passed to
- ** each output_value() call so that namespaces can be added on-demand.
- ** It can also be used to look up prefixes or URIs during the output
- ** process.
- */
- dav_error * (*output_value)(dav_db *db, const dav_prop_name *name,
- dav_xmlns_info *xi,
- apr_text_header *phdr, int *found);
-
- /*
- ** Build a mapping from "global" namespaces (stored in apr_xml_*)
- ** into provider-local namespace identifiers.
- **
- ** This mapping should be done once per set of namespaces, and the
- ** resulting mapping should be passed into the store() hook function.
- **
- ** Note: usually, there is just a single document/namespaces for all
- ** elements passed. However, the generality of creating multiple
- ** mappings and passing them to store() is provided here.
- **
- ** Note: this is only in preparation for a series of store() calls.
- ** As a result, the propdb must be open for read/write access when
- ** this function is called.
- */
- dav_error * (*map_namespaces)(dav_db *db,
- const apr_array_header_t *namespaces,
- dav_namespace_map **mapping);
-
- /*
- ** Store a property value for a given name. The value->combined field
- ** MUST be set for this call.
- **
- ** ### WARNING: current providers will quote the text within ELEM.
- ** ### this implies you can call this function only once with a given
- ** ### element structure (a second time will quote it again).
- */
- dav_error * (*store)(dav_db *db, const dav_prop_name *name,
- const apr_xml_elem *elem,
- dav_namespace_map *mapping);
-
- /* remove a given property */
- dav_error * (*remove)(dav_db *db, const dav_prop_name *name);
-
- /* returns 1 if the record specified by "key" exists; 0 otherwise */
- int (*exists)(dav_db *db, const dav_prop_name *name);
-
- /*
- ** Iterate over the property names in the database.
- **
- ** iter->name.ns == iter->name.name == NULL when there are no more names.
- **
- ** Note: only one iteration may occur over the propdb at a time.
- */
- dav_error * (*first_name)(dav_db *db, dav_prop_name *pname);
- dav_error * (*next_name)(dav_db *db, dav_prop_name *pname);
-
- /*
- ** Rollback support: get rollback context, and apply it.
- **
- ** struct dav_deadprop_rollback is a provider-private structure; it
- ** should remember the name, and the name's old value (or the fact that
- ** the value was not present, and should be deleted if a rollback occurs).
- */
- dav_error * (*get_rollback)(dav_db *db, const dav_prop_name *name,
- dav_deadprop_rollback **prollback);
- dav_error * (*apply_rollback)(dav_db *db,
- dav_deadprop_rollback *rollback);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-};
-
-
-/* --------------------------------------------------------------------
-**
-** LOCK FUNCTIONS
-*/
-
-/* Used to represent a Timeout header of "Infinity" */
-#define DAV_TIMEOUT_INFINITE 0
-
-DAV_DECLARE(time_t) dav_get_timeout(request_rec *r);
-
-/*
-** Opaque, provider-specific information for a lock database.
-*/
-typedef struct dav_lockdb_private dav_lockdb_private;
-
-/*
-** Opaque, provider-specific information for a lock record.
-*/
-typedef struct dav_lock_private dav_lock_private;
-
-/*
-** Lock database type. Lock providers are urged to implement a "lazy" open, so
-** doing an "open" is cheap until something is actually needed from the DB.
-*/
-typedef struct
-{
- const dav_hooks_locks *hooks; /* the hooks used for this lockdb */
- int ro; /* was it opened readonly? */
-
- dav_lockdb_private *info;
-
-} dav_lockdb;
-
-typedef enum {
- DAV_LOCKSCOPE_UNKNOWN,
- DAV_LOCKSCOPE_EXCLUSIVE,
- DAV_LOCKSCOPE_SHARED
-} dav_lock_scope;
-
-typedef enum {
- DAV_LOCKTYPE_UNKNOWN,
- DAV_LOCKTYPE_WRITE
-} dav_lock_type;
-
-typedef enum {
- DAV_LOCKREC_DIRECT, /* lock asserted on this resource */
- DAV_LOCKREC_INDIRECT, /* lock inherited from a parent */
- DAV_LOCKREC_INDIRECT_PARTIAL /* most info is not filled in */
-} dav_lock_rectype;
-
-/*
-** dav_lock: hold information about a lock on a resource.
-**
-** This structure is used for both direct and indirect locks. A direct lock
-** is a lock applied to a specific resource by the client. An indirect lock
-** is one that is inherited from a parent resource by virtue of a non-zero
-** Depth: header when the lock was applied.
-**
-** mod_dav records both types of locks in the lock database, managing their
-** addition/removal as resources are moved about the namespace.
-**
-** Note that the lockdb is free to marshal this structure in any form that
-** it likes.
-**
-** For a "partial" lock, the <rectype> and <locktoken> fields must be filled
-** in. All other (user) fields should be zeroed. The lock provider will
-** usually fill in the <info> field, and the <next> field may be used to
-** construct a list of partial locks.
-**
-** The lock provider MUST use the info field to store a value such that a
-** dav_lock structure can locate itself in the underlying lock database.
-** This requirement is needed for refreshing: when an indirect dav_lock is
-** refreshed, its reference to the direct lock does not specify the direct's
-** resource, so the only way to locate the (refreshed, direct) lock in the
-** database is to use the info field.
-**
-** Note that <is_locknull> only refers to the resource where this lock was
-** found.
-** ### hrm. that says the abstraction is wrong. is_locknull may disappear.
-*/
-typedef struct dav_lock
-{
- dav_lock_rectype rectype; /* type of lock record */
- int is_locknull; /* lock establishes a locknull resource */
-
- /* ### put the resource in here? */
-
- dav_lock_scope scope; /* scope of the lock */
- dav_lock_type type; /* type of lock */
- int depth; /* depth of the lock */
- time_t timeout; /* when the lock will timeout */
-
- const dav_locktoken *locktoken; /* the token that was issued */
-
- const char *owner; /* (XML) owner of the lock */
- const char *auth_user; /* auth'd username owning lock */
-
- dav_lock_private *info; /* private to the lockdb */
-
- struct dav_lock *next; /* for managing a list of locks */
-} dav_lock;
-
-/* Property-related public lock functions */
-DAV_DECLARE(const char *)dav_lock_get_activelock(request_rec *r,
- dav_lock *locks,
- dav_buffer *pbuf);
-
-/* LockDB-related public lock functions */
-DAV_DECLARE(dav_error *) dav_lock_parse_lockinfo(request_rec *r,
- const dav_resource *resrouce,
- dav_lockdb *lockdb,
- const apr_xml_doc *doc,
- dav_lock **lock_request);
-DAV_DECLARE(int) dav_unlock(request_rec *r,
- const dav_resource *resource,
- const dav_locktoken *locktoken);
-DAV_DECLARE(dav_error *) dav_add_lock(request_rec *r,
- const dav_resource *resource,
- dav_lockdb *lockdb, dav_lock *request,
- dav_response **response);
-DAV_DECLARE(dav_error *) dav_notify_created(request_rec *r,
- dav_lockdb *lockdb,
- const dav_resource *resource,
- int resource_state,
- int depth);
-
-DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb,
- const dav_resource *resource,
- dav_lock **locks);
-
-DAV_DECLARE(dav_error *) dav_validate_request(request_rec *r,
- dav_resource *resource,
- int depth,
- dav_locktoken *locktoken,
- dav_response **response,
- int flags,
- dav_lockdb *lockdb);
-/*
-** flags:
-** 0x0F -- reserved for <dav_lock_scope> values
-**
-** other flags, detailed below
-*/
-#define DAV_VALIDATE_RESOURCE 0x0010 /* validate just the resource */
-#define DAV_VALIDATE_PARENT 0x0020 /* validate resource AND its parent */
-#define DAV_VALIDATE_ADD_LD 0x0040 /* add DAV:lockdiscovery into
- the 424 DAV:response */
-#define DAV_VALIDATE_USE_424 0x0080 /* return 424 status, not 207 */
-#define DAV_VALIDATE_IS_PARENT 0x0100 /* for internal use */
-
-/* Lock-null related public lock functions */
-DAV_DECLARE(int) dav_get_resource_state(request_rec *r,
- const dav_resource *resource);
-
-/* Lock provider hooks. Locking is optional, so there may be no
- * lock provider for a given repository.
- */
-struct dav_hooks_locks
-{
- /* Return the supportedlock property for a resource */
- const char * (*get_supportedlock)(
- const dav_resource *resource
- );
-
- /* Parse a lock token URI, returning a lock token object allocated
- * in the given pool.
- */
- dav_error * (*parse_locktoken)(
- apr_pool_t *p,
- const char *char_token,
- dav_locktoken **locktoken_p
- );
-
- /* Format a lock token object into a URI string, allocated in
- * the given pool.
- *
- * Always returns non-NULL.
- */
- const char * (*format_locktoken)(
- apr_pool_t *p,
- const dav_locktoken *locktoken
- );
-
- /* Compare two lock tokens.
- *
- * Result < 0 => lt1 < lt2
- * Result == 0 => lt1 == lt2
- * Result > 0 => lt1 > lt2
- */
- int (*compare_locktoken)(
- const dav_locktoken *lt1,
- const dav_locktoken *lt2
- );
-
- /* Open the provider's lock database.
- *
- * The provider may or may not use a "real" database for locks
- * (a lock could be an attribute on a resource, for example).
- *
- * The provider may choose to use the value of the DAVLockDB directive
- * (as returned by dav_get_lockdb_path()) to decide where to place
- * any storage it may need.
- *
- * The request storage pool should be associated with the lockdb,
- * so it can be used in subsequent operations.
- *
- * If ro != 0, only readonly operations will be performed.
- * If force == 0, the open can be "lazy"; no subsequent locking operations
- * may occur.
- * If force != 0, locking operations will definitely occur.
- */
- dav_error * (*open_lockdb)(
- request_rec *r,
- int ro,
- int force,
- dav_lockdb **lockdb
- );
-
- /* Indicates completion of locking operations */
- void (*close_lockdb)(
- dav_lockdb *lockdb
- );
-
- /* Take a resource out of the lock-null state. */
- dav_error * (*remove_locknull_state)(
- dav_lockdb *lockdb,
- const dav_resource *resource
- );
-
- /*
- ** Create a (direct) lock structure for the given resource. A locktoken
- ** will be created.
- **
- ** The lock provider may store private information into lock->info.
- */
- dav_error * (*create_lock)(dav_lockdb *lockdb,
- const dav_resource *resource,
- dav_lock **lock);
-
- /*
- ** Get the locks associated with the specified resource.
- **
- ** If resolve_locks is true (non-zero), then any indirect locks are
- ** resolved to their actual, direct lock (i.e. the reference to followed
- ** to the original lock).
- **
- ** The locks, if any, are returned as a linked list in no particular
- ** order. If no locks are present, then *locks will be NULL.
- */
- dav_error * (*get_locks)(dav_lockdb *lockdb,
- const dav_resource *resource,
- int calltype,
- dav_lock **locks);
-
-#define DAV_GETLOCKS_RESOLVED 0 /* resolve indirects to directs */
-#define DAV_GETLOCKS_PARTIAL 1 /* leave indirects partially filled */
-#define DAV_GETLOCKS_COMPLETE 2 /* fill out indirect locks */
-
- /*
- ** Find a particular lock on a resource (specified by its locktoken).
- **
- ** *lock will be set to NULL if the lock is not found.
- **
- ** Note that the provider can optimize the unmarshalling -- only one
- ** lock (or none) must be constructed and returned.
- **
- ** If partial_ok is true (non-zero), then an indirect lock can be
- ** partially filled in. Otherwise, another lookup is done and the
- ** lock structure will be filled out as a DAV_LOCKREC_INDIRECT.
- */
- dav_error * (*find_lock)(dav_lockdb *lockdb,
- const dav_resource *resource,
- const dav_locktoken *locktoken,
- int partial_ok,
- dav_lock **lock);
-
- /*
- ** Quick test to see if the resource has *any* locks on it.
- **
- ** This is typically used to determine if a non-existent resource
- ** has a lock and is (therefore) a locknull resource.
- **
- ** WARNING: this function may return TRUE even when timed-out locks
- ** exist (i.e. it may not perform timeout checks).
- */
- dav_error * (*has_locks)(dav_lockdb *lockdb,
- const dav_resource *resource,
- int *locks_present);
-
- /*
- ** Append the specified lock(s) to the set of locks on this resource.
- **
- ** If "make_indirect" is true (non-zero), then the specified lock(s)
- ** should be converted to an indirect lock (if it is a direct lock)
- ** before appending. Note that the conversion to an indirect lock does
- ** not alter the passed-in lock -- the change is internal the
- ** append_locks function.
- **
- ** Multiple locks are specified using the lock->next links.
- */
- dav_error * (*append_locks)(dav_lockdb *lockdb,
- const dav_resource *resource,
- int make_indirect,
- const dav_lock *lock);
-
- /*
- ** Remove any lock that has the specified locktoken.
- **
- ** If locktoken == NULL, then ALL locks are removed.
- */
- dav_error * (*remove_lock)(dav_lockdb *lockdb,
- const dav_resource *resource,
- const dav_locktoken *locktoken);
-
- /*
- ** Refresh all locks, found on the specified resource, which has a
- ** locktoken in the provided list.
- **
- ** If the lock is indirect, then the direct lock is referenced and
- ** refreshed.
- **
- ** Each lock that is updated is returned in the <locks> argument.
- ** Note that the locks will be fully resolved.
- */
- dav_error * (*refresh_locks)(dav_lockdb *lockdb,
- const dav_resource *resource,
- const dav_locktoken_list *ltl,
- time_t new_time,
- dav_lock **locks);
-
- /*
- ** Look up the resource associated with a particular locktoken.
- **
- ** The search begins at the specified <start_resource> and the lock
- ** specified by <locktoken>.
- **
- ** If the resource/token specifies an indirect lock, then the direct
- ** lock will be looked up, and THAT resource will be returned. In other
- ** words, this function always returns the resource where a particular
- ** lock (token) was asserted.
- **
- ** NOTE: this function pointer is allowed to be NULL, indicating that
- ** the provider does not support this type of functionality. The
- ** caller should then traverse up the repository hierarchy looking
- ** for the resource defining a lock with this locktoken.
- */
- dav_error * (*lookup_resource)(dav_lockdb *lockdb,
- const dav_locktoken *locktoken,
- const dav_resource *start_resource,
- const dav_resource **resource);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-};
-
-/* what types of resources can be discovered by dav_get_resource_state() */
-#define DAV_RESOURCE_LOCK_NULL 10 /* resource lock-null */
-#define DAV_RESOURCE_NULL 11 /* resource null */
-#define DAV_RESOURCE_EXISTS 12 /* resource exists */
-#define DAV_RESOURCE_ERROR 13 /* an error occurred */
-
-
-/* --------------------------------------------------------------------
-**
-** PROPERTY HANDLING
-*/
-
-typedef struct dav_propdb dav_propdb;
-
-
-DAV_DECLARE(dav_error *) dav_open_propdb(
- request_rec *r,
- dav_lockdb *lockdb,
- const dav_resource *resource,
- int ro,
- apr_array_header_t *ns_xlate,
- dav_propdb **propdb);
-
-DAV_DECLARE(void) dav_close_propdb(dav_propdb *db);
-
-DAV_DECLARE(dav_get_props_result) dav_get_props(
- dav_propdb *db,
- apr_xml_doc *doc);
-
-DAV_DECLARE(dav_get_props_result) dav_get_allprops(
- dav_propdb *db,
- dav_prop_insert what);
-
-DAV_DECLARE(void) dav_get_liveprop_supported(
- dav_propdb *propdb,
- const char *ns_uri,
- const char *propname,
- apr_text_header *body);
-
-/*
-** 3-phase property modification.
-**
-** 1) validate props. readable? unlocked? ACLs allow access?
-** 2) execute operation (set/delete)
-** 3) commit or rollback
-**
-** ### eventually, auth must be available. a ref to the request_rec (which
-** ### contains the auth info) should be in the shared context struct.
-**
-** Each function may alter the error values and information contained within
-** the context record. This should be done as an "increasing" level of
-** error, rather than overwriting any previous error.
-**
-** Note that commit() cannot generate errors. It should simply free the
-** rollback information.
-**
-** rollback() may generate additional errors because the rollback operation
-** can sometimes fail(!).
-**
-** The caller should allocate an array of these, one per operation. It should
-** be zero-initialized, then the db, operation, and prop fields should be
-** filled in before calling dav_prop_validate. Note that the set/delete
-** operations are order-dependent. For a given (logical) context, the same
-** pointer must be passed to each phase.
-**
-** error_type is an internal value, but will have the same numeric value
-** for each possible "desc" value. This allows the caller to group the
-** descriptions via the error_type variable, rather than through string
-** comparisons. Note that "status" does not provide enough granularity to
-** differentiate/group the "desc" values.
-**
-** Note that the propdb will maintain some (global) context across all
-** of the property change contexts. This implies that you can have only
-** one open transaction per propdb.
-*/
-typedef struct dav_prop_ctx
-{
- dav_propdb *propdb;
-
- int operation;
-#define DAV_PROP_OP_SET 1 /* set a property value */
-#define DAV_PROP_OP_DELETE 2 /* delete a prop value */
-/* ### add a GET? */
-
- apr_xml_elem *prop; /* property to affect */
-
- dav_error *err; /* error (if any) */
-
- /* private items to the propdb */
- int is_liveprop;
- void *liveprop_ctx;
- struct dav_rollback_item *rollback; /* optional rollback info */
-
- /* private to mod_dav.c */
- request_rec *r;
-
-} dav_prop_ctx;
-
-DAV_DECLARE_NONSTD(void) dav_prop_validate(dav_prop_ctx *ctx);
-DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx);
-DAV_DECLARE_NONSTD(void) dav_prop_commit(dav_prop_ctx *ctx);
-DAV_DECLARE_NONSTD(void) dav_prop_rollback(dav_prop_ctx *ctx);
-
-#define DAV_PROP_CTX_HAS_ERR(dpc) ((dpc).err && (dpc).err->status >= 300)
-
-
-/* --------------------------------------------------------------------
-**
-** WALKER STRUCTURE
-*/
-
-enum {
- DAV_CALLTYPE_MEMBER = 1, /* called for a member resource */
- DAV_CALLTYPE_COLLECTION, /* called for a collection */
- DAV_CALLTYPE_LOCKNULL /* called for a locknull resource */
-};
-
-typedef struct
-{
- /* the client-provided context */
- void *walk_ctx;
-
- /* pool to use for allocations in the callback */
- apr_pool_t *pool;
-
- /* the current resource */
- const dav_resource *resource;
-
- /* OUTPUT: add responses to this */
- dav_response *response;
-
-} dav_walk_resource;
-
-typedef struct
-{
- int walk_type;
-#define DAV_WALKTYPE_AUTH 0x0001 /* limit to authorized files */
-#define DAV_WALKTYPE_NORMAL 0x0002 /* walk normal files */
-#define DAV_WALKTYPE_LOCKNULL 0x0004 /* walk locknull resources */
-
- /* callback function and a client context for the walk */
- dav_error * (*func)(dav_walk_resource *wres, int calltype);
- void *walk_ctx;
-
- /* what pool to use for allocations needed by walk logic */
- apr_pool_t *pool;
-
- /* beginning root of the walk */
- const dav_resource *root;
-
- /* lock database to enable walking LOCKNULL resources */
- dav_lockdb *lockdb;
-
-} dav_walk_params;
-
-/* directory tree walking context */
-typedef struct dav_walker_ctx
-{
- /* input: */
- dav_walk_params w;
-
-
- /* ### client data... phasing out this big glom */
-
- /* this brigade buffers data being sent to r->output_filters */
- apr_bucket_brigade *bb;
-
- /* a scratch pool, used to stream responses and iteratively cleared. */
- apr_pool_t *scratchpool;
-
- request_rec *r; /* original request */
-
- /* for PROPFIND operations */
- apr_xml_doc *doc;
- int propfind_type;
-#define DAV_PROPFIND_IS_ALLPROP 1
-#define DAV_PROPFIND_IS_PROPNAME 2
-#define DAV_PROPFIND_IS_PROP 3
-
- apr_text *propstat_404; /* (cached) propstat giving a 404 error */
-
- const dav_if_header *if_header; /* for validation */
- const dav_locktoken *locktoken; /* for UNLOCK */
- const dav_lock *lock; /* for LOCK */
- int skip_root; /* for dav_inherit_locks() */
-
- int flags;
-
- dav_buffer work_buf; /* for dav_validate_request() */
-
-} dav_walker_ctx;
-
-DAV_DECLARE(void) dav_add_response(dav_walk_resource *wres,
- int status,
- dav_get_props_result *propstats);
-
-
-/* --------------------------------------------------------------------
-**
-** "STREAM" STRUCTURE
-**
-** mod_dav uses this abstraction for interacting with the repository
-** while fetching/storing resources. mod_dav views resources as a stream
-** of bytes.
-**
-** Note that the structure is opaque -- it is private to the repository
-** that created the stream in the repository's "open" function.
-**
-** ### THIS STUFF IS GOING AWAY ... GET/read requests are handled by
-** ### having the provider jam stuff straight into the filter stack.
-** ### this is only left for handling PUT/write requests.
-*/
-
-typedef struct dav_stream dav_stream;
-
-typedef enum {
- DAV_MODE_WRITE_TRUNC, /* truncate and open for writing */
- DAV_MODE_WRITE_SEEKABLE /* open for writing; random access */
-} dav_stream_mode;
-
-
-/* --------------------------------------------------------------------
-**
-** REPOSITORY FUNCTIONS
-*/
-
-/* Repository provider hooks */
-struct dav_hooks_repository
-{
- /* Flag for whether repository requires special GET handling.
- * If resources in the repository are not visible in the
- * filesystem location which URLs map to, then special handling
- * is required to first fetch a resource from the repository,
- * respond to the GET request, then free the resource copy.
- */
- int handle_get;
-
- /* Get a resource descriptor for the URI in a request. A descriptor
- * should always be returned even if the resource does not exist. This
- * repository has been identified as handling the resource given by
- * the URI, so an answer must be given. If there is a problem with the
- * URI or accessing the resource or whatever, then an error should be
- * returned.
- *
- * root_dir:
- * the root of the directory for which this repository is configured.
- *
- * label:
- * if a Label: header is present (and allowed), this is the label
- * to use to identify a version resource from the resource's
- * corresponding version history. Otherwise, it will be NULL.
- *
- * use_checked_in:
- * use the DAV:checked-in property of the resource identified by the
- * Request-URI to identify and return a version resource
- *
- * The provider may associate the request storage pool with the resource
- * (in the resource->pool field), to use in other operations on that
- * resource.
- */
- dav_error * (*get_resource)(
- request_rec *r,
- const char *root_dir,
- const char *label,
- int use_checked_in,
- dav_resource **resource
- );
-
- /* Get a resource descriptor for the parent of the given resource.
- * The resources need not exist. NULL is returned if the resource
- * is the root collection.
- *
- * An error should be returned only if there is a fatal error in
- * fetching information about the parent resource.
- */
- dav_error * (*get_parent_resource)(
- const dav_resource *resource,
- dav_resource **parent_resource
- );
-
- /* Determine whether two resource descriptors refer to the same resource.
- *
- * Result != 0 => the resources are the same.
- */
- int (*is_same_resource)(
- const dav_resource *res1,
- const dav_resource *res2
- );
-
- /* Determine whether one resource is a parent (immediate or otherwise)
- * of another.
- *
- * Result != 0 => res1 is a parent of res2.
- */
- int (*is_parent_resource)(
- const dav_resource *res1,
- const dav_resource *res2
- );
-
- /*
- ** Open a stream for this resource, using the specified mode. The
- ** stream will be returned in *stream.
- */
- dav_error * (*open_stream)(const dav_resource *resource,
- dav_stream_mode mode,
- dav_stream **stream);
-
- /*
- ** Close the specified stream.
- **
- ** mod_dav will (ideally) make sure to call this. For safety purposes,
- ** a provider should (ideally) register a cleanup function with the
- ** request pool to get this closed and cleaned up.
- **
- ** Note the possibility of an error from the close -- it is entirely
- ** feasible that the close does a "commit" of some kind, which can
- ** produce an error.
- **
- ** commit should be TRUE (non-zero) or FALSE (0) if the stream was
- ** opened for writing. This flag states whether to retain the file
- ** or not.
- ** Note: the commit flag is ignored for streams opened for reading.
- */
- dav_error * (*close_stream)(dav_stream *stream, int commit);
-
- /*
- ** Write data to the stream.
- **
- ** All of the bytes must be written, or an error should be returned.
- */
- dav_error * (*write_stream)(dav_stream *stream,
- const void *buf, apr_size_t bufsize);
-
- /*
- ** Seek to an absolute position in the stream. This is used to support
- ** Content-Range in a GET/PUT.
- **
- ** NOTE: if this function is NULL (which is allowed), then any
- ** operations using Content-Range will be refused.
- */
- dav_error * (*seek_stream)(dav_stream *stream, apr_off_t abs_position);
-
- /*
- ** If a GET is processed using a stream (open_stream, read_stream)
- ** rather than via a sub-request (on get_pathname), then this function
- ** is used to provide the repository with a way to set the headers
- ** in the response.
- **
- ** This function may be called without a following deliver(), to
- ** handle a HEAD request.
- **
- ** This may be NULL if handle_get is FALSE.
- */
- dav_error * (*set_headers)(request_rec *r,
- const dav_resource *resource);
-
- /*
- ** The provider should deliver the resource into the specified filter.
- ** Basically, this is the response to the GET method.
- **
- ** Note that this is called for all resources, including collections.
- ** The provider should determine what has content to deliver or not.
- **
- ** set_headers will be called prior to this function, allowing the
- ** provider to set the appropriate response headers.
- **
- ** This may be NULL if handle_get is FALSE.
- ** ### maybe toss handle_get and just use this function as the marker
- */
- dav_error * (*deliver)(const dav_resource *resource,
- ap_filter_t *output);
-
- /* Create a collection resource. The resource must not already exist.
- *
- * Result == NULL if the collection was created successfully. Also, the
- * resource object is updated to reflect that the resource exists, and
- * is a collection.
- */
- dav_error * (*create_collection)(
- dav_resource *resource
- );
-
- /* Copy one resource to another. The destination may exist, if it is
- * versioned.
- * Handles both files and collections. Properties are copied as well.
- * If the destination exists and is versioned, the provider must update
- * the destination to have identical content to the source,
- * recursively for collections.
- * The depth argument is ignored for a file, and can be either 0 or
- * DAV_INFINITY for a collection.
- * If an error occurs in a child resource, then the return value is
- * non-NULL, and *response is set to a multistatus response.
- * If the copy is successful, the dst resource object is
- * updated to reflect that the resource exists.
- */
- dav_error * (*copy_resource)(
- const dav_resource *src,
- dav_resource *dst,
- int depth,
- dav_response **response
- );
-
- /* Move one resource to another. The destination must not exist.
- * Handles both files and collections. Properties are moved as well.
- * If an error occurs in a child resource, then the return value is
- * non-NULL, and *response is set to a multistatus response.
- * If the move is successful, the src and dst resource objects are
- * updated to reflect that the source no longer exists, and the
- * destination does.
- */
- dav_error * (*move_resource)(
- dav_resource *src,
- dav_resource *dst,
- dav_response **response
- );
-
- /* Remove a resource. Handles both files and collections.
- * Removes any associated properties as well.
- * If an error occurs in a child resource, then the return value is
- * non-NULL, and *response is set to a multistatus response.
- * If the delete is successful, the resource object is updated to
- * reflect that the resource no longer exists.
- */
- dav_error * (*remove_resource)(
- dav_resource *resource,
- dav_response **response
- );
-
- /* Walk a resource hierarchy.
- *
- * Iterates over the resource hierarchy specified by params->root.
- * Control of the walk and the callback are specified by 'params'.
- *
- * An error may be returned. *response will contain multistatus
- * responses (if any) suitable for the body of the error. It is also
- * possible to return NULL, yet still have multistatus responses.
- * In this case, typically the caller should return a 207 (Multistatus)
- * and the responses (in the body) as the HTTP response.
- */
- dav_error * (*walk)(const dav_walk_params *params, int depth,
- dav_response **response);
-
- /* Get the entity tag for a resource */
- const char * (*getetag)(const dav_resource *resource);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-};
-
-
-/* --------------------------------------------------------------------
-**
-** VERSIONING FUNCTIONS
-*/
-
-
-/* dav_add_vary_header
- *
- * If there were any headers in the request which require a Vary header
- * in the response, add it.
- */
-DAV_DECLARE(void) dav_add_vary_header(request_rec *in_req,
- request_rec *out_req,
- const dav_resource *resource);
-
-/*
-** Flags specifying auto-versioning behavior, returned by
-** the auto_versionable hook. The value returned depends
-** on both the state of the resource and the value of the
-** DAV:auto-versioning property for the resource.
-**
-** If the resource does not exist (null or lock-null),
-** DAV_AUTO_VERSION_ALWAYS causes creation of a new version-controlled resource
-**
-** If the resource is checked in,
-** DAV_AUTO_VERSION_ALWAYS causes it to be checked out always,
-** DAV_AUTO_VERSION_LOCKED causes it to be checked out only when locked
-**
-** If the resource is checked out,
-** DAV_AUTO_VERSION_ALWAYS causes it to be checked in always,
-** DAV_AUTO_VERSION_LOCKED causes it to be checked in when unlocked
-** (note: a provider should allow auto-checkin only for resources which
-** were automatically checked out)
-**
-** In all cases, DAV_AUTO_VERSION_NEVER results in no auto-versioning behavior.
-*/
-typedef enum {
- DAV_AUTO_VERSION_NEVER,
- DAV_AUTO_VERSION_ALWAYS,
- DAV_AUTO_VERSION_LOCKED
-} dav_auto_version;
-
-/*
-** This structure is used to record what auto-versioning operations
-** were done to make a resource writable, so that they can be undone
-** at the end of a request.
-*/
-typedef struct {
- int resource_versioned; /* 1 => resource was auto-version-controlled */
- int resource_checkedout; /* 1 => resource was auto-checked-out */
- int parent_checkedout; /* 1 => parent was auto-checked-out */
- dav_resource *parent_resource; /* parent resource, if it was needed */
-} dav_auto_version_info;
-
-/* Ensure that a resource is writable. If there is no versioning
- * provider, then this is essentially a no-op. Versioning repositories
- * require explicit resource creation and checkout before they can
- * be written to. If a new resource is to be created, or an existing
- * resource deleted, the parent collection must be checked out as well.
- *
- * Set the parent_only flag to only make the parent collection writable.
- * Otherwise, both parent and child are made writable as needed. If the
- * child does not exist, then a new versioned resource is created and
- * checked out.
- *
- * If auto-versioning is not enabled for a versioned resource, then an error is
- * returned, since the resource cannot be modified.
- *
- * The dav_auto_version_info structure is filled in with enough information
- * to restore both parent and child resources to the state they were in
- * before the auto-versioning operations occurred.
- */
-DAV_DECLARE(dav_error *) dav_auto_checkout(
- request_rec *r,
- dav_resource *resource,
- int parent_only,
- dav_auto_version_info *av_info);
-
-/* Revert the writability of resources back to what they were
- * before they were modified. If undo == 0, then the resource
- * modifications are maintained (i.e. they are checked in).
- * If undo != 0, then resource modifications are discarded
- * (i.e. they are unchecked out).
- *
- * Set the unlock flag to indicate that the resource is about
- * to be unlocked; it will be checked in if the resource
- * auto-versioning property indicates it should be. In this case,
- * av_info is ignored, so it can be NULL.
- *
- * The resource argument may be NULL if only the parent resource
- * was checked out (i.e. the parent_only was != 0 in the
- * dav_auto_checkout call).
- */
-DAV_DECLARE(dav_error *) dav_auto_checkin(
- request_rec *r,
- dav_resource *resource,
- int undo,
- int unlock,
- dav_auto_version_info *av_info);
-
-/*
-** This structure is used to describe available reports
-**
-** "nmspace" should be valid XML and URL-quoted. mod_dav will place
-** double-quotes around it and use it in an xmlns declaration.
-*/
-typedef struct {
- const char *nmspace; /* namespace of the XML report element */
- const char *name; /* element name for the XML report */
-} dav_report_elem;
-
-
-/* Versioning provider hooks */
-struct dav_hooks_vsn
-{
- /*
- ** MANDATORY HOOKS
- ** The following hooks are mandatory for all versioning providers;
- ** they define the functionality needed to implement "core" versioning.
- */
-
- /* Return supported versioning options.
- * Each dav_text item in the list will be returned as a separate
- * DAV header. Providers are advised to limit the length of an
- * individual text item to 63 characters, to conform to the limit
- * used by MS Web Folders.
- */
- void (*get_vsn_options)(apr_pool_t *p, apr_text_header *phdr);
-
- /* Get the value of a specific option for an OPTIONS request.
- * The option being requested is given by the parsed XML
- * element object "elem". The value of the option should be
- * appended to the "option" text object.
- */
- dav_error * (*get_option)(const dav_resource *resource,
- const apr_xml_elem *elem,
- apr_text_header *option);
-
- /* Determine whether a non-versioned (or non-existent) resource
- * is versionable. Returns != 0 if resource can be versioned.
- */
- int (*versionable)(const dav_resource *resource);
-
- /* Determine whether auto-versioning is enabled for a resource
- * (which may not exist, or may not be versioned). If the resource
- * is a checked-out resource, the provider must only enable
- * auto-checkin if the resource was automatically checked out.
- *
- * The value returned depends on both the state of the resource
- * and the value of its DAV:auto-version property. See the description
- * of the dav_auto_version enumeration above for the details.
- */
- dav_auto_version (*auto_versionable)(const dav_resource *resource);
-
- /* Put a resource under version control. If the resource already
- * exists unversioned, then it becomes the initial version of the
- * new version history, and it is replaced by a version selector
- * which targets the new version.
- *
- * If the resource does not exist, then a new version-controlled
- * resource is created which either targets an existing version (if the
- * "target" argument is not NULL), or the initial, empty version
- * in a new history resource (if the "target" argument is NULL).
- *
- * If successful, the resource object state is updated appropriately
- * (that is, changed to refer to the new version-controlled resource).
- */
- dav_error * (*vsn_control)(dav_resource *resource,
- const char *target);
-
- /* Checkout a resource. If successful, the resource
- * object state is updated appropriately.
- *
- * The auto_checkout flag will be set if this checkout is being
- * done automatically, as part of some method which modifies
- * the resource. The provider must remember that the resource
- * was automatically checked out, so it can determine whether it
- * can be automatically checked in. (Auto-checkin should only be
- * enabled for resources which were automatically checked out.)
- *
- * If the working resource has a different URL from the
- * target resource, a dav_resource descriptor is returned
- * for the new working resource. Otherwise, the original
- * resource descriptor will refer to the working resource.
- * The working_resource argument can be NULL if the caller
- * is not interested in the working resource.
- *
- * If the client has specified DAV:unreserved or DAV:fork-ok in the
- * checkout request, then the corresponding flags are set. If
- * DAV:activity-set has been specified, then create_activity is set
- * if DAV:new was specified; otherwise, the DAV:href elements' CDATA
- * (the actual href text) is passed in the "activities" array (each
- * element of the array is a const char *). activities will be NULL
- * no DAV:activity-set was provided or when create_activity is set.
- */
- dav_error * (*checkout)(dav_resource *resource,
- int auto_checkout,
- int is_unreserved, int is_fork_ok,
- int create_activity,
- apr_array_header_t *activities,
- dav_resource **working_resource);
-
- /* Uncheckout a checked-out resource. If successful, the resource
- * object state is updated appropriately.
- */
- dav_error * (*uncheckout)(dav_resource *resource);
-
- /* Checkin a checked-out resource. If successful, the resource
- * object state is updated appropriately, and the
- * version_resource descriptor will refer to the new version.
- * The version_resource argument can be NULL if the caller
- * is not interested in the new version resource.
- *
- * If the client has specified DAV:keep-checked-out in the checkin
- * request, then the keep_checked_out flag is set. The provider
- * should create a new version, but keep the resource in the
- * checked-out state.
- */
- dav_error * (*checkin)(dav_resource *resource,
- int keep_checked_out,
- dav_resource **version_resource);
-
- /*
- ** Return the set of reports available at this resource.
- **
- ** An array of report elements should be returned, with an end-marker
- ** element containing namespace==NULL. The value of the
- ** DAV:supported-report-set property will be constructed and
- ** returned.
- */
- dav_error * (*avail_reports)(const dav_resource *resource,
- const dav_report_elem **reports);
-
- /*
- ** Determine whether a Label header can be used
- ** with a particular report. The dav_xml_doc structure
- ** contains the parsed report request body.
- ** Returns 0 if the Label header is not allowed.
- */
- int (*report_label_header_allowed)(const apr_xml_doc *doc);
-
- /*
- ** Generate a report on a resource. Since a provider is free
- ** to define its own reports, and the value of request headers
- ** may affect the interpretation of a report, the request record
- ** must be passed to this routine.
- **
- ** The dav_xml_doc structure contains the parsed report request
- ** body. The report response should be generated into the specified
- ** output filter.
- **
- ** If an error occurs, and a response has not yet been generated,
- ** then an error can be returned from this function. mod_dav will
- ** construct an appropriate error response. Once some output has
- ** been placed into the filter, however, the provider should not
- ** return an error -- there is no way that mod_dav can deliver it
- ** properly.
- **
- ** ### maybe we need a way to signal an error anyways, and then
- ** ### apache can abort the connection?
- */
- dav_error * (*deliver_report)(request_rec *r,
- const dav_resource *resource,
- const apr_xml_doc *doc,
- ap_filter_t *output);
-
- /*
- ** OPTIONAL HOOKS
- ** The following hooks are optional; if not defined, then the
- ** corresponding protocol methods will be unsupported.
- */
-
- /*
- ** Set the state of a checked-in version-controlled resource.
- **
- ** If the request specified a version, the version resource
- ** represents that version. If the request specified a label,
- ** then "version" is NULL, and "label" is the label.
- **
- ** The depth argument is ignored for a file, and can be 0, 1, or
- ** DAV_INFINITY for a collection. The depth argument only applies
- ** with a label, not a version.
- **
- ** If an error occurs in a child resource, then the return value is
- ** non-NULL, and *response is set to a multistatus response.
- **
- ** This hook is optional; if not defined, then the UPDATE method
- ** will not be supported.
- */
- dav_error * (*update)(const dav_resource *resource,
- const dav_resource *version,
- const char *label,
- int depth,
- dav_response **response);
-
- /*
- ** Add a label to a version. The resource is either a specific
- ** version, or a version selector, in which case the label should
- ** be added to the current target of the version selector. The
- ** version selector cannot be checked out.
- **
- ** If replace != 0, any existing label by the same name is
- ** effectively deleted first. Otherwise, it is an error to
- ** attempt to add a label which already exists on some version
- ** of the same history resource.
- **
- ** This hook is optional; if not defined, then the LABEL method
- ** will not be supported. If it is defined, then the remove_label
- ** hook must be defined also.
- */
- dav_error * (*add_label)(const dav_resource *resource,
- const char *label,
- int replace);
-
- /*
- ** Remove a label from a version. The resource is either a specific
- ** version, or a version selector, in which case the label should
- ** be added to the current target of the version selector. The
- ** version selector cannot be checked out.
- **
- ** It is an error if no such label exists on the specified version.
- **
- ** This hook is optional, but if defined, the add_label hook
- ** must be defined also.
- */
- dav_error * (*remove_label)(const dav_resource *resource,
- const char *label);
-
- /*
- ** Determine whether a null resource can be created as a workspace.
- ** The provider may restrict workspaces to certain locations.
- ** Returns 0 if the resource cannot be a workspace.
- **
- ** This hook is optional; if the provider does not support workspaces,
- ** it should be set to NULL.
- */
- int (*can_be_workspace)(const dav_resource *resource);
-
- /*
- ** Create a workspace resource. The resource must not already
- ** exist. Any <DAV:mkworkspace> element is passed to the provider
- ** in the "doc" structure; it may be empty.
- **
- ** If workspace creation is succesful, the state of the resource
- ** object is updated appropriately.
- **
- ** This hook is optional; if the provider does not support workspaces,
- ** it should be set to NULL.
- */
- dav_error * (*make_workspace)(dav_resource *resource,
- apr_xml_doc *doc);
-
- /*
- ** Determine whether a null resource can be created as an activity.
- ** The provider may restrict activities to certain locations.
- ** Returns 0 if the resource cannot be an activity.
- **
- ** This hook is optional; if the provider does not support activities,
- ** it should be set to NULL.
- */
- int (*can_be_activity)(const dav_resource *resource);
-
- /*
- ** Create an activity resource. The resource must not already
- ** exist.
- **
- ** If activity creation is succesful, the state of the resource
- ** object is updated appropriately.
- **
- ** This hook is optional; if the provider does not support activities,
- ** it should be set to NULL.
- */
- dav_error * (*make_activity)(dav_resource *resource);
-
- /*
- ** Merge a resource (tree) into target resource (tree).
- **
- ** ### more doc...
- **
- ** This hook is optional; if the provider does not support merging,
- ** then this should be set to NULL.
- */
- dav_error * (*merge)(dav_resource *target, dav_resource *source,
- int no_auto_merge, int no_checkout,
- apr_xml_elem *prop_elem,
- ap_filter_t *output);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-};
-
-
-/* --------------------------------------------------------------------
-**
-** BINDING FUNCTIONS
-*/
-
-/* binding provider hooks */
-struct dav_hooks_binding {
-
- /* Determine whether a resource can be the target of a binding.
- * Returns 0 if the resource cannot be a binding target.
- */
- int (*is_bindable)(const dav_resource *resource);
-
- /* Create a binding to a resource.
- * The resource argument is the target of the binding;
- * the binding argument must be a resource which does not already
- * exist.
- */
- dav_error * (*bind_resource)(const dav_resource *resource,
- dav_resource *binding);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-
-};
-
-
-/* --------------------------------------------------------------------
-**
-** SEARCH(DASL) FUNCTIONS
-*/
-
-/* search provider hooks */
-struct dav_hooks_search {
- /* Set header for a OPTION method
- * An error may be returned.
- * To set a hadder, this function might call
- * apr_table_setn(r->headers_out, "DASL", dasl_optin1);
- *
- * Examples:
- * DASL: <DAV:basicsearch>
- * DASL: <http://foo.bar.com/syntax1>
- * DASL: <http://akuma.com/syntax2>
- */
- dav_error * (*set_option_head)(request_rec *r);
-
- /* Search resources
- * An error may be returned. *response will contain multistatus
- * responses (if any) suitable for the body of the error. It is also
- * possible to return NULL, yet still have multistatus responses.
- * In this case, typically the caller should return a 207 (Multistatus)
- * and the responses (in the body) as the HTTP response.
- */
- dav_error * (*search_resource)(request_rec *r,
- dav_response **response);
-
- /*
- ** If a provider needs a context to associate with this hooks structure,
- ** then this field may be used. In most cases, it will just be NULL.
- */
- void *ctx;
-
-};
-
-
-/* --------------------------------------------------------------------
-**
-** MISCELLANEOUS STUFF
-*/
-
-/* fetch the "LimitXMLRequestBody" in force for this resource */
-DAV_DECLARE(apr_size_t) dav_get_limit_xml_body(const request_rec *r);
-
-typedef struct {
- int propid; /* live property ID */
- const dav_hooks_liveprop *provider; /* the provider defining this prop */
-} dav_elem_private;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _MOD_DAV_H_ */
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/modules.mk b/rubbos/app/httpd-2.0.64/modules/dav/main/modules.mk
deleted file mode 100644
index ceb52a1b..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/modules.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-DISTCLEAN_TARGETS = modules.mk
-static =
-shared =
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/props.c b/rubbos/app/httpd-2.0.64/modules/dav/main/props.c
deleted file mode 100644
index fc28532d..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/props.c
+++ /dev/null
@@ -1,1116 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-** DAV extension module for Apache 2.0.*
-** - Property database handling (repository-independent)
-**
-** NOTES:
-**
-** PROPERTY DATABASE
-**
-** This version assumes that there is a per-resource database provider
-** to record properties. The database provider decides how and where to
-** store these databases.
-**
-** The DBM keys for the properties have the following form:
-**
-** namespace ":" propname
-**
-** For example: 5:author
-**
-** The namespace provides an integer index into the namespace table
-** (see below). propname is simply the property name, without a namespace
-** prefix.
-**
-** A special case exists for properties that had a prefix starting with
-** "xml". The XML Specification reserves these for future use. mod_dav
-** stores and retrieves them unchanged. The keys for these properties
-** have the form:
-**
-** ":" propname
-**
-** The propname will contain the prefix and the property name. For
-** example, a key might be ":xmlfoo:name"
-**
-** The ":name" style will also be used for properties that do not
-** exist within a namespace.
-**
-** The DBM values consist of two null-terminated strings, appended
-** together (the null-terms are retained and stored in the database).
-** The first string is the xml:lang value for the property. An empty
-** string signifies that a lang value was not in context for the value.
-** The second string is the property value itself.
-**
-**
-** NAMESPACE TABLE
-**
-** The namespace table is an array that lists each of the namespaces
-** that are in use by the properties in the given propdb. Each entry
-** in the array is a simple URI.
-**
-** For example: http://www.foo.bar/standards/props/
-**
-** The prefix used for the property is stripped and the URI for it
-** is entered into the namespace table. Also, any namespaces used
-** within the property value will be entered into the table (and
-** stripped from the child elements).
-**
-** The namespaces are stored in the DBM database under the "METADATA" key.
-**
-**
-** STRIPPING NAMESPACES
-**
-** Within the property values, the namespace declarations (xmlns...)
-** are stripped. Each element and attribute will have its prefix removed
-** and a new prefix inserted.
-**
-** This must be done so that we can return multiple properties in a
-** PROPFIND which may have (originally) used conflicting prefixes. For
-** that case, we must bind all property value elements to new namespace
-** values.
-**
-** This implies that clients must NOT be sensitive to the namespace
-** prefix used for their properties. It WILL change when the properties
-** are returned (we return them as "ns<index>", e.g. "ns5"). Also, the
-** property value can contain ONLY XML elements and CDATA. PI and comment
-** elements will be stripped. CDATA whitespace will be preserved, but
-** whitespace within element tags will be altered. Attribute ordering
-** may be altered. Element and CDATA ordering will be preserved.
-**
-**
-** ATTRIBUTES ON PROPERTY NAME ELEMENTS
-**
-** When getting/setting properties, the XML used looks like:
-**
-** <prop>
-** <propname1>value</propname1>
-** <propname2>value</propname1>
-** </prop>
-**
-** This implementation (mod_dav) DOES NOT save any attributes that are
-** associated with the <propname1> element. The property value is deemed
-** to be only the contents ("value" in the above example).
-**
-** We do store the xml:lang value (if any) that applies to the context
-** of the <propname1> element. Whether the xml:lang attribute is on
-** <propname1> itself, or from a higher level element, we will store it
-** with the property value.
-**
-**
-** VERSIONING
-**
-** The DBM db contains a key named "METADATA" that holds database-level
-** information, such as the namespace table. The record also contains the
-** db's version number as the very first 16-bit value. This first number
-** is actually stored as two single bytes: the first byte is a "major"
-** version number. The second byte is a "minor" number.
-**
-** If the major number is not what mod_dav expects, then the db is closed
-** immediately and an error is returned. A minor number change is
-** acceptable -- it is presumed that old/new dav_props.c can deal with
-** the database format. For example, a newer dav_props might update the
-** minor value and append information to the end of the metadata record
-** (which would be ignored by previous versions).
-**
-**
-** ISSUES:
-**
-** At the moment, for the dav_get_allprops() and dav_get_props() functions,
-** we must return a set of xmlns: declarations for ALL known namespaces
-** in the file. There isn't a way to filter this because we don't know
-** which are going to be used or not. Examining property names is not
-** sufficient because the property values could use entirely different
-** namespaces.
-**
-** ==> we must devise a scheme where we can "garbage collect" the namespace
-** entries from the property database.
-*/
-
-#include "apr.h"
-#include "apr_strings.h"
-
-#define APR_WANT_STDIO
-#define APR_WANT_BYTEFUNC
-#include "apr_want.h"
-
-#include "mod_dav.h"
-
-#include "http_log.h"
-#include "http_request.h"
-
-/*
-** There is some rough support for writable DAV:getcontenttype and
-** DAV:getcontentlanguage properties. If this #define is (1), then
-** this support is disabled.
-**
-** We are disabling it because of a lack of support in GET and PUT
-** operations. For GET, it would be "expensive" to look for a propdb,
-** open it, and attempt to extract the Content-Type and Content-Language
-** values for the response.
-** (Handling the PUT would not be difficult, though)
-*/
-#define DAV_DISABLE_WRITABLE_PROPS 1
-
-#define DAV_EMPTY_VALUE "\0" /* TWO null terms */
-
-struct dav_propdb {
- apr_pool_t *p; /* the pool we should use */
- request_rec *r; /* the request record */
-
- const dav_resource *resource; /* the target resource */
-
- int deferred; /* open of db has been deferred */
- dav_db *db; /* underlying database containing props */
-
- apr_array_header_t *ns_xlate; /* translation of an elem->ns to URI */
- dav_namespace_map *mapping; /* namespace mapping */
-
- dav_lockdb *lockdb; /* the lock database */
-
- dav_buffer wb_lock; /* work buffer for lockdiscovery property */
-
- /* if we ever run a GET subreq, it will be stored here */
- request_rec *subreq;
-
- /* hooks we should use for processing (based on the target resource) */
- const dav_hooks_db *db_hooks;
-};
-
-/* NOTE: dav_core_props[] and the following enum must stay in sync. */
-/* ### move these into a "core" liveprop provider? */
-static const char * const dav_core_props[] =
-{
- "getcontenttype",
- "getcontentlanguage",
- "lockdiscovery",
- "supportedlock",
-
- NULL /* sentinel */
-};
-enum {
- DAV_PROPID_CORE_getcontenttype = DAV_PROPID_CORE,
- DAV_PROPID_CORE_getcontentlanguage,
- DAV_PROPID_CORE_lockdiscovery,
- DAV_PROPID_CORE_supportedlock,
-
- DAV_PROPID_CORE_UNKNOWN
-};
-
-/*
-** This structure is used to track information needed for a rollback.
-*/
-typedef struct dav_rollback_item {
- /* select one of the two rollback context structures based on the
- value of dav_prop_ctx.is_liveprop */
- dav_deadprop_rollback *deadprop;
- dav_liveprop_rollback *liveprop;
-
-} dav_rollback_item;
-
-
-static int dav_find_liveprop_provider(dav_propdb *propdb,
- const char *ns_uri,
- const char *propname,
- const dav_hooks_liveprop **provider)
-{
- int propid;
-
- *provider = NULL;
-
- if (ns_uri == NULL) {
- /* policy: liveprop providers cannot define no-namespace properties */
- return DAV_PROPID_CORE_UNKNOWN;
- }
-
- /* check liveprop providers first, so they can define core properties */
- propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname,
- provider);
- if (propid != 0) {
- return propid;
- }
-
- /* check for core property */
- if (strcmp(ns_uri, "DAV:") == 0) {
- const char * const *p = dav_core_props;
-
- for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid)
- if (strcmp(propname, *p) == 0) {
- return propid;
- }
- }
-
- /* no provider for this property */
- return DAV_PROPID_CORE_UNKNOWN;
-}
-
-static void dav_find_liveprop(dav_propdb *propdb, apr_xml_elem *elem)
-{
- const char *ns_uri;
- dav_elem_private *priv = elem->priv;
- const dav_hooks_liveprop *hooks;
-
-
- if (elem->ns == APR_XML_NS_NONE)
- ns_uri = NULL;
- else if (elem->ns == APR_XML_NS_DAV_ID)
- ns_uri = "DAV:";
- else
- ns_uri = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns);
-
- priv->propid = dav_find_liveprop_provider(propdb, ns_uri, elem->name,
- &hooks);
-
- /* ### this test seems redundant... */
- if (priv->propid != DAV_PROPID_CORE_UNKNOWN) {
- priv->provider = hooks;
- }
-}
-
-/* is the live property read/write? */
-static int dav_rw_liveprop(dav_propdb *propdb, dav_elem_private *priv)
-{
- int propid = priv->propid;
-
- /*
- ** Check the liveprop provider (if this is a provider-defined prop)
- */
- if (priv->provider != NULL) {
- return (*priv->provider->is_writable)(propdb->resource, propid);
- }
-
- /* these are defined as read-only */
- if (propid == DAV_PROPID_CORE_lockdiscovery
-#if DAV_DISABLE_WRITABLE_PROPS
- || propid == DAV_PROPID_CORE_getcontenttype
- || propid == DAV_PROPID_CORE_getcontentlanguage
-#endif
- || propid == DAV_PROPID_CORE_supportedlock
- ) {
-
- return 0;
- }
-
- /* these are defined as read/write */
- if (propid == DAV_PROPID_CORE_getcontenttype
- || propid == DAV_PROPID_CORE_getcontentlanguage
- || propid == DAV_PROPID_CORE_UNKNOWN) {
-
- return 1;
- }
-
- /*
- ** We don't recognize the property, so it must be dead (and writable)
- */
- return 1;
-}
-
-/* do a sub-request to fetch properties for the target resource's URI. */
-static void dav_do_prop_subreq(dav_propdb *propdb)
-{
- /* perform a "GET" on the resource's URI (note that the resource
- may not correspond to the current request!). */
- propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r,
- NULL);
-}
-
-static dav_error * dav_insert_coreprop(dav_propdb *propdb,
- int propid, const char *name,
- dav_prop_insert what,
- apr_text_header *phdr,
- dav_prop_insert *inserted)
-{
- const char *value = NULL;
- dav_error *err;
-
- *inserted = DAV_PROP_INSERT_NOTDEF;
-
- /* fast-path the common case */
- if (propid == DAV_PROPID_CORE_UNKNOWN)
- return NULL;
-
- switch (propid) {
-
- case DAV_PROPID_CORE_lockdiscovery:
- if (propdb->lockdb != NULL) {
- dav_lock *locks;
-
- if ((err = dav_lock_query(propdb->lockdb, propdb->resource,
- &locks)) != NULL) {
- return dav_push_error(propdb->p, err->status, 0,
- "DAV:lockdiscovery could not be "
- "determined due to a problem fetching "
- "the locks for this resource.",
- err);
- }
-
- /* fast-path the no-locks case */
- if (locks == NULL) {
- value = "";
- }
- else {
- /*
- ** This may modify the buffer. value may point to
- ** wb_lock.pbuf or a string constant.
- */
- value = dav_lock_get_activelock(propdb->r, locks,
- &propdb->wb_lock);
-
- /* make a copy to isolate it from changes to wb_lock */
- value = apr_pstrdup(propdb->p, propdb->wb_lock.buf);
- }
- }
- break;
-
- case DAV_PROPID_CORE_supportedlock:
- if (propdb->lockdb != NULL) {
- value = (*propdb->lockdb->hooks->get_supportedlock)(propdb->resource);
- }
- break;
-
- case DAV_PROPID_CORE_getcontenttype:
- if (propdb->subreq == NULL) {
- dav_do_prop_subreq(propdb);
- }
- if (propdb->subreq->content_type != NULL) {
- value = propdb->subreq->content_type;
- }
- break;
-
- case DAV_PROPID_CORE_getcontentlanguage:
- {
- const char *lang;
-
- if (propdb->subreq == NULL) {
- dav_do_prop_subreq(propdb);
- }
- if ((lang = apr_table_get(propdb->subreq->headers_out,
- "Content-Language")) != NULL) {
- value = lang;
- }
- break;
- }
-
- default:
- /* fall through to interpret as a dead property */
- break;
- }
-
- /* if something was supplied, then insert it */
- if (value != NULL) {
- const char *s;
-
- if (what == DAV_PROP_INSERT_SUPPORTED) {
- /* use D: prefix to refer to the DAV: namespace URI,
- * and let the namespace attribute default to "DAV:"
- */
- s = apr_psprintf(propdb->p,
- "<D:supported-live-property D:name=\"%s\"/>" DEBUG_CR,
- name);
- }
- else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') {
- /* use D: prefix to refer to the DAV: namespace URI */
- s = apr_psprintf(propdb->p, "<D:%s>%s</D:%s>" DEBUG_CR,
- name, value, name);
- }
- else {
- /* use D: prefix to refer to the DAV: namespace URI */
- s = apr_psprintf(propdb->p, "<D:%s/>" DEBUG_CR, name);
- }
- apr_text_append(propdb->p, phdr, s);
-
- *inserted = what;
- }
-
- return NULL;
-}
-
-static dav_error * dav_insert_liveprop(dav_propdb *propdb,
- const apr_xml_elem *elem,
- dav_prop_insert what,
- apr_text_header *phdr,
- dav_prop_insert *inserted)
-{
- dav_elem_private *priv = elem->priv;
-
- *inserted = DAV_PROP_INSERT_NOTDEF;
-
- if (priv->provider == NULL) {
- /* this is a "core" property that we define */
- return dav_insert_coreprop(propdb, priv->propid, elem->name,
- what, phdr, inserted);
- }
-
- /* ask the provider (that defined this prop) to insert the prop */
- *inserted = (*priv->provider->insert_prop)(propdb->resource, priv->propid,
- what, phdr);
-
- return NULL;
-}
-
-static void dav_output_prop_name(apr_pool_t *pool,
- const dav_prop_name *name,
- dav_xmlns_info *xi,
- apr_text_header *phdr)
-{
- const char *s;
-
- if (*name->ns == '\0')
- s = apr_psprintf(pool, "<%s/>" DEBUG_CR, name->name);
- else {
- const char *prefix = dav_xmlns_add_uri(xi, name->ns);
-
- s = apr_psprintf(pool, "<%s:%s/>" DEBUG_CR, prefix, name->name);
- }
-
- apr_text_append(pool, phdr, s);
-}
-
-static void dav_insert_xmlns(apr_pool_t *p, const char *pre_prefix, int ns,
- const char *ns_uri, apr_text_header *phdr)
-{
- const char *s;
-
- s = apr_psprintf(p, " xmlns:%s%d=\"%s\"", pre_prefix, ns, ns_uri);
- apr_text_append(p, phdr, s);
-}
-
-static dav_error *dav_really_open_db(dav_propdb *propdb, int ro)
-{
- dav_error *err;
-
- /* we're trying to open the db; turn off the 'deferred' flag */
- propdb->deferred = 0;
-
- /* ask the DB provider to open the thing */
- err = (*propdb->db_hooks->open)(propdb->p, propdb->resource, ro,
- &propdb->db);
- if (err != NULL) {
- return dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
- DAV_ERR_PROP_OPENING,
- "Could not open the property database.",
- err);
- }
-
- /*
- ** NOTE: propdb->db could be NULL if we attempted to open a readonly
- ** database that doesn't exist. If we require read/write
- ** access, then a database was created and opened.
- */
-
- return NULL;
-}
-
-DAV_DECLARE(dav_error *)dav_open_propdb(request_rec *r, dav_lockdb *lockdb,
- const dav_resource *resource,
- int ro,
- apr_array_header_t * ns_xlate,
- dav_propdb **p_propdb)
-{
- dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb));
-
- *p_propdb = NULL;
-
-#if DAV_DEBUG
- if (resource->uri == NULL) {
- return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "INTERNAL DESIGN ERROR: resource must define "
- "its URI.");
- }
-#endif
-
- propdb->r = r;
- propdb->p = r->pool; /* ### get rid of this */
- propdb->resource = resource;
- propdb->ns_xlate = ns_xlate;
-
- propdb->db_hooks = DAV_GET_HOOKS_PROPDB(r);
-
- propdb->lockdb = lockdb;
-
- /* always defer actual open, to avoid expense of accessing db
- * when only live properties are involved
- */
- propdb->deferred = 1;
-
- /* ### what to do about closing the propdb on server failure? */
-
- *p_propdb = propdb;
- return NULL;
-}
-
-DAV_DECLARE(void) dav_close_propdb(dav_propdb *propdb)
-{
- if (propdb->db == NULL)
- return;
-
- (*propdb->db_hooks->close)(propdb->db);
-}
-
-DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb,
- dav_prop_insert what)
-{
- const dav_hooks_db *db_hooks = propdb->db_hooks;
- apr_text_header hdr = { 0 };
- apr_text_header hdr_ns = { 0 };
- dav_get_props_result result = { 0 };
- int found_contenttype = 0;
- int found_contentlang = 0;
- dav_prop_insert unused_inserted;
-
- /* if not just getting supported live properties,
- * scan all properties in the dead prop database
- */
- if (what != DAV_PROP_INSERT_SUPPORTED) {
- if (propdb->deferred) {
- /* ### what to do with db open error? */
- (void) dav_really_open_db(propdb, 1 /*ro*/);
- }
-
- /* initialize the result with some start tags... */
- apr_text_append(propdb->p, &hdr,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" DEBUG_CR);
-
- /* if there ARE properties, then scan them */
- if (propdb->db != NULL) {
- dav_xmlns_info *xi = dav_xmlns_create(propdb->p);
- dav_prop_name name;
-
- /* define (up front) any namespaces the db might need */
- (void) (*db_hooks->define_namespaces)(propdb->db, xi);
-
- /* get the first property name, beginning the scan */
- (void) (*db_hooks->first_name)(propdb->db, &name);
- while (name.ns != NULL) {
-
- /*
- ** We also look for <DAV:getcontenttype> and
- ** <DAV:getcontentlanguage>. If they are not stored as dead
- ** properties, then we need to perform a subrequest to get
- ** their values (if any).
- */
- if (*name.ns == 'D' && strcmp(name.ns, "DAV:") == 0
- && *name.name == 'g') {
- if (strcmp(name.name, "getcontenttype") == 0) {
- found_contenttype = 1;
- }
- else if (strcmp(name.name, "getcontentlanguage") == 0) {
- found_contentlang = 1;
- }
- }
-
- if (what == DAV_PROP_INSERT_VALUE) {
- dav_error *err;
- int found;
-
- if ((err = (*db_hooks->output_value)(propdb->db, &name,
- xi, &hdr,
- &found)) != NULL) {
- /* ### anything better to do? */
- /* ### probably should enter a 500 error */
- goto next_key;
- }
- /* assert: found == 1 */
- }
- else {
- /* the value was not requested, so just add an empty
- tag specifying the property name. */
- dav_output_prop_name(propdb->p, &name, xi, &hdr);
- }
-
- next_key:
- (void) (*db_hooks->next_name)(propdb->db, &name);
- }
-
- /* all namespaces have been entered into xi. generate them into
- the output now. */
- dav_xmlns_generate(xi, &hdr_ns);
-
- } /* propdb->db != NULL */
-
- /* add namespaces for all the liveprop providers */
- dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns);
- }
-
- /* ask the liveprop providers to insert their properties */
- dav_run_insert_all_liveprops(propdb->r, propdb->resource, what, &hdr);
-
- /* insert the standard properties */
- /* ### should be handling the return errors here */
- (void)dav_insert_coreprop(propdb,
- DAV_PROPID_CORE_supportedlock, "supportedlock",
- what, &hdr, &unused_inserted);
- (void)dav_insert_coreprop(propdb,
- DAV_PROPID_CORE_lockdiscovery, "lockdiscovery",
- what, &hdr, &unused_inserted);
-
- /* if we didn't find these, then do the whole subreq thing. */
- if (!found_contenttype) {
- /* ### should be handling the return error here */
- (void)dav_insert_coreprop(propdb,
- DAV_PROPID_CORE_getcontenttype,
- "getcontenttype",
- what, &hdr, &unused_inserted);
- }
- if (!found_contentlang) {
- /* ### should be handling the return error here */
- (void)dav_insert_coreprop(propdb,
- DAV_PROPID_CORE_getcontentlanguage,
- "getcontentlanguage",
- what, &hdr, &unused_inserted);
- }
-
- /* if not just reporting on supported live props,
- * terminate the result */
- if (what != DAV_PROP_INSERT_SUPPORTED) {
- apr_text_append(propdb->p, &hdr,
- "</D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
- "</D:propstat>" DEBUG_CR);
- }
-
- result.propstats = hdr.first;
- result.xmlns = hdr_ns.first;
- return result;
-}
-
-DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb,
- apr_xml_doc *doc)
-{
- const dav_hooks_db *db_hooks = propdb->db_hooks;
- apr_xml_elem *elem = dav_find_child(doc->root, "prop");
- apr_text_header hdr_good = { 0 };
- apr_text_header hdr_bad = { 0 };
- apr_text_header hdr_ns = { 0 };
- int have_good = 0;
- dav_get_props_result result = { 0 };
- char *marks_liveprop;
- dav_xmlns_info *xi;
- int xi_filled = 0;
-
- /* ### NOTE: we should pass in TWO buffers -- one for keys, one for
- the marks */
-
- /* we will ALWAYS provide a "good" result, even if it is EMPTY */
- apr_text_append(propdb->p, &hdr_good,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" DEBUG_CR);
-
- /* ### the marks should be in a buffer! */
- /* allocate zeroed-memory for the marks. These marks indicate which
- liveprop namespaces we've generated into the output xmlns buffer */
-
- /* same for the liveprops */
- marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1);
-
- xi = dav_xmlns_create(propdb->p);
-
- for (elem = elem->first_child; elem; elem = elem->next) {
- dav_elem_private *priv;
- dav_error *err;
- dav_prop_insert inserted;
- dav_prop_name name;
-
- /*
- ** First try live property providers; if they don't handle
- ** the property, then try looking it up in the propdb.
- */
-
- if (elem->priv == NULL) {
- elem->priv = apr_pcalloc(propdb->p, sizeof(*priv));
- }
- priv = elem->priv;
-
- /* cache the propid; dav_get_props() could be called many times */
- if (priv->propid == 0)
- dav_find_liveprop(propdb, elem);
-
- if (priv->propid != DAV_PROPID_CORE_UNKNOWN) {
-
- /* insert the property. returns 1 if an insertion was done. */
- if ((err = dav_insert_liveprop(propdb, elem, DAV_PROP_INSERT_VALUE,
- &hdr_good, &inserted)) != NULL) {
- /* ### need to propagate the error to the caller... */
- /* ### skip it for now, as if nothing was inserted */
- }
- if (inserted == DAV_PROP_INSERT_VALUE) {
- have_good = 1;
-
- /*
- ** Add the liveprop's namespace URIs. Note that provider==NULL
- ** for core properties.
- */
- if (priv->provider != NULL) {
- const char * const * scan_ns_uri;
-
- for (scan_ns_uri = priv->provider->namespace_uris;
- *scan_ns_uri != NULL;
- ++scan_ns_uri) {
- int ns;
-
- ns = dav_get_liveprop_ns_index(*scan_ns_uri);
- if (marks_liveprop[ns])
- continue;
- marks_liveprop[ns] = 1;
-
- dav_insert_xmlns(propdb->p, "lp", ns, *scan_ns_uri,
- &hdr_ns);
- }
- }
-
- /* property added. move on to the next property. */
- continue;
- }
- else if (inserted == DAV_PROP_INSERT_NOTDEF) {
- /* nothing to do. fall thru to allow property to be handled
- as a dead property */
- }
-#if DAV_DEBUG
- else {
-#if 0
- /* ### need to change signature to return an error */
- return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0,
- "INTERNAL DESIGN ERROR: insert_liveprop "
- "did not insert what was asked for.");
-#endif
- }
-#endif
- }
-
- /* The property wasn't a live property, so look in the dead property
- database. */
-
- /* make sure propdb is really open */
- if (propdb->deferred) {
- /* ### what to do with db open error? */
- (void) dav_really_open_db(propdb, 1 /*ro*/);
- }
-
- if (elem->ns == APR_XML_NS_NONE)
- name.ns = "";
- else
- name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns);
- name.name = elem->name;
-
- /* only bother to look if a database exists */
- if (propdb->db != NULL) {
- int found;
-
- if ((err = (*db_hooks->output_value)(propdb->db, &name,
- xi, &hdr_good,
- &found)) != NULL) {
- /* ### what to do? continue doesn't seem right... */
- continue;
- }
-
- if (found) {
- have_good = 1;
-
- /* if we haven't added the db's namespaces, then do so... */
- if (!xi_filled) {
- (void) (*db_hooks->define_namespaces)(propdb->db, xi);
- xi_filled = 1;
- }
- continue;
- }
- }
-
- /* not found as a live OR dead property. add a record to the "bad"
- propstats */
-
- /* make sure we've started our "bad" propstat */
- if (hdr_bad.first == NULL) {
- apr_text_append(propdb->p, &hdr_bad,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" DEBUG_CR);
- }
-
- /* output this property's name (into the bad propstats) */
- dav_output_prop_name(propdb->p, &name, xi, &hdr_bad);
- }
-
- apr_text_append(propdb->p, &hdr_good,
- "</D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
- "</D:propstat>" DEBUG_CR);
-
- /* default to start with the good */
- result.propstats = hdr_good.first;
-
- /* we may not have any "bad" results */
- if (hdr_bad.first != NULL) {
- /* "close" the bad propstat */
- apr_text_append(propdb->p, &hdr_bad,
- "</D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
- "</D:propstat>" DEBUG_CR);
-
- /* if there are no good props, then just return the bad */
- if (!have_good) {
- result.propstats = hdr_bad.first;
- }
- else {
- /* hook the bad propstat to the end of the good one */
- hdr_good.last->next = hdr_bad.first;
- }
- }
-
- /* add in all the various namespaces, and return them */
- dav_xmlns_generate(xi, &hdr_ns);
- result.xmlns = hdr_ns.first;
-
- return result;
-}
-
-DAV_DECLARE(void) dav_get_liveprop_supported(dav_propdb *propdb,
- const char *ns_uri,
- const char *propname,
- apr_text_header *body)
-{
- int propid;
- const dav_hooks_liveprop *hooks;
-
- propid = dav_find_liveprop_provider(propdb, ns_uri, propname, &hooks);
-
- if (propid != DAV_PROPID_CORE_UNKNOWN) {
- if (hooks == NULL) {
- /* this is a "core" property that we define */
- dav_prop_insert unused_inserted;
- dav_insert_coreprop(propdb, propid, propname,
- DAV_PROP_INSERT_SUPPORTED, body, &unused_inserted);
- }
- else {
- (*hooks->insert_prop)(propdb->resource, propid,
- DAV_PROP_INSERT_SUPPORTED, body);
- }
- }
-}
-
-DAV_DECLARE_NONSTD(void) dav_prop_validate(dav_prop_ctx *ctx)
-{
- dav_propdb *propdb = ctx->propdb;
- apr_xml_elem *prop = ctx->prop;
- dav_elem_private *priv;
-
- priv = ctx->prop->priv = apr_pcalloc(propdb->p, sizeof(*priv));
-
- /*
- ** Check to see if this is a live property, and fill the fields
- ** in the XML elem, as appropriate.
- **
- ** Verify that the property is read/write. If not, then it cannot
- ** be SET or DELETEd.
- */
- if (priv->propid == 0) {
- dav_find_liveprop(propdb, prop);
-
- /* it's a liveprop if a provider was found */
- /* ### actually the "core" props should really be liveprops, but
- ### there is no "provider" for those and the r/w props are
- ### treated as dead props anyhow */
- ctx->is_liveprop = priv->provider != NULL;
- }
-
- if (!dav_rw_liveprop(propdb, priv)) {
- ctx->err = dav_new_error(propdb->p, HTTP_CONFLICT,
- DAV_ERR_PROP_READONLY,
- "Property is read-only.");
- return;
- }
-
- if (ctx->is_liveprop) {
- int defer_to_dead = 0;
-
- ctx->err = (*priv->provider->patch_validate)(propdb->resource,
- prop, ctx->operation,
- &ctx->liveprop_ctx,
- &defer_to_dead);
- if (ctx->err != NULL || !defer_to_dead)
- return;
-
- /* clear is_liveprop -- act as a dead prop now */
- ctx->is_liveprop = 0;
- }
-
- /*
- ** The property is supposed to be stored into the dead-property
- ** database. Make sure the thing is truly open (and writable).
- */
- if (propdb->deferred
- && (ctx->err = dav_really_open_db(propdb, 0 /* ro */)) != NULL) {
- return;
- }
-
- /*
- ** There should be an open, writable database in here!
- **
- ** Note: the database would be NULL if it was opened readonly and it
- ** did not exist.
- */
- if (propdb->db == NULL) {
- ctx->err = dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
- DAV_ERR_PROP_NO_DATABASE,
- "Attempted to set/remove a property "
- "without a valid, open, read/write "
- "property database.");
- return;
- }
-
- if (ctx->operation == DAV_PROP_OP_SET) {
- /*
- ** Prep the element => propdb namespace index mapping, inserting
- ** namespace URIs into the propdb that don't exist.
- */
- (void) (*propdb->db_hooks->map_namespaces)(propdb->db,
- propdb->ns_xlate,
- &propdb->mapping);
- }
- else if (ctx->operation == DAV_PROP_OP_DELETE) {
- /*
- ** There are no checks to perform here. If a property exists, then
- ** we will delete it. If it does not exist, then it does not matter
- ** (see S12.13.1).
- **
- ** Note that if a property does not exist, that does not rule out
- ** that a SET will occur during this PROPPATCH (thusly creating it).
- */
- }
-}
-
-DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx)
-{
- dav_propdb *propdb = ctx->propdb;
- dav_error *err = NULL;
- dav_elem_private *priv = ctx->prop->priv;
-
- ctx->rollback = apr_pcalloc(propdb->p, sizeof(*ctx->rollback));
-
- if (ctx->is_liveprop) {
- err = (*priv->provider->patch_exec)(propdb->resource,
- ctx->prop, ctx->operation,
- ctx->liveprop_ctx,
- &ctx->rollback->liveprop);
- }
- else {
- dav_prop_name name;
-
- if (ctx->prop->ns == APR_XML_NS_NONE)
- name.ns = "";
- else
- name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, ctx->prop->ns);
- name.name = ctx->prop->name;
-
- /* save the old value so that we can do a rollback. */
- if ((err = (*propdb->db_hooks
- ->get_rollback)(propdb->db, &name,
- &ctx->rollback->deadprop)) != NULL)
- goto error;
-
- if (ctx->operation == DAV_PROP_OP_SET) {
-
- /* Note: propdb->mapping was set in dav_prop_validate() */
- err = (*propdb->db_hooks->store)(propdb->db, &name, ctx->prop,
- propdb->mapping);
-
- /*
- ** If an error occurred, then assume that we didn't change the
- ** value. Remove the rollback item so that we don't try to set
- ** its value during the rollback.
- */
- /* ### euh... where is the removal? */
- }
- else if (ctx->operation == DAV_PROP_OP_DELETE) {
-
- /*
- ** Delete the property. Ignore errors -- the property is there, or
- ** we are deleting it for a second time.
- */
- /* ### but what about other errors? */
- (void) (*propdb->db_hooks->remove)(propdb->db, &name);
- }
- }
-
- error:
- /* push a more specific error here */
- if (err != NULL) {
- /*
- ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen
- ** any errors at this point.
- */
- ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
- DAV_ERR_PROP_EXEC,
- "Could not execute PROPPATCH.", err);
- }
-}
-
-DAV_DECLARE_NONSTD(void) dav_prop_commit(dav_prop_ctx *ctx)
-{
- dav_elem_private *priv = ctx->prop->priv;
-
- /*
- ** Note that a commit implies ctx->err is NULL. The caller should assume
- ** a status of HTTP_OK for this case.
- */
-
- if (ctx->is_liveprop) {
- (*priv->provider->patch_commit)(ctx->propdb->resource,
- ctx->operation,
- ctx->liveprop_ctx,
- ctx->rollback->liveprop);
- }
-}
-
-DAV_DECLARE_NONSTD(void) dav_prop_rollback(dav_prop_ctx *ctx)
-{
- dav_error *err = NULL;
- dav_elem_private *priv = ctx->prop->priv;
-
- /* do nothing if there is no rollback information. */
- if (ctx->rollback == NULL)
- return;
-
- /*
- ** ### if we have an error, and a rollback occurs, then the namespace
- ** ### mods should not happen at all. Basically, the namespace management
- ** ### is simply a bitch.
- */
-
- if (ctx->is_liveprop) {
- err = (*priv->provider->patch_rollback)(ctx->propdb->resource,
- ctx->operation,
- ctx->liveprop_ctx,
- ctx->rollback->liveprop);
- }
- else {
- err = (*ctx->propdb->db_hooks
- ->apply_rollback)(ctx->propdb->db, ctx->rollback->deadprop);
- }
-
- if (err != NULL) {
- if (ctx->err == NULL)
- ctx->err = err;
- else {
- dav_error *scan = err;
-
- /* hook previous errors at the end of the rollback error */
- while (scan->prev != NULL)
- scan = scan->prev;
- scan->prev = ctx->err;
- ctx->err = err;
- }
- }
-}
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/providers.c b/rubbos/app/httpd-2.0.64/modules/dav/main/providers.c
deleted file mode 100644
index a2ccd1ca..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/providers.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "apr_pools.h"
-#include "apr_hash.h"
-#include "ap_provider.h"
-#include "mod_dav.h"
-
-#define DAV_PROVIDER_GROUP "dav"
-
-DAV_DECLARE(void) dav_register_provider(apr_pool_t *p, const char *name,
- const dav_provider *provider)
-{
- ap_register_provider(p, DAV_PROVIDER_GROUP, name, "0", provider);
-}
-
-DAV_DECLARE(const dav_provider *) dav_lookup_provider(const char *name)
-{
- return ap_lookup_provider(DAV_PROVIDER_GROUP, name, "0");
-}
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/std_liveprop.c b/rubbos/app/httpd-2.0.64/modules/dav/main/std_liveprop.c
deleted file mode 100644
index e97d0fda..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/std_liveprop.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "httpd.h"
-#include "util_xml.h"
-#include "apr_strings.h"
-
-#include "mod_dav.h"
-
-/* forward-declare */
-static const dav_hooks_liveprop dav_core_hooks_liveprop;
-
-/*
-** The namespace URIs that we use. There will only ever be "DAV:".
-*/
-static const char * const dav_core_namespace_uris[] =
-{
- "DAV:",
- NULL /* sentinel */
-};
-
-/*
-** Define each of the core properties that this provider will handle.
-** Note that all of them are in the DAV: namespace, which has a
-** provider-local index of 0.
-*/
-static const dav_liveprop_spec dav_core_props[] =
-{
- { 0, "comment", DAV_PROPID_comment, 1 },
- { 0, "creator-displayname", DAV_PROPID_creator_displayname, 1 },
- { 0, "displayname", DAV_PROPID_displayname, 1 },
- { 0, "resourcetype", DAV_PROPID_resourcetype, 0 },
- { 0, "source", DAV_PROPID_source, 1 },
-
- { 0 } /* sentinel */
-};
-
-static const dav_liveprop_group dav_core_liveprop_group =
-{
- dav_core_props,
- dav_core_namespace_uris,
- &dav_core_hooks_liveprop
-};
-
-static dav_prop_insert dav_core_insert_prop(const dav_resource *resource,
- int propid, dav_prop_insert what,
- apr_text_header *phdr)
-{
- const char *value;
- const char *s;
- apr_pool_t *p = resource->pool;
- const dav_liveprop_spec *info;
- int global_ns;
-
- switch (propid)
- {
- case DAV_PROPID_resourcetype:
- switch (resource->type) {
- case DAV_RESOURCE_TYPE_VERSION:
- if (resource->baselined) {
- value = "<D:baseline/>";
- break;
- }
- /* fall through */
- case DAV_RESOURCE_TYPE_REGULAR:
- case DAV_RESOURCE_TYPE_WORKING:
- if (resource->collection) {
- value = "<D:collection/>";
- }
- else {
- /* ### should we denote lock-null resources? */
-
- value = ""; /* becomes: <D:resourcetype/> */
- }
- break;
- case DAV_RESOURCE_TYPE_HISTORY:
- value = "<D:version-history/>";
- break;
- case DAV_RESOURCE_TYPE_WORKSPACE:
- value = "<D:collection/>";
- break;
- case DAV_RESOURCE_TYPE_ACTIVITY:
- value = "<D:activity/>";
- break;
-
- default:
- /* ### bad juju */
- return DAV_PROP_INSERT_NOTDEF;
- }
- break;
-
- case DAV_PROPID_comment:
- case DAV_PROPID_creator_displayname:
- case DAV_PROPID_displayname:
- case DAV_PROPID_source:
- default:
- /*
- ** This property is known, but not defined as a liveprop. However,
- ** it may be a dead property.
- */
- return DAV_PROP_INSERT_NOTDEF;
- }
-
- /* assert: value != NULL */
-
- /* get the information and global NS index for the property */
- global_ns = dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info);
-
- /* assert: info != NULL && info->name != NULL */
-
- if (what == DAV_PROP_INSERT_SUPPORTED) {
- s = apr_psprintf(p,
- "<D:supported-live-property D:name=\"%s\" "
- "D:namespace=\"%s\"/>" DEBUG_CR,
- info->name, dav_core_namespace_uris[info->ns]);
- }
- else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') {
- s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
- global_ns, info->name, value, global_ns, info->name);
- }
- else {
- s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
- }
- apr_text_append(p, phdr, s);
-
- /* we inserted what was asked for */
- return what;
-}
-
-static int dav_core_is_writable(const dav_resource *resource, int propid)
-{
- const dav_liveprop_spec *info;
-
- (void) dav_get_liveprop_info(propid, &dav_core_liveprop_group, &info);
- return info->is_writable;
-}
-
-static dav_error * dav_core_patch_validate(const dav_resource *resource,
- const apr_xml_elem *elem,
- int operation, void **context,
- int *defer_to_dead)
-{
- /* all of our writable props go in the dead prop database */
- *defer_to_dead = 1;
-
- return NULL;
-}
-
-static const dav_hooks_liveprop dav_core_hooks_liveprop = {
- dav_core_insert_prop,
- dav_core_is_writable,
- dav_core_namespace_uris,
- dav_core_patch_validate,
- NULL, /* patch_exec */
- NULL, /* patch_commit */
- NULL, /* patch_rollback */
-};
-
-DAV_DECLARE_NONSTD(int) dav_core_find_liveprop(
- const dav_resource *resource,
- const char *ns_uri, const char *name,
- const dav_hooks_liveprop **hooks)
-{
- return dav_do_find_liveprop(ns_uri, name, &dav_core_liveprop_group, hooks);
-}
-
-DAV_DECLARE_NONSTD(void) dav_core_insert_all_liveprops(
- request_rec *r,
- const dav_resource *resource,
- dav_prop_insert what,
- apr_text_header *phdr)
-{
- (void) dav_core_insert_prop(resource, DAV_PROPID_resourcetype,
- what, phdr);
-}
-
-DAV_DECLARE_NONSTD(void) dav_core_register_uris(apr_pool_t *p)
-{
- /* register the namespace URIs */
- dav_register_liveprop_group(p, &dav_core_liveprop_group);
-}
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/util.c b/rubbos/app/httpd-2.0.64/modules/dav/main/util.c
deleted file mode 100644
index 3ff3a19f..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/util.c
+++ /dev/null
@@ -1,2021 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-** DAV extension module for Apache 2.0.*
-** - various utilities, repository-independent
-*/
-
-#include "apr_strings.h"
-#include "apr_lib.h"
-
-#define APR_WANT_STRFUNC
-#include "apr_want.h"
-
-#include "mod_dav.h"
-
-#include "http_request.h"
-#include "http_config.h"
-#include "http_vhost.h"
-#include "http_log.h"
-#include "http_protocol.h"
-
-DAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status,
- int error_id, const char *desc)
-{
- int save_errno = errno;
- dav_error *err = apr_pcalloc(p, sizeof(*err));
-
- /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */
-
- err->status = status;
- err->error_id = error_id;
- err->desc = desc;
- err->save_errno = save_errno;
-
- return err;
-}
-
-DAV_DECLARE(dav_error*) dav_new_error_tag(apr_pool_t *p, int status,
- int error_id, const char *desc,
- const char *namespace,
- const char *tagname)
-{
- dav_error *err = dav_new_error(p, status, error_id, desc);
-
- err->tagname = tagname;
- err->namespace = namespace;
-
- return err;
-}
-
-
-DAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status,
- int error_id, const char *desc,
- dav_error *prev)
-{
- dav_error *err = apr_pcalloc(p, sizeof(*err));
-
- err->status = status;
- err->error_id = error_id;
- err->desc = desc;
- err->prev = prev;
-
- return err;
-}
-
-DAV_DECLARE(void) dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf,
- apr_size_t extra_needed)
-{
- /* grow the buffer if necessary */
- if (pbuf->cur_len + extra_needed > pbuf->alloc_len) {
- char *newbuf;
-
- pbuf->alloc_len += extra_needed + DAV_BUFFER_PAD;
- newbuf = apr_palloc(p, pbuf->alloc_len);
- memcpy(newbuf, pbuf->buf, pbuf->cur_len);
- pbuf->buf = newbuf;
- }
-}
-
-DAV_DECLARE(void) dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf,
- apr_size_t size)
-{
- /* NOTE: this does not retain prior contents */
-
- /* NOTE: this function is used to init the first pointer, too, since
- the PAD will be larger than alloc_len (0) for zeroed structures */
-
- /* grow if we don't have enough for the requested size plus padding */
- if (size + DAV_BUFFER_PAD > pbuf->alloc_len) {
- /* set the new length; min of MINSIZE */
- pbuf->alloc_len = size + DAV_BUFFER_PAD;
- if (pbuf->alloc_len < DAV_BUFFER_MINSIZE)
- pbuf->alloc_len = DAV_BUFFER_MINSIZE;
-
- pbuf->buf = apr_palloc(p, pbuf->alloc_len);
- }
- pbuf->cur_len = size;
-}
-
-
-/* initialize a buffer and copy the specified (null-term'd) string into it */
-DAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf,
- const char *str)
-{
- dav_set_bufsize(p, pbuf, strlen(str));
- memcpy(pbuf->buf, str, pbuf->cur_len + 1);
-}
-
-/* append a string to the end of the buffer, adjust length */
-DAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf,
- const char *str)
-{
- apr_size_t len = strlen(str);
-
- dav_check_bufsize(p, pbuf, len + 1);
- memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
- pbuf->cur_len += len;
-}
-
-/* place a string on the end of the buffer, do NOT adjust length */
-DAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf,
- const char *str)
-{
- apr_size_t len = strlen(str);
-
- dav_check_bufsize(p, pbuf, len + 1);
- memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
-}
-
-/* place some memory on the end of a buffer; do NOT adjust length */
-DAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf,
- const void *mem, apr_size_t amt,
- apr_size_t pad)
-{
- dav_check_bufsize(p, pbuf, amt + pad);
- memcpy(pbuf->buf + pbuf->cur_len, mem, amt);
-}
-
-/*
-** dav_lookup_uri()
-**
-** Extension for ap_sub_req_lookup_uri() which can't handle absolute
-** URIs properly.
-**
-** If NULL is returned, then an error occurred with parsing the URI or
-** the URI does not match the current server.
-*/
-DAV_DECLARE(dav_lookup_result) dav_lookup_uri(const char *uri,
- request_rec * r,
- int must_be_absolute)
-{
- dav_lookup_result result = { 0 };
- const char *scheme;
- apr_port_t port;
- apr_uri_t comp;
- char *new_file;
- const char *domain;
-
- /* first thing to do is parse the URI into various components */
- if (apr_uri_parse(r->pool, uri, &comp) != APR_SUCCESS) {
- result.err.status = HTTP_BAD_REQUEST;
- result.err.desc = "Invalid syntax in Destination URI.";
- return result;
- }
-
- /* the URI must be an absoluteURI (WEBDAV S9.3) */
- if (comp.scheme == NULL && must_be_absolute) {
- result.err.status = HTTP_BAD_REQUEST;
- result.err.desc = "Destination URI must be an absolute URI.";
- return result;
- }
-
- /* the URI must not have a query (args) or a fragment */
- if (comp.query != NULL || comp.fragment != NULL) {
- result.err.status = HTTP_BAD_REQUEST;
- result.err.desc =
- "Destination URI contains invalid components "
- "(a query or a fragment).";
- return result;
- }
-
- /* If the scheme or port was provided, then make sure that it matches
- the scheme/port of this request. If the request must be absolute,
- then require the (explicit/implicit) scheme/port be matching.
-
- ### hmm. if a port wasn't provided (does the parse return port==0?),
- ### but we're on a non-standard port, then we won't detect that the
- ### URI's port implies the wrong one.
- */
- if (comp.scheme != NULL || comp.port != 0 || must_be_absolute)
- {
- /* ### not sure this works if the current request came in via https: */
- scheme = r->parsed_uri.scheme;
- if (scheme == NULL)
- scheme = ap_http_method(r);
-
- /* insert a port if the URI did not contain one */
- if (comp.port == 0)
- comp.port = apr_uri_port_of_scheme(comp.scheme);
-
- /* now, verify that the URI uses the same scheme as the current.
- request. the port must match our port.
- */
- apr_sockaddr_port_get(&port, r->connection->local_addr);
- if (strcasecmp(comp.scheme, scheme) != 0
-#ifdef APACHE_PORT_HANDLING_IS_BUSTED
- || comp.port != port
-#endif
- ) {
- result.err.status = HTTP_BAD_GATEWAY;
- result.err.desc = apr_psprintf(r->pool,
- "Destination URI refers to "
- "different scheme or port "
- "(%s://hostname:%d)" APR_EOL_STR
- "(want: %s://hostname:%d)",
- comp.scheme ? comp.scheme : scheme,
- comp.port ? comp.port : port,
- scheme, port);
- return result;
- }
- }
-
- /* we have verified the scheme, port, and general structure */
-
- /*
- ** Hrm. IE5 will pass unqualified hostnames for both the
- ** Host: and Destination: headers. This breaks the
- ** http_vhost.c::matches_aliases function.
- **
- ** For now, qualify unqualified comp.hostnames with
- ** r->server->server_hostname.
- **
- ** ### this is a big hack. Apache should provide a better way.
- ** ### maybe the admin should list the unqualified hosts in a
- ** ### <ServerAlias> block?
- */
- if (comp.hostname != NULL
- && strrchr(comp.hostname, '.') == NULL
- && (domain = strchr(r->server->server_hostname, '.')) != NULL) {
- comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL);
- }
-
- /* now, if a hostname was provided, then verify that it represents the
- same server as the current connection. note that we just use our
- port, since we've verified the URI matches ours */
-#ifdef APACHE_PORT_HANDLING_IS_BUSTED
- if (comp.hostname != NULL &&
- !ap_matches_request_vhost(r, comp.hostname, port)) {
- result.err.status = HTTP_BAD_GATEWAY;
- result.err.desc = "Destination URI refers to a different server.";
- return result;
- }
-#endif
-
- /* we have verified that the requested URI denotes the same server as
- the current request. Therefore, we can use ap_sub_req_lookup_uri() */
-
- /* reconstruct a URI as just the path */
- new_file = apr_uri_unparse(r->pool, &comp, APR_URI_UNP_OMITSITEPART);
-
- /*
- * Lookup the URI and return the sub-request. Note that we use the
- * same HTTP method on the destination. This allows the destination
- * to apply appropriate restrictions (e.g. readonly).
- */
- result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL);
-
- return result;
-}
-
-/* ---------------------------------------------------------------
-**
-** XML UTILITY FUNCTIONS
-*/
-
-/* validate that the root element uses a given DAV: tagname (TRUE==valid) */
-DAV_DECLARE(int) dav_validate_root(const apr_xml_doc *doc,
- const char *tagname)
-{
- return doc->root &&
- doc->root->ns == APR_XML_NS_DAV_ID &&
- strcmp(doc->root->name, tagname) == 0;
-}
-
-/* find and return the (unique) child with a given DAV: tagname */
-DAV_DECLARE(apr_xml_elem *) dav_find_child(const apr_xml_elem *elem,
- const char *tagname)
-{
- apr_xml_elem *child = elem->first_child;
-
- for (; child; child = child->next)
- if (child->ns == APR_XML_NS_DAV_ID && !strcmp(child->name, tagname))
- return child;
- return NULL;
-}
-
-/* gather up all the CDATA into a single string */
-DAV_DECLARE(const char *) dav_xml_get_cdata(const apr_xml_elem *elem, apr_pool_t *pool,
- int strip_white)
-{
- apr_size_t len = 0;
- apr_text *scan;
- const apr_xml_elem *child;
- char *cdata;
- char *s;
- apr_size_t tlen;
- const char *found_text = NULL; /* initialize to avoid gcc warning */
- int found_count = 0;
-
- for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
- found_text = scan->text;
- ++found_count;
- len += strlen(found_text);
- }
-
- for (child = elem->first_child; child != NULL; child = child->next) {
- for (scan = child->following_cdata.first;
- scan != NULL;
- scan = scan->next) {
- found_text = scan->text;
- ++found_count;
- len += strlen(found_text);
- }
- }
-
- /* some fast-path cases:
- * 1) zero-length cdata
- * 2) a single piece of cdata with no whitespace to strip
- */
- if (len == 0)
- return "";
- if (found_count == 1) {
- if (!strip_white
- || (!apr_isspace(*found_text)
- && !apr_isspace(found_text[len - 1])))
- return found_text;
- }
-
- cdata = s = apr_palloc(pool, len + 1);
-
- for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
- tlen = strlen(scan->text);
- memcpy(s, scan->text, tlen);
- s += tlen;
- }
-
- for (child = elem->first_child; child != NULL; child = child->next) {
- for (scan = child->following_cdata.first;
- scan != NULL;
- scan = scan->next) {
- tlen = strlen(scan->text);
- memcpy(s, scan->text, tlen);
- s += tlen;
- }
- }
-
- *s = '\0';
-
- if (strip_white) {
- /* trim leading whitespace */
- while (apr_isspace(*cdata)) /* assume: return false for '\0' */
- ++cdata;
-
- /* trim trailing whitespace */
- while (len-- > 0 && apr_isspace(cdata[len]))
- continue;
- cdata[len + 1] = '\0';
- }
-
- return cdata;
-}
-
-DAV_DECLARE(dav_xmlns_info *) dav_xmlns_create(apr_pool_t *pool)
-{
- dav_xmlns_info *xi = apr_pcalloc(pool, sizeof(*xi));
-
- xi->pool = pool;
- xi->uri_prefix = apr_hash_make(pool);
- xi->prefix_uri = apr_hash_make(pool);
-
- return xi;
-}
-
-DAV_DECLARE(void) dav_xmlns_add(dav_xmlns_info *xi,
- const char *prefix, const char *uri)
-{
- /* this "should" not overwrite a prefix mapping */
- apr_hash_set(xi->prefix_uri, prefix, APR_HASH_KEY_STRING, uri);
-
- /* note: this may overwrite an existing URI->prefix mapping, but it
- doesn't matter -- any prefix is usuable to specify the URI. */
- apr_hash_set(xi->uri_prefix, uri, APR_HASH_KEY_STRING, prefix);
-}
-
-DAV_DECLARE(const char *) dav_xmlns_add_uri(dav_xmlns_info *xi,
- const char *uri)
-{
- const char *prefix;
-
- if ((prefix = apr_hash_get(xi->uri_prefix, uri,
- APR_HASH_KEY_STRING)) != NULL)
- return prefix;
-
- prefix = apr_psprintf(xi->pool, "g%d", xi->count++);
- dav_xmlns_add(xi, prefix, uri);
- return prefix;
-}
-
-DAV_DECLARE(const char *) dav_xmlns_get_uri(dav_xmlns_info *xi,
- const char *prefix)
-{
- return apr_hash_get(xi->prefix_uri, prefix, APR_HASH_KEY_STRING);
-}
-
-DAV_DECLARE(const char *) dav_xmlns_get_prefix(dav_xmlns_info *xi,
- const char *uri)
-{
- return apr_hash_get(xi->uri_prefix, uri, APR_HASH_KEY_STRING);
-}
-
-DAV_DECLARE(void) dav_xmlns_generate(dav_xmlns_info *xi,
- apr_text_header *phdr)
-{
- apr_hash_index_t *hi = apr_hash_first(xi->pool, xi->prefix_uri);
-
- for (; hi != NULL; hi = apr_hash_next(hi)) {
- const void *prefix;
- void *uri;
- const char *s;
-
- apr_hash_this(hi, &prefix, NULL, &uri);
-
- s = apr_psprintf(xi->pool, " xmlns:%s=\"%s\"",
- (const char *)prefix, (const char *)uri);
- apr_text_append(xi->pool, phdr, s);
- }
-}
-
-/* ---------------------------------------------------------------
-**
-** Timeout header processing
-**
-*/
-
-/* dav_get_timeout: If the Timeout: header exists, return a time_t
- * when this lock is expected to expire. Otherwise, return
- * a time_t of DAV_TIMEOUT_INFINITE.
- *
- * It's unclear if DAV clients are required to understand
- * Seconds-xxx and Infinity time values. We assume that they do.
- * In addition, for now, that's all we understand, too.
- */
-DAV_DECLARE(time_t) dav_get_timeout(request_rec *r)
-{
- time_t now, expires = DAV_TIMEOUT_INFINITE;
-
- const char *timeout_const = apr_table_get(r->headers_in, "Timeout");
- const char *timeout = apr_pstrdup(r->pool, timeout_const), *val;
-
- if (timeout == NULL)
- return DAV_TIMEOUT_INFINITE;
-
- /* Use the first thing we understand, or infinity if
- * we don't understand anything.
- */
-
- while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) {
- if (!strncmp(val, "Infinite", 8)) {
- return DAV_TIMEOUT_INFINITE;
- }
-
- if (!strncmp(val, "Second-", 7)) {
- val += 7;
- /* ### We need to handle overflow better:
- * ### timeout will be <= 2^32 - 1
- */
- expires = atol(val);
- now = time(NULL);
- return now + expires;
- }
- }
-
- return DAV_TIMEOUT_INFINITE;
-}
-
-/* ---------------------------------------------------------------
-**
-** If Header processing
-**
-*/
-
-/* add_if_resource returns a new if_header, linking it to next_ih.
- */
-static dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih,
- const char *uri, apr_size_t uri_len)
-{
- dav_if_header *ih;
-
- if ((ih = apr_pcalloc(p, sizeof(*ih))) == NULL)
- return NULL;
-
- ih->uri = uri;
- ih->uri_len = uri_len;
- ih->next = next_ih;
-
- return ih;
-}
-
-/* add_if_state adds a condition to an if_header.
- */
-static dav_error * dav_add_if_state(apr_pool_t *p, dav_if_header *ih,
- const char *state_token,
- dav_if_state_type t, int condition,
- const dav_hooks_locks *locks_hooks)
-{
- dav_if_state_list *new_sl;
-
- new_sl = apr_pcalloc(p, sizeof(*new_sl));
-
- new_sl->condition = condition;
- new_sl->type = t;
-
- if (t == dav_if_opaquelock) {
- dav_error *err;
-
- if ((err = (*locks_hooks->parse_locktoken)(p, state_token,
- &new_sl->locktoken)) != NULL) {
- /* In cases where the state token is invalid, we'll just skip
- * it rather than return 400.
- */
- if (err->error_id == DAV_ERR_LOCK_UNK_STATE_TOKEN) {
- return NULL;
- }
- else {
- /* ### maybe add a higher-level description */
- return err;
- }
- }
- }
- else
- new_sl->etag = state_token;
-
- new_sl->next = ih->state;
- ih->state = new_sl;
-
- return NULL;
-}
-
-/* fetch_next_token returns the substring from str+1
- * to the next occurence of char term, or \0, whichever
- * occurs first. Leading whitespace is ignored.
- */
-static char *dav_fetch_next_token(char **str, char term)
-{
- char *sp;
- char *token;
-
- token = *str + 1;
-
- while (*token && (*token == ' ' || *token == '\t'))
- token++;
-
- if ((sp = strchr(token, term)) == NULL)
- return NULL;
-
- *sp = '\0';
- *str = sp;
- return token;
-}
-
-/* dav_process_if_header:
- *
- * If NULL (no error) is returned, then **if_header points to the
- * "If" productions structure (or NULL if "If" is not present).
- *
- * ### this part is bogus:
- * If an error is encountered, the error is logged. Parent should
- * return err->status.
- */
-static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
-{
- dav_error *err;
- char *str;
- char *list;
- const char *state_token;
- const char *uri = NULL; /* scope of current production; NULL=no-tag */
- apr_size_t uri_len = 0;
- dav_if_header *ih = NULL;
- apr_uri_t parsed_uri;
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- enum {no_tagged, tagged, unknown} list_type = unknown;
- int condition;
-
- *p_ih = NULL;
-
- if ((str = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "If"))) == NULL)
- return NULL;
-
- while (*str) {
- switch(*str) {
- case '<':
- /* Tagged-list production - following states apply to this uri */
- if (list_type == no_tagged
- || ((uri = dav_fetch_next_token(&str, '>')) == NULL)) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_TAGGED,
- "Invalid If-header: unclosed \"<\" or "
- "unexpected tagged-list production.");
- }
-
- /* 2518 specifies this must be an absolute URI; just take the
- * relative part for later comparison against r->uri */
- if (apr_uri_parse(r->pool, uri, &parsed_uri) != APR_SUCCESS
- || !parsed_uri.path) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_TAGGED,
- "Invalid URI in tagged If-header.");
- }
- /* note that parsed_uri.path is allocated; we can trash it */
-
- /* clean up the URI a bit */
- ap_getparents(parsed_uri.path);
- uri_len = strlen(parsed_uri.path);
- if (uri_len > 1 && parsed_uri.path[uri_len - 1] == '/')
- parsed_uri.path[--uri_len] = '\0';
-
- uri = parsed_uri.path;
- list_type = tagged;
- break;
-
- case '(':
- /* List production */
-
- /* If a uri has not been encountered, this is a No-Tagged-List */
- if (list_type == unknown)
- list_type = no_tagged;
-
- if ((list = dav_fetch_next_token(&str, ')')) == NULL) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_UNCLOSED_PAREN,
- "Invalid If-header: unclosed \"(\".");
- }
-
- if ((ih = dav_add_if_resource(r->pool, ih, uri, uri_len)) == NULL) {
- /* ### dav_add_if_resource() should return an error for us! */
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_PARSE,
- "Internal server error parsing \"If:\" "
- "header.");
- }
-
- condition = DAV_IF_COND_NORMAL;
-
- while (*list) {
- /* List is the entire production (in a uri scope) */
-
- switch (*list) {
- case '<':
- if ((state_token = dav_fetch_next_token(&list, '>')) == NULL) {
- /* ### add a description to this error */
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_PARSE, NULL);
- }
-
- if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_opaquelock,
- condition, locks_hooks)) != NULL) {
- /* ### maybe add a higher level description */
- return err;
- }
- condition = DAV_IF_COND_NORMAL;
- break;
-
- case '[':
- if ((state_token = dav_fetch_next_token(&list, ']')) == NULL) {
- /* ### add a description to this error */
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_PARSE, NULL);
- }
-
- if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_etag,
- condition, locks_hooks)) != NULL) {
- /* ### maybe add a higher level description */
- return err;
- }
- condition = DAV_IF_COND_NORMAL;
- break;
-
- case 'N':
- if (list[1] == 'o' && list[2] == 't') {
- if (condition != DAV_IF_COND_NORMAL) {
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_MULTIPLE_NOT,
- "Invalid \"If:\" header: "
- "Multiple \"not\" entries "
- "for the same state.");
- }
- condition = DAV_IF_COND_NOT;
- }
- list += 2;
- break;
-
- case ' ':
- case '\t':
- break;
-
- default:
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_UNK_CHAR,
- apr_psprintf(r->pool,
- "Invalid \"If:\" "
- "header: Unexpected "
- "character encountered "
- "(0x%02x, '%c').",
- *list, *list));
- }
-
- list++;
- }
- break;
-
- case ' ':
- case '\t':
- break;
-
- default:
- return dav_new_error(r->pool, HTTP_BAD_REQUEST,
- DAV_ERR_IF_UNK_CHAR,
- apr_psprintf(r->pool,
- "Invalid \"If:\" header: "
- "Unexpected character "
- "encountered (0x%02x, '%c').",
- *str, *str));
- }
-
- str++;
- }
-
- *p_ih = ih;
- return NULL;
-}
-
-static int dav_find_submitted_locktoken(const dav_if_header *if_header,
- const dav_lock *lock_list,
- const dav_hooks_locks *locks_hooks)
-{
- for (; if_header != NULL; if_header = if_header->next) {
- const dav_if_state_list *state_list;
-
- for (state_list = if_header->state;
- state_list != NULL;
- state_list = state_list->next) {
-
- if (state_list->type == dav_if_opaquelock) {
- const dav_lock *lock;
-
- /* given state_list->locktoken, match it */
-
- /*
- ** The resource will have one or more lock tokens. We only
- ** need to match one of them against any token in the
- ** If: header.
- **
- ** One token case: It is an exclusive or shared lock. Either
- ** way, we must find it.
- **
- ** N token case: They are shared locks. By policy, we need
- ** to match only one. The resource's other
- ** tokens may belong to somebody else (so we
- ** shouldn't see them in the If: header anyway)
- */
- for (lock = lock_list; lock != NULL; lock = lock->next) {
-
- if (!(*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
- return 1;
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-/* dav_validate_resource_state:
- * Returns NULL if path/uri meets if-header and lock requirements
- */
-static dav_error * dav_validate_resource_state(apr_pool_t *p,
- const dav_resource *resource,
- dav_lockdb *lockdb,
- const dav_if_header *if_header,
- int flags,
- dav_buffer *pbuf,
- request_rec *r)
-{
- dav_error *err;
- const char *uri;
- const char *etag;
- const dav_hooks_locks *locks_hooks = (lockdb ? lockdb->hooks : NULL);
- const dav_if_header *ifhdr_scan;
- dav_if_state_list *state_list;
- dav_lock *lock_list;
- dav_lock *lock;
- int num_matched;
- int num_that_apply;
- int seen_locktoken;
- apr_size_t uri_len;
- const char *reason = NULL;
-
- /* DBG1("validate: <%s>", resource->uri); */
-
- /*
- ** The resource will have one of three states:
- **
- ** 1) No locks. We have no special requirements that the user supply
- ** specific locktokens. One of the state lists must match, and
- ** we're done.
- **
- ** 2) One exclusive lock. The locktoken must appear *anywhere* in the
- ** If: header. Of course, asserting the token in a "Not" term will
- ** quickly fail that state list :-). If the locktoken appears in
- ** one of the state lists *and* one state list matches, then we're
- ** done.
- **
- ** 3) One or more shared locks. One of the locktokens must appear
- ** *anywhere* in the If: header. If one of the locktokens appears,
- ** and we match one state list, then we are done.
- **
- ** The <seen_locktoken> variable determines whether we have seen one
- ** of this resource's locktokens in the If: header.
- */
-
- /*
- ** If this is a new lock request, <flags> will contain the requested
- ** lock scope. Three rules apply:
- **
- ** 1) Do not require a (shared) locktoken to be seen (when we are
- ** applying another shared lock)
- ** 2) If the scope is exclusive and we see any locks, fail.
- ** 3) If the scope is shared and we see an exclusive lock, fail.
- */
-
- if (lockdb == NULL) {
- /* we're in State 1. no locks. */
- lock_list = NULL;
- }
- else {
- /*
- ** ### hrm... we don't need to have these fully
- ** ### resolved since we're only looking at the
- ** ### locktokens...
- **
- ** ### use get_locks w/ calltype=PARTIAL
- */
- if ((err = dav_lock_query(lockdb, resource, &lock_list)) != NULL) {
- return dav_push_error(p,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "The locks could not be queried for "
- "verification against a possible \"If:\" "
- "header.",
- err);
- }
-
- /* lock_list now determines whether we're in State 1, 2, or 3. */
- }
-
- /*
- ** For a new, exclusive lock: if any locks exist, fail.
- ** For a new, shared lock: if an exclusive lock exists, fail.
- ** else, do not require a token to be seen.
- */
- if (flags & DAV_LOCKSCOPE_EXCLUSIVE) {
- if (lock_list != NULL) {
- return dav_new_error(p, HTTP_LOCKED, 0,
- "Existing lock(s) on the requested resource "
- "prevent an exclusive lock.");
- }
-
- /*
- ** There are no locks, so we can pretend that we've already met
- ** any requirement to find the resource's locks in an If: header.
- */
- seen_locktoken = 1;
- }
- else if (flags & DAV_LOCKSCOPE_SHARED) {
- /*
- ** Strictly speaking, we don't need this loop. Either the first
- ** (and only) lock will be EXCLUSIVE, or none of them will be.
- */
- for (lock = lock_list; lock != NULL; lock = lock->next) {
- if (lock->scope == DAV_LOCKSCOPE_EXCLUSIVE) {
- return dav_new_error(p, HTTP_LOCKED, 0,
- "The requested resource is already "
- "locked exclusively.");
- }
- }
-
- /*
- ** The locks on the resource (if any) are all shared. Set the
- ** <seen_locktoken> flag to indicate that we do not need to find
- ** the locks in an If: header.
- */
- seen_locktoken = 1;
- }
- else {
- /*
- ** For methods other than LOCK:
- **
- ** If we have no locks, then <seen_locktoken> can be set to true --
- ** pretending that we've already met the requirement of seeing one
- ** of the resource's locks in the If: header.
- **
- ** Otherwise, it must be cleared and we'll look for one.
- */
- seen_locktoken = (lock_list == NULL);
- }
-
- /*
- ** If there is no If: header, then we can shortcut some logic:
- **
- ** 1) if we do not need to find a locktoken in the (non-existent) If:
- ** header, then we are successful.
- **
- ** 2) if we must find a locktoken in the (non-existent) If: header, then
- ** we fail.
- */
- if (if_header == NULL) {
- if (seen_locktoken)
- return NULL;
-
- return dav_new_error(p, HTTP_LOCKED, 0,
- "This resource is locked and an \"If:\" header "
- "was not supplied to allow access to the "
- "resource.");
- }
- /* the If: header is present */
-
- /*
- ** If a dummy header is present (because of a Lock-Token: header), then
- ** we are required to find that token in this resource's set of locks.
- ** If we have no locks, then we immediately fail.
- **
- ** This is a 400 (Bad Request) since they should only submit a locktoken
- ** that actually exists.
- **
- ** Don't issue this response if we're talking about the parent resource.
- ** It is okay for that resource to NOT have this locktoken.
- ** (in fact, it certainly will not: a dummy_header only occurs for the
- ** UNLOCK method, the parent is checked only for locknull resources,
- ** and the parent certainly does not have the (locknull's) locktoken)
- */
- if (lock_list == NULL && if_header->dummy_header) {
- if (flags & DAV_VALIDATE_IS_PARENT)
- return NULL;
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "The locktoken specified in the \"Lock-Token:\" "
- "header is invalid because this resource has no "
- "outstanding locks.");
- }
-
- /*
- ** Prepare the input URI. We want the URI to never have a trailing slash.
- **
- ** When URIs are placed into the dav_if_header structure, they are
- ** guaranteed to never have a trailing slash. If the URIs are equivalent,
- ** then it doesn't matter if they both lack a trailing slash -- they're
- ** still equivalent.
- **
- ** Note: we could also ensure that a trailing slash is present on both
- ** URIs, but the majority of URIs provided to us via a resource walk
- ** will not contain that trailing slash.
- */
- uri = resource->uri;
- uri_len = strlen(uri);
- if (uri[uri_len - 1] == '/') {
- dav_set_bufsize(p, pbuf, uri_len);
- memcpy(pbuf->buf, uri, uri_len);
- pbuf->buf[--uri_len] = '\0';
- uri = pbuf->buf;
- }
-
- /* get the resource's etag; we may need it during the checks */
- etag = (*resource->hooks->getetag)(resource);
-
- /* how many state_lists apply to this URI? */
- num_that_apply = 0;
-
- /* If there are if-headers, fail if this resource
- * does not match at least one state_list.
- */
- for (ifhdr_scan = if_header;
- ifhdr_scan != NULL;
- ifhdr_scan = ifhdr_scan->next) {
-
- /* DBG2("uri=<%s> if_uri=<%s>", uri, ifhdr_scan->uri ? ifhdr_scan->uri : "(no uri)"); */
-
- if (ifhdr_scan->uri != NULL
- && (uri_len != ifhdr_scan->uri_len
- || memcmp(uri, ifhdr_scan->uri, uri_len) != 0)) {
- /*
- ** A tagged-list's URI doesn't match this resource's URI.
- ** Skip to the next state_list to see if it will match.
- */
- continue;
- }
-
- /* this state_list applies to this resource */
-
- /*
- ** ### only one state_list should ever apply! a no-tag, or a tagged
- ** ### where S9.4.2 states only one can match.
- **
- ** ### revamp this code to loop thru ifhdr_scan until we find the
- ** ### matching state_list. process it. stop.
- */
- ++num_that_apply;
-
- /* To succeed, resource must match *all* of the states
- * specified in the state_list.
- */
- for (state_list = ifhdr_scan->state;
- state_list != NULL;
- state_list = state_list->next) {
-
- switch(state_list->type) {
- case dav_if_etag:
- {
- int mismatch = strcmp(state_list->etag, etag);
-
- if (state_list->condition == DAV_IF_COND_NORMAL && mismatch) {
- /*
- ** The specified entity-tag does not match the
- ** entity-tag on the resource. This state_list is
- ** not going to match. Bust outta here.
- */
- reason =
- "an entity-tag was specified, but the resource's "
- "actual ETag does not match.";
- goto state_list_failed;
- }
- else if (state_list->condition == DAV_IF_COND_NOT
- && !mismatch) {
- /*
- ** The specified entity-tag DOES match the
- ** entity-tag on the resource. This state_list is
- ** not going to match. Bust outta here.
- */
- reason =
- "an entity-tag was specified using the \"Not\" form, "
- "but the resource's actual ETag matches the provided "
- "entity-tag.";
- goto state_list_failed;
- }
- break;
- }
-
- case dav_if_opaquelock:
- if (lockdb == NULL) {
- if (state_list->condition == DAV_IF_COND_NOT) {
- /* the locktoken is definitely not there! (success) */
- continue;
- }
-
- /* condition == DAV_IF_COND_NORMAL */
-
- /*
- ** If no lockdb is provided, then validation fails for
- ** this state_list (NORMAL means we were supposed to
- ** find the token, which we obviously cannot do without
- ** a lock database).
- **
- ** Go and try the next state list.
- */
- reason =
- "a State-token was supplied, but a lock database "
- "is not available for to provide the required lock.";
- goto state_list_failed;
- }
-
- /* Resource validation 'fails' if:
- * ANY of the lock->locktokens match
- * a NOT state_list->locktoken,
- * OR
- * NONE of the lock->locktokens match
- * a NORMAL state_list->locktoken.
- */
- num_matched = 0;
- for (lock = lock_list; lock != NULL; lock = lock->next) {
-
- /*
- DBG2("compare: rsrc=%s ifhdr=%s",
- (*locks_hooks->format_locktoken)(p, lock->locktoken),
- (*locks_hooks->format_locktoken)(p, state_list->locktoken));
- */
-
- /* nothing to do if the locktokens do not match. */
- if ((*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
- continue;
- }
-
- /*
- ** We have now matched up one of the resource's locktokens
- ** to a locktoken in a State-token in the If: header.
- ** Note this fact, so that we can pass the overall
- ** requirement of seeing at least one of the resource's
- ** locktokens.
- */
- seen_locktoken = 1;
-
- if (state_list->condition == DAV_IF_COND_NOT) {
- /*
- ** This state requires that the specified locktoken
- ** is NOT present on the resource. But we just found
- ** it. There is no way this state-list can now
- ** succeed, so go try another one.
- */
- reason =
- "a State-token was supplied, which used a "
- "\"Not\" condition. The State-token was found "
- "in the locks on this resource";
- goto state_list_failed;
- }
-
- /* condition == DAV_IF_COND_NORMAL */
-
- /* Validate auth_user: If an authenticated user created
- ** the lock, only the same user may submit that locktoken
- ** to manipulate a resource.
- */
- if (lock->auth_user &&
- (!r->user ||
- strcmp(lock->auth_user, r->user))) {
- const char *errmsg;
-
- errmsg = apr_pstrcat(p, "User \"",
- r->user,
- "\" submitted a locktoken created "
- "by user \"",
- lock->auth_user, "\".", NULL);
- return dav_new_error(p, HTTP_FORBIDDEN, 0, errmsg);
- }
-
- /*
- ** We just matched a specified State-Token to one of the
- ** resource's locktokens.
- **
- ** Break out of the lock scan -- we only needed to find
- ** one match (actually, there shouldn't be any other
- ** matches in the lock list).
- */
- num_matched = 1;
- break;
- }
-
- if (num_matched == 0
- && state_list->condition == DAV_IF_COND_NORMAL) {
- /*
- ** We had a NORMAL state, meaning that we should have
- ** found the State-Token within the locks on this
- ** resource. We didn't, so this state_list must fail.
- */
- reason =
- "a State-token was supplied, but it was not found "
- "in the locks on this resource.";
- goto state_list_failed;
- }
-
- break;
-
- } /* switch */
- } /* foreach ( state_list ) */
-
- /*
- ** We've checked every state in this state_list and none of them
- ** have failed. Since all of them succeeded, then we have a matching
- ** state list and we may be done.
- **
- ** The next requirement is that we have seen one of the resource's
- ** locktokens (if any). If we have, then we can just exit. If we
- ** haven't, then we need to keep looking.
- */
- if (seen_locktoken) {
- /* woo hoo! */
- return NULL;
- }
-
- /*
- ** Haven't seen one. Let's break out of the search and just look
- ** for a matching locktoken.
- */
- break;
-
- /*
- ** This label is used when we detect that a state_list is not
- ** going to match this resource. We bust out and try the next
- ** state_list.
- */
- state_list_failed:
- ;
-
- } /* foreach ( ifhdr_scan ) */
-
- /*
- ** The above loop exits for one of two reasons:
- ** 1) a state_list matched and seen_locktoken is false.
- ** 2) all if_header structures were scanned, without (1) occurring
- */
-
- if (ifhdr_scan == NULL) {
- /*
- ** We finished the loop without finding any matching state lists.
- */
-
- /*
- ** If none of the state_lists apply to this resource, then we
- ** may have succeeded. Note that this scenario implies a
- ** tagged-list with no matching state_lists. If the If: header
- ** was a no-tag-list, then it would have applied to this resource.
- **
- ** S9.4.2 states that when no state_lists apply, then the header
- ** should be ignored.
- **
- ** If we saw one of the resource's locktokens, then we're done.
- ** If we did not see a locktoken, then we fail.
- */
- if (num_that_apply == 0) {
- if (seen_locktoken)
- return NULL;
-
- /*
- ** We may have aborted the scan before seeing the locktoken.
- ** Rescan the If: header to see if we can find the locktoken
- ** somewhere.
- **
- ** Note that seen_locktoken == 0 implies lock_list != NULL
- ** which implies locks_hooks != NULL.
- */
- if (dav_find_submitted_locktoken(if_header, lock_list,
- locks_hooks)) {
- /*
- ** We found a match! We're set... none of the If: header
- ** assertions apply (implicit success), and the If: header
- ** specified the locktoken somewhere. We're done.
- */
- return NULL;
- }
-
- return dav_new_error(p, HTTP_LOCKED, 0 /* error_id */,
- "This resource is locked and the \"If:\" "
- "header did not specify one of the "
- "locktokens for this resource's lock(s).");
- }
- /* else: one or more state_lists were applicable, but failed. */
-
- /*
- ** If the dummy_header did not match, then they specified an
- ** incorrect token in the Lock-Token header. Forget whether the
- ** If: statement matched or not... we'll tell them about the
- ** bad Lock-Token first. That is considered a 400 (Bad Request).
- */
- if (if_header->dummy_header) {
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "The locktoken specified in the "
- "\"Lock-Token:\" header did not specify one "
- "of this resource's locktoken(s).");
- }
-
- if (reason == NULL) {
- return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
- "The preconditions specified by the \"If:\" "
- "header did not match this resource.");
- }
-
- return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
- apr_psprintf(p,
- "The precondition(s) specified by "
- "the \"If:\" header did not match "
- "this resource. At least one "
- "failure is because: %s", reason));
- }
-
- /* assert seen_locktoken == 0 */
-
- /*
- ** ifhdr_scan != NULL implies we found a matching state_list.
- **
- ** Since we're still here, it also means that we have not yet found
- ** one the resource's locktokens in the If: header.
- **
- ** Scan all the if_headers and states looking for one of this
- ** resource's locktokens. Note that we need to go back and scan them
- ** all -- we may have aborted a scan with a failure before we saw a
- ** matching token.
- **
- ** Note that seen_locktoken == 0 implies lock_list != NULL which implies
- ** locks_hooks != NULL.
- */
- if (dav_find_submitted_locktoken(if_header, lock_list, locks_hooks)) {
- /*
- ** We found a match! We're set... we have a matching state list,
- ** and the If: header specified the locktoken somewhere. We're done.
- */
- return NULL;
- }
-
- /*
- ** We had a matching state list, but the user agent did not specify one
- ** of this resource's locktokens. Tell them so.
- **
- ** Note that we need to special-case the message on whether a "dummy"
- ** header exists. If it exists, yet we didn't see a needed locktoken,
- ** then that implies the dummy header (Lock-Token header) did NOT
- ** specify one of this resource's locktokens. (this implies something
- ** in the real If: header matched)
- **
- ** We want to note the 400 (Bad Request) in favor of a 423 (Locked).
- */
- if (if_header->dummy_header) {
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "The locktoken specified in the "
- "\"Lock-Token:\" header did not specify one "
- "of this resource's locktoken(s).");
- }
-
- return dav_new_error(p, HTTP_LOCKED, 1 /* error_id */,
- "This resource is locked and the \"If:\" header "
- "did not specify one of the "
- "locktokens for this resource's lock(s).");
-}
-
-/* dav_validate_walker: Walker callback function to validate resource state */
-static dav_error * dav_validate_walker(dav_walk_resource *wres, int calltype)
-{
- dav_walker_ctx *ctx = wres->walk_ctx;
- dav_error *err;
-
- if ((err = dav_validate_resource_state(ctx->w.pool, wres->resource,
- ctx->w.lockdb,
- ctx->if_header, ctx->flags,
- &ctx->work_buf, ctx->r)) == NULL) {
- /* There was no error, so just bug out. */
- return NULL;
- }
-
- /*
- ** If we have a serious server error, or if the request itself failed,
- ** then just return error (not a multistatus).
- */
- if (ap_is_HTTP_SERVER_ERROR(err->status)
- || (*wres->resource->hooks->is_same_resource)(wres->resource,
- ctx->w.root)) {
- /* ### maybe push a higher-level description? */
- return err;
- }
-
- /* associate the error with the current URI */
- dav_add_response(wres, err->status, NULL);
-
- return NULL;
-}
-
-/*
-** dav_validate_request: Validate if-headers (and check for locks) on:
-** (1) r->filename @ depth;
-** (2) Parent of r->filename if check_parent == 1
-**
-** The check of parent should be done when it is necessary to verify that
-** the parent collection will accept a new member (ie current resource
-** state is null).
-**
-** Return OK on successful validation.
-** On error, return appropriate HTTP_* code, and log error. If a multi-stat
-** error is necessary, response will point to it, else NULL.
-*/
-DAV_DECLARE(dav_error *) dav_validate_request(request_rec *r,
- dav_resource *resource,
- int depth,
- dav_locktoken *locktoken,
- dav_response **response,
- int flags,
- dav_lockdb *lockdb)
-{
- dav_error *err;
- int result;
- dav_if_header *if_header;
- int lock_db_opened_locally = 0;
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
- const dav_hooks_repository *repos_hooks = resource->hooks;
- dav_buffer work_buf = { 0 };
- dav_response *new_response;
-
-#if DAV_DEBUG
- if (depth && response == NULL) {
- /*
- ** ### bleck. we can't return errors for other URIs unless we have
- ** ### a "response" ptr.
- */
- return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "DESIGN ERROR: dav_validate_request called "
- "with depth>0, but no response ptr.");
- }
-#endif
-
- if (response != NULL)
- *response = NULL;
-
- /* Do the standard checks for conditional requests using
- * If-..-Since, If-Match etc */
- if ((result = ap_meets_conditions(r)) != OK) {
- /* ### fix this up... how? */
- return dav_new_error(r->pool, result, 0, NULL);
- }
-
- /* always parse (and later process) the If: header */
- if ((err = dav_process_if_header(r, &if_header)) != NULL) {
- /* ### maybe add higher-level description */
- return err;
- }
-
- /* If a locktoken was specified, create a dummy if_header with which
- * to validate resources. In the interim, figure out why DAV uses
- * locktokens in an if-header without a Lock-Token header to refresh
- * locks, but a Lock-Token header without an if-header to remove them.
- */
- if (locktoken != NULL) {
- dav_if_header *ifhdr_new;
-
- ifhdr_new = apr_pcalloc(r->pool, sizeof(*ifhdr_new));
- ifhdr_new->uri = resource->uri;
- ifhdr_new->uri_len = strlen(resource->uri);
- ifhdr_new->dummy_header = 1;
-
- ifhdr_new->state = apr_pcalloc(r->pool, sizeof(*ifhdr_new->state));
- ifhdr_new->state->type = dav_if_opaquelock;
- ifhdr_new->state->condition = DAV_IF_COND_NORMAL;
- ifhdr_new->state->locktoken = locktoken;
-
- ifhdr_new->next = if_header;
- if_header = ifhdr_new;
- }
-
- /*
- ** If necessary, open the lock database (read-only, lazily);
- ** the validation process may need to retrieve or update lock info.
- ** Otherwise, assume provided lockdb is valid and opened rw.
- */
- if (lockdb == NULL) {
- if (locks_hooks != NULL) {
- if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
- /* ### maybe insert higher-level comment */
- return err;
- }
- lock_db_opened_locally = 1;
- }
- }
-
- /* (1) Validate the specified resource, at the specified depth */
- if (resource->exists && depth > 0) {
- dav_walker_ctx ctx = { { 0 } };
- dav_response *multi_status;
-
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
- ctx.w.func = dav_validate_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = resource;
-
- ctx.if_header = if_header;
- ctx.r = r;
- ctx.flags = flags;
-
- if (lockdb != NULL) {
- ctx.w.lockdb = lockdb;
- ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL;
- }
-
- err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
- if (err == NULL) {
- *response = multi_status;;
- }
- /* else: implies a 5xx status code occurred. */
- }
- else {
- err = dav_validate_resource_state(r->pool, resource, lockdb,
- if_header, flags, &work_buf, r);
- }
-
- /* (2) Validate the parent resource if requested */
- if (err == NULL && (flags & DAV_VALIDATE_PARENT)) {
- dav_resource *parent_resource;
-
- err = (*repos_hooks->get_parent_resource)(resource, &parent_resource);
-
- if (err == NULL && parent_resource == NULL) {
- err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0,
- "Cannot access parent of repository root.");
- }
- else if (err == NULL) {
- err = dav_validate_resource_state(r->pool, parent_resource, lockdb,
- if_header,
- flags | DAV_VALIDATE_IS_PARENT,
- &work_buf, r);
-
- /*
- ** This error occurred on the parent resource. This implies that
- ** we have to create a multistatus response (to report the error
- ** against a URI other than the Request-URI). "Convert" this error
- ** into a multistatus response.
- */
- if (err != NULL) {
- new_response = apr_pcalloc(r->pool, sizeof(*new_response));
-
- new_response->href = parent_resource->uri;
- new_response->status = err->status;
- new_response->desc =
- "A validation error has occurred on the parent resource, "
- "preventing the operation on the resource specified by "
- "the Request-URI.";
- if (err->desc != NULL) {
- new_response->desc = apr_pstrcat(r->pool,
- new_response->desc,
- " The error was: ",
- err->desc, NULL);
- }
-
- /* assert: DAV_VALIDATE_PARENT implies response != NULL */
- new_response->next = *response;
- *response = new_response;
-
- err = NULL;
- }
- }
- }
-
- if (lock_db_opened_locally)
- (*locks_hooks->close_lockdb)(lockdb);
-
- /*
- ** If we don't have a (serious) error, and we have multistatus responses,
- ** then we need to construct an "error". This error will be the overall
- ** status returned, and the multistatus responses will go into its body.
- **
- ** For certain methods, the overall error will be a 424. The default is
- ** to construct a standard 207 response.
- */
- if (err == NULL && response != NULL && *response != NULL) {
- apr_text *propstat = NULL;
-
- if ((flags & DAV_VALIDATE_USE_424) != 0) {
- /* manufacture a 424 error to hold the multistatus response(s) */
- return dav_new_error(r->pool, HTTP_FAILED_DEPENDENCY, 0,
- "An error occurred on another resource, "
- "preventing the requested operation on "
- "this resource.");
- }
-
- /*
- ** Whatever caused the error, the Request-URI should have a 424
- ** associated with it since we cannot complete the method.
- **
- ** For a LOCK operation, insert an empty DAV:lockdiscovery property.
- ** For other methods, return a simple 424.
- */
- if ((flags & DAV_VALIDATE_ADD_LD) != 0) {
- propstat = apr_pcalloc(r->pool, sizeof(*propstat));
- propstat->text =
- "<D:propstat>" DEBUG_CR
- "<D:prop><D:lockdiscovery/></D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 424 Failed Dependency</D:status>" DEBUG_CR
- "</D:propstat>" DEBUG_CR;
- }
-
- /* create the 424 response */
- new_response = apr_pcalloc(r->pool, sizeof(*new_response));
- new_response->href = resource->uri;
- new_response->status = HTTP_FAILED_DEPENDENCY;
- new_response->propresult.propstats = propstat;
- new_response->desc =
- "An error occurred on another resource, preventing the "
- "requested operation on this resource.";
-
- new_response->next = *response;
- *response = new_response;
-
- /* manufacture a 207 error for the multistatus response(s) */
- return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
- "Error(s) occurred on resources during the "
- "validation process.");
- }
-
- return err;
-}
-
-/* dav_get_locktoken_list:
- *
- * Sets ltl to a locktoken_list of all positive locktokens in header,
- * else NULL if no If-header, or no positive locktokens.
- */
-DAV_DECLARE(dav_error *) dav_get_locktoken_list(request_rec *r,
- dav_locktoken_list **ltl)
-{
- dav_error *err;
- dav_if_header *if_header;
- dav_if_state_list *if_state;
- dav_locktoken_list *lock_token = NULL;
-
- *ltl = NULL;
-
- if ((err = dav_process_if_header(r, &if_header)) != NULL) {
- /* ### add a higher-level description? */
- return err;
- }
-
- while (if_header != NULL) {
- if_state = if_header->state; /* Begining of the if_state linked list */
- while (if_state != NULL) {
- if (if_state->condition == DAV_IF_COND_NORMAL
- && if_state->type == dav_if_opaquelock) {
- lock_token = apr_pcalloc(r->pool, sizeof(dav_locktoken_list));
- lock_token->locktoken = if_state->locktoken;
- lock_token->next = *ltl;
- *ltl = lock_token;
- }
- if_state = if_state->next;
- }
- if_header = if_header->next;
- }
- if (*ltl == NULL) {
- /* No nodes added */
- return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_ABSENT,
- "No locktokens were specified in the \"If:\" "
- "header, so the refresh could not be performed.");
- }
-
- return NULL;
-}
-
-#if 0 /* not needed right now... */
-
-static const char *strip_white(const char *s, apr_pool_t *pool)
-{
- apr_size_t idx;
-
- /* trim leading whitespace */
- while (apr_isspace(*s)) /* assume: return false for '\0' */
- ++s;
-
- /* trim trailing whitespace */
- idx = strlen(s) - 1;
- if (apr_isspace(s[idx])) {
- char *s2 = apr_pstrdup(pool, s);
-
- while (apr_isspace(s2[idx]) && idx > 0)
- --idx;
- s2[idx + 1] = '\0';
- return s2;
- }
-
- return s;
-}
-#endif
-
-#define DAV_LABEL_HDR "Label"
-
-/* dav_add_vary_header
- *
- * If there were any headers in the request which require a Vary header
- * in the response, add it.
- */
-DAV_DECLARE(void) dav_add_vary_header(request_rec *in_req,
- request_rec *out_req,
- const dav_resource *resource)
-{
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req);
-
- /* ### this is probably all wrong... I think there is a function in
- ### the Apache API to add things to the Vary header. need to check */
-
- /* Only versioning headers require a Vary response header,
- * so only do this check if there is a versioning provider */
- if (vsn_hooks != NULL) {
- const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR);
- const char *vary = apr_table_get(out_req->headers_out, "Vary");
-
- /* If Target-Selector specified, add it to the Vary header */
- if (target != NULL) {
- if (vary == NULL)
- vary = DAV_LABEL_HDR;
- else
- vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR,
- NULL);
-
- apr_table_setn(out_req->headers_out, "Vary", vary);
- }
- }
-}
-
-/* dav_can_auto_checkout
- *
- * Determine whether auto-checkout is enabled for a resource.
- * r - the request_rec
- * resource - the resource
- * auto_version - the value of the auto_versionable hook for the resource
- * lockdb - pointer to lock database (opened if necessary)
- * auto_checkout - set to 1 if auto-checkout enabled
- */
-static dav_error * dav_can_auto_checkout(
- request_rec *r,
- dav_resource *resource,
- dav_auto_version auto_version,
- dav_lockdb **lockdb,
- int *auto_checkout)
-{
- dav_error *err;
- dav_lock *lock_list;
-
- *auto_checkout = 0;
-
- if (auto_version == DAV_AUTO_VERSION_ALWAYS) {
- *auto_checkout = 1;
- }
- else if (auto_version == DAV_AUTO_VERSION_LOCKED) {
- if (*lockdb == NULL) {
- const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
-
- if (locks_hooks == NULL) {
- return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Auto-checkout is only enabled for locked resources, "
- "but there is no lock provider.");
- }
-
- if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, lockdb)) != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Cannot open lock database to determine "
- "auto-versioning behavior.",
- err);
- }
- }
-
- if ((err = dav_lock_query(*lockdb, resource, &lock_list)) != NULL) {
- return dav_push_error(r->pool,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "The locks could not be queried for "
- "determining auto-versioning behavior.",
- err);
- }
-
- if (lock_list != NULL)
- *auto_checkout = 1;
- }
-
- return NULL;
-}
-
-/* see mod_dav.h for docco */
-DAV_DECLARE(dav_error *) dav_auto_checkout(
- request_rec *r,
- dav_resource *resource,
- int parent_only,
- dav_auto_version_info *av_info)
-{
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_lockdb *lockdb = NULL;
- dav_error *err = NULL;
-
- /* Initialize results */
- memset(av_info, 0, sizeof(*av_info));
-
- /* if no versioning provider, just return */
- if (vsn_hooks == NULL)
- return NULL;
-
- /* check parent resource if requested or if resource must be created */
- if (!resource->exists || parent_only) {
- dav_resource *parent;
-
- if ((err = (*resource->hooks->get_parent_resource)(resource,
- &parent)) != NULL)
- goto done;
-
- if (parent == NULL || !parent->exists) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Missing one or more intermediate "
- "collections. Cannot create resource %s.",
- ap_escape_html(r->pool, resource->uri)));
- goto done;
- }
-
- av_info->parent_resource = parent;
-
- /* if parent versioned and not checked out, see if it can be */
- if (parent->versioned && !parent->working) {
- int checkout_parent;
-
- if ((err = dav_can_auto_checkout(r, parent,
- (*vsn_hooks->auto_versionable)(parent),
- &lockdb, &checkout_parent))
- != NULL) {
- goto done;
- }
-
- if (!checkout_parent) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:cannot-modify-checked-in-parent>");
- goto done;
- }
-
- /* Try to checkout the parent collection.
- * Note that auto-versioning can only be applied to a version selector,
- * so no separate working resource will be created.
- */
- if ((err = (*vsn_hooks->checkout)(parent, 1 /*auto_checkout*/,
- 0, 0, 0, NULL, NULL))
- != NULL)
- {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Unable to auto-checkout parent collection. "
- "Cannot create resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- goto done;
- }
-
- /* remember that parent was checked out */
- av_info->parent_checkedout = 1;
- }
- }
-
- /* if only checking parent, we're done */
- if (parent_only)
- goto done;
-
- /* if creating a new resource, see if it should be version-controlled */
- if (!resource->exists
- && (*vsn_hooks->auto_versionable)(resource) == DAV_AUTO_VERSION_ALWAYS) {
-
- if ((err = (*vsn_hooks->vsn_control)(resource, NULL)) != NULL) {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Unable to create versioned resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- goto done;
- }
-
- /* remember that resource was created */
- av_info->resource_versioned = 1;
- }
-
- /* if resource is versioned, make sure it is checked out */
- if (resource->versioned && !resource->working) {
- int checkout_resource;
-
- if ((err = dav_can_auto_checkout(r, resource,
- (*vsn_hooks->auto_versionable)(resource),
- &lockdb, &checkout_resource)) != NULL) {
- goto done;
- }
-
- if (!checkout_resource) {
- err = dav_new_error(r->pool, HTTP_CONFLICT, 0,
- "<DAV:cannot-modify-version-controlled-content>");
- goto done;
- }
-
- /* Auto-versioning can only be applied to version selectors, so
- * no separate working resource will be created. */
- if ((err = (*vsn_hooks->checkout)(resource, 1 /*auto_checkout*/,
- 0, 0, 0, NULL, NULL))
- != NULL)
- {
- err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
- apr_psprintf(r->pool,
- "Unable to checkout resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- goto done;
- }
-
- /* remember that resource was checked out */
- av_info->resource_checkedout = 1;
- }
-
-done:
-
- /* make sure lock database is closed */
- if (lockdb != NULL)
- (*lockdb->hooks->close_lockdb)(lockdb);
-
- /* if an error occurred, undo any auto-versioning operations already done */
- if (err != NULL) {
- dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, av_info);
- return err;
- }
-
- return NULL;
-}
-
-/* see mod_dav.h for docco */
-DAV_DECLARE(dav_error *) dav_auto_checkin(
- request_rec *r,
- dav_resource *resource,
- int undo,
- int unlock,
- dav_auto_version_info *av_info)
-{
- const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
- dav_error *err = NULL;
- dav_auto_version auto_version;
-
- /* If no versioning provider, this is a no-op */
- if (vsn_hooks == NULL)
- return NULL;
-
- /* If undoing auto-checkouts, then do uncheckouts */
- if (undo) {
- if (resource != NULL) {
- if (av_info->resource_checkedout) {
- if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_psprintf(r->pool,
- "Unable to undo auto-checkout "
- "of resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- }
- }
-
- if (av_info->resource_versioned) {
- dav_response *response;
-
- /* ### should we do anything with the response? */
- if ((err = (*resource->hooks->remove_resource)(resource,
- &response)) != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_psprintf(r->pool,
- "Unable to undo auto-version-control "
- "of resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- }
- }
- }
-
- if (av_info->parent_resource != NULL && av_info->parent_checkedout) {
- if ((err = (*vsn_hooks->uncheckout)(av_info->parent_resource)) != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_psprintf(r->pool,
- "Unable to undo auto-checkout "
- "of parent collection %s.",
- ap_escape_html(r->pool, av_info->parent_resource->uri)),
- err);
- }
- }
-
- return NULL;
- }
-
- /* If the resource was checked out, and auto-checkin is enabled,
- * then check it in.
- */
- if (resource != NULL && resource->working
- && (unlock || av_info->resource_checkedout)) {
-
- auto_version = (*vsn_hooks->auto_versionable)(resource);
-
- if (auto_version == DAV_AUTO_VERSION_ALWAYS ||
- (unlock && (auto_version == DAV_AUTO_VERSION_LOCKED))) {
-
- if ((err = (*vsn_hooks->checkin)(resource,
- 0 /*keep_checked_out*/, NULL))
- != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_psprintf(r->pool,
- "Unable to auto-checkin resource %s.",
- ap_escape_html(r->pool, resource->uri)),
- err);
- }
- }
- }
-
- /* If parent resource was checked out, and auto-checkin is enabled,
- * then check it in.
- */
- if (!unlock
- && av_info->parent_checkedout
- && av_info->parent_resource != NULL
- && av_info->parent_resource->working) {
-
- auto_version = (*vsn_hooks->auto_versionable)(av_info->parent_resource);
-
- if (auto_version == DAV_AUTO_VERSION_ALWAYS) {
- if ((err = (*vsn_hooks->checkin)(av_info->parent_resource,
- 0 /*keep_checked_out*/, NULL))
- != NULL) {
- return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- apr_psprintf(r->pool,
- "Unable to auto-checkin parent collection %s.",
- ap_escape_html(r->pool, av_info->parent_resource->uri)),
- err);
- }
- }
- }
-
- return NULL;
-}
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/util_lock.c b/rubbos/app/httpd-2.0.64/modules/dav/main/util_lock.c
deleted file mode 100644
index cd39f067..00000000
--- a/rubbos/app/httpd-2.0.64/modules/dav/main/util_lock.c
+++ /dev/null
@@ -1,791 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-** DAV repository-independent lock functions
-*/
-
-#include "apr.h"
-#include "apr_strings.h"
-
-#if APR_HAVE_STDIO_H
-#include <stdio.h> /* for sprintf() */
-#endif
-
-#include "mod_dav.h"
-#include "http_log.h"
-#include "http_config.h"
-#include "http_protocol.h"
-#include "http_core.h"
-
-
-/* ---------------------------------------------------------------
-**
-** Property-related lock functions
-**
-*/
-
-/*
-** dav_lock_get_activelock: Returns a <lockdiscovery> containing
-** an activelock element for every item in the lock_discovery tree
-*/
-DAV_DECLARE(const char *) dav_lock_get_activelock(request_rec *r,
- dav_lock *lock,
- dav_buffer *pbuf)
-{
- dav_lock *lock_scan;
- const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
- int count = 0;
- dav_buffer work_buf = { 0 };
- apr_pool_t *p = r->pool;
-
- /* If no locks or no lock provider, there are no locks */
- if (lock == NULL || hooks == NULL) {
- /*
- ** Since resourcediscovery is defined with (activelock)*,
- ** <D:activelock/> shouldn't be necessary for an empty lock.
- */
- return "";
- }
-
- /*
- ** Note: it could be interesting to sum the lengths of the owners
- ** and locktokens during this loop. However, the buffer
- ** mechanism provides some rough padding so that we don't
- ** really need to have an exact size. Further, constructing
- ** locktoken strings could be relatively expensive.
- */
- for (lock_scan = lock; lock_scan != NULL; lock_scan = lock_scan->next)
- count++;
-
- /* if a buffer was not provided, then use an internal buffer */
- if (pbuf == NULL)
- pbuf = &work_buf;
-
- /* reset the length before we start appending stuff */
- pbuf->cur_len = 0;
-
- /* prep the buffer with a "good" size */
- dav_check_bufsize(p, pbuf, count * 300);
-
- for (; lock != NULL; lock = lock->next) {
- char tmp[100];
-
-#if DAV_DEBUG
- if (lock->rectype == DAV_LOCKREC_INDIRECT_PARTIAL) {
- /* ### crap. design error */
- dav_buffer_append(p, pbuf,
- "DESIGN ERROR: attempted to product an "
- "activelock element from a partial, indirect "
- "lock record. Creating an XML parsing error "
- "to ease detection of this situation: <");
- }
-#endif
-
- dav_buffer_append(p, pbuf, "<D:activelock>" DEBUG_CR "<D:locktype>");
- switch (lock->type) {
- case DAV_LOCKTYPE_WRITE:
- dav_buffer_append(p, pbuf, "<D:write/>");
- break;
- default:
- /* ### internal error. log something? */
- break;
- }
- dav_buffer_append(p, pbuf, "</D:locktype>" DEBUG_CR "<D:lockscope>");
- switch (lock->scope) {
- case DAV_LOCKSCOPE_EXCLUSIVE:
- dav_buffer_append(p, pbuf, "<D:exclusive/>");
- break;
- case DAV_LOCKSCOPE_SHARED:
- dav_buffer_append(p, pbuf, "<D:shared/>");
- break;
- default:
- /* ### internal error. log something? */
- break;
- }
- dav_buffer_append(p, pbuf, "</D:lockscope>" DEBUG_CR);
- sprintf(tmp, "<D:depth>%s</D:depth>" DEBUG_CR,
- lock->depth == DAV_INFINITY ? "infinity" : "0");
- dav_buffer_append(p, pbuf, tmp);
-
- if (lock->owner) {
- /*
- ** This contains a complete, self-contained <DAV:owner> element,
- ** with namespace declarations and xml:lang handling. Just drop
- ** it in.
- */
- dav_buffer_append(p, pbuf, lock->owner);
- }
-
- dav_buffer_append(p, pbuf, "<D:timeout>");
- if (lock->timeout == DAV_TIMEOUT_INFINITE) {
- dav_buffer_append(p, pbuf, "Infinite");
- }
- else {
- time_t now = time(NULL);
- sprintf(tmp, "Second-%lu", (long unsigned int)(lock->timeout - now));
- dav_buffer_append(p, pbuf, tmp);
- }
-
- dav_buffer_append(p, pbuf,
- "</D:timeout>" DEBUG_CR
- "<D:locktoken>" DEBUG_CR
- "<D:href>");
- dav_buffer_append(p, pbuf,
- (*hooks->format_locktoken)(p, lock->locktoken));
- dav_buffer_append(p, pbuf,
- "</D:href>" DEBUG_CR
- "</D:locktoken>" DEBUG_CR
- "</D:activelock>" DEBUG_CR);
- }
-
- return pbuf->buf;
-}
-
-/*
-** dav_lock_parse_lockinfo: Validates the given xml_doc to contain a
-** lockinfo XML element, then populates a dav_lock structure
-** with its contents.
-*/
-DAV_DECLARE(dav_error *) dav_lock_parse_lockinfo(request_rec *r,
- const dav_resource *resource,
- dav_lockdb *lockdb,
- const apr_xml_doc *doc,
- dav_lock **lock_request)
-{
- apr_pool_t *p = r->pool;
- dav_error *err;
- apr_xml_elem *child;
- dav_lock *lock;
-
- if (!dav_validate_root(doc, "lockinfo")) {
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "The request body contains an unexpected "
- "XML root element.");
- }
-
- if ((err = (*lockdb->hooks->create_lock)(lockdb, resource,
- &lock)) != NULL) {
- return dav_push_error(p, err->status, 0,
- "Could not parse the lockinfo due to an "
- "internal problem creating a lock structure.",
- err);
- }
-
- lock->depth = dav_get_depth(r, DAV_INFINITY);
- if (lock->depth == -1) {
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "An invalid Depth header was specified.");
- }
- lock->timeout = dav_get_timeout(r);
-
- /* Parse elements in the XML body */
- for (child = doc->root->first_child; child; child = child->next) {
- if (strcmp(child->name, "locktype") == 0
- && child->first_child
- && lock->type == DAV_LOCKTYPE_UNKNOWN) {
- if (strcmp(child->first_child->name, "write") == 0) {
- lock->type = DAV_LOCKTYPE_WRITE;
- continue;
- }
- }
- if (strcmp(child->name, "lockscope") == 0
- && child->first_child
- && lock->scope == DAV_LOCKSCOPE_UNKNOWN) {
- if (strcmp(child->first_child->name, "exclusive") == 0)
- lock->scope = DAV_LOCKSCOPE_EXCLUSIVE;
- else if (strcmp(child->first_child->name, "shared") == 0)
- lock->scope = DAV_LOCKSCOPE_SHARED;
- if (lock->scope != DAV_LOCKSCOPE_UNKNOWN)
- continue;
- }
-
- if (strcmp(child->name, "owner") == 0 && lock->owner == NULL) {
- const char *text;
-
- /* quote all the values in the <DAV:owner> element */
- apr_xml_quote_elem(p, child);
-
- /*
- ** Store a full <DAV:owner> element with namespace definitions
- ** and an xml:lang definition, if applicable.
- */
- apr_xml_to_text(p, child, APR_XML_X2T_FULL_NS_LANG, doc->namespaces,
- NULL, &text, NULL);
- lock->owner = text;
-
- continue;
- }
-
- return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
- apr_psprintf(p,
- "The server cannot satisfy the "
- "LOCK request due to an unknown XML "
- "element (\"%s\") within the "
- "DAV:lockinfo element.",
- child->name));
- }
-
- *lock_request = lock;
- return NULL;
-}
-
-/* ---------------------------------------------------------------
-**
-** General lock functions
-**
-*/
-
-/* dav_lock_walker: Walker callback function to record indirect locks */
-static dav_error * dav_lock_walker(dav_walk_resource *wres, int calltype)
-{
- dav_walker_ctx *ctx = wres->walk_ctx;
- dav_error *err;
-
- /* We don't want to set indirects on the target */
- if ((*wres->resource->hooks->is_same_resource)(wres->resource,
- ctx->w.root))
- return NULL;
-
- if ((err = (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb,
- wres->resource, 1,
- ctx->lock)) != NULL) {
- if (ap_is_HTTP_SERVER_ERROR(err->status)) {
- /* ### add a higher-level description? */
- return err;
- }
-
- /* add to the multistatus response */
- dav_add_response(wres, err->status, NULL);
-
- /*
- ** ### actually, this is probably wrong: we want to fail the whole
- ** ### LOCK process if something goes bad. maybe the caller should
- ** ### do a dav_unlock() (e.g. a rollback) if any errors occurred.
- */
- }
-
- return NULL;
-}
-
-/*
-** dav_add_lock: Add a direct lock for resource, and indirect locks for
-** all children, bounded by depth.
-** ### assume request only contains one lock
-*/
-DAV_DECLARE(dav_error *) dav_add_lock(request_rec *r,
- const dav_resource *resource,
- dav_lockdb *lockdb, dav_lock *lock,
- dav_response **response)
-{
- dav_error *err;
- int depth = lock->depth;
-
- *response = NULL;
-
- /* Requested lock can be:
- * Depth: 0 for null resource, existing resource, or existing collection
- * Depth: Inf for existing collection
- */
-
- /*
- ** 2518 9.2 says to ignore depth if target is not a collection (it has
- ** no internal children); pretend the client gave the correct depth.
- */
- if (!resource->collection) {
- depth = 0;
- }
-
- /* In all cases, first add direct entry in lockdb */
-
- /*
- ** Append the new (direct) lock to the resource's existing locks.
- **
- ** Note: this also handles locknull resources
- */
- if ((err = (*lockdb->hooks->append_locks)(lockdb, resource, 0,
- lock)) != NULL) {
- /* ### maybe add a higher-level description */
- return err;
- }
-
- if (depth > 0) {
- /* Walk existing collection and set indirect locks */
- dav_walker_ctx ctx = { { 0 } };
- dav_response *multi_status;
-
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH;
- ctx.w.func = dav_lock_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = resource;
- ctx.w.lockdb = lockdb;
-
- ctx.r = r;
- ctx.lock = lock;
-
- err = (*resource->hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
- if (err != NULL) {
- /* implies a 5xx status code occurred. screw the multistatus */
- return err;
- }
-
- if (multi_status != NULL) {
- /* manufacture a 207 error for the multistatus response */
- *response = multi_status;
- return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
- "Error(s) occurred on resources during the "
- "addition of a depth lock.");
- }
- }
-
- return NULL;
-}
-
-/*
-** dav_lock_query: Opens the lock database. Returns a linked list of
-** dav_lock structures for all direct locks on path.
-*/
-DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb,
- const dav_resource *resource,
- dav_lock **locks)
-{
- /* If no lock database, return empty result */
- if (lockdb == NULL) {
- *locks = NULL;
- return NULL;
- }
-
- /* ### insert a higher-level description? */
- return (*lockdb->hooks->get_locks)(lockdb, resource,
- DAV_GETLOCKS_RESOLVED,
- locks);
-}
-
-/* dav_unlock_walker: Walker callback function to remove indirect locks */
-static dav_error * dav_unlock_walker(dav_walk_resource *wres, int calltype)
-{
- dav_walker_ctx *ctx = wres->walk_ctx;
- dav_error *err;
-
- /* Before removing the lock, do any auto-checkin required */
- if (wres->resource->working) {
- /* ### get rid of this typecast */
- if ((err = dav_auto_checkin(ctx->r, (dav_resource *) wres->resource,
- 0 /*undo*/, 1 /*unlock*/, NULL))
- != NULL) {
- return err;
- }
- }
-
- if ((err = (*ctx->w.lockdb->hooks->remove_lock)(ctx->w.lockdb,
- wres->resource,
- ctx->locktoken)) != NULL) {
- /* ### should we stop or return a multistatus? looks like STOP */
- /* ### add a higher-level description? */
- return err;
- }
-
- return NULL;
-}
-
-/*
-** dav_get_direct_resource:
-**
-** Find a lock on the specified resource, then return the resource the
-** lock was applied to (in other words, given a (possibly) indirect lock,
-** return the direct lock's corresponding resource).
-**
-** If the lock is an indirect lock, this usually means traversing up the
-** namespace [repository] hierarchy. Note that some lock providers may be
-** able to return this information with a traversal.
-*/
-static dav_error * dav_get_direct_resource(apr_pool_t *p,
- dav_lockdb *lockdb,
- const dav_locktoken *locktoken,
- const dav_resource *resource,
- const dav_resource **direct_resource)
-{
- if (lockdb->hooks->lookup_resource != NULL) {
- return (*lockdb->hooks->lookup_resource)(lockdb, locktoken,
- resource, direct_resource);
- }
-
- *direct_resource = NULL;
-
- /* Find the top of this lock-
- * If r->filename's direct locks include locktoken, use r->filename.
- * If r->filename's indirect locks include locktoken, retry r->filename/..
- * Else fail.
- */
- while (resource != NULL) {
- dav_error *err;
- dav_lock *lock;
- dav_resource *parent;
-
- /*
- ** Find the lock specified by <locktoken> on <resource>. If it is
- ** an indirect lock, then partial results are okay. We're just
- ** trying to find the thing and know whether it is a direct or
- ** an indirect lock.
- */
- if ((err = (*lockdb->hooks->find_lock)(lockdb, resource, locktoken,
- 1, &lock)) != NULL) {
- /* ### add a higher-level desc? */
- return err;
- }
-
- /* not found! that's an error. */
- if (lock == NULL) {
- return dav_new_error(p, HTTP_BAD_REQUEST, 0,
- "The specified locktoken does not correspond "
- "to an existing lock on this resource.");
- }
-
- if (lock->rectype == DAV_LOCKREC_DIRECT) {
- /* we found the direct lock. return this resource. */
-
- *direct_resource = resource;
- return NULL;
- }
-
- /* the lock was indirect. move up a level in the URL namespace */
- if ((err = (*resource->hooks->get_parent_resource)(resource,
- &parent)) != NULL) {
- /* ### add a higher-level desc? */
- return err;
- }
- resource = parent;
- }
-
- return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
- "The lock database is corrupt. A direct lock could "
- "not be found for the corresponding indirect lock "
- "on this resource.");
-}
-
-/*
-** dav_unlock: Removes all direct and indirect locks for r->filename,
-** with given locktoken. If locktoken == null_locktoken, all locks
-** are removed. If r->filename represents an indirect lock,
-** we must unlock the appropriate direct lock.
-** Returns OK or appropriate HTTP_* response and logs any errors.
-**
-** ### We've already crawled the tree to ensure everything was locked
-** by us; there should be no need to incorporate a rollback.
-*/
-DAV_DECLARE(int) dav_unlock(request_rec *r, const dav_resource *resource,
- const dav_locktoken *locktoken)
-{
- int result;
- dav_lockdb *lockdb;
- const dav_resource *lock_resource = resource;
- const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
- const dav_hooks_repository *repos_hooks = resource->hooks;
- dav_walker_ctx ctx = { { 0 } };
- dav_response *multi_status;
- dav_error *err;
-
- /* If no locks provider, then there is nothing to unlock. */
- if (hooks == NULL) {
- return OK;
- }
-
- /* 2518 requires the entire lock to be removed if resource/locktoken
- * point to an indirect lock. We need resource of the _direct_
- * lock in order to walk down the tree and remove the locks. So,
- * If locktoken != null_locktoken,
- * Walk up the resource hierarchy until we see a direct lock.
- * Or, we could get the direct lock's db/key, pick out the URL
- * and do a subrequest. I think walking up is faster and will work
- * all the time.
- * Else
- * Just start removing all locks at and below resource.
- */
-
- if ((err = (*hooks->open_lockdb)(r, 0, 1, &lockdb)) != NULL) {
- /* ### return err! maybe add a higher-level desc */
- /* ### map result to something nice; log an error */
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
- if (locktoken != NULL
- && (err = dav_get_direct_resource(r->pool, lockdb,
- locktoken, resource,
- &lock_resource)) != NULL) {
- /* ### add a higher-level desc? */
- /* ### should return err! */
- return err->status;
- }
-
- /* At this point, lock_resource/locktoken refers to a direct lock (key), ie
- * the root of a depth > 0 lock, or locktoken is null.
- */
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL;
- ctx.w.func = dav_unlock_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = lock_resource;
- ctx.w.lockdb = lockdb;
-
- ctx.r = r;
- ctx.locktoken = locktoken;
-
- err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
-
- /* ### fix this! */
- /* ### do something with multi_status */
- result = err == NULL ? OK : err->status;
-
- (*hooks->close_lockdb)(lockdb);
-
- return result;
-}
-
-/* dav_inherit_walker: Walker callback function to inherit locks */
-static dav_error * dav_inherit_walker(dav_walk_resource *wres, int calltype)
-{
- dav_walker_ctx *ctx = wres->walk_ctx;
-
- if (ctx->skip_root
- && (*wres->resource->hooks->is_same_resource)(wres->resource,
- ctx->w.root)) {
- return NULL;
- }
-
- /* ### maybe add a higher-level desc */
- return (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb,
- wres->resource, 1,
- ctx->lock);
-}
-
-/*
-** dav_inherit_locks: When a resource or collection is added to a collection,
-** locks on the collection should be inherited to the resource/collection.
-** (MOVE, MKCOL, etc) Here we propagate any direct or indirect locks from
-** parent of resource to resource and below.
-*/
-static dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb,
- const dav_resource *resource,
- int use_parent)
-{
- dav_error *err;
- const dav_resource *which_resource;
- dav_lock *locks;
- dav_lock *scan;
- dav_lock *prev;
- dav_walker_ctx ctx = { { 0 } };
- const dav_hooks_repository *repos_hooks = resource->hooks;
- dav_response *multi_status;
-
- if (use_parent) {
- dav_resource *parent;
- if ((err = (*repos_hooks->get_parent_resource)(resource,
- &parent)) != NULL) {
- /* ### add a higher-level desc? */
- return err;
- }
- if (parent == NULL) {
- /* ### map result to something nice; log an error */
- return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not fetch parent resource. Unable to "
- "inherit locks from the parent and apply "
- "them to this resource.");
- }
- which_resource = parent;
- }
- else {
- which_resource = resource;
- }
-
- if ((err = (*lockdb->hooks->get_locks)(lockdb, which_resource,
- DAV_GETLOCKS_PARTIAL,
- &locks)) != NULL) {
- /* ### maybe add a higher-level desc */
- return err;
- }
-
- if (locks == NULL) {
- /* No locks to propagate, just return */
- return NULL;
- }
-
- /*
- ** (1) Copy all indirect locks from our parent;
- ** (2) Create indirect locks for the depth infinity, direct locks
- ** in our parent.
- **
- ** The append_locks call in the walker callback will do the indirect
- ** conversion, but we need to remove any direct locks that are NOT
- ** depth "infinity".
- */
- for (scan = locks, prev = NULL;
- scan != NULL;
- prev = scan, scan = scan->next) {
-
- if (scan->rectype == DAV_LOCKREC_DIRECT
- && scan->depth != DAV_INFINITY) {
-
- if (prev == NULL)
- locks = scan->next;
- else
- prev->next = scan->next;
- }
- }
-
- /* <locks> has all our new locks. Walk down and propagate them. */
-
- ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL;
- ctx.w.func = dav_inherit_walker;
- ctx.w.walk_ctx = &ctx;
- ctx.w.pool = r->pool;
- ctx.w.root = resource;
- ctx.w.lockdb = lockdb;
-
- ctx.r = r;
- ctx.lock = locks;
- ctx.skip_root = !use_parent;
-
- /* ### do something with multi_status */
- return (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
-}
-
-/* ---------------------------------------------------------------
-**
-** Functions dealing with lock-null resources
-**
-*/
-
-/*
-** dav_get_resource_state: Returns the state of the resource
-** r->filename: DAV_RESOURCE_NULL, DAV_RESOURCE_LOCK_NULL,
-** or DAV_RESOURCE_EXIST.
-**
-** Returns DAV_RESOURCE_ERROR if an error occurs.
-*/
-DAV_DECLARE(int) dav_get_resource_state(request_rec *r,
- const dav_resource *resource)
-{
- const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
-
- if (resource->exists)
- return DAV_RESOURCE_EXISTS;
-
- if (hooks != NULL) {
- dav_error *err;
- dav_lockdb *lockdb;
- int locks_present;
-
- /*
- ** A locknull resource has the form:
- **
- ** known-dir "/" locknull-file
- **
- ** It would be nice to look into <resource> to verify this form,
- ** but it does not have enough information for us. Instead, we
- ** can look at the path_info. If the form does not match, then
- ** there is no way we could have a locknull resource -- it must
- ** be a plain, null resource.
- **
- ** Apache sets r->filename to known-dir/unknown-file and r->path_info
- ** to "" for the "proper" case. If anything is in path_info, then
- ** it can't be a locknull resource.
- **
- ** ### I bet this path_info hack doesn't work for repositories.
- ** ### Need input from repository implementors! What kind of
- ** ### restructure do we need? New provider APIs?
- */
- if (r->path_info != NULL && *r->path_info != '\0') {
- return DAV_RESOURCE_NULL;
- }
-
- if ((err = (*hooks->open_lockdb)(r, 1, 1, &lockdb)) == NULL) {
- /* note that we might see some expired locks... *shrug* */
- err = (*hooks->has_locks)(lockdb, resource, &locks_present);
- (*hooks->close_lockdb)(lockdb);
- }
-
- if (err != NULL) {
- /* ### don't log an error. return err. add higher-level desc. */
-
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Failed to query lock-null status for %s",
- r->filename);
-
- return DAV_RESOURCE_ERROR;
- }
-
- if (locks_present)
- return DAV_RESOURCE_LOCK_NULL;
- }
-
- return DAV_RESOURCE_NULL;
-}
-
-DAV_DECLARE(dav_error *) dav_notify_created(request_rec *r,
- dav_lockdb *lockdb,
- const dav_resource *resource,
- int resource_state,
- int depth)
-{
- dav_error *err;
-
- if (resource_state == DAV_RESOURCE_LOCK_NULL) {
-
- /*
- ** The resource is no longer a locknull resource. This will remove
- ** the special marker.
- **
- ** Note that a locknull resource has already inherited all of the
- ** locks from the parent. We do not need to call dav_inherit_locks.
- **
- ** NOTE: some lock providers record locks for locknull resources using
- ** a different key than for regular resources. this will shift
- ** the lock information between the two key types.
- */
- (void)(*lockdb->hooks->remove_locknull_state)(lockdb, resource);
-
- /*
- ** There are resources under this one, which are new. We must
- ** propagate the locks down to the new resources.
- */
- if (depth > 0 &&
- (err = dav_inherit_locks(r, lockdb, resource, 0)) != NULL) {
- /* ### add a higher level desc? */
- return err;
- }
- }
- else if (resource_state == DAV_RESOURCE_NULL) {
-
- /* ### should pass depth to dav_inherit_locks so that it can
- ** ### optimize for the depth==0 case.
- */
-
- /* this resource should inherit locks from its parent */
- if ((err = dav_inherit_locks(r, lockdb, resource, 1)) != NULL) {
-
- err = dav_push_error(r->pool, err->status, 0,
- "The resource was created successfully, but "
- "there was a problem inheriting locks from "
- "the parent resource.",
- err);
- return err;
- }
- }
- /* else the resource already exists and its locks are correct. */
-
- return NULL;
-}