842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * http://www.apache.org/licenses/LICENSE-2.0
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein *
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * Unless required by applicable law or agreed to in writing, software
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * distributed under the License is distributed on an "AS IS" BASIS,
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * See the License for the specific language governing permissions and
71da3cca78eea6010f89b139ecadb79e6d213c4fnd * limitations under the License.
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
b0fb330a8581c8bfab5e523084f9f39264a52b12gstein** DAV extension module for Apache 2.0.*
f4c310fd2555c6faca1f980f00b161eadb089023gstein** - various utilities, repository-independent
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1b21d7b3d97def358b2e923655edeb16613a1c31gstein#include "apr_strings.h"
952023a04a2f9d51553babd9094fb857f1c97548trawick#include "apr_lib.h"
1b21d7b3d97def358b2e923655edeb16613a1c31gstein
1b21d7b3d97def358b2e923655edeb16613a1c31gstein#define APR_WANT_STRFUNC
1b21d7b3d97def358b2e923655edeb16613a1c31gstein#include "apr_want.h"
1b21d7b3d97def358b2e923655edeb16613a1c31gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "mod_dav.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_request.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_config.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_vhost.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_log.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein#include "http_protocol.h"
f4c310fd2555c6faca1f980f00b161eadb089023gstein
99d46a23c6eac800f327b29f8009f7d7da986230trawickDAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status, int error_id,
99d46a23c6eac800f327b29f8009f7d7da986230trawick apr_status_t aprerr, const char *desc)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dav_error *err = apr_pcalloc(p, sizeof(*err));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->status = status;
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->error_id = error_id;
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->desc = desc;
99d46a23c6eac800f327b29f8009f7d7da986230trawick err->aprerr = aprerr;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(dav_error*) dav_new_error_tag(apr_pool_t *p, int status,
99d46a23c6eac800f327b29f8009f7d7da986230trawick int error_id, apr_status_t aprerr,
99d46a23c6eac800f327b29f8009f7d7da986230trawick const char *desc,
5b03ba47ff7225cacb131f14b019332af27da960gstein const char *namespace,
5b03ba47ff7225cacb131f14b019332af27da960gstein const char *tagname)
5b03ba47ff7225cacb131f14b019332af27da960gstein{
99d46a23c6eac800f327b29f8009f7d7da986230trawick dav_error *err = dav_new_error(p, status, error_id, aprerr, desc);
5b03ba47ff7225cacb131f14b019332af27da960gstein
5b03ba47ff7225cacb131f14b019332af27da960gstein err->tagname = tagname;
5b03ba47ff7225cacb131f14b019332af27da960gstein err->namespace = namespace;
5b03ba47ff7225cacb131f14b019332af27da960gstein
5b03ba47ff7225cacb131f14b019332af27da960gstein return err;
5b03ba47ff7225cacb131f14b019332af27da960gstein}
5b03ba47ff7225cacb131f14b019332af27da960gstein
5b03ba47ff7225cacb131f14b019332af27da960gstein
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status,
e8f95a682820a599fe41b22977010636be5c2717jim int error_id, const char *desc,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe dav_error *prev)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dav_error *err = apr_pcalloc(p, sizeof(*err));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->status = status;
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->error_id = error_id;
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->desc = desc;
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->prev = prev;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
691db92094897494d6c31326108da20088bc175etrawickDAV_DECLARE(dav_error*) dav_join_error(dav_error *dest, dav_error *src)
691db92094897494d6c31326108da20088bc175etrawick{
691db92094897494d6c31326108da20088bc175etrawick dav_error *curr = dest;
691db92094897494d6c31326108da20088bc175etrawick
691db92094897494d6c31326108da20088bc175etrawick /* src error doesn't exist so nothing to join just return dest */
691db92094897494d6c31326108da20088bc175etrawick if (src == NULL) {
691db92094897494d6c31326108da20088bc175etrawick return dest;
691db92094897494d6c31326108da20088bc175etrawick }
691db92094897494d6c31326108da20088bc175etrawick
691db92094897494d6c31326108da20088bc175etrawick /* dest error doesn't exist so nothing to join just return src */
691db92094897494d6c31326108da20088bc175etrawick if (curr == NULL) {
691db92094897494d6c31326108da20088bc175etrawick return src;
691db92094897494d6c31326108da20088bc175etrawick }
691db92094897494d6c31326108da20088bc175etrawick
691db92094897494d6c31326108da20088bc175etrawick /* find last error in dest stack */
691db92094897494d6c31326108da20088bc175etrawick while (curr->prev != NULL) {
691db92094897494d6c31326108da20088bc175etrawick curr = curr->prev;
691db92094897494d6c31326108da20088bc175etrawick }
691db92094897494d6c31326108da20088bc175etrawick
691db92094897494d6c31326108da20088bc175etrawick /* add the src error onto end of dest stack and return it */
691db92094897494d6c31326108da20088bc175etrawick curr->prev = src;
691db92094897494d6c31326108da20088bc175etrawick return dest;
691db92094897494d6c31326108da20088bc175etrawick}
691db92094897494d6c31326108da20088bc175etrawick
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe apr_size_t extra_needed)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* grow the buffer if necessary */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (pbuf->cur_len + extra_needed > pbuf->alloc_len) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe char *newbuf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->alloc_len += extra_needed + DAV_BUFFER_PAD;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe newbuf = apr_palloc(p, pbuf->alloc_len);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe memcpy(newbuf, pbuf->buf, pbuf->cur_len);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->buf = newbuf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe apr_size_t size)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* NOTE: this does not retain prior contents */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* NOTE: this function is used to init the first pointer, too, since
f4c310fd2555c6faca1f980f00b161eadb089023gstein the PAD will be larger than alloc_len (0) for zeroed structures */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* grow if we don't have enough for the requested size plus padding */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (size + DAV_BUFFER_PAD > pbuf->alloc_len) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* set the new length; min of MINSIZE */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->alloc_len = size + DAV_BUFFER_PAD;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (pbuf->alloc_len < DAV_BUFFER_MINSIZE)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->alloc_len = DAV_BUFFER_MINSIZE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->buf = apr_palloc(p, pbuf->alloc_len);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein pbuf->cur_len = size;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* initialize a buffer and copy the specified (null-term'd) string into it */
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe const char *str)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_set_bufsize(p, pbuf, strlen(str));
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(pbuf->buf, str, pbuf->cur_len + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* append a string to the end of the buffer, adjust length */
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe const char *str)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
58fd79b56eb624bf011772994e9761d3c2e228c1orlikowski apr_size_t len = strlen(str);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_check_bufsize(p, pbuf, len + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein pbuf->cur_len += len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* place a string on the end of the buffer, do NOT adjust length */
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe const char *str)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
58fd79b56eb624bf011772994e9761d3c2e228c1orlikowski apr_size_t len = strlen(str);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_check_bufsize(p, pbuf, len + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* place some memory on the end of a buffer; do NOT adjust length */
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf,
e8f95a682820a599fe41b22977010636be5c2717jim const void *mem, apr_size_t amt,
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe apr_size_t pad)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_check_bufsize(p, pbuf, amt + pad);
f4c310fd2555c6faca1f980f00b161eadb089023gstein memcpy(pbuf->buf + pbuf->cur_len, mem, amt);
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein** dav_lookup_uri()
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** Extension for ap_sub_req_lookup_uri() which can't handle absolute
f4c310fd2555c6faca1f980f00b161eadb089023gstein** URIs properly.
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** If NULL is returned, then an error occurred with parsing the URI or
f4c310fd2555c6faca1f980f00b161eadb089023gstein** the URI does not match the current server.
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(dav_lookup_result) dav_lookup_uri(const char *uri,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz request_rec * r,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz int must_be_absolute)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_lookup_result result = { 0 };
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *scheme;
91644a5f4d3e992dc208304b50e80bbb236fca89trawick apr_port_t port;
8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921dougm apr_uri_t comp;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *new_file;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *domain;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* first thing to do is parse the URI into various components */
8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921dougm if (apr_uri_parse(r->pool, uri, &comp) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.status = HTTP_BAD_REQUEST;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.desc = "Invalid syntax in Destination URI.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the URI must be an absoluteURI (WEBDAV S9.3) */
48f35e10f195dd594d75738fc536bb885eda537cgstein if (comp.scheme == NULL && must_be_absolute) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.status = HTTP_BAD_REQUEST;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.desc = "Destination URI must be an absolute URI.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
48f35e10f195dd594d75738fc536bb885eda537cgstein /* the URI must not have a query (args) or a fragment */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (comp.query != NULL || comp.fragment != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.status = HTTP_BAD_REQUEST;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.desc =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Destination URI contains invalid components "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "(a query or a fragment).";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
48f35e10f195dd594d75738fc536bb885eda537cgstein /* If the scheme or port was provided, then make sure that it matches
48f35e10f195dd594d75738fc536bb885eda537cgstein the scheme/port of this request. If the request must be absolute,
48f35e10f195dd594d75738fc536bb885eda537cgstein then require the (explicit/implicit) scheme/port be matching.
48f35e10f195dd594d75738fc536bb885eda537cgstein
48f35e10f195dd594d75738fc536bb885eda537cgstein ### hmm. if a port wasn't provided (does the parse return port==0?),
48f35e10f195dd594d75738fc536bb885eda537cgstein ### but we're on a non-standard port, then we won't detect that the
48f35e10f195dd594d75738fc536bb885eda537cgstein ### URI's port implies the wrong one.
48f35e10f195dd594d75738fc536bb885eda537cgstein */
48f35e10f195dd594d75738fc536bb885eda537cgstein if (comp.scheme != NULL || comp.port != 0 || must_be_absolute)
48f35e10f195dd594d75738fc536bb885eda537cgstein {
48f35e10f195dd594d75738fc536bb885eda537cgstein /* ### not sure this works if the current request came in via https: */
48f35e10f195dd594d75738fc536bb885eda537cgstein scheme = r->parsed_uri.scheme;
48f35e10f195dd594d75738fc536bb885eda537cgstein if (scheme == NULL)
7b6ba9c468f26bdb3492d5e8cb79628a3b04e8c8wrowe scheme = ap_http_scheme(r);
48f35e10f195dd594d75738fc536bb885eda537cgstein
48f35e10f195dd594d75738fc536bb885eda537cgstein /* insert a port if the URI did not contain one */
48f35e10f195dd594d75738fc536bb885eda537cgstein if (comp.port == 0)
24efed0910118b762a4eb84830875d4714b8d315ianh comp.port = apr_uri_port_of_scheme(comp.scheme);
48f35e10f195dd594d75738fc536bb885eda537cgstein
48f35e10f195dd594d75738fc536bb885eda537cgstein /* now, verify that the URI uses the same scheme as the current.
48f35e10f195dd594d75738fc536bb885eda537cgstein request. the port must match our port.
48f35e10f195dd594d75738fc536bb885eda537cgstein */
c1b808d160bfb5c849263be8d4acff600853a328trawick port = r->connection->local_addr->port;
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein if (strcasecmp(comp.scheme, scheme) != 0
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein#ifdef APACHE_PORT_HANDLING_IS_BUSTED
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein || comp.port != port
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein#endif
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein ) {
48f35e10f195dd594d75738fc536bb885eda537cgstein result.err.status = HTTP_BAD_GATEWAY;
48f35e10f195dd594d75738fc536bb885eda537cgstein result.err.desc = apr_psprintf(r->pool,
48f35e10f195dd594d75738fc536bb885eda537cgstein "Destination URI refers to "
48f35e10f195dd594d75738fc536bb885eda537cgstein "different scheme or port "
48f35e10f195dd594d75738fc536bb885eda537cgstein "(%s://hostname:%d)" APR_EOL_STR
48f35e10f195dd594d75738fc536bb885eda537cgstein "(want: %s://hostname:%d)",
48f35e10f195dd594d75738fc536bb885eda537cgstein comp.scheme ? comp.scheme : scheme,
48f35e10f195dd594d75738fc536bb885eda537cgstein comp.port ? comp.port : port,
48f35e10f195dd594d75738fc536bb885eda537cgstein scheme, port);
48f35e10f195dd594d75738fc536bb885eda537cgstein return result;
48f35e10f195dd594d75738fc536bb885eda537cgstein }
48f35e10f195dd594d75738fc536bb885eda537cgstein }
48f35e10f195dd594d75738fc536bb885eda537cgstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we have verified the scheme, port, and general structure */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
e8f95a682820a599fe41b22977010636be5c2717jim ** Hrm. IE5 will pass unqualified hostnames for both the
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Host: and Destination: headers. This breaks the
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** http_vhost.c::matches_aliases function.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For now, qualify unqualified comp.hostnames with
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** r->server->server_hostname.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** ### this is a big hack. Apache should provide a better way.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** ### maybe the admin should list the unqualified hosts in a
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** ### <ServerAlias> block?
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
48f35e10f195dd594d75738fc536bb885eda537cgstein if (comp.hostname != NULL
48f35e10f195dd594d75738fc536bb885eda537cgstein && strrchr(comp.hostname, '.') == NULL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && (domain = strchr(r->server->server_hostname, '.')) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* now, if a hostname was provided, then verify that it represents the
f4c310fd2555c6faca1f980f00b161eadb089023gstein same server as the current connection. note that we just use our
f4c310fd2555c6faca1f980f00b161eadb089023gstein port, since we've verified the URI matches ours */
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein#ifdef APACHE_PORT_HANDLING_IS_BUSTED
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (comp.hostname != NULL &&
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe !ap_matches_request_vhost(r, comp.hostname, port)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.status = HTTP_BAD_GATEWAY;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe result.err.desc = "Destination URI refers to a different server.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
77c2148c53e0a4a20a80af735caa4e0e6bd448e0gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we have verified that the requested URI denotes the same server as
f4c310fd2555c6faca1f980f00b161eadb089023gstein the current request. Therefore, we can use ap_sub_req_lookup_uri() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* reconstruct a URI as just the path */
8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921dougm new_file = apr_uri_unparse(r->pool, &comp, APR_URI_UNP_OMITSITEPART);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Lookup the URI and return the sub-request. Note that we use the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * same HTTP method on the destination. This allows the destination
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to apply appropriate restrictions (e.g. readonly).
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f958dac1550254a59b45f4655138bb34dad5e76egstein result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* ---------------------------------------------------------------
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** XML UTILITY FUNCTIONS
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* validate that the root element uses a given DAV: tagname (TRUE==valid) */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(int) dav_validate_root(const apr_xml_doc *doc,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz const char *tagname)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein return doc->root &&
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe doc->root->ns == APR_XML_NS_DAV_ID &&
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe strcmp(doc->root->name, tagname) == 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* find and return the (unique) child with a given DAV: tagname */
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(apr_xml_elem *) dav_find_child(const apr_xml_elem *elem,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz const char *tagname)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe apr_xml_elem *child = elem->first_child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (; child; child = child->next)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (child->ns == APR_XML_NS_DAV_ID && !strcmp(child->name, tagname))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return child;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f39230a531b23d94f86a087963299bbe2e431a4agstein/* gather up all the CDATA into a single string */
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wroweDAV_DECLARE(const char *) dav_xml_get_cdata(const apr_xml_elem *elem, apr_pool_t *pool,
f39230a531b23d94f86a087963299bbe2e431a4agstein int strip_white)
f39230a531b23d94f86a087963299bbe2e431a4agstein{
f39230a531b23d94f86a087963299bbe2e431a4agstein apr_size_t len = 0;
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe apr_text *scan;
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe const apr_xml_elem *child;
f39230a531b23d94f86a087963299bbe2e431a4agstein char *cdata;
f39230a531b23d94f86a087963299bbe2e431a4agstein char *s;
f39230a531b23d94f86a087963299bbe2e431a4agstein apr_size_t tlen;
1e2133fe37e6cbcd683233057ef62236bc8e5826trawick const char *found_text = NULL; /* initialize to avoid gcc warning */
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein int found_count = 0;
f39230a531b23d94f86a087963299bbe2e431a4agstein
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein found_text = scan->text;
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein ++found_count;
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein len += strlen(found_text);
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein for (child = elem->first_child; child != NULL; child = child->next) {
f39230a531b23d94f86a087963299bbe2e431a4agstein for (scan = child->following_cdata.first;
f39230a531b23d94f86a087963299bbe2e431a4agstein scan != NULL;
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein scan = scan->next) {
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein found_text = scan->text;
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein ++found_count;
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein len += strlen(found_text);
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein }
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein }
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein /* some fast-path cases:
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein * 1) zero-length cdata
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein * 2) a single piece of cdata with no whitespace to strip
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein */
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein if (len == 0)
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein return "";
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein if (found_count == 1) {
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein if (!strip_white
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein || (!apr_isspace(*found_text)
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein && !apr_isspace(found_text[len - 1])))
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein return found_text;
f39230a531b23d94f86a087963299bbe2e431a4agstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein cdata = s = apr_palloc(pool, len + 1);
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) {
f39230a531b23d94f86a087963299bbe2e431a4agstein tlen = strlen(scan->text);
f39230a531b23d94f86a087963299bbe2e431a4agstein memcpy(s, scan->text, tlen);
f39230a531b23d94f86a087963299bbe2e431a4agstein s += tlen;
f39230a531b23d94f86a087963299bbe2e431a4agstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein for (child = elem->first_child; child != NULL; child = child->next) {
f39230a531b23d94f86a087963299bbe2e431a4agstein for (scan = child->following_cdata.first;
f39230a531b23d94f86a087963299bbe2e431a4agstein scan != NULL;
f39230a531b23d94f86a087963299bbe2e431a4agstein scan = scan->next) {
f39230a531b23d94f86a087963299bbe2e431a4agstein tlen = strlen(scan->text);
f39230a531b23d94f86a087963299bbe2e431a4agstein memcpy(s, scan->text, tlen);
f39230a531b23d94f86a087963299bbe2e431a4agstein s += tlen;
f39230a531b23d94f86a087963299bbe2e431a4agstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein *s = '\0';
f39230a531b23d94f86a087963299bbe2e431a4agstein
ab78b55c6dc4431d2c68d6bb4d169ba1554290a8gstein if (strip_white) {
f39230a531b23d94f86a087963299bbe2e431a4agstein /* trim leading whitespace */
057480777378361da24068b75e3cb07b95fd6ffdbreser while (apr_isspace(*cdata)) { /* assume: return false for '\0' */
f39230a531b23d94f86a087963299bbe2e431a4agstein ++cdata;
057480777378361da24068b75e3cb07b95fd6ffdbreser --len;
057480777378361da24068b75e3cb07b95fd6ffdbreser }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein /* trim trailing whitespace */
f39230a531b23d94f86a087963299bbe2e431a4agstein while (len-- > 0 && apr_isspace(cdata[len]))
f39230a531b23d94f86a087963299bbe2e431a4agstein continue;
f39230a531b23d94f86a087963299bbe2e431a4agstein cdata[len + 1] = '\0';
f39230a531b23d94f86a087963299bbe2e431a4agstein }
f39230a531b23d94f86a087963299bbe2e431a4agstein
f39230a531b23d94f86a087963299bbe2e431a4agstein return cdata;
f39230a531b23d94f86a087963299bbe2e431a4agstein}
f39230a531b23d94f86a087963299bbe2e431a4agstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(dav_xmlns_info *) dav_xmlns_create(apr_pool_t *pool)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein dav_xmlns_info *xi = apr_pcalloc(pool, sizeof(*xi));
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
6810bf1570bed88d16239b27ce47d48408bb2e51gstein xi->pool = pool;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein xi->uri_prefix = apr_hash_make(pool);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein xi->prefix_uri = apr_hash_make(pool);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein return xi;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(void) dav_xmlns_add(dav_xmlns_info *xi,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *prefix, const char *uri)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein /* this "should" not overwrite a prefix mapping */
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein apr_hash_set(xi->prefix_uri, prefix, APR_HASH_KEY_STRING, uri);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein /* note: this may overwrite an existing URI->prefix mapping, but it
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein doesn't matter -- any prefix is usuable to specify the URI. */
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein apr_hash_set(xi->uri_prefix, uri, APR_HASH_KEY_STRING, prefix);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(const char *) dav_xmlns_add_uri(dav_xmlns_info *xi,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *uri)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *prefix;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein if ((prefix = apr_hash_get(xi->uri_prefix, uri,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein APR_HASH_KEY_STRING)) != NULL)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein return prefix;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein prefix = apr_psprintf(xi->pool, "g%d", xi->count++);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein dav_xmlns_add(xi, prefix, uri);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein return prefix;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(const char *) dav_xmlns_get_uri(dav_xmlns_info *xi,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *prefix)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein return apr_hash_get(xi->prefix_uri, prefix, APR_HASH_KEY_STRING);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(const char *) dav_xmlns_get_prefix(dav_xmlns_info *xi,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *uri)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein return apr_hash_get(xi->uri_prefix, uri, APR_HASH_KEY_STRING);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gsteinDAV_DECLARE(void) dav_xmlns_generate(dav_xmlns_info *xi,
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein apr_text_header *phdr)
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein{
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein apr_hash_index_t *hi = apr_hash_first(xi->pool, xi->prefix_uri);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein for (; hi != NULL; hi = apr_hash_next(hi)) {
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const void *prefix;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein void *uri;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein const char *s;
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein apr_hash_this(hi, &prefix, NULL, &uri);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein s = apr_psprintf(xi->pool, " xmlns:%s=\"%s\"",
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein (const char *)prefix, (const char *)uri);
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe apr_text_append(xi->pool, phdr, s);
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein }
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein}
b5989e567e4fac5b3ab1252024ae19b0a54893a7gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* ---------------------------------------------------------------
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** Timeout header processing
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_get_timeout: If the Timeout: header exists, return a time_t
f4c310fd2555c6faca1f980f00b161eadb089023gstein * when this lock is expected to expire. Otherwise, return
f4c310fd2555c6faca1f980f00b161eadb089023gstein * a time_t of DAV_TIMEOUT_INFINITE.
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * It's unclear if DAV clients are required to understand
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Seconds-xxx and Infinity time values. We assume that they do.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * In addition, for now, that's all we understand, too.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(time_t) dav_get_timeout(request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein time_t now, expires = DAV_TIMEOUT_INFINITE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *timeout_const = apr_table_get(r->headers_in, "Timeout");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm const char *timeout = apr_pstrdup(r->pool, timeout_const), *val;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (timeout == NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return DAV_TIMEOUT_INFINITE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Use the first thing we understand, or infinity if
f4c310fd2555c6faca1f980f00b161eadb089023gstein * we don't understand anything.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!strncmp(val, "Infinite", 8)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return DAV_TIMEOUT_INFINITE;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!strncmp(val, "Second-", 7)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe val += 7;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### We need to handle overflow better:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * ### timeout will be <= 2^32 - 1
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe expires = atol(val);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe now = time(NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return now + expires;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return DAV_TIMEOUT_INFINITE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* ---------------------------------------------------------------
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** If Header processing
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* add_if_resource returns a new if_header, linking it to next_ih.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *uri, apr_size_t uri_len)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_header *ih;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if ((ih = apr_pcalloc(p, sizeof(*ih))) == NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein ih->uri = uri;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ih->uri_len = uri_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ih->next = next_ih;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return ih;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* add_if_state adds a condition to an if_header.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_error * dav_add_if_state(apr_pool_t *p, dav_if_header *ih,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *state_token,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_if_state_type t, int condition,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_hooks_locks *locks_hooks)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_state_list *new_sl;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm new_sl = apr_pcalloc(p, sizeof(*new_sl));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_sl->condition = condition;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_sl->type = t;
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (t == dav_if_opaquelock) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = (*locks_hooks->parse_locktoken)(p, state_token,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe &new_sl->locktoken)) != NULL) {
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton /* If the state token cannot be parsed, treat it as an
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton * unknown state; this will evaluate to "false" later
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton * during If header validation. */
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz if (err->error_id == DAV_ERR_LOCK_UNK_STATE_TOKEN) {
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton new_sl->type = dav_if_unknown;
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz }
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz else {
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz /* ### maybe add a higher-level description */
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz return err;
5a8f3bcf803321e69b226d3b98314305a68a586cjerenkrantz }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_sl->etag = state_token;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_sl->next = ih->state;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ih->state = new_sl;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* fetch_next_token returns the substring from str+1
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to the next occurence of char term, or \0, whichever
f4c310fd2555c6faca1f980f00b161eadb089023gstein * occurs first. Leading whitespace is ignored.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic char *dav_fetch_next_token(char **str, char term)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *sp;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *token;
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein token = *str + 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*token && (*token == ' ' || *token == '\t'))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe token++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((sp = strchr(token, term)) == NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein *sp = '\0';
f4c310fd2555c6faca1f980f00b161eadb089023gstein *str = sp;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return token;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_process_if_header:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If NULL (no error) is returned, then **if_header points to the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * "If" productions structure (or NULL if "If" is not present).
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * ### this part is bogus:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If an error is encountered, the error is logged. Parent should
f4c310fd2555c6faca1f980f00b161eadb089023gstein * return err->status.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *str;
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *list;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *state_token;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *uri = NULL; /* scope of current production; NULL=no-tag */
58fd79b56eb624bf011772994e9761d3c2e228c1orlikowski apr_size_t uri_len = 0;
99d46a23c6eac800f327b29f8009f7d7da986230trawick apr_status_t rv;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_header *ih = NULL;
8b99f2a316c5e2fa6ab208206fdd7fc2bfc4a921dougm apr_uri_t parsed_uri;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein enum {no_tagged, tagged, unknown} list_type = unknown;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int condition;
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein *p_ih = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if ((str = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "If"))) == NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (*str) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch(*str) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '<':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Tagged-list production - following states apply to this uri */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (list_type == no_tagged
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe || ((uri = dav_fetch_next_token(&str, '>')) == NULL)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_TAGGED, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Invalid If-header: unclosed \"<\" or "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "unexpected tagged-list production.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* 2518 specifies this must be an absolute URI; just take the
f4c310fd2555c6faca1f980f00b161eadb089023gstein * relative part for later comparison against r->uri */
f8033d657a57eab45af44368774d8beb3e4f7f35pquerna if ((rv = apr_uri_parse(r->pool, uri, &parsed_uri)) != APR_SUCCESS
f8033d657a57eab45af44368774d8beb3e4f7f35pquerna || !parsed_uri.path) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_TAGGED, rv,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Invalid URI in tagged If-header.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* note that parsed_uri.path is allocated; we can trash it */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* clean up the URI a bit */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_getparents(parsed_uri.path);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
1aac1c71105133d669960501bdf2274e63561054minfrin /* the resources we will compare to have unencoded paths */
1aac1c71105133d669960501bdf2274e63561054minfrin if (ap_unescape_url(parsed_uri.path) != OK) {
1aac1c71105133d669960501bdf2274e63561054minfrin return dav_new_error(r->pool, HTTP_BAD_REQUEST,
f0d00d46501a748e59cf7e0ab04f493d33833818rjung DAV_ERR_IF_TAGGED, rv,
f0d00d46501a748e59cf7e0ab04f493d33833818rjung "Invalid percent encoded URI in "
f0d00d46501a748e59cf7e0ab04f493d33833818rjung "tagged If-header.");
1aac1c71105133d669960501bdf2274e63561054minfrin }
1aac1c71105133d669960501bdf2274e63561054minfrin
28418cf4450c797588e74e91a3b22ed85f42423aminfrin uri_len = strlen(parsed_uri.path);
28418cf4450c797588e74e91a3b22ed85f42423aminfrin if (uri_len > 1 && parsed_uri.path[uri_len - 1] == '/') {
28418cf4450c797588e74e91a3b22ed85f42423aminfrin parsed_uri.path[--uri_len] = '\0';
28418cf4450c797588e74e91a3b22ed85f42423aminfrin }
28418cf4450c797588e74e91a3b22ed85f42423aminfrin
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe uri = parsed_uri.path;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe list_type = tagged;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '(':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* List production */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* If a uri has not been encountered, this is a No-Tagged-List */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (list_type == unknown)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe list_type = no_tagged;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((list = dav_fetch_next_token(&str, ')')) == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_UNCLOSED_PAREN, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Invalid If-header: unclosed \"(\".");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((ih = dav_add_if_resource(r->pool, ih, uri, uri_len)) == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### dav_add_if_resource() should return an error for us! */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_PARSE, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Internal server error parsing \"If:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition = DAV_IF_COND_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (*list) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* List is the entire production (in a uri scope) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch (*list) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '<':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((state_token = dav_fetch_next_token(&list, '>')) == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### add a description to this error */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_PARSE, 0, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_opaquelock,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition, locks_hooks)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher level description */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition = DAV_IF_COND_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '[':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((state_token = dav_fetch_next_token(&list, ']')) == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### add a description to this error */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_PARSE, 0, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_etag,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition, locks_hooks)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher level description */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition = DAV_IF_COND_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case 'N':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (list[1] == 'o' && list[2] == 't') {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (condition != DAV_IF_COND_NORMAL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_MULTIPLE_NOT, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Invalid \"If:\" header: "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Multiple \"not\" entries "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "for the same state.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe condition = DAV_IF_COND_NOT;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe list += 2;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case ' ':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '\t':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe default:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_UNK_CHAR, 0,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_psprintf(r->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Invalid \"If:\" "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "header: Unexpected "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "character encountered "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "(0x%02x, '%c').",
f4c310fd2555c6faca1f980f00b161eadb089023gstein *list, *list));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe list++;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case ' ':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case '\t':
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe default:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(r->pool, HTTP_BAD_REQUEST,
99d46a23c6eac800f327b29f8009f7d7da986230trawick DAV_ERR_IF_UNK_CHAR, 0,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_psprintf(r->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Invalid \"If:\" header: "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Unexpected character "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "encountered (0x%02x, '%c').",
f4c310fd2555c6faca1f980f00b161eadb089023gstein *str, *str));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe str++;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein *p_ih = ih;
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic int dav_find_submitted_locktoken(const dav_if_header *if_header,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_lock *lock_list,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_hooks_locks *locks_hooks)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (; if_header != NULL; if_header = if_header->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_if_state_list *state_list;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (state_list = if_header->state;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe state_list != NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe state_list = state_list->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (state_list->type == dav_if_opaquelock) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_lock *lock;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* given state_list->locktoken, match it */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The resource will have one or more lock tokens. We only
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** need to match one of them against any token in the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If: header.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** One token case: It is an exclusive or shared lock. Either
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** way, we must find it.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** N token case: They are shared locks. By policy, we need
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** to match only one. The resource's other
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** tokens may belong to somebody else (so we
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** shouldn't see them in the If: header anyway)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (lock = lock_list; lock != NULL; lock = lock->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (!(*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_validate_resource_state:
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Returns NULL if path/uri meets if-header and lock requirements
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_error * dav_validate_resource_state(apr_pool_t *p,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_resource *resource,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_lockdb *lockdb,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const dav_if_header *if_header,
f4c310fd2555c6faca1f980f00b161eadb089023gstein int flags,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_buffer *pbuf,
f4c310fd2555c6faca1f980f00b161eadb089023gstein request_rec *r)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *uri;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *etag;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_locks *locks_hooks = (lockdb ? lockdb->hooks : NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_if_header *ifhdr_scan;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_state_list *state_list;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_lock *lock_list;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_lock *lock;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int num_matched;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int num_that_apply;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int seen_locktoken;
98e9c4a310bb623ff788680f88b6bd200ff36a24wrowe apr_size_t uri_len;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *reason = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* DBG1("validate: <%s>", resource->uri); */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** The resource will have one of three states:
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 1) No locks. We have no special requirements that the user supply
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** specific locktokens. One of the state lists must match, and
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** we're done.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 2) One exclusive lock. The locktoken must appear *anywhere* in the
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If: header. Of course, asserting the token in a "Not" term will
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** quickly fail that state list :-). If the locktoken appears in
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** one of the state lists *and* one state list matches, then we're
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** done.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 3) One or more shared locks. One of the locktokens must appear
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** *anywhere* in the If: header. If one of the locktokens appears,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** and we match one state list, then we are done.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** The <seen_locktoken> variable determines whether we have seen one
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** of this resource's locktokens in the If: header.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If this is a new lock request, <flags> will contain the requested
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** lock scope. Three rules apply:
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 1) Do not require a (shared) locktoken to be seen (when we are
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** applying another shared lock)
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 2) If the scope is exclusive and we see any locks, fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 3) If the scope is shared and we see an exclusive lock, fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (lockdb == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* we're in State 1. no locks. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe lock_list = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### hrm... we don't need to have these fully
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### resolved since we're only looking at the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### locktokens...
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### use get_locks w/ calltype=PARTIAL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_lock_query(lockdb, resource, &lock_list)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_push_error(p,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The locks could not be queried for "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "verification against a possible \"If:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* lock_list now determines whether we're in State 1, 2, or 3. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
e8f95a682820a599fe41b22977010636be5c2717jim /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For a new, exclusive lock: if any locks exist, fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For a new, shared lock: if an exclusive lock exists, fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** else, do not require a token to be seen.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (flags & DAV_LOCKSCOPE_EXCLUSIVE) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (lock_list != NULL) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_LOCKED, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Existing lock(s) on the requested resource "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "prevent an exclusive lock.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** There are no locks, so we can pretend that we've already met
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** any requirement to find the resource's locks in an If: header.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe seen_locktoken = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else if (flags & DAV_LOCKSCOPE_SHARED) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Strictly speaking, we don't need this loop. Either the first
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** (and only) lock will be EXCLUSIVE, or none of them will be.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (lock = lock_list; lock != NULL; lock = lock->next) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (lock->scope == DAV_LOCKSCOPE_EXCLUSIVE) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_LOCKED, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The requested resource is already "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "locked exclusively.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The locks on the resource (if any) are all shared. Set the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** <seen_locktoken> flag to indicate that we do not need to find
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** the locks in an If: header.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gstein seen_locktoken = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** For methods other than LOCK:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
89fc13eb43e6c78d3377e9ef0d79d343a138041bbreser ** If we have no locks or if the resource is not being modified
89fc13eb43e6c78d3377e9ef0d79d343a138041bbreser ** (per RFC 4918 the lock token is not required on resources
89fc13eb43e6c78d3377e9ef0d79d343a138041bbreser ** we are not changing), then <seen_locktoken> can be set to true --
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** pretending that we've already met the requirement of seeing one
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** of the resource's locks in the If: header.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Otherwise, it must be cleared and we'll look for one.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
89fc13eb43e6c78d3377e9ef0d79d343a138041bbreser seen_locktoken = (lock_list == NULL
89fc13eb43e6c78d3377e9ef0d79d343a138041bbreser || flags & DAV_VALIDATE_NO_MODIFY);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If there is no If: header, then we can shortcut some logic:
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 1) if we do not need to find a locktoken in the (non-existent) If:
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** header, then we are successful.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 2) if we must find a locktoken in the (non-existent) If: header, then
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** we fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (if_header == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (seen_locktoken)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_LOCKED, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "This resource is locked and an \"If:\" header "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "was not supplied to allow access to the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "resource.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the If: header is present */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If a dummy header is present (because of a Lock-Token: header), then
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** we are required to find that token in this resource's set of locks.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If we have no locks, then we immediately fail.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** This is a 400 (Bad Request) since they should only submit a locktoken
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** that actually exists.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Don't issue this response if we're talking about the parent resource.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** It is okay for that resource to NOT have this locktoken.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** (in fact, it certainly will not: a dummy_header only occurs for the
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** UNLOCK method, the parent is checked only for locknull resources,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** and the parent certainly does not have the (locknull's) locktoken)
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (lock_list == NULL && if_header->dummy_header) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (flags & DAV_VALIDATE_IS_PARENT)
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_BAD_REQUEST, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The locktoken specified in the \"Lock-Token:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header is invalid because this resource has no "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "outstanding locks.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Prepare the input URI. We want the URI to never have a trailing slash.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** When URIs are placed into the dav_if_header structure, they are
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** guaranteed to never have a trailing slash. If the URIs are equivalent,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** then it doesn't matter if they both lack a trailing slash -- they're
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** still equivalent.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Note: we could also ensure that a trailing slash is present on both
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** URIs, but the majority of URIs provided to us via a resource walk
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** will not contain that trailing slash.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein uri = resource->uri;
f4c310fd2555c6faca1f980f00b161eadb089023gstein uri_len = strlen(uri);
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (uri[uri_len - 1] == '/') {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_set_bufsize(p, pbuf, uri_len);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe memcpy(pbuf->buf, uri, uri_len);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe pbuf->buf[--uri_len] = '\0';
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe uri = pbuf->buf;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* get the resource's etag; we may need it during the checks */
f4c310fd2555c6faca1f980f00b161eadb089023gstein etag = (*resource->hooks->getetag)(resource);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* how many state_lists apply to this URI? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein num_that_apply = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If there are if-headers, fail if this resource
f4c310fd2555c6faca1f980f00b161eadb089023gstein * does not match at least one state_list.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein for (ifhdr_scan = if_header;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_scan != NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_scan = ifhdr_scan->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* DBG2("uri=<%s> if_uri=<%s>", uri, ifhdr_scan->uri ? ifhdr_scan->uri : "(no uri)"); */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (ifhdr_scan->uri != NULL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && (uri_len != ifhdr_scan->uri_len
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe || memcmp(uri, ifhdr_scan->uri, uri_len) != 0)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** A tagged-list's URI doesn't match this resource's URI.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Skip to the next state_list to see if it will match.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe continue;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* this state_list applies to this resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### only one state_list should ever apply! a no-tag, or a tagged
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### where S9.4.2 states only one can match.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### revamp this code to loop thru ifhdr_scan until we find the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### matching state_list. process it. stop.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ++num_that_apply;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* To succeed, resource must match *all* of the states
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * specified in the state_list.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (state_list = ifhdr_scan->state;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe state_list != NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe state_list = state_list->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe switch(state_list->type) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case dav_if_etag:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe {
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz const char *given_etag, *current_etag;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz int mismatch;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz /* Do a weak entity comparison function as defined in
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz * RFC 2616 13.3.3.
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz */
0fad1368edb71b1411d6d00684900e5d2a6e6b78jerenkrantz if (state_list->etag[0] == 'W' &&
0df0055470838140d9797dd186b2fdbe67edcc57jorton state_list->etag[1] == '/') {
0df0055470838140d9797dd186b2fdbe67edcc57jorton given_etag = state_list->etag + 2;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz }
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz else {
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz given_etag = state_list->etag;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz }
0fad1368edb71b1411d6d00684900e5d2a6e6b78jerenkrantz if (etag[0] == 'W' &&
0df0055470838140d9797dd186b2fdbe67edcc57jorton etag[1] == '/') {
0df0055470838140d9797dd186b2fdbe67edcc57jorton current_etag = etag + 2;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz }
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz else {
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz current_etag = etag;
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz }
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz
3ded62d7f2c9b12616d718b8c97d3044baa9ecdbjerenkrantz mismatch = strcmp(given_etag, current_etag);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (state_list->condition == DAV_IF_COND_NORMAL && mismatch) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The specified entity-tag does not match the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** entity-tag on the resource. This state_list is
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** not going to match. Bust outta here.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe reason =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "an entity-tag was specified, but the resource's "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "actual ETag does not match.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto state_list_failed;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (state_list->condition == DAV_IF_COND_NOT
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && !mismatch) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The specified entity-tag DOES match the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** entity-tag on the resource. This state_list is
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** not going to match. Bust outta here.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe reason =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "an entity-tag was specified using the \"Not\" form, "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "but the resource's actual ETag matches the provided "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "entity-tag.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto state_list_failed;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe case dav_if_opaquelock:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (lockdb == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (state_list->condition == DAV_IF_COND_NOT) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* the locktoken is definitely not there! (success) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe continue;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* condition == DAV_IF_COND_NORMAL */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If no lockdb is provided, then validation fails for
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** this state_list (NORMAL means we were supposed to
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** find the token, which we obviously cannot do without
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** a lock database).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Go and try the next state list.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe reason =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "a State-token was supplied, but a lock database "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "is not available for to provide the required lock.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto state_list_failed;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Resource validation 'fails' if:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * ANY of the lock->locktokens match
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * a NOT state_list->locktoken,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * OR
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * NONE of the lock->locktokens match
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * a NORMAL state_list->locktoken.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe num_matched = 0;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for (lock = lock_list; lock != NULL; lock = lock->next) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe DBG2("compare: rsrc=%s ifhdr=%s",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe (*locks_hooks->format_locktoken)(p, lock->locktoken),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe (*locks_hooks->format_locktoken)(p, state_list->locktoken));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* nothing to do if the locktokens do not match. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe continue;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We have now matched up one of the resource's locktokens
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** to a locktoken in a State-token in the If: header.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Note this fact, so that we can pass the overall
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** requirement of seeing at least one of the resource's
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** locktokens.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe seen_locktoken = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (state_list->condition == DAV_IF_COND_NOT) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** This state requires that the specified locktoken
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** is NOT present on the resource. But we just found
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** it. There is no way this state-list can now
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** succeed, so go try another one.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe reason =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "a State-token was supplied, which used a "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "\"Not\" condition. The State-token was found "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "in the locks on this resource";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto state_list_failed;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* condition == DAV_IF_COND_NORMAL */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Validate auth_user: If an authenticated user created
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** the lock, only the same user may submit that locktoken
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** to manipulate a resource.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
e8f95a682820a599fe41b22977010636be5c2717jim if (lock->auth_user &&
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein (!r->user ||
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein strcmp(lock->auth_user, r->user))) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *errmsg;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm errmsg = apr_pstrcat(p, "User \"",
e8f95a682820a599fe41b22977010636be5c2717jim r->user,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "\" submitted a locktoken created "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "by user \"",
f4c310fd2555c6faca1f980f00b161eadb089023gstein lock->auth_user, "\".", NULL);
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_FORBIDDEN, 0, 0, errmsg);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We just matched a specified State-Token to one of the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** resource's locktokens.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Break out of the lock scan -- we only needed to find
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** one match (actually, there shouldn't be any other
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** matches in the lock list).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe num_matched = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (num_matched == 0
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && state_list->condition == DAV_IF_COND_NORMAL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We had a NORMAL state, meaning that we should have
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** found the State-Token within the locks on this
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** resource. We didn't, so this state_list must fail.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe reason =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "a State-token was supplied, but it was not found "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "in the locks on this resource.";
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe goto state_list_failed;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton case dav_if_unknown:
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton /* Request is predicated on some unknown state token,
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton * which must be presumed to *not* match, so fail
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton * unless this is a Not condition. */
e8f95a682820a599fe41b22977010636be5c2717jim
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton if (state_list->condition == DAV_IF_COND_NORMAL) {
e8f95a682820a599fe41b22977010636be5c2717jim reason =
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton "an unknown state token was supplied";
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton goto state_list_failed;
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton }
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton break;
42f2b4b0e9b84dfd8acbb9c0da18a07c664e30a1jorton
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe } /* switch */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe } /* foreach ( state_list ) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We've checked every state in this state_list and none of them
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** have failed. Since all of them succeeded, then we have a matching
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** state list and we may be done.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The next requirement is that we have seen one of the resource's
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** locktokens (if any). If we have, then we can just exit. If we
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** haven't, then we need to keep looking.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (seen_locktoken) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* woo hoo! */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Haven't seen one. Let's break out of the search and just look
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** for a matching locktoken.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe break;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** This label is used when we detect that a state_list is not
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** going to match this resource. We bust out and try the next
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** state_list.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
f4c310fd2555c6faca1f980f00b161eadb089023gstein state_list_failed:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein } /* foreach ( ifhdr_scan ) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** The above loop exits for one of two reasons:
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 1) a state_list matched and seen_locktoken is false.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** 2) all if_header structures were scanned, without (1) occurring
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ifhdr_scan == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We finished the loop without finding any matching state lists.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If none of the state_lists apply to this resource, then we
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** may have succeeded. Note that this scenario implies a
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** tagged-list with no matching state_lists. If the If: header
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** was a no-tag-list, then it would have applied to this resource.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** S9.4.2 states that when no state_lists apply, then the header
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** should be ignored.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe **
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If we saw one of the resource's locktokens, then we're done.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If we did not see a locktoken, then we fail.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (num_that_apply == 0) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (seen_locktoken)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We may have aborted the scan before seeing the locktoken.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Rescan the If: header to see if we can find the locktoken
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** somewhere.
f80b9e9d38dff8bc3f51406475adb99d7fe888cegstein **
f80b9e9d38dff8bc3f51406475adb99d7fe888cegstein ** Note that seen_locktoken == 0 implies lock_list != NULL
f80b9e9d38dff8bc3f51406475adb99d7fe888cegstein ** which implies locks_hooks != NULL.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (dav_find_submitted_locktoken(if_header, lock_list,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe locks_hooks)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We found a match! We're set... none of the If: header
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** assertions apply (implicit success), and the If: header
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** specified the locktoken somewhere. We're done.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_LOCKED, 0 /* error_id */, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "This resource is locked and the \"If:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header did not specify one of the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "locktokens for this resource's lock(s).");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* else: one or more state_lists were applicable, but failed. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If the dummy_header did not match, then they specified an
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** incorrect token in the Lock-Token header. Forget whether the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** If: statement matched or not... we'll tell them about the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** bad Lock-Token first. That is considered a 400 (Bad Request).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (if_header->dummy_header) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_BAD_REQUEST, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The locktoken specified in the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "\"Lock-Token:\" header did not specify one "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "of this resource's locktoken(s).");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (reason == NULL) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The preconditions specified by the \"If:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header did not match this resource.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(p,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The precondition(s) specified by "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "the \"If:\" header did not match "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "this resource. At least one "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "failure is because: %s", reason));
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* assert seen_locktoken == 0 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** ifhdr_scan != NULL implies we found a matching state_list.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Since we're still here, it also means that we have not yet found
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** one the resource's locktokens in the If: header.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Scan all the if_headers and states looking for one of this
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** resource's locktokens. Note that we need to go back and scan them
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** all -- we may have aborted a scan with a failure before we saw a
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** matching token.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Note that seen_locktoken == 0 implies lock_list != NULL which implies
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** locks_hooks != NULL.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (dav_find_submitted_locktoken(if_header, lock_list, locks_hooks)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** We found a match! We're set... we have a matching state list,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** and the If: header specified the locktoken somewhere. We're done.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** We had a matching state list, but the user agent did not specify one
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** of this resource's locktokens. Tell them so.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Note that we need to special-case the message on whether a "dummy"
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** header exists. If it exists, yet we didn't see a needed locktoken,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** then that implies the dummy header (Lock-Token header) did NOT
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** specify one of this resource's locktokens. (this implies something
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** in the real If: header matched)
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** We want to note the 400 (Bad Request) in favor of a 423 (Locked).
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (if_header->dummy_header) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_BAD_REQUEST, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The locktoken specified in the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "\"Lock-Token:\" header did not specify one "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "of this resource's locktoken(s).");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_LOCKED, 1 /* error_id */, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "This resource is locked and the \"If:\" header "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "did not specify one of the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "locktokens for this resource's lock(s).");
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_validate_walker: Walker callback function to validate resource state */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gsteinstatic dav_error * dav_validate_walker(dav_walk_resource *wres, int calltype)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_walker_ctx *ctx = wres->walk_ctx;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein if ((err = dav_validate_resource_state(ctx->w.pool, wres->resource,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx->w.lockdb,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx->if_header, ctx->flags,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe &ctx->work_buf, ctx->r)) == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* There was no error, so just bug out. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If we have a serious server error, or if the request itself failed,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** then just return error (not a multistatus).
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (ap_is_HTTP_SERVER_ERROR(err->status)
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein || (*wres->resource->hooks->is_same_resource)(wres->resource,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ctx->w.root)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe push a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* associate the error with the current URI */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_add_response(wres, err->status, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
ef1ab47476366272bf32be1439057f972bfe86edniq/* If-* header checking */
ef1ab47476366272bf32be1439057f972bfe86edniqstatic int dav_meets_conditions(request_rec *r, int resource_state)
ef1ab47476366272bf32be1439057f972bfe86edniq{
ef1ab47476366272bf32be1439057f972bfe86edniq const char *if_match, *if_none_match;
ef1ab47476366272bf32be1439057f972bfe86edniq int retVal;
ef1ab47476366272bf32be1439057f972bfe86edniq
ef1ab47476366272bf32be1439057f972bfe86edniq /* If-Match '*' fix. Resource existence not checked by ap_meets_conditions.
ef1ab47476366272bf32be1439057f972bfe86edniq * If-Match '*' request should succeed only if the resource exists. */
ef1ab47476366272bf32be1439057f972bfe86edniq if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) {
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem if (if_match[0] == '*' && resource_state != DAV_RESOURCE_EXISTS)
ef1ab47476366272bf32be1439057f972bfe86edniq return HTTP_PRECONDITION_FAILED;
ef1ab47476366272bf32be1439057f972bfe86edniq }
ef1ab47476366272bf32be1439057f972bfe86edniq
ef1ab47476366272bf32be1439057f972bfe86edniq retVal = ap_meets_conditions(r);
ef1ab47476366272bf32be1439057f972bfe86edniq
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim /* If-None-Match '*' fix. If-None-Match '*' request should succeed
ef1ab47476366272bf32be1439057f972bfe86edniq * if the resource does not exist. */
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem if (retVal == HTTP_PRECONDITION_FAILED) {
ef1ab47476366272bf32be1439057f972bfe86edniq /* Note. If if_none_match != NULL, if_none_match is the culprit.
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim * Since, in presence of If-None-Match,
ef1ab47476366272bf32be1439057f972bfe86edniq * other If-* headers are undefined. */
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem if ((if_none_match =
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem apr_table_get(r->headers_in, "If-None-Match")) != NULL) {
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem if (if_none_match[0] == '*'
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem && resource_state != DAV_RESOURCE_EXISTS) {
ef1ab47476366272bf32be1439057f972bfe86edniq return OK;
5d760c4a4841be07965080c4cec527d8f5172ef5rpluem }
ef1ab47476366272bf32be1439057f972bfe86edniq }
ef1ab47476366272bf32be1439057f972bfe86edniq }
ef1ab47476366272bf32be1439057f972bfe86edniq
ef1ab47476366272bf32be1439057f972bfe86edniq return retVal;
ef1ab47476366272bf32be1439057f972bfe86edniq}
ef1ab47476366272bf32be1439057f972bfe86edniq
f4c310fd2555c6faca1f980f00b161eadb089023gstein/*
f4c310fd2555c6faca1f980f00b161eadb089023gstein** dav_validate_request: Validate if-headers (and check for locks) on:
f4c310fd2555c6faca1f980f00b161eadb089023gstein** (1) r->filename @ depth;
f4c310fd2555c6faca1f980f00b161eadb089023gstein** (2) Parent of r->filename if check_parent == 1
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** The check of parent should be done when it is necessary to verify that
f4c310fd2555c6faca1f980f00b161eadb089023gstein** the parent collection will accept a new member (ie current resource
f4c310fd2555c6faca1f980f00b161eadb089023gstein** state is null).
f4c310fd2555c6faca1f980f00b161eadb089023gstein**
f4c310fd2555c6faca1f980f00b161eadb089023gstein** Return OK on successful validation.
f4c310fd2555c6faca1f980f00b161eadb089023gstein** On error, return appropriate HTTP_* code, and log error. If a multi-stat
f4c310fd2555c6faca1f980f00b161eadb089023gstein** error is necessary, response will point to it, else NULL.
f4c310fd2555c6faca1f980f00b161eadb089023gstein*/
e8f95a682820a599fe41b22977010636be5c2717jimDAV_DECLARE(dav_error *) dav_validate_request(request_rec *r,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz dav_resource *resource,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz int depth,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz dav_locktoken *locktoken,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz dav_response **response,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz int flags,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz dav_lockdb *lockdb)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int result;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_header *if_header;
f4c310fd2555c6faca1f980f00b161eadb089023gstein int lock_db_opened_locally = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_repository *repos_hooks = resource->hooks;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_buffer work_buf = { 0 };
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_response *new_response;
ef1ab47476366272bf32be1439057f972bfe86edniq int resource_state;
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem const char *etag;
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem int set_etag = 0;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein#if DAV_DEBUG
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (depth && response == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### bleck. we can't return errors for other URIs unless we have
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** ### a "response" ptr.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "DESIGN ERROR: dav_validate_request called "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "with depth>0, but no response ptr.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein#endif
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (response != NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *response = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
ef1ab47476366272bf32be1439057f972bfe86edniq /* Set the ETag header required by dav_meets_conditions() */
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem etag = apr_table_get(r->headers_out, "ETag");
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem if (!etag) {
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem etag = (*resource->hooks->getetag)(resource);
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem if (etag && *etag) {
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem apr_table_set(r->headers_out, "ETag", etag);
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem set_etag = 1;
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem }
ef1ab47476366272bf32be1439057f972bfe86edniq }
e8f95a682820a599fe41b22977010636be5c2717jim /* Do the standard checks for conditional requests using
f4c310fd2555c6faca1f980f00b161eadb089023gstein * If-..-Since, If-Match etc */
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem resource_state = dav_get_resource_state(r, resource);
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem result = dav_meets_conditions(r, resource_state);
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem if (set_etag) {
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem /*
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem * If we have set an ETag to headers out above for
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem * dav_meets_conditions() revert this here as we do not want to set
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem * the ETag in responses to requests with methods where this might not
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem * be desired.
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem */
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem apr_table_unset(r->headers_out, "ETag");
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem }
d64231e66711504d8e33d594fc5c27ae86e7b629rpluem if (result != OK) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, result, 0, 0, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* always parse (and later process) the If: header */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((err = dav_process_if_header(r, &if_header)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add higher-level description */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* If a locktoken was specified, create a dummy if_header with which
f4c310fd2555c6faca1f980f00b161eadb089023gstein * to validate resources. In the interim, figure out why DAV uses
f4c310fd2555c6faca1f980f00b161eadb089023gstein * locktokens in an if-header without a Lock-Token header to refresh
f4c310fd2555c6faca1f980f00b161eadb089023gstein * locks, but a Lock-Token header without an if-header to remove them.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (locktoken != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_if_header *ifhdr_new;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new = apr_pcalloc(r->pool, sizeof(*ifhdr_new));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->uri = resource->uri;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->uri_len = strlen(resource->uri);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->dummy_header = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->state = apr_pcalloc(r->pool, sizeof(*ifhdr_new->state));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->state->type = dav_if_opaquelock;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->state->condition = DAV_IF_COND_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->state->locktoken = locktoken;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ifhdr_new->next = if_header;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if_header = ifhdr_new;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If necessary, open the lock database (read-only, lazily);
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** the validation process may need to retrieve or update lock info.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Otherwise, assume provided lockdb is valid and opened rw.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (lockdb == NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (locks_hooks != NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe insert higher-level comment */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein lock_db_opened_locally = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* (1) Validate the specified resource, at the specified depth */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (resource->exists && depth > 0) {
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_walker_ctx ctx = { { 0 } };
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein dav_response *multi_status;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.w.func = dav_validate_walker;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ctx.w.walk_ctx = &ctx;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.w.pool = r->pool;
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein ctx.w.root = resource;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.if_header = if_header;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.r = r;
f4c310fd2555c6faca1f980f00b161eadb089023gstein ctx.flags = flags;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (lockdb != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.w.lockdb = lockdb;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (err == NULL) {
4f71b58f8cd75489a8e7e6e710a016a73a911efcjailletc *response = multi_status;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* else: implies a 5xx status code occurred. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein else {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = dav_validate_resource_state(r->pool, resource, lockdb,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if_header, flags, &work_buf, r);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* (2) Validate the parent resource if requested */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (err == NULL && (flags & DAV_VALIDATE_PARENT)) {
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein dav_resource *parent_resource;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein err = (*repos_hooks->get_parent_resource)(resource, &parent_resource);
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (err == NULL && parent_resource == NULL) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Cannot access parent of repository root.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else if (err == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = dav_validate_resource_state(r->pool, parent_resource, lockdb,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if_header,
f4c310fd2555c6faca1f980f00b161eadb089023gstein flags | DAV_VALIDATE_IS_PARENT,
f4c310fd2555c6faca1f980f00b161eadb089023gstein &work_buf, r);
e8f95a682820a599fe41b22977010636be5c2717jim
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /*
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** This error occurred on the parent resource. This implies that
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** we have to create a multistatus response (to report the error
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** against a URI other than the Request-URI). "Convert" this error
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** into a multistatus response.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (err != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_response = apr_pcalloc(r->pool, sizeof(*new_response));
e8f95a682820a599fe41b22977010636be5c2717jim
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_response->href = parent_resource->uri;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_response->status = err->status;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_response->desc =
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "A validation error has occurred on the parent resource, "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "preventing the operation on the resource specified by "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "the Request-URI.";
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (err->desc != NULL) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm new_response->desc = apr_pstrcat(r->pool,
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->desc,
f4c310fd2555c6faca1f980f00b161eadb089023gstein " The error was: ",
f4c310fd2555c6faca1f980f00b161eadb089023gstein err->desc, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
e8f95a682820a599fe41b22977010636be5c2717jim
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* assert: DAV_VALIDATE_PARENT implies response != NULL */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe new_response->next = *response;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *response = new_response;
e8f95a682820a599fe41b22977010636be5c2717jim
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = NULL;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (lock_db_opened_locally)
f4c310fd2555c6faca1f980f00b161eadb089023gstein (*locks_hooks->close_lockdb)(lockdb);
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If we don't have a (serious) error, and we have multistatus responses,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** then we need to construct an "error". This error will be the overall
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** status returned, and the multistatus responses will go into its body.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For certain methods, the overall error will be a 424. The default is
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** to construct a standard 207 response.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (err == NULL && response != NULL && *response != NULL) {
0946f90438dcf29a5fe5d9e21559b3b9d640bc12wrowe apr_text *propstat = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((flags & DAV_VALIDATE_USE_424) != 0) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* manufacture a 424 error to hold the multistatus response(s) */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_FAILED_DEPENDENCY, 0, 0,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "An error occurred on another resource, "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "preventing the requested operation on "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "this resource.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /*
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Whatever caused the error, the Request-URI should have a 424
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** associated with it since we cannot complete the method.
f4c310fd2555c6faca1f980f00b161eadb089023gstein **
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For a LOCK operation, insert an empty DAV:lockdiscovery property.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For other methods, return a simple 424.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((flags & DAV_VALIDATE_ADD_LD) != 0) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm propstat = apr_pcalloc(r->pool, sizeof(*propstat));
f4c310fd2555c6faca1f980f00b161eadb089023gstein propstat->text =
f4c310fd2555c6faca1f980f00b161eadb089023gstein "<D:propstat>" DEBUG_CR
f4c310fd2555c6faca1f980f00b161eadb089023gstein "<D:prop><D:lockdiscovery/></D:prop>" DEBUG_CR
f4c310fd2555c6faca1f980f00b161eadb089023gstein "<D:status>HTTP/1.1 424 Failed Dependency</D:status>" DEBUG_CR
f4c310fd2555c6faca1f980f00b161eadb089023gstein "</D:propstat>" DEBUG_CR;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* create the 424 response */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm new_response = apr_pcalloc(r->pool, sizeof(*new_response));
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->href = resource->uri;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->status = HTTP_FAILED_DEPENDENCY;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->propresult.propstats = propstat;
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->desc =
f4c310fd2555c6faca1f980f00b161eadb089023gstein "An error occurred on another resource, preventing the "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "requested operation on this resource.";
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein new_response->next = *response;
f4c310fd2555c6faca1f980f00b161eadb089023gstein *response = new_response;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* manufacture a 207 error for the multistatus response(s) */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, 0,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Error(s) occurred on resources during the "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "validation process.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_get_locktoken_list:
f4c310fd2555c6faca1f980f00b161eadb089023gstein *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * Sets ltl to a locktoken_list of all positive locktokens in header,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * else NULL if no If-header, or no positive locktokens.
f4c310fd2555c6faca1f980f00b161eadb089023gstein */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(dav_error *) dav_get_locktoken_list(request_rec *r,
e8f95a682820a599fe41b22977010636be5c2717jim dav_locktoken_list **ltl)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_error *err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_header *if_header;
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_if_state_list *if_state;
e8f95a682820a599fe41b22977010636be5c2717jim dav_locktoken_list *lock_token = NULL;
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein *ltl = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((err = dav_process_if_header(r, &if_header)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return err;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
e8f95a682820a599fe41b22977010636be5c2717jim
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (if_header != NULL) {
5f6996f1e3091d47af542c2437464bbc7e2e5b67jailletc if_state = if_header->state; /* Beginning of the if_state linked list */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe while (if_state != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (if_state->condition == DAV_IF_COND_NORMAL
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && if_state->type == dav_if_opaquelock) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe lock_token = apr_pcalloc(r->pool, sizeof(dav_locktoken_list));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe lock_token->locktoken = if_state->locktoken;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe lock_token->next = *ltl;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe *ltl = lock_token;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
e8f95a682820a599fe41b22977010636be5c2717jim if_state = if_state->next;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if_header = if_header->next;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (*ltl == NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* No nodes added */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_ABSENT, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "No locktokens were specified in the \"If:\" "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "header, so the refresh could not be performed.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f39230a531b23d94f86a087963299bbe2e431a4agstein#if 0 /* not needed right now... */
f39230a531b23d94f86a087963299bbe2e431a4agstein
50bd75672ef114fb839dd9643c192b432fdf344cgsteinstatic const char *strip_white(const char *s, apr_pool_t *pool)
50bd75672ef114fb839dd9643c192b432fdf344cgstein{
50bd75672ef114fb839dd9643c192b432fdf344cgstein apr_size_t idx;
50bd75672ef114fb839dd9643c192b432fdf344cgstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein /* trim leading whitespace */
50bd75672ef114fb839dd9643c192b432fdf344cgstein while (apr_isspace(*s)) /* assume: return false for '\0' */
50bd75672ef114fb839dd9643c192b432fdf344cgstein ++s;
50bd75672ef114fb839dd9643c192b432fdf344cgstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein /* trim trailing whitespace */
50bd75672ef114fb839dd9643c192b432fdf344cgstein idx = strlen(s) - 1;
50bd75672ef114fb839dd9643c192b432fdf344cgstein if (apr_isspace(s[idx])) {
50bd75672ef114fb839dd9643c192b432fdf344cgstein char *s2 = apr_pstrdup(pool, s);
50bd75672ef114fb839dd9643c192b432fdf344cgstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein while (apr_isspace(s2[idx]) && idx > 0)
50bd75672ef114fb839dd9643c192b432fdf344cgstein --idx;
50bd75672ef114fb839dd9643c192b432fdf344cgstein s2[idx + 1] = '\0';
50bd75672ef114fb839dd9643c192b432fdf344cgstein return s2;
50bd75672ef114fb839dd9643c192b432fdf344cgstein }
50bd75672ef114fb839dd9643c192b432fdf344cgstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein return s;
50bd75672ef114fb839dd9643c192b432fdf344cgstein}
f39230a531b23d94f86a087963299bbe2e431a4agstein#endif
50bd75672ef114fb839dd9643c192b432fdf344cgstein
f39230a531b23d94f86a087963299bbe2e431a4agstein#define DAV_LABEL_HDR "Label"
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein/* dav_add_vary_header
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein *
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * If there were any headers in the request which require a Vary header
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * in the response, add it.
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(void) dav_add_vary_header(request_rec *in_req,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz request_rec *out_req,
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantz const dav_resource *resource)
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein{
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req);
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
f39230a531b23d94f86a087963299bbe2e431a4agstein /* ### this is probably all wrong... I think there is a function in
f39230a531b23d94f86a087963299bbe2e431a4agstein ### the Apache API to add things to the Vary header. need to check */
f39230a531b23d94f86a087963299bbe2e431a4agstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* Only versioning headers require a Vary response header,
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * so only do this check if there is a versioning provider */
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein if (vsn_hooks != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *vary = apr_table_get(out_req->headers_out, "Vary");
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* If Target-Selector specified, add it to the Vary header */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (target != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (vary == NULL)
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe vary = DAV_LABEL_HDR;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe else
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR,
f39230a531b23d94f86a087963299bbe2e431a4agstein NULL);
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_table_setn(out_req->headers_out, "Vary", vary);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein/* dav_can_auto_checkout
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein *
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * Determine whether auto-checkout is enabled for a resource.
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * r - the request_rec
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * resource - the resource
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * auto_version - the value of the auto_versionable hook for the resource
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * lockdb - pointer to lock database (opened if necessary)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * auto_checkout - set to 1 if auto-checkout enabled
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gsteinstatic dav_error * dav_can_auto_checkout(
e8f95a682820a599fe41b22977010636be5c2717jim request_rec *r,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_resource *resource,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_auto_version auto_version,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_lockdb **lockdb,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein int *auto_checkout)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein{
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_error *err;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_lock *lock_list;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein *auto_checkout = 0;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (auto_version == DAV_AUTO_VERSION_ALWAYS) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein *auto_checkout = 1;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein else if (auto_version == DAV_AUTO_VERSION_LOCKED) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (*lockdb == NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (locks_hooks == NULL) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "Auto-checkout is only enabled for locked resources, "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "but there is no lock provider.");
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, lockdb)) != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "Cannot open lock database to determine "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "auto-versioning behavior.",
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = dav_lock_query(*lockdb, resource, &lock_list)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_push_error(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The locks could not be queried for "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "determining auto-versioning behavior.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (lock_list != NULL)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein *auto_checkout = 1;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein}
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein/* see mod_dav.h for docco */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(dav_error *) dav_auto_checkout(
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein request_rec *r,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_resource *resource,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein int parent_only,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_auto_version_info *av_info)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_lockdb *lockdb = NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_error *err = NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* Initialize results */
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein memset(av_info, 0, sizeof(*av_info));
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if no versioning provider, just return */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (vsn_hooks == NULL)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* check parent resource if requested or if resource must be created */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (!resource->exists || parent_only) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_resource *parent;
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein if ((err = (*resource->hooks->get_parent_resource)(resource,
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein &parent)) != NULL)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein if (parent == NULL || !parent->exists) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(r->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Missing one or more intermediate "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "collections. Cannot create resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)));
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein av_info->parent_resource = parent;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if parent versioned and not checked out, see if it can be */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (parent->versioned && !parent->working) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein int checkout_parent;
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = dav_can_auto_checkout(r, parent,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein (*vsn_hooks->auto_versionable)(parent),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein &lockdb, &checkout_parent))
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (!checkout_parent) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(r->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "<DAV:cannot-modify-checked-in-parent>");
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein }
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* Try to checkout the parent collection.
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * Note that auto-versioning can only be applied to a version selector,
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * so no separate working resource will be created.
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = (*vsn_hooks->checkout)(parent, 1 /*auto_checkout*/,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein 0, 0, 0, NULL, NULL))
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein != NULL)
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to auto-checkout parent collection. "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Cannot create resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
50bd75672ef114fb839dd9643c192b432fdf344cgstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* remember that parent was checked out */
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein av_info->parent_checkedout = 1;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if only checking parent, we're done */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (parent_only)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if creating a new resource, see if it should be version-controlled */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (!resource->exists
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein && (*vsn_hooks->auto_versionable)(resource) == DAV_AUTO_VERSION_ALWAYS) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = (*vsn_hooks->vsn_control)(resource, NULL)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to create versioned resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* remember that resource was created */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein av_info->resource_versioned = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if resource is versioned, make sure it is checked out */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (resource->versioned && !resource->working) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein int checkout_resource;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = dav_can_auto_checkout(r, resource,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein (*vsn_hooks->auto_versionable)(resource),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein &lockdb, &checkout_resource)) != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (!checkout_resource) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(r->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "<DAV:cannot-modify-version-controlled-content>");
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* Auto-versioning can only be applied to version selectors, so
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein * no separate working resource will be created. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = (*vsn_hooks->checkout)(resource, 1 /*auto_checkout*/,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein 0, 0, 0, NULL, NULL))
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein != NULL)
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err = dav_push_error(r->pool, HTTP_CONFLICT, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to checkout resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein goto done;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
50bd75672ef114fb839dd9643c192b432fdf344cgstein
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein /* remember that resource was checked out */
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein av_info->resource_checkedout = 1;
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gsteindone:
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* make sure lock database is closed */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (lockdb != NULL)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein (*lockdb->hooks->close_lockdb)(lockdb);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* if an error occurred, undo any auto-versioning operations already done */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (err != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_auto_checkin(r, resource, 1 /*undo*/, 0 /*unlock*/, av_info);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return err;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}
f4c310fd2555c6faca1f980f00b161eadb089023gstein
50bd75672ef114fb839dd9643c192b432fdf344cgstein/* see mod_dav.h for docco */
0206c121a68a63559b2e843288e81bcf16093e46jerenkrantzDAV_DECLARE(dav_error *) dav_auto_checkin(
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein request_rec *r,
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein dav_resource *resource,
83719c22db4a6d0575bb4f7f34382d7b185a6f74gstein int undo,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein int unlock,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_auto_version_info *av_info)
f4c310fd2555c6faca1f980f00b161eadb089023gstein{
f4c310fd2555c6faca1f980f00b161eadb089023gstein const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_error *err = NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein dav_auto_version auto_version;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* If no versioning provider, this is a no-op */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (vsn_hooks == NULL)
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* If undoing auto-checkouts, then do uncheckouts */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (undo) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (resource != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (av_info->resource_checkedout) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = (*vsn_hooks->uncheckout)(resource)) != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to undo auto-checkout "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "of resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (av_info->resource_versioned) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_response *response;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should we do anything with the response? */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = (*resource->hooks->remove_resource)(resource,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe &response)) != NULL) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to undo auto-version-control "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "of resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein err);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (av_info->parent_resource != NULL && av_info->parent_checkedout) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = (*vsn_hooks->uncheckout)(av_info->parent_resource)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to undo auto-checkout "
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein "of parent collection %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, av_info->parent_resource->uri)),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein return NULL;
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* If the resource was checked out, and auto-checkin is enabled,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * then check it in.
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein */
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (resource != NULL && resource->working
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein && (unlock || av_info->resource_checkedout)) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein auto_version = (*vsn_hooks->auto_versionable)(resource);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if (auto_version == DAV_AUTO_VERSION_ALWAYS ||
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein (unlock && (auto_version == DAV_AUTO_VERSION_LOCKED))) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein if ((err = (*vsn_hooks->checkin)(resource,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein 0 /*keep_checked_out*/, NULL))
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein != NULL) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to auto-checkin resource %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, resource->uri)),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err);
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein /* If parent resource was checked out, and auto-checkin is enabled,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein * then check it in.
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein */
cdcb6937fbc9f4283e1783a0d43b62e9e8ad08d3gstein if (!unlock
cdcb6937fbc9f4283e1783a0d43b62e9e8ad08d3gstein && av_info->parent_checkedout
cdcb6937fbc9f4283e1783a0d43b62e9e8ad08d3gstein && av_info->parent_resource != NULL
cdcb6937fbc9f4283e1783a0d43b62e9e8ad08d3gstein && av_info->parent_resource->working) {
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein auto_version = (*vsn_hooks->auto_versionable)(av_info->parent_resource);
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein
cdcb6937fbc9f4283e1783a0d43b62e9e8ad08d3gstein if (auto_version == DAV_AUTO_VERSION_ALWAYS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = (*vsn_hooks->checkin)(av_info->parent_resource,
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein 0 /*keep_checked_out*/, NULL))
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_psprintf(r->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Unable to auto-checkin parent collection %s.",
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ap_escape_html(r->pool, av_info->parent_resource->uri)),
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe err);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe }
4d0b0b6d8341c5e54b2081665fc91b4e4f781753gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein }
f4c310fd2555c6faca1f980f00b161eadb089023gstein
f4c310fd2555c6faca1f980f00b161eadb089023gstein return NULL;
f4c310fd2555c6faca1f980f00b161eadb089023gstein}