props.c revision 252e2478cb56afb5ca8585b50bc2ffb780d2efb6
842ae4bd224140319ae7feec1872b93dfd491143fielding/* ====================================================================
842ae4bd224140319ae7feec1872b93dfd491143fielding * The Apache Software License, Version 1.1
842ae4bd224140319ae7feec1872b93dfd491143fielding * Copyright (c) 2000 The Apache Software Foundation. All rights
842ae4bd224140319ae7feec1872b93dfd491143fielding * reserved.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 2. Redistributions in binary form must reproduce the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the documentation and/or other materials provided with the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distribution.
e8f95a682820a599fe41b22977010636be5c2717jim * 3. The end-user documentation included with the redistribution,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if any, must include the following acknowledgment:
e8f95a682820a599fe41b22977010636be5c2717jim * "This product includes software developed by the
1747d30b98aa1bdbc43994c02cd46ab4cb9319e4fielding * Apache Software Foundation (http://www.apache.org/)."
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Alternately, this acknowledgment may appear in the software itself,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if and wherever such third-party acknowledgments normally appear.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 4. The names "Apache" and "Apache Software Foundation" must
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * not be used to endorse or promote products derived from this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * software without prior written permission. For written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission, please contact apache@apache.org.
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * 5. Products derived from this software may not be called "Apache",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * nor may "Apache" appear in their name, without prior written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission of the Apache Software Foundation.
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * SUCH DAMAGE.
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * ====================================================================
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * This software consists of voluntary contributions made by many
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * individuals on behalf of the Apache Software Foundation. For more
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * information on the Apache Software Foundation, please see
0f60998368b493f90120180a93fc2e1e74490872covener** DAV extension module for Apache 2.0.*
0f60998368b493f90120180a93fc2e1e74490872covener** - Property database handling (repository-independent)
0f60998368b493f90120180a93fc2e1e74490872covener** PROPERTY DATABASE
87587593f1a53030e840acc0dec6cc881022ea40covener** This version assumes that there is a per-resource database provider
87587593f1a53030e840acc0dec6cc881022ea40covener** to record properties. The database provider decides how and where to
87587593f1a53030e840acc0dec6cc881022ea40covener** store these databases.
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener** The DBM keys for the properties have the following form:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** namespace ":" propname
fa123db15501821e36e513afa78e839775ad2800covener** For example: 5:author
0568280364eb026393be492ebc732795c4934643jorton** The namespace provides an integer index into the namespace table
0568280364eb026393be492ebc732795c4934643jorton** (see below). propname is simply the property name, without a namespace
0568280364eb026393be492ebc732795c4934643jorton** A special case exists for properties that had a prefix starting with
0568280364eb026393be492ebc732795c4934643jorton** "xml". The XML Specification reserves these for future use. mod_dav
0568280364eb026393be492ebc732795c4934643jorton** stores and retrieves them unchanged. The keys for these properties
0568280364eb026393be492ebc732795c4934643jorton** have the form:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** ":" propname
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The propname will contain the prefix and the property name. For
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** example, a key might be ":xmlfoo:name"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The ":name" style will also be used for properties that do not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** exist within a namespace.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The DBM values consist of two null-terminated strings, appended
796e4a7141265d8ed7036e4628161c6eafb2a789jorton** together (the null-terms are retained and stored in the database).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The first string is the xml:lang value for the property. An empty
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** string signifies that a lang value was not in context for the value.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The second string is the property value itself.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** NAMESPACE TABLE
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The namespace table is an array that lists each of the namespaces
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** that are in use by the properties in the given propdb. Each entry
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** in the array is a simple URI.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** For example: http://www.foo.bar/standards/props/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The prefix used for the property is stripped and the URI for it
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** is entered into the namespace table. Also, any namespaces used
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** within the property value will be entered into the table (and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** stripped from the child elements).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** The namespaces are stored in the DBM database under the "METADATA" key.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** STRIPPING NAMESPACES
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** Within the property values, the namespace declarations (xmlns...)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** are stripped. Each element and attribute will have its prefix removed
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** and a new prefix inserted.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** This must be done so that we can return multiple properties in a
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin** PROPFIND which may have (originally) used conflicting prefixes. For
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin** that case, we must bind all property value elements to new namespace
713a2b68bac4aeb1e9c48785006c0732451039depquerna** This implies that clients must NOT be sensitive to the namespace
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** prefix used for their properties. It WILL change when the properties
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** are returned (we return them as "ns<index>", e.g. "ns5"). Also, the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** property value can contain ONLY XML elements and CDATA. PI and comment
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** elements will be stripped. CDATA whitespace will be preserved, but
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** whitespace within element tags will be altered. Attribute ordering
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe** may be altered. Element and CDATA ordering will be preserved.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** ATTRIBUTES ON PROPERTY NAME ELEMENTS
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** When getting/setting properties, the XML used looks like:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** <propname1>value</propname1>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** <propname2>value</propname1>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** This implementation (mod_dav) DOES NOT save any attributes that are
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes** associated with the <propname1> element. The property value is deemed
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** to be only the contents ("value" in the above example).
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** We do store the xml:lang value (if any) that applies to the context
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** of the <propname1> element. Whether the xml:lang attribute is on
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** <propname1> itself, or from a higher level element, we will store it
fa123db15501821e36e513afa78e839775ad2800covener** with the property value.
fa123db15501821e36e513afa78e839775ad2800covener** VERSIONING
fa123db15501821e36e513afa78e839775ad2800covener** The DBM db contains a key named "METADATA" that holds database-level
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** information, such as the namespace table. The record also contains the
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** db's version number as the very first 16-bit value. This first number
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** is actually stored as two single bytes: the first byte is a "major"
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener** version number. The second byte is a "minor" number.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** If the major number is not what mod_dav expects, then the db is closed
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** immediately and an error is returned. A minor number change is
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** acceptable -- it is presumed that old/new dav_props.c can deal with
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** the database format. For example, a newer dav_props might update the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** minor value and append information to the end of the metadata record
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** (which would be ignored by previous versions).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** At the moment, for the dav_get_allprops() and dav_get_props() functions,
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** we must return a set of xmlns: declarations for ALL known namespaces
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** in the file. There isn't a way to filter this because we don't know
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** which are going to be used or not. Examining property names is not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** sufficient because the property values could use entirely different
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** namespaces.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** ==> we must devise a scheme where we can "garbage collect" the namespace
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** entries from the property database.
f2be127030aa4190033084f0a6add531c9bc41desf** There is some rough support for writeable DAV:getcontenttype and
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** DAV:getcontentlanguage properties. If this #define is (1), then
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** this support is disabled.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** We are disabling it because of a lack of support in GET and PUT
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covener** operations. For GET, it would be "expensive" to look for a propdb,
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covener** open it, and attempt to extract the Content-Type and Content-Language
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** values for the response.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener** (Handling the PUT would not be difficult, though)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/* the namespace URI was not found; no ID is available */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener#define AP_XML_NS_ERROR_NOT_FOUND (AP_XML_NS_ERROR_BASE)
6683642c1e0032eeeed5f99e8c14880692ef84c5sftypedef struct {
6683642c1e0032eeeed5f99e8c14880692ef84c5sf unsigned char major;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** V4 -- 0.9.9 ..
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** Prior versions could have keys or values with invalid
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** namespace prefixes as a result of the xmlns="" form not
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** resetting the default namespace to be "no namespace". The
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** namespace would be set to "" which is invalid; it should
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** be set to "no namespace".
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** V3 -- 0.9.8
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** Prior versions could have values with invalid namespace
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** prefixes due to an incorrect mapping of input to propdb
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** namespace indices. Version bumped to obsolete the old
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** V2 -- 0.9.7
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** This introduced the xml:lang value into the property value's
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** record in the propdb.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** V1 -- .. 0.9.6
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ** Initial version.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener unsigned char minor;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_db *db; /* underlying database containing props */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_buffer ns_table; /* table of namespace URIs */
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj ap_array_header_t *ns_xlate; /* translation of an elem->ns to URI */
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj int incomplete_map; /* some mappings do not exist */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin dav_buffer wb_key; /* work buffer for dav_gdbm_key */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes dav_buffer wb_lock; /* work buffer for lockdiscovery property */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* if we ever run a GET subreq, it will be stored here */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* hooks we should use for processing (based on the target resource) */
513b324e774c559b579896df131fd7c8471ed529rederpj/* ### move these into a "core" liveprop provider? */
513b324e774c559b579896df131fd7c8471ed529rederpjstatic const char * const dav_core_props[] =
513b324e774c559b579896df131fd7c8471ed529rederpj "getcontenttype",
513b324e774c559b579896df131fd7c8471ed529rederpj "getcontentlanguage",
513b324e774c559b579896df131fd7c8471ed529rederpj "lockdiscovery",
513b324e774c559b579896df131fd7c8471ed529rederpj "resourcetype",
513b324e774c559b579896df131fd7c8471ed529rederpj "supportedlock",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes#define DAV_IS_CORE_PROP(propid) ((propid) >= DAV_PROPID_CORE && \
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** This structure is used to track information needed for a rollback.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes** If a SET was performed and no prior value existed, then value.dptr
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** will be NULL.
707f6d077f73cc948deead8df5b40ea42c1eaa78covenertypedef struct dav_rollback_item {
707f6d077f73cc948deead8df5b40ea42c1eaa78covener dav_datum value; /* value before set/replace/delete */
707f6d077f73cc948deead8df5b40ea42c1eaa78covener /* or use the following (choice selected by dav_prop_ctx.is_liveprop) */
707f6d077f73cc948deead8df5b40ea42c1eaa78covener struct dav_liveprop_rollback *liveprop; /* liveprop rollback ctx */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/* ### unused */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *dav_get_ns_table_uri(dav_propdb *propdb, int ns)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic void dav_find_liveprop(dav_propdb *propdb, ap_xml_elem *elem)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *ns_uri;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char * const *p = dav_core_props;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* didn't find it. fall thru. a provider can define DAV: props */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* policy: liveprop providers cannot define no-namespace properties */
707f6d077f73cc948deead8df5b40ea42c1eaa78covener ns_uri = AP_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns);
707f6d077f73cc948deead8df5b40ea42c1eaa78covener for (ddh = propdb->liveprop; ddh != NULL; ddh = ddh->next) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj propid = (*DAV_AS_HOOKS_LIVEPROP(ddh)->find_prop)(ns_uri, elem->name);
707f6d077f73cc948deead8df5b40ea42c1eaa78covener/* is the live property read/write? */
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic int dav_rw_liveprop(dav_propdb *propdb, int propid)
707f6d077f73cc948deead8df5b40ea42c1eaa78covener /* these are defined as read-only */
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* these are defined as read/write */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ** Check the liveprop providers
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for (ddh = propdb->liveprop; ddh != NULL; ddh = ddh->next) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes rw = (*DAV_AS_HOOKS_LIVEPROP(ddh)->is_writeable)(propdb->resource,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ** No provider recognized the property, so it must be dead (and writable)
7add8f7fb048534390571801b7794f71cd9e127abnicholes/* do a sub-request to fetch properties for the target resource's URI. */
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes /* perform a "GET" on the resource's URI (note that the resource
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes may not correspond to the current request!). */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic dav_error * dav_insert_coreprop(dav_propdb *propdb,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* fast-path the common case */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf switch (propid) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### should we denote lock-null resources? */
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* ### bad juju */
7dbf29be626018bc389ef94c1846aeac4b72633bsf if ((err = dav_lock_query(propdb->lockdb, propdb->resource,
7dbf29be626018bc389ef94c1846aeac4b72633bsf "DAV:lockdiscovery could not be "
7dbf29be626018bc389ef94c1846aeac4b72633bsf "determined due to a problem fetching "
7dbf29be626018bc389ef94c1846aeac4b72633bsf "the locks for this resource.",
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* fast-path the no-locks case */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ** This may modify the buffer. value may point to
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ** wb_lock.pbuf or a string constant.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* make a copy to isolate it from changes to wb_lock */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes value = (*propdb->lockdb->hooks->get_supportedlock)();
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *lang;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((lang = ap_table_get(propdb->subreq->headers_out,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* fall through to interpret as a dead property */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if something was supplied, then insert it */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *s;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* use D: prefix to refer to the DAV: namespace URI */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* use D: prefix to refer to the DAV: namespace URI */
9c63a05713cb83a44a1590b4af33edeebf39f118sfstatic dav_error * dav_insert_liveprop(dav_propdb *propdb,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_insert_coreprop(propdb, priv->propid, elem->name,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ask the provider (that defined this prop) to insert the prop */
9c63a05713cb83a44a1590b4af33edeebf39f118sf pi = (*priv->provider->insert_prop)(propdb->resource, priv->propid,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### the provider should have returned NOTDEF, at least */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "DESIGN ERROR: a liveprop provider defined "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "a property, but did not respond to the "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "insert_prop hook for it.");
54d22ed1c429b903b029bbd62621f11a9e286137minfrin const char *s;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* skip past the xml:lang value */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* the property is an empty value */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* "no namespace" case */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin s = ap_psprintf(propdb->p, "<%s/>" DEBUG_CR, name+1);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin s = ap_psprintf(propdb->p, "<ns%s/>" DEBUG_CR, name);
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener /* "no namespace" case */
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener s = ap_psprintf(propdb->p, "<%s xml:lang=\"%s\">%s</%s>" DEBUG_CR,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin s = ap_psprintf(propdb->p, "<ns%s xml:lang=\"%s\">%s</ns%s>" DEBUG_CR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* "no namespace" case */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes s = ap_psprintf(propdb->p, "<%s>%s</%s>" DEBUG_CR, name+1, value, name+1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes s = ap_psprintf(propdb->p, "<ns%s>%s</ns%s>" DEBUG_CR, name, value, name);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** Prepare the ns_map variable in the propdb structure. This entails copying
e8f95a682820a599fe41b22977010636be5c2717jim** all URIs from the "input" namespace list (in propdb->ns_xlate) into the
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** propdb's list of namespaces. As each URI is copied (or pre-existing
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** URI looked up), the index mapping is stored into the ns_map variable.
f0f6f1b90ab582896f8a7d56d85bd62a55e57d90covener** Note: we must copy all declared namespaces because we cannot easily
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe** determine which input namespaces were actually used within the property
54d22ed1c429b903b029bbd62621f11a9e286137minfrin** values that are being stored within the propdb. Theoretically, we can
560fd0658902ab57754616c172d8953e69fc4722bnicholes** determine this at the point where we serialize the property values
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener** back into strings. This would require a bit more work, and will be
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** left to future optimizations.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** ### we should always initialize the propdb namespace array with "DAV:"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** ### since we know it will be entered anyhow (by virtue of it always
9ad7b260be233be7d7b5576979825cac72e15498rederpj** ### occurring in the ns_xlate array). That will allow us to use
9ad7b260be233be7d7b5576979825cac72e15498rederpj** ### AP_XML_NS_DAV_ID for propdb ns values, too.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void dav_prep_ns_map(dav_propdb *propdb, int add_ns)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char **puri;
560fd0658902ab57754616c172d8953e69fc4722bnicholes int updating = 0; /* are we updating an existing ns_map? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we must revisit the map and insert new entries */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* nothing to do: we have a proper ns_map */
e8f95a682820a599fe41b22977010636be5c2717jim propdb->ns_map = ap_palloc(propdb->p, propdb->ns_xlate->nelts * sizeof(*propdb->ns_map));
7a55c294da84865fe13262ed66ffd0c5841a9da5covener /* ### stupid O(n * orig_count) algorithm */
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener for (i = propdb->ns_xlate->nelts, puri = (const char **)propdb->ns_xlate->elts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* updating an existing mapping... we can skip a lot of stuff */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This entry has been filled in, so we can skip it */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *p;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** GIVEN: uri (a namespace URI from the request input)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** FIND: an equivalent URI in the propdb namespace table
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* only scan original entries (we may have added some in here) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (p = propdb->ns_table.buf + sizeof(dav_propdb_metadata),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** This flag indicates that we have an ns_map with missing
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** entries. If dav_prep_ns_map() is called with add_ns==1 AND
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** this flag is set, then we zip thru the array and add those
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** URIs (effectively updating the ns_map as if add_ns=1 was
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** passed when the initial prep was called).
0e05808dc59a321566303084c84b9826a4353cefrederpj ** The input URI was not found in the propdb namespace table, and
ebe5305f8b22507374358f32b74d12fb50c05a25covener ** we are supposed to add it. Append it to the table and store
ebe5305f8b22507374358f32b74d12fb50c05a25covener ** the index into the ns_map.
ebe5305f8b22507374358f32b74d12fb50c05a25covener dav_check_bufsize(propdb->p, &propdb->ns_table, uri_len + 1);
ebe5305f8b22507374358f32b74d12fb50c05a25covener memcpy(propdb->ns_table.buf + propdb->ns_table.cur_len, uri, uri_len + 1);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/* find the "DAV:" namespace in our table and return its ID. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata);
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* the "DAV:" namespace is not present */
54d22ed1c429b903b029bbd62621f11a9e286137minfrinstatic void dav_insert_xmlns(ap_pool_t *p, const char *pre_prefix, int ns,
560fd0658902ab57754616c172d8953e69fc4722bnicholes const char *s;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin s = ap_psprintf(p, " xmlns:%s%d=\"%s\"", pre_prefix, ns, ns_uri);
7a55c294da84865fe13262ed66ffd0c5841a9da5covener/* return all known namespaces (in this propdb) */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void dav_get_propdb_xmlns(dav_propdb *propdb, ap_text_header *phdr)
fa123db15501821e36e513afa78e839775ad2800covener const char *p = propdb->ns_table.buf + sizeof(dav_propdb_metadata);
fa123db15501821e36e513afa78e839775ad2800covener /* note: ns_count == 0 when we have no propdb file */
fa123db15501821e36e513afa78e839775ad2800covener for (i = 0; i < propdb->ns_count; ++i, p += len + 1) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* add a namespace decl from one of the namespace tables */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void dav_add_marked_xmlns(dav_propdb *propdb, char *marks, int ns,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes pre_prefix, ns, AP_XML_GET_URI_ITEM(ns_table, ns),
e8f95a682820a599fe41b22977010636be5c2717jim** Internal function to build a key
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe** WARNING: returns a pointer to a "static" buffer holding the key. The
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** value must be copied or no longer used if this function is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes** called again.
e8f95a682820a599fe41b22977010636be5c2717jimstatic dav_datum dav_gdbm_key(dav_propdb *propdb, const ap_xml_elem *elem)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Convert namespace ID to a string. "no namespace" is an empty string,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * so the keys will have the form ":name". Otherwise, the keys will
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * have the form "#:name".
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Note that we prep the map and do NOT add namespaces. If that
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is required, then the caller should have called prep
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * beforehand, passing the correct values.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* assemble: #:name */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_set_bufsize(propdb->p, &propdb->wb_key, l_ns + 1 + l_name + 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes memcpy(&propdb->wb_key.buf[l_ns + 1], elem->name, l_name + 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* build the database key */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic dav_error *dav_really_open_db(dav_propdb *propdb, int ro)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we're trying to open the db; turn off the 'deferred' flag */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ask the DB provider to open the thing */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = (*propdb->db_hooks->open)(propdb->p, propdb->resource, ro,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Could not open the property database.",
43c3e6a4b559b76b750c245ee95e2782c15b4296jim ** NOTE: propdb->db could be NULL if we attempted to open a readonly
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** database that doesn't exist. If we require read/write
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** access, then a database was created and opened.
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener if ((err = (*propdb->db_hooks->fetch)(propdb->db, key,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* ### push a higher-level description? */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * If there is no METADATA key, then the database may be
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * from versions 0.9.0 .. 0.9.4 (which would be incompatible).
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * These can be identified by the presence of an NS_TABLE entry.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((*propdb->db_hooks->exists)(propdb->db, key)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* call it a major version error */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Prop database has the wrong major "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "version number and cannot be used.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* initialize a new metadata structure */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_set_bufsize(propdb->p, &propdb->ns_table, sizeof(m));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes dav_set_bufsize(propdb->p, &propdb->ns_table, value.dsize);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Prop database has the wrong major "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "version number and cannot be used.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (*propdb->db_hooks->freedatum)(propdb->db, value);
e8f95a682820a599fe41b22977010636be5c2717jimdav_error *dav_open_propdb(request_rec *r, dav_lockdb *lockdb,
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe dav_propdb *propdb = ap_pcalloc(r->pool, sizeof(*propdb));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "INTERNAL DESIGN ERROR: resource must define "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "its URI.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes propdb->liveprop = dav_get_provider_hooks(r, DAV_DYN_TYPE_LIVEPROP);
e8f95a682820a599fe41b22977010636be5c2717jim else if ((err = dav_really_open_db(propdb, 1 /* ro */)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### what to do about closing the propdb on server failure? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* fill in the metadata that we store into the prop db. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes m.minor = propdb->version; /* ### keep current minor version? */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj err = (*propdb->db_hooks->store)(propdb->db, key, value);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* ### what to do with the error? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesdav_get_props_result dav_get_allprops(dav_propdb *propdb, int getvals)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char * const * scan_uri;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* generate all the namespaces that are in the propdb */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* initialize the result with some start tags... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if there ARE properties, then scan them */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* any keys with leading capital letters should be skipped
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (real keys start with a number or a colon) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** See if this is the <DAV:resourcetype> property. We need to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** know whether it was found (and therefore, whether to supply
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** a default later).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** We also look for <DAV:getcontenttype> and
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ** <DAV:getcontentlanguage>. If they are not stored as dead
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ** properties, then we need to perform a subrequest to get
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** their values (if any).
e8f95a682820a599fe41b22977010636be5c2717jim const char *colon;
e8f95a682820a599fe41b22977010636be5c2717jim /* find the colon */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (strcmp(colon + 1, "getcontentlanguage") == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (void) (*db_hooks->fetch)(propdb->db, key, &value);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### anything better to do? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### probably should enter a 500 error */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* put the prop name and value into the result */
8869662bb1a4078297020e94ae5e928626d877c6rederpj dav_append_prop(propdb, key.dptr, value.dptr, &hdr);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* simple, empty element if a value isn't needed */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* add namespaces for all the liveprop providers */
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (i = 0, scan_uri = (const char * const *)dav_liveprop_uris->elts;
8869662bb1a4078297020e94ae5e928626d877c6rederpj dav_insert_xmlns(propdb->p, "lp", i, *scan_uri, &hdr_ns);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ask the liveprop providers to insert their properties */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem for (ddh = propdb->liveprop; ddh != NULL; ddh = ddh->next) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem (*DAV_AS_HOOKS_LIVEPROP(ddh)->insert_all)(propdb->resource, getvals,
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* insert the standard properties */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### should be handling the return errors here */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* if the resourcetype wasn't stored, then prepare one */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ### should be handling the return error here */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* if we didn't find these, then do the whole subreq thing. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* ### should be handling the return error here */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "getcontenttype",
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### should be handling the return error here */
8869662bb1a4078297020e94ae5e928626d877c6rederpj "getcontentlanguage",
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* terminate the result */
8869662bb1a4078297020e94ae5e928626d877c6rederpjdav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc)
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_xml_elem *elem = dav_find_child(doc->root, "prop");
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### NOTE: we should pass in TWO buffers -- one for keys, one for
8869662bb1a4078297020e94ae5e928626d877c6rederpj the marks */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* we will ALWAYS provide a "good" result, even if it is EMPTY */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* generate all the namespaces that are in the propdb */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ### the marks should be in a buffer! */
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* allocate zeroed-memory for the marks. These marks indicate which
8869662bb1a4078297020e94ae5e928626d877c6rederpj input namespaces we've generated into the output xmlns buffer */
8869662bb1a4078297020e94ae5e928626d877c6rederpj marks_input = ap_pcalloc(propdb->p, propdb->ns_xlate->nelts);
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* same for the liveprops */
8869662bb1a4078297020e94ae5e928626d877c6rederpj marks_liveprop = ap_pcalloc(propdb->p, dav_liveprop_uris->nelts);
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (elem = elem->first_child; elem; elem = elem->next) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** Note: the key may be NULL if we have no properties that are in
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** a namespace that matches the requested prop's namespace.
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* fetch IF we have a db and a key. otherwise, value is NULL */
8869662bb1a4078297020e94ae5e928626d877c6rederpj elem->private = ap_pcalloc(propdb->p, sizeof(*elem->private));
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** If we did not find the property in the database, then it may
8869662bb1a4078297020e94ae5e928626d877c6rederpj ** be a liveprop that we can handle specially.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* cache the propid; dav_get_props() could be called many times */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* insert the property. returns 1 if an insertion was done. */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((err = dav_insert_liveprop(propdb, elem, 1, &hdr_good,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ### need to propagate the error to the caller... */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ### skip it for now, as if nothing was inserted */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** Add the liveprop's namespace URIs. Note that provider==NULL
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** for core properties.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const char * const * scan_ns_uri;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const int * scan_ns;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_add_marked_xmlns(propdb, marks_liveprop, *scan_ns,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* not found. add a record to the "bad" propstats */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* make sure we've started our "bad" propstat */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* note: key.dptr may be NULL if the propdb doesn't have an
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj equivalent namespace stored */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj const char *s;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj * elem has a prefix already (xml...:name) or the elem
0e05808dc59a321566303084c84b9826a4353cefrederpj * simply has no namespace.
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg s = ap_psprintf(propdb->p, "<%s/>" DEBUG_CR, elem->name);
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* ensure that an xmlns is generated for the
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj input namespace */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* add in the bad prop using our namespace decl */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr_bad);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* found it. put the value into the "good" propstats */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem dav_append_prop(propdb, key.dptr, value.dptr, &hdr_good);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* default to start with the good */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* we may not have any "bad" results */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* if there are no good props, then just return the bad */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* hook the bad propstat to the end of the good one */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem priv = ctx->prop->private = ap_pcalloc(propdb->p, sizeof(*priv));
0e05808dc59a321566303084c84b9826a4353cefrederpj ** Check to see if this is a live property, and fill the fields
0e05808dc59a321566303084c84b9826a4353cefrederpj ** in the XML elem, as appropriate.
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** Verify that the property is read/write. If not, then it cannot
0e05808dc59a321566303084c84b9826a4353cefrederpj ** be SET or DELETEd.
0e05808dc59a321566303084c84b9826a4353cefrederpj /* it's a liveprop if a provider was found */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* ### actually the "core" props should really be liveprops, but
0e05808dc59a321566303084c84b9826a4353cefrederpj ### there is no "provider" for those and the r/w props are
0e05808dc59a321566303084c84b9826a4353cefrederpj ### treated as dead props anyhow */
0e05808dc59a321566303084c84b9826a4353cefrederpj "Property is read-only.");
0e05808dc59a321566303084c84b9826a4353cefrederpj ctx->err = (*priv->provider->patch_validate)(propdb->resource,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* clear is_liveprop -- act as a dead prop now */
0e05808dc59a321566303084c84b9826a4353cefrederpj ** The property is supposed to be stored into the dead-property
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** database. Make sure the thing is truly open (and writeable).
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj && (ctx->err = dav_really_open_db(propdb, 0 /* ro */)) != NULL) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj ** There should be an open, writable database in here!
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj ** Note: the database would be NULL if it was opened readonly and it
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ** did not exist.
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ctx->err = dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "Attempted to set/remove a property "
0e05808dc59a321566303084c84b9826a4353cefrederpj "without a valid, open, read/write "
0e05808dc59a321566303084c84b9826a4353cefrederpj "property database.");
0e05808dc59a321566303084c84b9826a4353cefrederpj ** Prep the element => propdb namespace index mapping, inserting
0e05808dc59a321566303084c84b9826a4353cefrederpj ** namespace URIs into the propdb that don't exist.
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** There are no checks to perform here. If a property exists, then
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** we will delete it. If it does not exist, then it does not matter
0e05808dc59a321566303084c84b9826a4353cefrederpj ** (see S12.13.1).
0e05808dc59a321566303084c84b9826a4353cefrederpj ** Note that if a property does not exist, that does not rule out
40a1aee60a66f7c8dbd0835fdd4f09334e12fc15rpluem ** that a SET will occur during this PROPPATCH (thusly creating it).
0e05808dc59a321566303084c84b9826a4353cefrederpj rollback = ap_pcalloc(propdb->p, sizeof(*rollback));
0e05808dc59a321566303084c84b9826a4353cefrederpj err = (*priv->provider->patch_exec)(propdb->resource,
0e05808dc59a321566303084c84b9826a4353cefrederpj /* we're going to need the key for all operations */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* save the old value so that we can do a rollback. */
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((err = (*propdb->db_hooks->fetch)(propdb->db, key,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Note: propdb->ns_map was set in dav_prop_validate() */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* quote all the values in the element */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* generate a text blob for the xml:lang plus the contents */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj ap_xml_to_text(propdb->p, ctx->prop, AP_XML_X2T_LANG_INNER, NULL,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj err = (*propdb->db_hooks->store)(propdb->db, key, value);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** If an error occurred, then assume that we didn't change the
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** value. Remove the rollback item so that we don't try to set
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** its value during the rollback.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ** Delete the property. Ignore errors -- the property is there, or
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** we are deleting it for a second time.
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf /* ### but what about other errors? */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* push a more specific error here */
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf ** any errors at this point.
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ** Note that a commit implies ctx->err is NULL. The caller should assume
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ** a status of HTTP_OK for this case.
f05787953018140838ad51456c86c965d6a86267jim /* do nothing if there is no rollback information. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** ### if we have an error, and a rollback occurs, then the namespace
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** ### mods should not happen at all. Basically, the namespace management
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ** ### is simply a bitch.
e8f95a682820a599fe41b22977010636be5c2717jim err = (*priv->provider->patch_rollback)(ctx->propdb->resource,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* don't fail if the thing isn't really there */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ### but what about other errors? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (void) (*ctx->propdb->db_hooks->remove)(ctx->propdb->db,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes err = (*ctx->propdb->db_hooks->store)(ctx->propdb->db,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* hook previous errors at the end of the rollback error */