📄 props.c
字号:
/* 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -