util.c revision 83719c22db4a6d0575bb4f7f34382d7b185a6f74
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* ====================================================================
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * The Apache Software License, Version 1.1
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * Copyright (c) 2000 The Apache Software Foundation. All rights
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * reserved.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * Redistribution and use in source and binary forms, with or without
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * modification, are permitted provided that the following conditions
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 1. Redistributions of source code must retain the above copyright
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * notice, this list of conditions and the following disclaimer.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 2. Redistributions in binary form must reproduce the above copyright
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * notice, this list of conditions and the following disclaimer in
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * the documentation and/or other materials provided with the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * distribution.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * 3. The end-user documentation included with the redistribution,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * if any, must include the following acknowledgment:
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * "This product includes software developed by the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * Apache Software Foundation (http://www.apache.org/)."
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Alternately, this acknowledgment may appear in the software itself,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * if and wherever such third-party acknowledgments normally appear.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * 4. The names "Apache" and "Apache Software Foundation" must
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * not be used to endorse or promote products derived from this
bc9d4698fce0238d2f6f2682e99423ebb1149976rbowen * software without prior written permission. For written
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * permission, please contact apache@apache.org.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * 5. Products derived from this software may not be called "Apache",
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem * nor may "Apache" appear in their name, without prior written
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem * permission of the Apache Software Foundation.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * SUCH DAMAGE.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * ====================================================================
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * This software consists of voluntary contributions made by many
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * individuals on behalf of the Apache Software Foundation. For more
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * information on the Apache Software Foundation, please see
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** DAV extension module for Apache 2.0.*
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** - various utilities, repository-independent
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakdav_error *dav_new_error(apr_pool_t *p, int status, int error_id, const char *desc)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakdav_error *dav_push_error(apr_pool_t *p, int status, int error_id, const char *desc,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf, size_t extra_needed)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* grow the buffer if necessary */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak if (pbuf->cur_len + extra_needed > pbuf->alloc_len) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf, size_t size)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* NOTE: this does not retain prior contents */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* NOTE: this function is used to init the first pointer, too, since
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak the PAD will be larger than alloc_len (0) for zeroed structures */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* grow if we don't have enough for the requested size plus padding */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* set the new length; min of MINSIZE */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* initialize a buffer and copy the specified (null-term'd) string into it */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, const char *str)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* append a string to the end of the buffer, adjust length */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, const char *str)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* place a string on the end of the buffer, do NOT adjust length */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, const char *str)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* place some memory on the end of a buffer; do NOT adjust length */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakvoid dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, const void *mem,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** dav_lookup_uri()
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** Extension for ap_sub_req_lookup_uri() which can't handle absolute
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** URIs properly.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** If NULL is returned, then an error occurred with parsing the URI or
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** the URI does not match the current server.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakdav_lookup_result dav_lookup_uri(const char *uri, request_rec * r)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak const char *scheme;
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak unsigned short port = ntohs(r->connection->local_addr.sin_port);
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak const char *domain;
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* first thing to do is parse the URI into various components */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak if (ap_parse_uri_components(r->pool, uri, &comp) != HTTP_OK) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak result.err.desc = "Invalid syntax in Destination URI.";
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* the URI must be an absoluteURI (WEBDAV S9.3) */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak result.err.desc = "Destination URI must be an absolute URI.";
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* ### not sure this works if the current request came in via https: */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* insert a port if the URI did not contain one */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak comp.port = ap_default_port_for_scheme(comp.scheme);
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* now, verify that the URI uses the same scheme as the current request.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak the port, must match our port.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak the URI must not have a query (args) or a fragment
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "Destination URI refers to different "
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "scheme or port (%s://hostname:%d)"
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "Destination URI contains invalid components "
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "(a query or a fragment).";
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* we have verified the scheme, port, and general structure */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** Hrm. IE5 will pass unqualified hostnames for both the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** Host: and Destination: headers. This breaks the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** http_vhost.c::matches_aliases function.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** For now, qualify unqualified comp.hostnames with
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** r->server->server_hostname.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** ### this is a big hack. Apache should provide a better way.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** ### maybe the admin should list the unqualified hosts in a
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ** ### <ServerAlias> block?
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak (domain = strchr(r->server->server_hostname, '.')) != NULL) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL);
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* now, if a hostname was provided, then verify that it represents the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak same server as the current connection. note that we just use our
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak port, since we've verified the URI matches ours */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak !ap_matches_request_vhost(r, comp.hostname, port)) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak result.err.desc = "Destination URI refers to a different server.";
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* we have verified that the requested URI denotes the same server as
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak the current request. Therefore, we can use ap_sub_req_lookup_uri() */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* reconstruct a URI as just the path */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak new_file = ap_unparse_uri_components(r->pool, &comp, UNP_OMITSITEPART);
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * Lookup the URI and return the sub-request. Note that we use the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * same HTTP method on the destination. This allows the destination
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * to apply appropriate restrictions (e.g. readonly).
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak result.rnew = ap_sub_req_method_uri(r->method, new_file, r);
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* ---------------------------------------------------------------
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** XML UTILITY FUNCTIONS
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* validate that the root element uses a given DAV: tagname (TRUE==valid) */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakint dav_validate_root(const ap_xml_doc *doc, const char *tagname)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* find and return the (unique) child with a given DAV: tagname */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniakap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname)
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak if (child->ns == AP_XML_NS_DAV_ID && !strcmp(child->name, tagname))
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* ---------------------------------------------------------------
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak** Timeout header processing
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak/* dav_get_timeout: If the Timeout: header exists, return a time_t
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * when this lock is expected to expire. Otherwise, return
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * a time_t of DAV_TIMEOUT_INFINITE.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * It's unclear if DAV clients are required to understand
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * Seconds-xxx and Infinity time values. We assume that they do.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * In addition, for now, that's all we understand, too.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak const char *timeout_const = apr_table_get(r->headers_in, "Timeout");
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak const char *timeout = apr_pstrdup(r->pool, timeout_const), *val;
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* Use the first thing we understand, or infinity if
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * we don't understand anything.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* ### We need to handle overflow better:
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * ### timeout will be <= 2^32 - 1
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh/* ---------------------------------------------------------------
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh** If Header processing
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh/* add_if_resource returns a new if_header, linking it to next_ih.
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohstatic dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih,
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;
/* see mod_dav.h for docco */
const char *ws_uri;
return HTTP_BAD_REQUEST;
return OK;
/* see mod_dav.h for docco */
const char **target,
int *is_label)
*is_label = 0;
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
return OK;
/* see mod_dav.h for docco */
int parent_only,
const char *body;
if (!parent_only) {
return NULL;
!= NULL)
if (!parent_only) {
return NULL;
!= NULL)
return NULL;
/* see mod_dav.h for docco */
request_rec *r,
int undo,
const char *body;
if (undo)
if (undo)
return NULL;