util.c revision 83719c22db4a6d0575bb4f7f34382d7b185a6f74
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering/* ====================================================================
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * The Apache Software License, Version 1.1
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen *
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * Copyright (c) 2000 The Apache Software Foundation. All rights
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * reserved.
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek *
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * Redistribution and use in source and binary forms, with or without
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * modification, are permitted provided that the following conditions
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * are met:
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek *
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * 1. Redistributions of source code must retain the above copyright
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer.
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek *
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * 2. Redistributions in binary form must reproduce the above copyright
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer in
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * the documentation and/or other materials provided with the
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * distribution.
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek *
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * 3. The end-user documentation included with the redistribution,
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * if any, must include the following acknowledgment:
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * "This product includes software developed by the
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * Apache Software Foundation (http://www.apache.org/)."
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek * Alternately, this acknowledgment may appear in the software itself,
21ac6ff143cc8bebfbd1818af28e8c6f82cd5265Zbigniew Jędrzejewski-Szmek * if and wherever such third-party acknowledgments normally appear.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * 4. The names "Apache" and "Apache Software Foundation" must
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * not be used to endorse or promote products derived from this
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * software without prior written permission. For written
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * permission, please contact apache@apache.org.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * 5. Products derived from this software may not be called "Apache",
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * nor may "Apache" appear in their name, without prior written
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * permission of the Apache Software Foundation.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * SUCH DAMAGE.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * ====================================================================
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * This software consists of voluntary contributions made by many
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * individuals on behalf of the Apache Software Foundation. For more
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * information on the Apache Software Foundation, please see
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * <http://www.apache.org/>.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** DAV extension module for Apache 2.0.*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** - various utilities, repository-independent
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek*/
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "mod_dav.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "http_request.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "http_config.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "http_vhost.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "http_log.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "http_protocol.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering#include "apr_strings.h"
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poetteringdav_error *dav_new_error(apr_pool_t *p, int status, int error_id, const char *desc)
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering{
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering int save_errno = errno;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering dav_error *err = apr_pcalloc(p, sizeof(*err));
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->status = status;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->error_id = error_id;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->desc = desc;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->save_errno = save_errno;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering return err;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering}
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poetteringdav_error *dav_push_error(apr_pool_t *p, int status, int error_id, const char *desc,
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt dav_error *prev)
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt{
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt dav_error *err = apr_pcalloc(p, sizeof(*err));
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->status = status;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->error_id = error_id;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->desc = desc;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering err->prev = prev;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering return err;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering}
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poetteringvoid dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf, size_t extra_needed)
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering{
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* grow the buffer if necessary */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering if (pbuf->cur_len + extra_needed > pbuf->alloc_len) {
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering char *newbuf;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering pbuf->alloc_len += extra_needed + DAV_BUFFER_PAD;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek newbuf = apr_palloc(p, pbuf->alloc_len);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(newbuf, pbuf->buf, pbuf->cur_len);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->buf = newbuf;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf, size_t size)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* NOTE: this does not retain prior contents */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* NOTE: this function is used to init the first pointer, too, since
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek the PAD will be larger than alloc_len (0) for zeroed structures */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* grow if we don't have enough for the requested size plus padding */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (size + DAV_BUFFER_PAD > pbuf->alloc_len) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* set the new length; min of MINSIZE */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->alloc_len = size + DAV_BUFFER_PAD;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (pbuf->alloc_len < DAV_BUFFER_MINSIZE)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->alloc_len = DAV_BUFFER_MINSIZE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->buf = apr_palloc(p, pbuf->alloc_len);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->cur_len = size;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* initialize a buffer and copy the specified (null-term'd) string into it */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, const char *str)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_set_bufsize(p, pbuf, strlen(str));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(pbuf->buf, str, pbuf->cur_len + 1);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* append a string to the end of the buffer, adjust length */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, const char *str)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek size_t len = strlen(str);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_check_bufsize(p, pbuf, len + 1);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->cur_len += len;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* place a string on the end of the buffer, do NOT adjust length */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, const char *str)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek size_t len = strlen(str);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_check_bufsize(p, pbuf, len + 1);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* place some memory on the end of a buffer; do NOT adjust length */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, const void *mem,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek size_t amt, size_t pad)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_check_bufsize(p, pbuf, amt + pad);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(pbuf->buf + pbuf->cur_len, mem, amt);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** dav_lookup_uri()
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek**
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** Extension for ap_sub_req_lookup_uri() which can't handle absolute
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** URIs properly.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek**
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** If NULL is returned, then an error occurred with parsing the URI or
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** the URI does not match the current server.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek*/
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekdav_lookup_result dav_lookup_uri(const char *uri, request_rec * r)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_lookup_result result = { 0 };
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering const char *scheme;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering unsigned short port = ntohs(r->connection->local_addr.sin_port);
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering uri_components comp;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering char *new_file;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering const char *domain;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering /* first thing to do is parse the URI into various components */
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering if (ap_parse_uri_components(r->pool, uri, &comp) != HTTP_OK) {
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering result.err.status = HTTP_BAD_REQUEST;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering result.err.desc = "Invalid syntax in Destination URI.";
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering return result;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering }
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering /* the URI must be an absoluteURI (WEBDAV S9.3) */
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering if (comp.scheme == NULL) {
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering result.err.status = HTTP_BAD_REQUEST;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering result.err.desc = "Destination URI must be an absolute URI.";
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering return result;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering }
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering /* ### not sure this works if the current request came in via https: */
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering scheme = r->parsed_uri.scheme;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering if (scheme == NULL)
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering scheme = ap_http_method(r);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* insert a port if the URI did not contain one */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (comp.port == 0)
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt comp.port = ap_default_port_for_scheme(comp.scheme);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* now, verify that the URI uses the same scheme as the current request.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek the port, must match our port.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek the URI must not have a query (args) or a fragment
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (strcasecmp(comp.scheme, scheme) != 0 ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek comp.port != port) {
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt result.err.status = HTTP_BAD_GATEWAY;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek result.err.desc = apr_psprintf(r->pool,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Destination URI refers to different "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "scheme or port (%s://hostname:%d)"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek APR_EOL_STR "(want: %s://hostname:%d)",
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek comp.scheme ? comp.scheme : scheme,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek comp.port ? comp.port : port,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek scheme, port);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return result;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (comp.query != NULL || comp.fragment != NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek result.err.status = HTTP_BAD_REQUEST;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek result.err.desc =
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Destination URI contains invalid components "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "(a query or a fragment).";
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return result;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* we have verified the scheme, port, and general structure */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Hrm. IE5 will pass unqualified hostnames for both the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Host: and Destination: headers. This breaks the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** http_vhost.c::matches_aliases function.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** For now, qualify unqualified comp.hostnames with
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** r->server->server_hostname.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### this is a big hack. Apache should provide a better way.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### maybe the admin should list the unqualified hosts in a
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### <ServerAlias> block?
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (strrchr(comp.hostname, '.') == NULL &&
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek (domain = strchr(r->server->server_hostname, '.')) != NULL) {
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL);
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* now, if a hostname was provided, then verify that it represents the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek same server as the current connection. note that we just use our
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek port, since we've verified the URI matches ours */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (comp.hostname != NULL &&
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek !ap_matches_request_vhost(r, comp.hostname, port)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek result.err.status = HTTP_BAD_GATEWAY;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek result.err.desc = "Destination URI refers to a different server.";
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return result;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* we have verified that the requested URI denotes the same server as
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek the current request. Therefore, we can use ap_sub_req_lookup_uri() */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* reconstruct a URI as just the path */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek new_file = ap_unparse_uri_components(r->pool, &comp, UNP_OMITSITEPART);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * Lookup the URI and return the sub-request. Note that we use the
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering * same HTTP method on the destination. This allows the destination
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering * to apply appropriate restrictions (e.g. readonly).
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering */
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering result.rnew = ap_sub_req_method_uri(r->method, new_file, r);
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering return result;
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering}
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering/* ---------------------------------------------------------------
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering**
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering** XML UTILITY FUNCTIONS
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering*/
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* validate that the root element uses a given DAV: tagname (TRUE==valid) */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekint dav_validate_root(const ap_xml_doc *doc, const char *tagname)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return doc->root &&
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek doc->root->ns == AP_XML_NS_DAV_ID &&
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strcmp(doc->root->name, tagname) == 0;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* find and return the (unique) child with a given DAV: tagname */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ap_xml_elem *child = elem->first_child;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (; child; child = child->next)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (child->ns == AP_XML_NS_DAV_ID && !strcmp(child->name, tagname))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return child;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* ---------------------------------------------------------------
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering**
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering** Timeout header processing
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering**
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering*/
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* dav_get_timeout: If the Timeout: header exists, return a time_t
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * when this lock is expected to expire. Otherwise, return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * a time_t of DAV_TIMEOUT_INFINITE.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * It's unclear if DAV clients are required to understand
28f90ea25f8d8f2bfbe6d3e6a4846943eb92e4c5Zbigniew Jędrzejewski-Szmek * Seconds-xxx and Infinity time values. We assume that they do.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * In addition, for now, that's all we understand, too.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmektime_t dav_get_timeout(request_rec *r)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek time_t now, expires = DAV_TIMEOUT_INFINITE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *timeout_const = apr_table_get(r->headers_in, "Timeout");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *timeout = apr_pstrdup(r->pool, timeout_const), *val;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (timeout == NULL)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return DAV_TIMEOUT_INFINITE;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Use the first thing we understand, or infinity if
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * we don't understand anything.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!strncmp(val, "Infinite", 8)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return DAV_TIMEOUT_INFINITE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
28f90ea25f8d8f2bfbe6d3e6a4846943eb92e4c5Zbigniew Jędrzejewski-Szmek if (!strncmp(val, "Second-", 7)) {
28f90ea25f8d8f2bfbe6d3e6a4846943eb92e4c5Zbigniew Jędrzejewski-Szmek val += 7;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### We need to handle overflow better:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * ### timeout will be <= 2^32 - 1
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek expires = atol(val);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek now = time(NULL);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return now + expires;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return DAV_TIMEOUT_INFINITE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* ---------------------------------------------------------------
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek**
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek** If Header processing
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek**
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt*/
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* add_if_resource returns a new if_header, linking it to next_ih.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *uri, size_t uri_len)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_if_header *ih;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((ih = apr_pcalloc(p, sizeof(*ih))) == NULL)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ih->uri = uri;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ih->uri_len = uri_len;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ih->next = next_ih;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return ih;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* add_if_state adds a condition to an if_header.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic dav_error * dav_add_if_state(apr_pool_t *p, dav_if_header *ih,
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering const char *state_token,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_if_state_type t, int condition,
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering const dav_hooks_locks *locks_hooks)
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt{
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering dav_if_state_list *new_sl;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering new_sl = apr_pcalloc(p, sizeof(*new_sl));
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering new_sl->condition = condition;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering new_sl->type = t;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering if (t == dav_if_opaquelock) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_error *err;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((err = (*locks_hooks->parse_locktoken)(p, state_token,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek &new_sl->locktoken)) != NULL) {
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* ### maybe add a higher-level description */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering return err;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering }
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering else
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering new_sl->etag = state_token;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek new_sl->next = ih->state;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering ih->state = new_sl;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering return NULL;
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering}
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering/* fetch_next_token returns the substring from str+1
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering * to the next occurence of char term, or \0, whichever
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering * occurs first. Leading whitespace is ignored.
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poetteringstatic char *dav_fetch_next_token(char **str, char term)
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering{
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering char *sp;
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt char *token;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering token = *str + 1;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering while (*token && (*token == ' ' || *token == '\t'))
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering token++;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering if ((sp = strchr(token, term)) == NULL)
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt return NULL;
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering *sp = '\0';
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt *str = sp;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering return token;
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering}
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering
762a5766dc65058c245c87d326ae3d403d85ea06Lennart Poettering/* dav_process_if_header:
762a5766dc65058c245c87d326ae3d403d85ea06Lennart Poettering *
762a5766dc65058c245c87d326ae3d403d85ea06Lennart Poettering * If NULL (no error) is returned, then **if_header points to the
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering * "If" productions structure (or NULL if "If" is not present).
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt *
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering * ### this part is bogus:
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering * If an error is encountered, the error is logged. Parent should
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering * return err->status.
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering */
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poetteringstatic dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering{
c454426c54c9beb274f415a80c64a4f1580700e7Lennart Poettering dav_error *err;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek char *str;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek char *list;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *state_token;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *uri = NULL; /* scope of current production; NULL=no-tag */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek size_t uri_len = 0;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_if_header *ih = NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek uri_components parsed_uri;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek enum {no_tagged, tagged, unknown} list_type = unknown;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek int condition;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *p_ih = NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((str = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "If"))) == NULL)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek while (*str) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek switch(*str) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case '<':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Tagged-list production - following states apply to this uri */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (list_type == no_tagged
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek || ((uri = dav_fetch_next_token(&str, '>')) == NULL)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_TAGGED,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid If-header: unclosed \"<\" or "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "unexpected tagged-list production.");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* 2518 specifies this must be an absolute URI; just take the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * relative part for later comparison against r->uri */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (ap_parse_uri_components(r->pool, uri, &parsed_uri) != HTTP_OK) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_TAGGED,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid URI in tagged If-header.");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* note that parsed_uri.path is allocated; we can trash it */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* clean up the URI a bit */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ap_getparents(parsed_uri.path);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek uri_len = strlen(parsed_uri.path);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (uri_len > 1 && parsed_uri.path[uri_len - 1] == '/')
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek parsed_uri.path[--uri_len] = '\0';
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek uri = parsed_uri.path;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek list_type = tagged;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case '(':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* List production */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* If a uri has not been encountered, this is a No-Tagged-List */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (list_type == unknown)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek list_type = no_tagged;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((list = dav_fetch_next_token(&str, ')')) == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_UNCLOSED_PAREN,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid If-header: unclosed \"(\".");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((ih = dav_add_if_resource(r->pool, ih, uri, uri_len)) == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### dav_add_if_resource() should return an error for us! */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_PARSE,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Internal server error parsing \"If:\" "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "header.");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
cb7bb815d2ad7945e63214d21cec1d70152ba6abMarkus Knetschke
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt condition = DAV_IF_COND_NORMAL;
cb7bb815d2ad7945e63214d21cec1d70152ba6abMarkus Knetschke
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt while (*list) {
cb7bb815d2ad7945e63214d21cec1d70152ba6abMarkus Knetschke /* List is the entire production (in a uri scope) */
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
cb7bb815d2ad7945e63214d21cec1d70152ba6abMarkus Knetschke switch (*list) {
cb7bb815d2ad7945e63214d21cec1d70152ba6abMarkus Knetschke case '<':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((state_token = dav_fetch_next_token(&list, '>')) == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### add a description to this error */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_PARSE, NULL);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_opaquelock,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek condition, locks_hooks)) != NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### maybe add a higher level description */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return err;
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek condition = DAV_IF_COND_NORMAL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case '[':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((state_token = dav_fetch_next_token(&list, ']')) == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### add a description to this error */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_PARSE, NULL);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_etag,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek condition, locks_hooks)) != NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* ### maybe add a higher level description */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return err;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek condition = DAV_IF_COND_NORMAL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case 'N':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (list[1] == 'o' && list[2] == 't') {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (condition != DAV_IF_COND_NORMAL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_MULTIPLE_NOT,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid \"If:\" header: "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Multiple \"not\" entries "
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt "for the same state.");
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek condition = DAV_IF_COND_NOT;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek list += 2;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case ' ':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case '\t':
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek default:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_UNK_CHAR,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek apr_psprintf(r->pool,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid \"If:\" "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "header: Unexpected "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "character encountered "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "(0x%02x, '%c').",
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering *list, *list));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek list++;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case ' ':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case '\t':
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek default:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(r->pool, HTTP_BAD_REQUEST,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek DAV_ERR_IF_UNK_CHAR,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek apr_psprintf(r->pool,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Invalid \"If:\" header: "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Unexpected character "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "encountered (0x%02x, '%c').",
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering *str, *str));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek str++;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering *p_ih = ih;
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering return NULL;
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering}
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poetteringstatic int dav_find_submitted_locktoken(const dav_if_header *if_header,
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering const dav_lock *lock_list,
3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9eLennart Poettering const dav_hooks_locks *locks_hooks)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek{
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (; if_header != NULL; if_header = if_header->next) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const dav_if_state_list *state_list;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (state_list = if_header->state;
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering state_list != NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek state_list = state_list->next) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (state_list->type == dav_if_opaquelock) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const dav_lock *lock;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* given state_list->locktoken, match it */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** The resource will have one or more lock tokens. We only
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** need to match one of them against any token in the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** If: header.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** One token case: It is an exclusive or shared lock. Either
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** way, we must find it.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** N token case: They are shared locks. By policy, we need
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering ** to match only one. The resource's other
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** tokens may belong to somebody else (so we
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** shouldn't see them in the If: header anyway)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (lock = lock_list; lock != NULL; lock = lock->next) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (!(*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering return 1;
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering }
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt }
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering }
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering }
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt return 0;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering}
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering/* dav_validate_resource_state:
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering * Returns NULL if path/uri meets if-header and lock requirements
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering */
7de304525deafe4eb86060321e39787138dbbadfLennart Poetteringstatic dav_error * dav_validate_resource_state(apr_pool_t *p,
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt const dav_resource *resource,
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt dav_lockdb *lockdb,
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering const dav_if_header *if_header,
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering int flags,
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering dav_buffer *pbuf,
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering request_rec *r)
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering{
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering dav_error *err;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering const char *uri;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering const char *etag;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering const dav_hooks_locks *locks_hooks = (lockdb ? lockdb->hooks : NULL);
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt const dav_if_header *ifhdr_scan;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering dav_if_state_list *state_list;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering dav_lock *lock_list;
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering dav_lock *lock;
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering int num_matched;
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering int num_that_apply;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek int seen_locktoken;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek size_t uri_len;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *reason = NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* DBG1("validate: <%s>", resource->uri); */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** The resource will have one of three states:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** 1) No locks. We have no special requirements that the user supply
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** specific locktokens. One of the state lists must match, and
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** we're done.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** 2) One exclusive lock. The locktoken must appear *anywhere* in the
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** If: header. Of course, asserting the token in a "Not" term will
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** quickly fail that state list :-). If the locktoken appears in
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** one of the state lists *and* one state list matches, then we're
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** done.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** 3) One or more shared locks. One of the locktokens must appear
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** *anywhere* in the If: header. If one of the locktokens appears,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** and we match one state list, then we are done.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** The <seen_locktoken> variable determines whether we have seen one
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** of this resource's locktokens in the If: header.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** If this is a new lock request, <flags> will contain the requested
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** lock scope. Three rules apply:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen ** 1) Do not require a (shared) locktoken to be seen (when we are
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen ** applying another shared lock)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** 2) If the scope is exclusive and we see any locks, fail.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** 3) If the scope is shared and we see an exclusive lock, fail.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (lockdb == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* we're in State 1. no locks. */
dd2b607b7d1ce355e93f9f71cd256ec20b8ae9c4Thomas Hindoe Paaboel Andersen lock_list = NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### hrm... we don't need to have these fully
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### resolved since we're only looking at the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### locktokens...
6b94875fa3a7280e7f1c0df11027b927b6961edeRichard Maw **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** ### use get_locks w/ calltype=PARTIAL
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((err = dav_lock_query(lockdb, resource, &lock_list)) != NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_push_error(p,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek HTTP_INTERNAL_SERVER_ERROR, 0,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "The locks could not be queried for "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "verification against a possible \"If:\" "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "header.",
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek err);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* lock_list now determines whether we're in State 1, 2, or 3. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** For a new, exclusive lock: if any locks exist, fail.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** For a new, shared lock: if an exclusive lock exists, fail.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** else, do not require a token to be seen.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (flags & DAV_LOCKSCOPE_EXCLUSIVE) {
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt if (lock_list != NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(p, HTTP_LOCKED, 0,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "Existing lock(s) on the requested resource "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "prevent an exclusive lock.");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
1d3eaa93616a2e9f6568b754a65c884766bac6c4Jay Strict ** There are no locks, so we can pretend that we've already met
6b94875fa3a7280e7f1c0df11027b927b6961edeRichard Maw ** any requirement to find the resource's locks in an If: header.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek seen_locktoken = 1;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else if (flags & DAV_LOCKSCOPE_SHARED) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Strictly speaking, we don't need this loop. Either the first
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** (and only) lock will be EXCLUSIVE, or none of them will be.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (lock = lock_list; lock != NULL; lock = lock->next) {
dd2b607b7d1ce355e93f9f71cd256ec20b8ae9c4Thomas Hindoe Paaboel Andersen if (lock->scope == DAV_LOCKSCOPE_EXCLUSIVE) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return dav_new_error(p, HTTP_LOCKED, 0,
6b94875fa3a7280e7f1c0df11027b927b6961edeRichard Maw "The requested resource is already "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "locked exclusively.");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** The locks on the resource (if any) are all shared. Set the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** <seen_locktoken> flag to indicate that we do not need to find
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** the locks in an If: header.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering seen_locktoken = 1;
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering }
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering else {
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering /*
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** For methods other than LOCK:
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering **
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** If we have no locks, then <seen_locktoken> can be set to true --
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt ** pretending that we've already met the requirement of seeing one
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** of the resource's locks in the If: header.
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering **
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** Otherwise, it must be cleared and we'll look for one.
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering */
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering seen_locktoken = (lock_list == NULL);
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering /*
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** If there is no If: header, then we can shortcut some logic:
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering **
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** 1) if we do not need to find a locktoken in the (non-existent) If:
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** header, then we are successful.
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering **
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** 2) if we must find a locktoken in the (non-existent) If: header, then
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** we fail.
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering */
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering if (if_header == NULL) {
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering if (seen_locktoken)
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering return NULL;
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering return dav_new_error(p, HTTP_LOCKED, 0,
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering "This resource is locked and an \"If:\" header "
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering "was not supplied to allow access to the "
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering "resource.");
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering }
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering /* the If: header is present */
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering /*
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** If a dummy header is present (because of a Lock-Token: header), then
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** we are required to find that token in this resource's set of locks.
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** If we have no locks, then we immediately fail.
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt **
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** This is a 400 (Bad Request) since they should only submit a locktoken
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt ** that actually exists.
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt **
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** Don't issue this response if we're talking about the parent resource.
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** It is okay for that resource to NOT have this locktoken.
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** (in fact, it certainly will not: a dummy_header only occurs for the
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** UNLOCK method, the parent is checked only for locknull resources,
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** and the parent certainly does not have the (locknull's) locktoken)
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering */
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering if (lock_list == NULL && if_header->dummy_header) {
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering if (flags & DAV_VALIDATE_IS_PARENT)
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering return NULL;
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt return dav_new_error(p, HTTP_BAD_REQUEST, 0,
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering "The locktoken specified in the \"Lock-Token:\" "
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering "header is invalid because this resource has no "
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering "outstanding locks.");
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Prepare the input URI. We want the URI to never have a trailing slash.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** When URIs are placed into the dav_if_header structure, they are
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering ** guaranteed to never have a trailing slash. If the URIs are equivalent,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** then it doesn't matter if they both lack a trailing slash -- they're
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** still equivalent.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Note: we could also ensure that a trailing slash is present on both
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** URIs, but the majority of URIs provided to us via a resource walk
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** will not contain that trailing slash.
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering */
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering uri = resource->uri;
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering uri_len = strlen(uri);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (uri[uri_len - 1] == '/') {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek dav_set_bufsize(p, pbuf, uri_len);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek memcpy(pbuf->buf, uri, uri_len);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek pbuf->buf[--uri_len] = '\0';
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek uri = pbuf->buf;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* get the resource's etag; we may need it during the checks */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering etag = (*resource->hooks->getetag)(resource);
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt /* how many state_lists apply to this URI? */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering num_that_apply = 0;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* If there are if-headers, fail if this resource
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering * does not match at least one state_list.
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering */
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt for (ifhdr_scan = if_header;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ifhdr_scan != NULL;
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ifhdr_scan = ifhdr_scan->next) {
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* DBG2("uri=<%s> if_uri=<%s>", uri, ifhdr_scan->uri ? ifhdr_scan->uri : "(no uri)"); */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt if (ifhdr_scan->uri != NULL
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering && (uri_len != ifhdr_scan->uri_len
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering || memcmp(uri, ifhdr_scan->uri, uri_len) != 0)) {
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /*
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt ** A tagged-list's URI doesn't match this resource's URI.
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ** Skip to the next state_list to see if it will match.
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering continue;
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt }
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering /* this state_list applies to this resource */
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt /*
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ** ### only one state_list should ever apply! a no-tag, or a tagged
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ** ### where S9.4.2 states only one can match.
7ca4155737730ece73ae4b4ac80571005cb99b69Jan Engelhardt **
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ** ### revamp this code to loop thru ifhdr_scan until we find the
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering ** ### matching state_list. process it. stop.
91913f584af38b29a816cca959ba648acd60ac9fLennart Poettering */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ++num_that_apply;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* To succeed, resource must match *all* of the states
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * specified in the state_list.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (state_list = ifhdr_scan->state;
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt state_list != NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek state_list = state_list->next) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek switch(state_list->type) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case dav_if_etag:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek int mismatch = strcmp(state_list->etag, etag);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering if (state_list->condition == DAV_IF_COND_NORMAL && mismatch) {
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering /*
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering ** The specified entity-tag does not match the
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering ** entity-tag on the resource. This state_list is
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering ** not going to match. Bust outta here.
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering */
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering reason =
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering "an entity-tag was specified, but the resource's "
b43d75c378d919900e5c1e82a82e3e17dd3de9f9Lennart Poettering "actual ETag does not match.";
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering goto state_list_failed;
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering }
af40e5d3acbdcff09c8809cd1b86ecf8871f65f0Lennart Poettering else if (state_list->condition == DAV_IF_COND_NOT
7de304525deafe4eb86060321e39787138dbbadfLennart Poettering && !mismatch) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** The specified entity-tag DOES match the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** entity-tag on the resource. This state_list is
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** not going to match. Bust outta here.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek reason =
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "an entity-tag was specified using the \"Not\" form, "
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "but the resource's actual ETag matches the provided "
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt "entity-tag.";
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek goto state_list_failed;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek break;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case dav_if_opaquelock:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (lockdb == NULL) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (state_list->condition == DAV_IF_COND_NOT) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* the locktoken is definitely not there! (success) */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek continue;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt /* condition == DAV_IF_COND_NORMAL */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** If no lockdb is provided, then validation fails for
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** this state_list (NORMAL means we were supposed to
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** find the token, which we obviously cannot do without
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** a lock database).
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek **
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** Go and try the next state list.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek reason =
e0ea94c1e2ab3930c85c6057189a2a829a13a800Lennart Poettering "a State-token was supplied, but a lock database "
e0ea94c1e2ab3930c85c6057189a2a829a13a800Lennart Poettering "is not available for to provide the required lock.";
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek goto state_list_failed;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Resource validation 'fails' if:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * ANY of the lock->locktokens match
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * a NOT state_list->locktoken,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * OR
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * NONE of the lock->locktokens match
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * a NORMAL state_list->locktoken.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke num_matched = 0;
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke for (lock = lock_list; lock != NULL; lock = lock->next) {
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke /*
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke DBG2("compare: rsrc=%s ifhdr=%s",
ac92ced5bb41def1d90f871d6c8cfec2b03c0c7dBenjamin Franzke (*locks_hooks->format_locktoken)(p, lock->locktoken),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek (*locks_hooks->format_locktoken)(p, state_list->locktoken));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* nothing to do if the locktokens do not match. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek continue;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering /*
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** We have now matched up one of the resource's locktokens
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** to a locktoken in a State-token in the If: header.
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** Note this fact, so that we can pass the overall
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering ** requirement of seeing at least one of the resource's
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt ** locktokens.
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt */
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering seen_locktoken = 1;
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering if (state_list->condition == DAV_IF_COND_NOT) {
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering /*
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering ** This state requires that the specified locktoken
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering ** is NOT present on the resource. But we just found
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering ** it. There is no way this state-list can now
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering ** succeed, so go try another one.
b938cb902c3b5bca807a94b277672c64d6767886Jan Engelhardt */
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering reason =
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering "a State-token was supplied, which used a "
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering "\"Not\" condition. The State-token was found "
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering "in the locks on this resource";
ef3100e9637adda26fa19e7ee8606788320dcde3Lennart Poettering goto state_list_failed;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* condition == DAV_IF_COND_NORMAL */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Validate auth_user: If an authenticated user created
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** the lock, only the same user may submit that locktoken
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** to manipulate a resource.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (lock->auth_user &&
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek (!r->user ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strcmp(lock->auth_user, r->user))) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek const char *errmsg;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek errmsg = apr_pstrcat(p, "User \"",
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r->user,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "\" submitted a locktoken created "
6e9efa59209d48fc69a456fbadb2b5c113f503a6Lennart Poettering "by user \"",
16eb4024887b1b79fc56706fda25eadaecdef2d4Zbigniew Jędrzejewski-Szmek lock->auth_user, "\".", NULL);
16eb4024887b1b79fc56706fda25eadaecdef2d4Zbigniew Jędrzejewski-Szmek return dav_new_error(p, HTTP_UNAUTHORIZED, 0, errmsg);
16eb4024887b1b79fc56706fda25eadaecdef2d4Zbigniew Jędrzejewski-Szmek }
16eb4024887b1b79fc56706fda25eadaecdef2d4Zbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /*
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek ** We just matched a specified State-Token to one of the
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek ** resource's locktokens.
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek **
** 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.
*/
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_walker_ctx *ctx, int calltype)
{
dav_error *err;
if ((err = dav_validate_resource_state(ctx->pool, ctx->resource,
ctx->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)
|| (*ctx->resource->hooks->is_same_resource)(ctx->resource,
ctx->root)) {
/* ### maybe push a higher-level description? */
return err;
}
/* associate the error with the current URI */
dav_add_response(ctx, ctx->uri.buf, 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_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;
}
else {
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"Resource validation failed because no "
"lock hooks were found.");
}
}
/* (1) Validate the specified resource, at the specified depth */
if (resource->exists && depth > 0) {
dav_walker_ctx ctx = { 0 };
ctx.walk_type = DAV_WALKTYPE_ALL;
ctx.postfix = 0;
ctx.func = dav_validate_walker;
ctx.pool = r->pool;
ctx.if_header = if_header;
ctx.r = r;
ctx.flags = flags;
ctx.resource = resource;
if (lockdb != NULL) {
ctx.lockdb = lockdb;
ctx.walk_type |= DAV_WALKTYPE_LOCKNULL;
}
dav_buffer_init(r->pool, &ctx.uri, resource->uri);
err = (*repos_hooks->walk)(&ctx, DAV_INFINITY);
if (err == NULL) {
*response = ctx.response;
}
/* 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 = (*repos_hooks->get_parent_resource)(resource);
if (parent_resource == NULL) {
err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0,
"Cannot access parent of repository root.");
}
else {
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) {
ap_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_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;
}
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;
}
#define DAV_WORKSPACE_HDR "Workspace"
#define DAV_TARGET_SELECTOR_HDR "Target-Selector"
/* see mod_dav.h for docco */
int dav_get_workspace(request_rec *r, const char **workspace)
{
const char *ws_uri;
*workspace = NULL;
ws_uri = apr_table_get(r->headers_in, DAV_WORKSPACE_HDR);
if (ws_uri != NULL) {
dav_lookup_result lookup;
/* make the URI server-relative */
lookup = dav_lookup_uri(ws_uri, r);
if (lookup.rnew == NULL) {
if (lookup.err.status == HTTP_BAD_REQUEST) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
lookup.err.desc);
return HTTP_BAD_REQUEST;
}
return lookup.err.status;
}
*workspace = lookup.rnew->uri;
}
return OK;
}
/* see mod_dav.h for docco */
int dav_get_target_selector(request_rec *r,
const ap_xml_elem *version,
const char **target,
int *is_label)
{
/* Initialize results */
*target = NULL;
*is_label = 0;
if (version != NULL) {
/* Expect either <DAV:version><DAV:href>URI</DAV:href></DAV:version>
* or <DAV:label-name>LABEL</DAV:label-name> */
if (strcmp(version->name, "version") == 0) {
if ((version = dav_find_child(version, "href")) == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Missing DAV:href in DAV:version element");
return HTTP_BAD_REQUEST;
}
/* return the contents of the DAV:href element */
/* ### this presumes no child elements */
*target = strip_white(version->first_cdata.first->text, r->pool);
}
else if (strcmp(version->name, "label-name") == 0) {
/* return contents of the DAV:label-name element */
*target = strip_white(version->first_cdata.first->text, r->pool);
*is_label = 1;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
"Unknown version specifier (not DAV:version or DAV:label-name)");
return HTTP_BAD_REQUEST;
}
}
else {
/* no element. see if a Target-Selector header was provided
* (which is always interpreted as a label) */
*target = apr_table_get(r->headers_in, DAV_TARGET_SELECTOR_HDR);
*is_label = 1;
}
return OK;
}
/* dav_add_vary_header
*
* If there were any headers in the request which require a Vary header
* in the response, add it.
*/
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);
/* 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 *workspace = apr_table_get(in_req->headers_in, DAV_WORKSPACE_HDR);
const char *target = apr_table_get(in_req->headers_in, DAV_TARGET_SELECTOR_HDR);
const char *vary = apr_table_get(out_req->headers_out, "Vary");
/* If Workspace header specified, add it to Vary header */
if (workspace != NULL) {
if (vary == NULL)
vary = DAV_WORKSPACE_HDR;
else
vary = apr_pstrcat(out_req->pool, vary, "," DAV_WORKSPACE_HDR, NULL);
}
/* If Target-Selector specified, add it to the Vary header */
if (target != NULL) {
if (vary == NULL)
vary = DAV_TARGET_SELECTOR_HDR;
else
vary = apr_pstrcat(out_req->pool, vary, "," DAV_TARGET_SELECTOR_HDR, NULL);
}
if (workspace != NULL || target != NULL)
apr_table_setn(out_req->headers_out, "Vary", vary);
}
}
/* see mod_dav.h for docco */
dav_error *dav_ensure_resource_writable(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);
const char *body;
dav_error *err;
/* Initialize results */
memset(av_info, 0, sizeof(*av_info));
if (!parent_only) {
av_info->resource_created = !resource->exists;
}
/* check parent resource if requested or if resource must be created */
if (!resource->exists || parent_only) {
dav_resource *parent = (*resource->hooks->get_parent_resource)(resource);
if (parent == NULL || !parent->exists) {
body = apr_psprintf(r->pool,
"Missing one or more intermediate collections. "
"Cannot create resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_new_error(r->pool, HTTP_CONFLICT, 0, body);
}
av_info->parent_resource = parent;
/* if parent not versioned, assume child can be created */
if (!parent->versioned) {
return NULL;
}
/* if no versioning provider, something is terribly wrong */
if (vsn_hooks == NULL) {
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"INTERNAL ERROR: "
"versioned resource with no versioning "
"provider?");
}
/* parent must be checked out */
if (!parent->working) {
/* if parent cannot be automatically checked out, fail */
if (!(*vsn_hooks->auto_version_enabled)(parent)) {
body = apr_psprintf(r->pool,
"Parent collection must be checked out. "
"Cannot create resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_new_error(r->pool, HTTP_CONFLICT, 0, body);
}
/* 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, NULL))
!= NULL)
{
body = apr_psprintf(r->pool,
"Unable to checkout parent collection. "
"Cannot create resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
/* remember that parent was checked out */
av_info->parent_checkedout = 1;
}
/* if not just checking parent, create new child resource */
if (!parent_only) {
if ((err = (*vsn_hooks->mkresource)(resource)) != NULL) {
body = apr_psprintf(r->pool,
"Unable to create versioned resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
/* remember that resource was created */
av_info->resource_created = 1;
}
}
else if (!resource->versioned) {
/* resource exists and is not versioned; assume it is writable */
return NULL;
}
/* if not just checking parent, make sure child resource is checked out */
if (!parent_only && !resource->working) {
/* Auto-versioning can only be applied to version selectors, so
* no separate working resource will be created. */
if ((err = (*vsn_hooks->checkout)(resource, NULL))
!= NULL)
{
body = apr_psprintf(r->pool,
"Unable to checkout resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_CONFLICT, 0, body, err);
}
/* remember that resource was checked out */
av_info->resource_checkedout = 1;
}
return NULL;
}
/* see mod_dav.h for docco */
dav_error *dav_revert_resource_writability(
request_rec *r,
dav_resource *resource,
int undo,
const dav_auto_version_info *av_info)
{
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
const char *body;
dav_error *err;
/* If a resource was provided, restore its writable state.
* Otherwise, only the parent must have been modified */
if (resource != NULL) {
if (av_info->resource_checkedout) {
if (undo)
err = (*vsn_hooks->uncheckout)(resource);
else
err = (*vsn_hooks->checkin)(resource, NULL);
if (err != NULL) {
body = apr_psprintf(r->pool,
"Unable to %s resource %s.",
undo ? "uncheckout" : "checkin",
ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}
}
/* If undoing because of an error, and the resource was created,
* then remove it */
if (undo && av_info->resource_created) {
dav_response *response;
/* ### should we do anything with the response? */
if ((err = (*resource->hooks->remove_resource)(resource,
&response)) != NULL) {
body = apr_psprintf(r->pool,
"Unable to undo creation of resource %s.",
ap_escape_html(r->pool, resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}
}
}
/* If parent resource was made writable, restore its state */
if (av_info->parent_resource != NULL && av_info->parent_checkedout) {
if (undo)
err = (*vsn_hooks->uncheckout)(av_info->parent_resource);
else
err = (*vsn_hooks->checkin)(av_info->parent_resource, NULL);
if (err != NULL) {
body = apr_psprintf(r->pool,
"Unable to %s parent collection %s.",
undo ? "uncheckout" : "checkin",
ap_escape_html(r->pool, av_info->parent_resource->uri));
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
body, err);
}
}
return NULL;
}