/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
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 */
int flags; /* ro, disable lock discovery */
/* 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? */ staticconstchar * const dav_core_props[] =
{ "getcontenttype", "getcontentlanguage", "lockdiscovery", "supportedlock",
/* **Thisstructureisusedtotrackinformationneededforarollback.
*/ typedefstruct 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;
/* 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
) {
return0;
}
/* these are defined as read/write */ if (propid == DAV_PROPID_CORE_getcontenttype
|| propid == DAV_PROPID_CORE_getcontentlanguage
|| propid == DAV_PROPID_CORE_UNKNOWN) {
/* do a sub-request to fetch properties for the target resource's URI. */ staticvoid dav_do_prop_subreq(dav_propdb *propdb)
{ /* need to escape the uri that's in the resource struct because during
* the property walker it's not encoded. */ constchar *e_uri = ap_escape_uri(propdb->p,
propdb->resource->uri);
/* 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(e_uri, propdb->r, NULL);
}
/* fast-path the common case */ if (propid == DAV_PROPID_CORE_UNKNOWN) return NULL;
switch (propid) {
case DAV_PROPID_CORE_lockdiscovery: if (propdb->flags & DAV_PROPDB_DISABLE_LOCKDISCOVERY) {
value = ""; break;
}
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 { /* **Thismaymodifythebuffer.valuemaypointto **wb_lock.pbuforastringconstant.
*/
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:
{ constchar *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) { constchar *s;
if (what == DAV_PROP_INSERT_SUPPORTED) { /* use D: prefix to refer to the DAV: namespace URI, *andletthenamespaceattributedefaultto"DAV:"
*/
s = apr_pstrcat(propdb->p, "<D:supported-live-property D:name=\"",
name, "\"/>" DEBUG_CR, NULL);
} elseif (what == DAV_PROP_INSERT_VALUE && *value != '\0') { /* use D: prefix to refer to the DAV: namespace URI */
s = apr_pstrcat(propdb->p, "<D:", name, ">", value, "</D:", name, ">" DEBUG_CR, NULL);
} else { /* use D: prefix to refer to the DAV: namespace URI */
s = apr_pstrcat(propdb->p, "<D:", name, "/>" DEBUG_CR, NULL);
}
apr_text_append(propdb->p, phdr, s);
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);
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);
}
/* if not just getting supported live properties, *scanallpropertiesinthedeadpropdatabase
*/ 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;
dav_error *err;
/* 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 */
err = (*db_hooks->first_name)(propdb->db, &name); while (!err && name.ns) {
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);
}
/* 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);
}
/* we lose both the document and the element when calling (insert_prop), *maketheseavailableinthepool.
*/
element = dav_get_liveprop_element(propdb->resource); if (!element) {
element = apr_pcalloc(propdb->resource->pool, sizeof(dav_liveprop_elem));
apr_pool_userdata_setn(element, DAV_PROP_ELEMENT, NULL, propdb->resource->pool);
} else {
memset(element, 0, sizeof(dav_liveprop_elem));
}
element->doc = doc;
/* ### 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);
if (elem->priv == NULL) { /* elem->priv outlives propdb->p. Hence use the request pool */
elem->priv = apr_pcalloc(propdb->r->pool, 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;
/* property added. move on to the next property. */ continue;
} elseif (inserted == DAV_PROP_INSERT_NOTDEF) { /* nothing to do. fall thru to allow property to be handled
as a dead property */
} #if DAV_DEBUG else { #if0 /* ### need to change signature to return an error */ return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0, 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*/);
}
/* 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);
}
/* 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;
/* it's a liveprop if a provider was found */ /* ### actually the "core" props should really be liveprops, but ###thereisno"provider"forthoseandther/wpropsare
### 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, 0, "Property is read-only."); return;
}
/* 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);
/* **Ifanerroroccurred,thenassumethatwedidn'tchangethe **value.Removetherollbackitemsothatwedon'ttrytoset **itsvalueduringtherollback.
*/ /* ### euh... where is the removal? */
} elseif (ctx->operation == DAV_PROP_OP_DELETE) {
/* **Deletetheproperty.Ignoreerrors--thepropertyisthere,or **wearedeletingitforasecondtime. ** **http://tools.ietf.org/html/rfc4918#section-14.23 says **"Specifyingtheremovalofapropertythatdoesnotexistis **notanerror"
*/ /* ### but what about other errors? */
(void) (*propdb->db_hooks->remove)(propdb->db, &name);
}
}
error: /* push a more specific error here */ if (err != NULL) { /* **UseHTTP_INTERNAL_SERVER_ERRORbecauseweshouldn'thaveseen **anyerrorsatthispoint.
*/
ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR,
DAV_ERR_PROP_EXEC, "Could not execute PROPPATCH.", err);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.