📄 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 + -