mod_dav.c revision 5a47cad1aef57039cd47eb34ebbc2959c610f326
97a9a944b5887e91042b019776c41d5dd74557aferikabele/* ====================================================================
97a9a944b5887e91042b019776c41d5dd74557aferikabele * The Apache Software License, Version 1.1
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * Copyright (c) 2000 The Apache Software Foundation. All rights
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * reserved.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Redistribution and use in source and binary forms, with or without
5a58787efeb02a1c3f06569d019ad81fd2efa06end * modification, are permitted provided that the following conditions
5a58787efeb02a1c3f06569d019ad81fd2efa06end * are met:
5a58787efeb02a1c3f06569d019ad81fd2efa06end * 1. Redistributions of source code must retain the above copyright
5a58787efeb02a1c3f06569d019ad81fd2efa06end * notice, this list of conditions and the following disclaimer.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * 2. Redistributions in binary form must reproduce the above copyright
5a58787efeb02a1c3f06569d019ad81fd2efa06end * notice, this list of conditions and the following disclaimer in
52fff662005b1866a3ff09bb6c902800c5cc6dedjerenkrantz * the documentation and/or other materials provided with the
5a58787efeb02a1c3f06569d019ad81fd2efa06end * distribution.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * 3. The end-user documentation included with the redistribution,
4b5981e276e93df97c34e4da05ca5cf8bbd937dand * if any, must include the following acknowledgment:
5a58787efeb02a1c3f06569d019ad81fd2efa06end * "This product includes software developed by the
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd * Apache Software Foundation (http://www.apache.org/)."
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * Alternately, this acknowledgment may appear in the software itself,
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * if and wherever such third-party acknowledgments normally appear.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * 4. The names "Apache" and "Apache Software Foundation" must
e1e8390280254f7f0580d701e583f670643d4f3fnilgun * not be used to endorse or promote products derived from this
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * software without prior written permission. For written
5a58787efeb02a1c3f06569d019ad81fd2efa06end * permission, please contact apache@apache.org.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * 5. Products derived from this software may not be called "Apache",
5a58787efeb02a1c3f06569d019ad81fd2efa06end * nor may "Apache" appear in their name, without prior written
5a58787efeb02a1c3f06569d019ad81fd2efa06end * permission of the Apache Software Foundation.
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
97a9a944b5887e91042b019776c41d5dd74557aferikabele * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * SUCH DAMAGE.
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive * ====================================================================
5a58787efeb02a1c3f06569d019ad81fd2efa06end * This software consists of voluntary contributions made by many
5a58787efeb02a1c3f06569d019ad81fd2efa06end * individuals on behalf of the Apache Software Foundation. For more
117c1f888a14e73cdd821dc6c23eb0411144a41cnd * information on the Apache Software Foundation, please see
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** DAV extension module for Apache 2.0.*
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** This module is repository-independent. It depends on hooks provided by a
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** repository implementation.
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** APACHE ISSUES:
2bc7f1cf720973a67f8ff7a8d523e40569ae5b6cnd** - within a DAV hierarchy, if an unknown method is used and we default
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** to Apache's implementation, it sends back an OPTIONS with the wrong
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** set of methods -- there is NO HOOK for us.
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED
117c1f888a14e73cdd821dc6c23eb0411144a41cnd** and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).
4db28ee269aa06f7c6232e11cd01f58c3349af23noodl** - process_mkcol_body() had to dup code from ap_setup_client_block().
5a58787efeb02a1c3f06569d019ad81fd2efa06end** - it would be nice to get status lines from Apache for arbitrary
5a58787efeb02a1c3f06569d019ad81fd2efa06end** status codes
5a58787efeb02a1c3f06569d019ad81fd2efa06end** - it would be nice to be able to extend Apache's set of response
5a58787efeb02a1c3f06569d019ad81fd2efa06end** codes so that it doesn't return 500 when an unknown code is placed
5a58787efeb02a1c3f06569d019ad81fd2efa06end** into r->status.
5a58787efeb02a1c3f06569d019ad81fd2efa06end** - http_vhost functions should apply "const" to their params
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd** DESIGN NOTES:
5a58787efeb02a1c3f06569d019ad81fd2efa06end** - For PROPFIND, we batch up the entire response in memory before
5a58787efeb02a1c3f06569d019ad81fd2efa06end** sending it. We may want to reorganize around sending the information
5a58787efeb02a1c3f06569d019ad81fd2efa06end** as we suck it in from the propdb. Alternatively, we should at least
5a58787efeb02a1c3f06569d019ad81fd2efa06end** generate a total Content-Length if we're going to buffer in memory
06ba4a61654b3763ad65f52283832ebf058fdf1cslive** so that we can keep the connection open.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/* ### what is the best way to set this? */
9b6a3a558cc90ffdaa0b50bd02546ffec424ded7slive/* per-dir configuration */
06ba4a61654b3763ad65f52283832ebf058fdf1cslivetypedef struct {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const char *dir;
709e3a21ba73b8433462959cd56c773454b34441trawick int handle_get; /* cached from repository hook structure */
709e3a21ba73b8433462959cd56c773454b34441trawick apr_table_t *d_params; /* per-directory DAV config parameters */
5a58787efeb02a1c3f06569d019ad81fd2efa06end/* per-server configuration */
5a58787efeb02a1c3f06569d019ad81fd2efa06endtypedef struct {
5a58787efeb02a1c3f06569d019ad81fd2efa06end/* forward-declare for use in configuration lookup */
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic void dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* DBG0("dav_init_handler"); */
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2ndstatic void *dav_create_server_config(apr_pool_t *p, server_rec *s)
5a58787efeb02a1c3f06569d019ad81fd2efa06end newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf));
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides)
5a58787efeb02a1c3f06569d019ad81fd2efa06end newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf));
06ba4a61654b3763ad65f52283832ebf058fdf1cslive /* ### hmm. we should share the uuid state rather than copy it. if we
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ### do another merge, then we'll just get the old one, rather than
06ba4a61654b3763ad65f52283832ebf058fdf1cslive ### an updated state.
a63f0ab647ad2ab72efc9bea7a66e24e9ebc5cc2nd ### of course... the UUID generation should move into APR
06ba4a61654b3763ad65f52283832ebf058fdf1cslive memcpy(&newconf->st, &child->st, sizeof(newconf->st));
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic void *dav_create_dir_config(apr_pool_t *p, char *dir)
5a58787efeb02a1c3f06569d019ad81fd2efa06end /* NOTE: dir==NULL creates the default per-dir config */
b036ef2952fb6924b308f954b39786443460ddc6rpluemstatic void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides)
return newconf;
void *data;
r->pool);
return hooks;
void *data;
r->pool);
return hooks;
void *data;
r->pool);
return hooks;
return NULL;
int arg)
if (arg)
return NULL;
const char *arg1)
return NULL;
return NULL;
(void) ap_discard_request_body(r);
ap_rvputs(r,
r->status_line,
NULL);
return DONE;
return e_uri;
ap_text *t;
ap_rprintf(r,
(void) ap_discard_request_body(r);
return DONE;
int replaced)
const char *body;
if (replaced) {
return HTTP_NO_CONTENT;
return def_depth;
return DAV_INFINITY;
void *data;
return OK;
return HTTP_NOT_FOUND;
r->pool);
return OK;
return NULL;
const char *range_c;
char *range;
char *dash;
char *slash;
err);
return DONE;
int result;
return result;
return HTTP_NOT_FOUND;
const char *pathname;
void *fhandle;
return HTTP_NOT_FOUND;
return HTTP_INTERNAL_SERVER_ERROR;
return result;
void *buffer;
int has_range;
err);
if (has_range) {
if (r->header_only) {
return DONE;
err);
if (has_range
if (!has_range)
if (amt == 0) {
if (has_range) {
return DONE;
int result;
return result;
return DECLINED;
int resource_state;
const char *body;
int result;
int resource_existed = 0;
int resource_was_writable = 0;
int parent_was_writable = 0;
int has_range;
return result;
return result;
if (has_range) {
err);
if (ap_should_client_block(r)) {
long len;
DAV_READ_BLOCKSIZE)) > 0) {
** ### then the resource might NOT exist (e.g. dav_fs_repos.c)
err2);
err);
err);
if (propstats) {
const char *body;
int result;
int depth;
int parent_was_writable = 0;
return result;
return result;
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
** multistatus response -- only internal members/collections.
err);
return result;
0, 0, parent_was_writable);
err);
err2);
return HTTP_NO_CONTENT;
const char *options;
const char *dav_level;
const char *vsn_level;
int result;
const char *uris;
return result;
ap_set_content_length(r, 0);
return result;
if (*uris) {
case DAV_RESOURCE_EXISTS:
NULL);
NULL);
case DAV_RESOURCE_LOCK_NULL:
NULL);
case DAV_RESOURCE_NULL:
NULL);
return DONE;
/* some props were expected on this collection/resource */
/* no props on this collection/resource */
return NULL;
return NULL;
int depth;
int result;
return result;
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
&dav_module);
r->uri)));
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
ctx.r = r;
err);
return DONE;
for ( ; i-- > 0; ++ctx ) {
s = apr_psprintf(p,
for ( ; i-- > 0; ++ctx ) {
int reverse)
if (reverse)
ctx += i;
if (reverse)
--ctx;
if (!reverse)
++ctx;
int result;
int failure = 0;
return result;
return HTTP_NOT_FOUND;
return result;
return HTTP_BAD_REQUEST;
err);
int is_remove;
return HTTP_BAD_REQUEST;
if (failure) {
return DONE;
r->read_chunked = 0;
r->remaining = 0;
if (tenc) {
return HTTP_NOT_IMPLEMENTED;
else if (lenp) {
++pos;
return HTTP_BAD_REQUEST;
return HTTP_UNSUPPORTED_MEDIA_TYPE;
return ap_discard_request_body(r);
int resource_state;
int result;
int parent_was_writable = 0;
return result;
&dav_module);
return result;
return HTTP_METHOD_NOT_ALLOWED;
0, 0, parent_was_writable);
err2);
err);
err);
const char *body;
const char *dest;
int is_dir;
int overwrite;
int depth;
int result;
int replaced;
int src_parent_was_writable = 0;
int dst_parent_was_writable = 0;
int resource_state;
return result;
return HTTP_NOT_FOUND;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return result;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (is_move
err);
err);
if (is_dir
if (is_dir
return result;
if (is_move) {
if (is_move) {
if (is_move)
0, 0, dst_parent_was_writable);
if (is_move) {
0, 0, src_parent_was_writable);
err);
err2);
err3);
err);
int result;
int depth;
int new_lock_request = 0;
int resource_state;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
return result;
goto error;
err);
goto error;
if (new_lock_request == 0) {
err);
goto error;
dav_get_timeout(r),
goto error;
char *locktoken_txt;
&dav_module);
goto error;
ap_rprintf(r,
return DONE;
int result;
const char *const_locktoken_txt;
char *locktoken_txt;
int resource_state;
return DECLINED;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
err);
return result;
return result;
return HTTP_NO_CONTENT;
return HTTP_METHOD_NOT_ALLOWED;
int result;
const char *target;
const char *location;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
return result;
return HTTP_NOT_FOUND;
err);
int result;
return DECLINED;
return result;
return result;
return HTTP_NOT_FOUND;
err);
ap_set_content_length(r, 0);
return DONE;
int result;
return DECLINED;
return result;
return result;
return HTTP_NOT_FOUND;
err);
ap_set_content_length(r, 0);
return DONE;
return HTTP_METHOD_NOT_ALLOWED;
return HTTP_METHOD_NOT_ALLOWED;
int result;
return DECLINED;
return result;
return HTTP_BAD_REQUEST;
return result;
return HTTP_NOT_FOUND;
return DECLINED;
return HTTP_METHOD_NOT_ALLOWED;
return HTTP_METHOD_NOT_ALLOWED;
return HTTP_METHOD_NOT_ALLOWED;
return HTTP_METHOD_NOT_ALLOWED;
if (r->assbackwards) {
return DECLINED;
&dav_module);
r->allowed = 0
r->allowed |= 0
r->allowed |= 0
return dav_method_get(r);
return dav_method_put(r);
return dav_method_post(r);
return dav_method_delete(r);
return dav_method_options(r);
return dav_method_propfind(r);
return dav_method_proppatch(r);
return dav_method_mkcol(r);
return dav_method_lock(r);
return dav_method_unlock(r);
return DECLINED;
return dav_method_vsn_control(r);
return dav_method_checkout(r);
return dav_method_uncheckout(r);
return dav_method_checkin(r);
return dav_method_set_target(r);
return dav_method_label(r);
return dav_method_report(r);
return dav_method_make_workspace(r);
return dav_method_make_activity(r);
return dav_method_baseline_control(r);
return dav_method_merge(r);
return DECLINED;
&dav_module);
return DECLINED;
return DECLINED;
return OK;
return DECLINED;
static void register_hooks(void)
{ NULL }
{ NULL }
(request_rec *r,