diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/dav/main/props.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/modules/dav/main/props.c | 1116 |
1 files changed, 0 insertions, 1116 deletions
diff --git a/rubbos/app/httpd-2.0.64/modules/dav/main/props.c b/rubbos/app/httpd-2.0.64/modules/dav/main/props.c deleted file mode 100644 index fc28532d..00000000 --- a/rubbos/app/httpd-2.0.64/modules/dav/main/props.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* -** DAV extension module for Apache 2.0.* -** - Property database handling (repository-independent) -** -** NOTES: -** -** PROPERTY DATABASE -** -** This version assumes that there is a per-resource database provider -** to record properties. The database provider decides how and where to -** store these databases. -** -** The DBM keys for the properties have the following form: -** -** namespace ":" propname -** -** For example: 5:author -** -** The namespace provides an integer index into the namespace table -** (see below). propname is simply the property name, without a namespace -** prefix. -** -** A special case exists for properties that had a prefix starting with -** "xml". The XML Specification reserves these for future use. mod_dav -** stores and retrieves them unchanged. The keys for these properties -** have the form: -** -** ":" propname -** -** The propname will contain the prefix and the property name. For -** example, a key might be ":xmlfoo:name" -** -** The ":name" style will also be used for properties that do not -** exist within a namespace. -** -** The DBM values consist of two null-terminated strings, appended -** together (the null-terms are retained and stored in the database). -** The first string is the xml:lang value for the property. An empty -** string signifies that a lang value was not in context for the value. -** The second string is the property value itself. -** -** -** NAMESPACE TABLE -** -** The namespace table is an array that lists each of the namespaces -** that are in use by the properties in the given propdb. Each entry -** in the array is a simple URI. -** -** For example: http://www.foo.bar/standards/props/ -** -** The prefix used for the property is stripped and the URI for it -** is entered into the namespace table. Also, any namespaces used -** within the property value will be entered into the table (and -** stripped from the child elements). -** -** The namespaces are stored in the DBM database under the "METADATA" key. -** -** -** STRIPPING NAMESPACES -** -** Within the property values, the namespace declarations (xmlns...) -** are stripped. Each element and attribute will have its prefix removed -** and a new prefix inserted. -** -** This must be done so that we can return multiple properties in a -** PROPFIND which may have (originally) used conflicting prefixes. For -** that case, we must bind all property value elements to new namespace -** values. -** -** This implies that clients must NOT be sensitive to the namespace -** prefix used for their properties. It WILL change when the properties -** are returned (we return them as "ns<index>", e.g. "ns5"). Also, the -** property value can contain ONLY XML elements and CDATA. PI and comment -** elements will be stripped. CDATA whitespace will be preserved, but -** whitespace within element tags will be altered. Attribute ordering -** may be altered. Element and CDATA ordering will be preserved. -** -** -** ATTRIBUTES ON PROPERTY NAME ELEMENTS -** -** When getting/setting properties, the XML used looks like: -** -** <prop> -** <propname1>value</propname1> -** <propname2>value</propname1> -** </prop> -** -** This implementation (mod_dav) DOES NOT save any attributes that are -** associated with the <propname1> element. The property value is deemed -** to be only the contents ("value" in the above example). -** -** We do store the xml:lang value (if any) that applies to the context -** of the <propname1> element. Whether the xml:lang attribute is on -** <propname1> itself, or from a higher level element, we will store it -** with the property value. -** -** -** VERSIONING -** -** The DBM db contains a key named "METADATA" that holds database-level -** information, such as the namespace table. The record also contains the -** db's version number as the very first 16-bit value. This first number -** is actually stored as two single bytes: the first byte is a "major" -** version number. The second byte is a "minor" number. -** -** If the major number is not what mod_dav expects, then the db is closed -** immediately and an error is returned. A minor number change is -** acceptable -- it is presumed that old/new dav_props.c can deal with -** the database format. For example, a newer dav_props might update the -** minor value and append information to the end of the metadata record -** (which would be ignored by previous versions). -** -** -** ISSUES: -** -** At the moment, for the dav_get_allprops() and dav_get_props() functions, -** we must return a set of xmlns: declarations for ALL known namespaces -** in the file. There isn't a way to filter this because we don't know -** which are going to be used or not. Examining property names is not -** sufficient because the property values could use entirely different -** namespaces. -** -** ==> we must devise a scheme where we can "garbage collect" the namespace -** entries from the property database. -*/ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STDIO -#define APR_WANT_BYTEFUNC -#include "apr_want.h" - -#include "mod_dav.h" - -#include "http_log.h" -#include "http_request.h" - -/* -** There is some rough support for writable DAV:getcontenttype and -** DAV:getcontentlanguage properties. If this #define is (1), then -** this support is disabled. -** -** We are disabling it because of a lack of support in GET and PUT -** operations. For GET, it would be "expensive" to look for a propdb, -** open it, and attempt to extract the Content-Type and Content-Language -** values for the response. -** (Handling the PUT would not be difficult, though) -*/ -#define DAV_DISABLE_WRITABLE_PROPS 1 - -#define DAV_EMPTY_VALUE "\0" /* TWO null terms */ - -struct dav_propdb { - apr_pool_t *p; /* the pool we should use */ - request_rec *r; /* the request record */ - - const dav_resource *resource; /* the target resource */ - - int deferred; /* open of db has been deferred */ - dav_db *db; /* underlying database containing props */ - - apr_array_header_t *ns_xlate; /* translation of an elem->ns to URI */ - dav_namespace_map *mapping; /* namespace mapping */ - - dav_lockdb *lockdb; /* the lock database */ - - dav_buffer wb_lock; /* work buffer for lockdiscovery property */ - - /* if we ever run a GET subreq, it will be stored here */ - request_rec *subreq; - - /* hooks we should use for processing (based on the target resource) */ - const dav_hooks_db *db_hooks; -}; - -/* NOTE: dav_core_props[] and the following enum must stay in sync. */ -/* ### move these into a "core" liveprop provider? */ -static const char * const dav_core_props[] = -{ - "getcontenttype", - "getcontentlanguage", - "lockdiscovery", - "supportedlock", - - NULL /* sentinel */ -}; -enum { - DAV_PROPID_CORE_getcontenttype = DAV_PROPID_CORE, - DAV_PROPID_CORE_getcontentlanguage, - DAV_PROPID_CORE_lockdiscovery, - DAV_PROPID_CORE_supportedlock, - - DAV_PROPID_CORE_UNKNOWN -}; - -/* -** This structure is used to track information needed for a rollback. -*/ -typedef struct dav_rollback_item { - /* select one of the two rollback context structures based on the - value of dav_prop_ctx.is_liveprop */ - dav_deadprop_rollback *deadprop; - dav_liveprop_rollback *liveprop; - -} dav_rollback_item; - - -static int dav_find_liveprop_provider(dav_propdb *propdb, - const char *ns_uri, - const char *propname, - const dav_hooks_liveprop **provider) -{ - int propid; - - *provider = NULL; - - if (ns_uri == NULL) { - /* policy: liveprop providers cannot define no-namespace properties */ - return DAV_PROPID_CORE_UNKNOWN; - } - - /* check liveprop providers first, so they can define core properties */ - propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname, - provider); - if (propid != 0) { - return propid; - } - - /* check for core property */ - if (strcmp(ns_uri, "DAV:") == 0) { - const char * const *p = dav_core_props; - - for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid) - if (strcmp(propname, *p) == 0) { - return propid; - } - } - - /* no provider for this property */ - return DAV_PROPID_CORE_UNKNOWN; -} - -static void dav_find_liveprop(dav_propdb *propdb, apr_xml_elem *elem) -{ - const char *ns_uri; - dav_elem_private *priv = elem->priv; - const dav_hooks_liveprop *hooks; - - - if (elem->ns == APR_XML_NS_NONE) - ns_uri = NULL; - else if (elem->ns == APR_XML_NS_DAV_ID) - ns_uri = "DAV:"; - else - ns_uri = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); - - priv->propid = dav_find_liveprop_provider(propdb, ns_uri, elem->name, - &hooks); - - /* ### this test seems redundant... */ - if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { - priv->provider = hooks; - } -} - -/* is the live property read/write? */ -static int dav_rw_liveprop(dav_propdb *propdb, dav_elem_private *priv) -{ - int propid = priv->propid; - - /* - ** Check the liveprop provider (if this is a provider-defined prop) - */ - if (priv->provider != NULL) { - return (*priv->provider->is_writable)(propdb->resource, propid); - } - - /* these are defined as read-only */ - if (propid == DAV_PROPID_CORE_lockdiscovery -#if DAV_DISABLE_WRITABLE_PROPS - || propid == DAV_PROPID_CORE_getcontenttype - || propid == DAV_PROPID_CORE_getcontentlanguage -#endif - || propid == DAV_PROPID_CORE_supportedlock - ) { - - return 0; - } - - /* these are defined as read/write */ - if (propid == DAV_PROPID_CORE_getcontenttype - || propid == DAV_PROPID_CORE_getcontentlanguage - || propid == DAV_PROPID_CORE_UNKNOWN) { - - return 1; - } - - /* - ** We don't recognize the property, so it must be dead (and writable) - */ - return 1; -} - -/* do a sub-request to fetch properties for the target resource's URI. */ -static void dav_do_prop_subreq(dav_propdb *propdb) -{ - /* perform a "GET" on the resource's URI (note that the resource - may not correspond to the current request!). */ - propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r, - NULL); -} - -static dav_error * dav_insert_coreprop(dav_propdb *propdb, - int propid, const char *name, - dav_prop_insert what, - apr_text_header *phdr, - dav_prop_insert *inserted) -{ - const char *value = NULL; - dav_error *err; - - *inserted = DAV_PROP_INSERT_NOTDEF; - - /* fast-path the common case */ - if (propid == DAV_PROPID_CORE_UNKNOWN) - return NULL; - - switch (propid) { - - case DAV_PROPID_CORE_lockdiscovery: - if (propdb->lockdb != NULL) { - dav_lock *locks; - - if ((err = dav_lock_query(propdb->lockdb, propdb->resource, - &locks)) != NULL) { - return dav_push_error(propdb->p, err->status, 0, - "DAV:lockdiscovery could not be " - "determined due to a problem fetching " - "the locks for this resource.", - err); - } - - /* fast-path the no-locks case */ - if (locks == NULL) { - value = ""; - } - else { - /* - ** This may modify the buffer. value may point to - ** wb_lock.pbuf or a string constant. - */ - value = dav_lock_get_activelock(propdb->r, locks, - &propdb->wb_lock); - - /* make a copy to isolate it from changes to wb_lock */ - value = apr_pstrdup(propdb->p, propdb->wb_lock.buf); - } - } - break; - - case DAV_PROPID_CORE_supportedlock: - if (propdb->lockdb != NULL) { - value = (*propdb->lockdb->hooks->get_supportedlock)(propdb->resource); - } - break; - - case DAV_PROPID_CORE_getcontenttype: - if (propdb->subreq == NULL) { - dav_do_prop_subreq(propdb); - } - if (propdb->subreq->content_type != NULL) { - value = propdb->subreq->content_type; - } - break; - - case DAV_PROPID_CORE_getcontentlanguage: - { - const char *lang; - - if (propdb->subreq == NULL) { - dav_do_prop_subreq(propdb); - } - if ((lang = apr_table_get(propdb->subreq->headers_out, - "Content-Language")) != NULL) { - value = lang; - } - break; - } - - default: - /* fall through to interpret as a dead property */ - break; - } - - /* if something was supplied, then insert it */ - if (value != NULL) { - const char *s; - - if (what == DAV_PROP_INSERT_SUPPORTED) { - /* use D: prefix to refer to the DAV: namespace URI, - * and let the namespace attribute default to "DAV:" - */ - s = apr_psprintf(propdb->p, - "<D:supported-live-property D:name=\"%s\"/>" DEBUG_CR, - name); - } - else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') { - /* use D: prefix to refer to the DAV: namespace URI */ - s = apr_psprintf(propdb->p, "<D:%s>%s</D:%s>" DEBUG_CR, - name, value, name); - } - else { - /* use D: prefix to refer to the DAV: namespace URI */ - s = apr_psprintf(propdb->p, "<D:%s/>" DEBUG_CR, name); - } - apr_text_append(propdb->p, phdr, s); - - *inserted = what; - } - - return NULL; -} - -static dav_error * dav_insert_liveprop(dav_propdb *propdb, - const apr_xml_elem *elem, - dav_prop_insert what, - apr_text_header *phdr, - dav_prop_insert *inserted) -{ - dav_elem_private *priv = elem->priv; - - *inserted = DAV_PROP_INSERT_NOTDEF; - - if (priv->provider == NULL) { - /* this is a "core" property that we define */ - return dav_insert_coreprop(propdb, priv->propid, elem->name, - what, phdr, inserted); - } - - /* ask the provider (that defined this prop) to insert the prop */ - *inserted = (*priv->provider->insert_prop)(propdb->resource, priv->propid, - what, phdr); - - return NULL; -} - -static void dav_output_prop_name(apr_pool_t *pool, - const dav_prop_name *name, - dav_xmlns_info *xi, - apr_text_header *phdr) -{ - const char *s; - - if (*name->ns == '\0') - s = apr_psprintf(pool, "<%s/>" DEBUG_CR, name->name); - else { - const char *prefix = dav_xmlns_add_uri(xi, name->ns); - - s = apr_psprintf(pool, "<%s:%s/>" DEBUG_CR, prefix, name->name); - } - - apr_text_append(pool, phdr, s); -} - -static void dav_insert_xmlns(apr_pool_t *p, const char *pre_prefix, int ns, - const char *ns_uri, apr_text_header *phdr) -{ - const char *s; - - s = apr_psprintf(p, " xmlns:%s%d=\"%s\"", pre_prefix, ns, ns_uri); - apr_text_append(p, phdr, s); -} - -static dav_error *dav_really_open_db(dav_propdb *propdb, int ro) -{ - dav_error *err; - - /* we're trying to open the db; turn off the 'deferred' flag */ - propdb->deferred = 0; - - /* ask the DB provider to open the thing */ - err = (*propdb->db_hooks->open)(propdb->p, propdb->resource, ro, - &propdb->db); - if (err != NULL) { - return dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_OPENING, - "Could not open the property database.", - err); - } - - /* - ** NOTE: propdb->db could be NULL if we attempted to open a readonly - ** database that doesn't exist. If we require read/write - ** access, then a database was created and opened. - */ - - return NULL; -} - -DAV_DECLARE(dav_error *)dav_open_propdb(request_rec *r, dav_lockdb *lockdb, - const dav_resource *resource, - int ro, - apr_array_header_t * ns_xlate, - dav_propdb **p_propdb) -{ - dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb)); - - *p_propdb = NULL; - -#if DAV_DEBUG - if (resource->uri == NULL) { - return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: resource must define " - "its URI."); - } -#endif - - propdb->r = r; - propdb->p = r->pool; /* ### get rid of this */ - propdb->resource = resource; - propdb->ns_xlate = ns_xlate; - - propdb->db_hooks = DAV_GET_HOOKS_PROPDB(r); - - propdb->lockdb = lockdb; - - /* always defer actual open, to avoid expense of accessing db - * when only live properties are involved - */ - propdb->deferred = 1; - - /* ### what to do about closing the propdb on server failure? */ - - *p_propdb = propdb; - return NULL; -} - -DAV_DECLARE(void) dav_close_propdb(dav_propdb *propdb) -{ - if (propdb->db == NULL) - return; - - (*propdb->db_hooks->close)(propdb->db); -} - -DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, - dav_prop_insert what) -{ - const dav_hooks_db *db_hooks = propdb->db_hooks; - apr_text_header hdr = { 0 }; - apr_text_header hdr_ns = { 0 }; - dav_get_props_result result = { 0 }; - int found_contenttype = 0; - int found_contentlang = 0; - dav_prop_insert unused_inserted; - - /* if not just getting supported live properties, - * scan all properties in the dead prop database - */ - if (what != DAV_PROP_INSERT_SUPPORTED) { - if (propdb->deferred) { - /* ### what to do with db open error? */ - (void) dav_really_open_db(propdb, 1 /*ro*/); - } - - /* initialize the result with some start tags... */ - apr_text_append(propdb->p, &hdr, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - /* if there ARE properties, then scan them */ - if (propdb->db != NULL) { - dav_xmlns_info *xi = dav_xmlns_create(propdb->p); - dav_prop_name name; - - /* define (up front) any namespaces the db might need */ - (void) (*db_hooks->define_namespaces)(propdb->db, xi); - - /* get the first property name, beginning the scan */ - (void) (*db_hooks->first_name)(propdb->db, &name); - while (name.ns != NULL) { - - /* - ** We also look for <DAV:getcontenttype> and - ** <DAV:getcontentlanguage>. If they are not stored as dead - ** properties, then we need to perform a subrequest to get - ** their values (if any). - */ - if (*name.ns == 'D' && strcmp(name.ns, "DAV:") == 0 - && *name.name == 'g') { - if (strcmp(name.name, "getcontenttype") == 0) { - found_contenttype = 1; - } - else if (strcmp(name.name, "getcontentlanguage") == 0) { - found_contentlang = 1; - } - } - - if (what == DAV_PROP_INSERT_VALUE) { - dav_error *err; - int found; - - if ((err = (*db_hooks->output_value)(propdb->db, &name, - xi, &hdr, - &found)) != NULL) { - /* ### anything better to do? */ - /* ### probably should enter a 500 error */ - goto next_key; - } - /* assert: found == 1 */ - } - else { - /* the value was not requested, so just add an empty - tag specifying the property name. */ - dav_output_prop_name(propdb->p, &name, xi, &hdr); - } - - next_key: - (void) (*db_hooks->next_name)(propdb->db, &name); - } - - /* all namespaces have been entered into xi. generate them into - the output now. */ - dav_xmlns_generate(xi, &hdr_ns); - - } /* propdb->db != NULL */ - - /* add namespaces for all the liveprop providers */ - dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns); - } - - /* ask the liveprop providers to insert their properties */ - dav_run_insert_all_liveprops(propdb->r, propdb->resource, what, &hdr); - - /* insert the standard properties */ - /* ### should be handling the return errors here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_supportedlock, "supportedlock", - what, &hdr, &unused_inserted); - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_lockdiscovery, "lockdiscovery", - what, &hdr, &unused_inserted); - - /* if we didn't find these, then do the whole subreq thing. */ - if (!found_contenttype) { - /* ### should be handling the return error here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_getcontenttype, - "getcontenttype", - what, &hdr, &unused_inserted); - } - if (!found_contentlang) { - /* ### should be handling the return error here */ - (void)dav_insert_coreprop(propdb, - DAV_PROPID_CORE_getcontentlanguage, - "getcontentlanguage", - what, &hdr, &unused_inserted); - } - - /* if not just reporting on supported live props, - * terminate the result */ - if (what != DAV_PROP_INSERT_SUPPORTED) { - apr_text_append(propdb->p, &hdr, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - } - - result.propstats = hdr.first; - result.xmlns = hdr_ns.first; - return result; -} - -DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb, - apr_xml_doc *doc) -{ - const dav_hooks_db *db_hooks = propdb->db_hooks; - apr_xml_elem *elem = dav_find_child(doc->root, "prop"); - apr_text_header hdr_good = { 0 }; - apr_text_header hdr_bad = { 0 }; - apr_text_header hdr_ns = { 0 }; - int have_good = 0; - dav_get_props_result result = { 0 }; - char *marks_liveprop; - dav_xmlns_info *xi; - int xi_filled = 0; - - /* ### NOTE: we should pass in TWO buffers -- one for keys, one for - the marks */ - - /* we will ALWAYS provide a "good" result, even if it is EMPTY */ - apr_text_append(propdb->p, &hdr_good, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - - /* ### the marks should be in a buffer! */ - /* allocate zeroed-memory for the marks. These marks indicate which - liveprop namespaces we've generated into the output xmlns buffer */ - - /* same for the liveprops */ - marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1); - - xi = dav_xmlns_create(propdb->p); - - for (elem = elem->first_child; elem; elem = elem->next) { - dav_elem_private *priv; - dav_error *err; - dav_prop_insert inserted; - dav_prop_name name; - - /* - ** First try live property providers; if they don't handle - ** the property, then try looking it up in the propdb. - */ - - if (elem->priv == NULL) { - elem->priv = apr_pcalloc(propdb->p, sizeof(*priv)); - } - priv = elem->priv; - - /* cache the propid; dav_get_props() could be called many times */ - if (priv->propid == 0) - dav_find_liveprop(propdb, elem); - - if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { - - /* insert the property. returns 1 if an insertion was done. */ - if ((err = dav_insert_liveprop(propdb, elem, DAV_PROP_INSERT_VALUE, - &hdr_good, &inserted)) != NULL) { - /* ### need to propagate the error to the caller... */ - /* ### skip it for now, as if nothing was inserted */ - } - if (inserted == DAV_PROP_INSERT_VALUE) { - have_good = 1; - - /* - ** Add the liveprop's namespace URIs. Note that provider==NULL - ** for core properties. - */ - if (priv->provider != NULL) { - const char * const * scan_ns_uri; - - for (scan_ns_uri = priv->provider->namespace_uris; - *scan_ns_uri != NULL; - ++scan_ns_uri) { - int ns; - - ns = dav_get_liveprop_ns_index(*scan_ns_uri); - if (marks_liveprop[ns]) - continue; - marks_liveprop[ns] = 1; - - dav_insert_xmlns(propdb->p, "lp", ns, *scan_ns_uri, - &hdr_ns); - } - } - - /* property added. move on to the next property. */ - continue; - } - else if (inserted == DAV_PROP_INSERT_NOTDEF) { - /* nothing to do. fall thru to allow property to be handled - as a dead property */ - } -#if DAV_DEBUG - else { -#if 0 - /* ### need to change signature to return an error */ - return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0, - "INTERNAL DESIGN ERROR: insert_liveprop " - "did not insert what was asked for."); -#endif - } -#endif - } - - /* The property wasn't a live property, so look in the dead property - database. */ - - /* make sure propdb is really open */ - if (propdb->deferred) { - /* ### what to do with db open error? */ - (void) dav_really_open_db(propdb, 1 /*ro*/); - } - - if (elem->ns == APR_XML_NS_NONE) - name.ns = ""; - else - name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); - name.name = elem->name; - - /* only bother to look if a database exists */ - if (propdb->db != NULL) { - int found; - - if ((err = (*db_hooks->output_value)(propdb->db, &name, - xi, &hdr_good, - &found)) != NULL) { - /* ### what to do? continue doesn't seem right... */ - continue; - } - - if (found) { - have_good = 1; - - /* if we haven't added the db's namespaces, then do so... */ - if (!xi_filled) { - (void) (*db_hooks->define_namespaces)(propdb->db, xi); - xi_filled = 1; - } - continue; - } - } - - /* not found as a live OR dead property. add a record to the "bad" - propstats */ - - /* make sure we've started our "bad" propstat */ - if (hdr_bad.first == NULL) { - apr_text_append(propdb->p, &hdr_bad, - "<D:propstat>" DEBUG_CR - "<D:prop>" DEBUG_CR); - } - - /* output this property's name (into the bad propstats) */ - dav_output_prop_name(propdb->p, &name, xi, &hdr_bad); - } - - apr_text_append(propdb->p, &hdr_good, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - /* default to start with the good */ - result.propstats = hdr_good.first; - - /* we may not have any "bad" results */ - if (hdr_bad.first != NULL) { - /* "close" the bad propstat */ - apr_text_append(propdb->p, &hdr_bad, - "</D:prop>" DEBUG_CR - "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR - "</D:propstat>" DEBUG_CR); - - /* if there are no good props, then just return the bad */ - if (!have_good) { - result.propstats = hdr_bad.first; - } - else { - /* hook the bad propstat to the end of the good one */ - hdr_good.last->next = hdr_bad.first; - } - } - - /* add in all the various namespaces, and return them */ - dav_xmlns_generate(xi, &hdr_ns); - result.xmlns = hdr_ns.first; - - return result; -} - -DAV_DECLARE(void) dav_get_liveprop_supported(dav_propdb *propdb, - const char *ns_uri, - const char *propname, - apr_text_header *body) -{ - int propid; - const dav_hooks_liveprop *hooks; - - propid = dav_find_liveprop_provider(propdb, ns_uri, propname, &hooks); - - if (propid != DAV_PROPID_CORE_UNKNOWN) { - if (hooks == NULL) { - /* this is a "core" property that we define */ - dav_prop_insert unused_inserted; - dav_insert_coreprop(propdb, propid, propname, - DAV_PROP_INSERT_SUPPORTED, body, &unused_inserted); - } - else { - (*hooks->insert_prop)(propdb->resource, propid, - DAV_PROP_INSERT_SUPPORTED, body); - } - } -} - -DAV_DECLARE_NONSTD(void) dav_prop_validate(dav_prop_ctx *ctx) -{ - dav_propdb *propdb = ctx->propdb; - apr_xml_elem *prop = ctx->prop; - dav_elem_private *priv; - - priv = ctx->prop->priv = apr_pcalloc(propdb->p, sizeof(*priv)); - - /* - ** Check to see if this is a live property, and fill the fields - ** in the XML elem, as appropriate. - ** - ** Verify that the property is read/write. If not, then it cannot - ** be SET or DELETEd. - */ - if (priv->propid == 0) { - dav_find_liveprop(propdb, prop); - - /* it's a liveprop if a provider was found */ - /* ### actually the "core" props should really be liveprops, but - ### there is no "provider" for those and the r/w props are - ### treated as dead props anyhow */ - ctx->is_liveprop = priv->provider != NULL; - } - - if (!dav_rw_liveprop(propdb, priv)) { - ctx->err = dav_new_error(propdb->p, HTTP_CONFLICT, - DAV_ERR_PROP_READONLY, - "Property is read-only."); - return; - } - - if (ctx->is_liveprop) { - int defer_to_dead = 0; - - ctx->err = (*priv->provider->patch_validate)(propdb->resource, - prop, ctx->operation, - &ctx->liveprop_ctx, - &defer_to_dead); - if (ctx->err != NULL || !defer_to_dead) - return; - - /* clear is_liveprop -- act as a dead prop now */ - ctx->is_liveprop = 0; - } - - /* - ** The property is supposed to be stored into the dead-property - ** database. Make sure the thing is truly open (and writable). - */ - if (propdb->deferred - && (ctx->err = dav_really_open_db(propdb, 0 /* ro */)) != NULL) { - return; - } - - /* - ** There should be an open, writable database in here! - ** - ** Note: the database would be NULL if it was opened readonly and it - ** did not exist. - */ - if (propdb->db == NULL) { - ctx->err = dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_NO_DATABASE, - "Attempted to set/remove a property " - "without a valid, open, read/write " - "property database."); - return; - } - - if (ctx->operation == DAV_PROP_OP_SET) { - /* - ** Prep the element => propdb namespace index mapping, inserting - ** namespace URIs into the propdb that don't exist. - */ - (void) (*propdb->db_hooks->map_namespaces)(propdb->db, - propdb->ns_xlate, - &propdb->mapping); - } - else if (ctx->operation == DAV_PROP_OP_DELETE) { - /* - ** There are no checks to perform here. If a property exists, then - ** we will delete it. If it does not exist, then it does not matter - ** (see S12.13.1). - ** - ** Note that if a property does not exist, that does not rule out - ** that a SET will occur during this PROPPATCH (thusly creating it). - */ - } -} - -DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx) -{ - dav_propdb *propdb = ctx->propdb; - dav_error *err = NULL; - dav_elem_private *priv = ctx->prop->priv; - - ctx->rollback = apr_pcalloc(propdb->p, sizeof(*ctx->rollback)); - - if (ctx->is_liveprop) { - err = (*priv->provider->patch_exec)(propdb->resource, - ctx->prop, ctx->operation, - ctx->liveprop_ctx, - &ctx->rollback->liveprop); - } - else { - dav_prop_name name; - - if (ctx->prop->ns == APR_XML_NS_NONE) - name.ns = ""; - else - name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, ctx->prop->ns); - name.name = ctx->prop->name; - - /* save the old value so that we can do a rollback. */ - if ((err = (*propdb->db_hooks - ->get_rollback)(propdb->db, &name, - &ctx->rollback->deadprop)) != NULL) - goto error; - - if (ctx->operation == DAV_PROP_OP_SET) { - - /* Note: propdb->mapping was set in dav_prop_validate() */ - err = (*propdb->db_hooks->store)(propdb->db, &name, ctx->prop, - propdb->mapping); - - /* - ** If an error occurred, then assume that we didn't change the - ** value. Remove the rollback item so that we don't try to set - ** its value during the rollback. - */ - /* ### euh... where is the removal? */ - } - else if (ctx->operation == DAV_PROP_OP_DELETE) { - - /* - ** Delete the property. Ignore errors -- the property is there, or - ** we are deleting it for a second time. - */ - /* ### but what about other errors? */ - (void) (*propdb->db_hooks->remove)(propdb->db, &name); - } - } - - error: - /* push a more specific error here */ - if (err != NULL) { - /* - ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen - ** any errors at this point. - */ - ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, - DAV_ERR_PROP_EXEC, - "Could not execute PROPPATCH.", err); - } -} - -DAV_DECLARE_NONSTD(void) dav_prop_commit(dav_prop_ctx *ctx) -{ - dav_elem_private *priv = ctx->prop->priv; - - /* - ** Note that a commit implies ctx->err is NULL. The caller should assume - ** a status of HTTP_OK for this case. - */ - - if (ctx->is_liveprop) { - (*priv->provider->patch_commit)(ctx->propdb->resource, - ctx->operation, - ctx->liveprop_ctx, - ctx->rollback->liveprop); - } -} - -DAV_DECLARE_NONSTD(void) dav_prop_rollback(dav_prop_ctx *ctx) -{ - dav_error *err = NULL; - dav_elem_private *priv = ctx->prop->priv; - - /* do nothing if there is no rollback information. */ - if (ctx->rollback == NULL) - return; - - /* - ** ### if we have an error, and a rollback occurs, then the namespace - ** ### mods should not happen at all. Basically, the namespace management - ** ### is simply a bitch. - */ - - if (ctx->is_liveprop) { - err = (*priv->provider->patch_rollback)(ctx->propdb->resource, - ctx->operation, - ctx->liveprop_ctx, - ctx->rollback->liveprop); - } - else { - err = (*ctx->propdb->db_hooks - ->apply_rollback)(ctx->propdb->db, ctx->rollback->deadprop); - } - - if (err != NULL) { - if (ctx->err == NULL) - ctx->err = err; - else { - dav_error *scan = err; - - /* hook previous errors at the end of the rollback error */ - while (scan->prev != NULL) - scan = scan->prev; - scan->prev = ctx->err; - ctx->err = err; - } - } -} |