util.c revision 8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* ====================================================================
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * The Apache Software License, Version 1.1
9bcfc3697a91b5215893a7d0206865b13fc72148nd * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * reserved.
ce69065dfde08a756f3b52e0dbe2f4f8d56b13cfnd * Redistribution and use in source and binary forms, with or without
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * modification, are permitted provided that the following conditions
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * are met:
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 1. Redistributions of source code must retain the above copyright
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * notice, this list of conditions and the following disclaimer.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 2. Redistributions in binary form must reproduce the above copyright
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * notice, this list of conditions and the following disclaimer in
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * the documentation and/or other materials provided with the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * distribution.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 3. The end-user documentation included with the redistribution,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * if any, must include the following acknowledgment:
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * "This product includes software developed by the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * Apache Software Foundation (http://www.apache.org/)."
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * Alternately, this acknowledgment may appear in the software itself,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * if and wherever such third-party acknowledgments normally appear.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 4. The names "Apache" and "Apache Software Foundation" must
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * not be used to endorse or promote products derived from this
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * software without prior written permission. For written
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * permission, please contact apache@apache.org.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 5. Products derived from this software may not be called "Apache",
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * nor may "Apache" appear in their name, without prior written
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * permission of the Apache Software Foundation.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * SUCH DAMAGE.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * ====================================================================
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * This software consists of voluntary contributions made by many
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * individuals on behalf of the Apache Software Foundation. For more
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * information on the Apache Software Foundation, please see
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** DAV extension module for Apache 2.0.*
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** - various utilities, repository-independent
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* grow the buffer if necessary */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* NOTE: this does not retain prior contents */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* NOTE: this function is used to init the first pointer, too, since
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd the PAD will be larger than alloc_len (0) for zeroed structures */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* grow if we don't have enough for the requested size plus padding */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* set the new length; min of MINSIZE */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* initialize a buffer and copy the specified (null-term'd) string into it */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *str)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* append a string to the end of the buffer, adjust length */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *str)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* place a string on the end of the buffer, do NOT adjust length */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *str)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* place some memory on the end of a buffer; do NOT adjust length */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndDAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** dav_lookup_uri()
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** Extension for ap_sub_req_lookup_uri() which can't handle absolute
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** URIs properly.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** If NULL is returned, then an error occurred with parsing the URI or
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** the URI does not match the current server.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nddav_lookup_result dav_lookup_uri(const char *uri, request_rec * r,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *scheme;
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *domain;
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* first thing to do is parse the URI into various components */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* the URI must be an absoluteURI (WEBDAV S9.3) */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd result.err.desc = "Destination URI must be an absolute URI.";
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* the URI must not have a query (args) or a fragment */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd "Destination URI contains invalid components "
b05b612c7dd1921c47081e9252ae61ef46b99924kess "(a query or a fragment).";
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* If the scheme or port was provided, then make sure that it matches
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd the scheme/port of this request. If the request must be absolute,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd then require the (explicit/implicit) scheme/port be matching.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ### hmm. if a port wasn't provided (does the parse return port==0?),
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ### but we're on a non-standard port, then we won't detect that the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ### URI's port implies the wrong one.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd if (comp.scheme != NULL || comp.port != 0 || must_be_absolute)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* ### not sure this works if the current request came in via https: */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* insert a port if the URI did not contain one */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd comp.port = apr_uri_default_port_for_scheme(comp.scheme);
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* now, verify that the URI uses the same scheme as the current.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd request. the port must match our port.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd "Destination URI refers to "
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd "different scheme or port "
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd "(want: %s://hostname:%d)",
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* we have verified the scheme, port, and general structure */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** Hrm. IE5 will pass unqualified hostnames for both the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** Host: and Destination: headers. This breaks the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** http_vhost.c::matches_aliases function.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** For now, qualify unqualified comp.hostnames with
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** r->server->server_hostname.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** ### this is a big hack. Apache should provide a better way.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** ### maybe the admin should list the unqualified hosts in a
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd ** ### <ServerAlias> block?
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd && (domain = strchr(r->server->server_hostname, '.')) != NULL) {
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL);
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* now, if a hostname was provided, then verify that it represents the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd same server as the current connection. note that we just use our
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd port, since we've verified the URI matches ours */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd result.err.desc = "Destination URI refers to a different server.";
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* we have verified that the requested URI denotes the same server as
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd the current request. Therefore, we can use ap_sub_req_lookup_uri() */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* reconstruct a URI as just the path */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd new_file = apr_uri_unparse(r->pool, &comp, APR_URI_UNP_OMITSITEPART);
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * Lookup the URI and return the sub-request. Note that we use the
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * same HTTP method on the destination. This allows the destination
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * to apply appropriate restrictions (e.g. readonly).
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL);
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* ---------------------------------------------------------------
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** XML UTILITY FUNCTIONS
4d7a2e153c599946b6afbe7bf883f477fcab7e53kess/* validate that the root element uses a given DAV: tagname (TRUE==valid) */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndint dav_validate_root(const ap_xml_doc *doc, const char *tagname)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* find and return the (unique) child with a given DAV: tagname */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname)
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd if (child->ns == AP_XML_NS_DAV_ID && !strcmp(child->name, tagname))
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* gather up all the CDATA into a single string */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7ndconst char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool,
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *found_text = NULL; /* initialize to avoid gcc warning */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd for (child = elem->first_child; child != NULL; child = child->next) {
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* some fast-path cases:
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 1) zero-length cdata
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * 2) a single piece of cdata with no whitespace to strip
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd return "";
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd for (child = elem->first_child; child != NULL; child = child->next) {
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd *s = '\0';
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* trim leading whitespace */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd while (apr_isspace(*cdata)) /* assume: return false for '\0' */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* trim trailing whitespace */
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* ---------------------------------------------------------------
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd** Timeout header processing
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd/* dav_get_timeout: If the Timeout: header exists, return a time_t
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * when this lock is expected to expire. Otherwise, return
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * a time_t of DAV_TIMEOUT_INFINITE.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * It's unclear if DAV clients are required to understand
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * Seconds-xxx and Infinity time values. We assume that they do.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * In addition, for now, that's all we understand, too.
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *timeout_const = apr_table_get(r->headers_in, "Timeout");
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd const char *timeout = apr_pstrdup(r->pool, timeout_const), *val;
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd /* Use the first thing we understand, or infinity if
41e3d6b4e67a52c6570c0412c3e5526278cf07d7nd * we don't understand anything.
return DAV_TIMEOUT_INFINITE;
return DAV_TIMEOUT_INFINITE;
return NULL;
return ih;
const char *state_token,
if (t == dav_if_opaquelock) {
return err;
return NULL;
char *sp;
char *token;
token++;
return NULL;
return token;
char *str;
char *list;
const char *state_token;
int condition;
return NULL;
while (*str) {
switch(*str) {
while (*list) {
switch (*list) {
return err;
return err;
list++;
str++;
return NULL;
int flags,
request_rec *r)
const char *uri;
const char *etag;
int num_matched;
int num_that_apply;
int seen_locktoken;
return dav_push_error(p,
err);
if (seen_locktoken)
return NULL;
return NULL;
num_that_apply = 0;
case dav_if_etag:
reason =
goto state_list_failed;
&& !mismatch) {
reason =
goto state_list_failed;
case dav_if_opaquelock:
reason =
goto state_list_failed;
num_matched = 0;
reason =
goto state_list_failed;
(!r->user ||
const char *errmsg;
r->user,
if (num_matched == 0
reason =
goto state_list_failed;
if (seen_locktoken) {
return NULL;
if (num_that_apply == 0) {
if (seen_locktoken)
return NULL;
locks_hooks)) {
return NULL;
apr_psprintf(p,
return NULL;
return NULL;
return err;
return NULL;
int result;
int lock_db_opened_locally = 0;
#if DAV_DEBUG
return err;
return err;
ctx.r = r;
&work_buf, r);
return err;
return err;
return NULL;
--idx;
return s2;
NULL);
request_rec *r,
int *auto_checkout)
*auto_checkout = 0;
err);
err);
return NULL;
/* see mod_dav.h for docco */
request_rec *r,
int parent_only,
return NULL;
goto done;
goto done;
int checkout_parent;
!= NULL) {
goto done;
if (!checkout_parent) {
goto done;
!= NULL)
err);
goto done;
if (parent_only)
goto done;
err);
goto done;
int checkout_resource;
goto done;
if (!checkout_resource) {
goto done;
!= NULL)
err);
goto done;
done:
return err;
return NULL;
/* see mod_dav.h for docco */
request_rec *r,
int undo,
int unlock,
return NULL;
if (undo) {
err);
err);
err);
return NULL;
!= NULL) {
err);
!= NULL) {
err);
return NULL;