📄 mod_dav.c
字号:
}
/* 2518 says that depth must be infinity only for collections.
* For non-collections, depth is ignored, unless it is an illegal value (1).
*/
depth = dav_get_depth(r, DAV_INFINITY);
if (resource->collection && depth != DAV_INFINITY) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Depth must be \"infinity\" for DELETE of a collection.");
return HTTP_BAD_REQUEST;
}
if (!resource->collection && depth == 1) {
/* This supplies additional information for the default message. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Depth of \"1\" is not allowed for DELETE.");
return HTTP_BAD_REQUEST;
}
/*
** If any resources fail the lock/If: conditions, then we must fail
** the delete. Each of the failing resources will be listed within
** a DAV:multistatus body, wrapped into a 424 response.
**
** Note that a failure on the resource itself does not generate a
** multistatus response -- only internal members/collections.
*/
if ((err = dav_validate_request(r, resource, depth, NULL,
&multi_response,
DAV_VALIDATE_PARENT
| DAV_VALIDATE_USE_424, NULL)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not DELETE %s due to a failed "
"precondition (e.g. locks).",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
/* ### RFC 2518 s. 8.10.5 says to remove _all_ locks, not just those
* locked by the token(s) in the if_header.
*/
if ((result = dav_unlock(r, resource, NULL)) != OK) {
return result;
}
/* if versioned resource, make sure parent is checked out */
if ((err = dav_auto_checkout(r, resource, 1 /* parent_only */,
&av_info)) != NULL) {
/* ### add a higher-level description? */
return dav_handle_err(r, err, NULL);
}
/* try to remove the resource */
err = (*resource->hooks->remove_resource)(resource, &multi_response);
/* restore writability of parent back to what it was */
err2 = dav_auto_checkin(r, NULL, err != NULL /* undo if error */,
0 /*unlock*/, &av_info);
/* check for errors now */
if (err != NULL) {
err = dav_push_error(r->pool, err->status, 0,
apr_psprintf(r->pool,
"Could not DELETE %s.",
ap_escape_html(r->pool, r->uri)),
err);
return dav_handle_err(r, err, multi_response);
}
if (err2 != NULL) {
/* just log a warning */
err = dav_push_error(r->pool, err2->status, 0,
"The DELETE was successful, but there "
"was a problem automatically checking in "
"the parent collection.",
err2);
dav_log_err(r, err, APLOG_WARNING);
}
/* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */
/* Apache will supply a default error for this. */
return HTTP_NO_CONTENT;
}
/* generate DAV:supported-method-set OPTIONS response */
static dav_error *dav_gen_supported_methods(request_rec *r,
const apr_xml_elem *elem,
const apr_table_t *methods,
apr_text_header *body)
{
const apr_array_header_t *arr;
const apr_table_entry_t *elts;
apr_xml_elem *child;
apr_xml_attr *attr;
char *s;
int i;
apr_text_append(r->pool, body, "<D:supported-method-set>" DEBUG_CR);
if (elem->first_child == NULL) {
/* show all supported methods */
arr = apr_table_elts(methods);
elts = (const apr_table_entry_t *)arr->elts;
for (i = 0; i < arr->nelts; ++i) {
if (elts[i].key == NULL)
continue;
s = apr_psprintf(r->pool,
"<D:supported-method D:name=\"%s\"/>"
DEBUG_CR,
elts[i].key);
apr_text_append(r->pool, body, s);
}
}
else {
/* check for support of specific methods */
for (child = elem->first_child; child != NULL; child = child->next) {
if (child->ns == APR_XML_NS_DAV_ID
&& strcmp(child->name, "supported-method") == 0) {
const char *name = NULL;
/* go through attributes to find method name */
for (attr = child->attr; attr != NULL; attr = attr->next) {
if (attr->ns == APR_XML_NS_DAV_ID
&& strcmp(attr->name, "name") == 0)
name = attr->value;
}
if (name == NULL) {
return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"A DAV:supported-method element "
"does not have a \"name\" attribute");
}
/* see if method is supported */
if (apr_table_get(methods, name) != NULL) {
s = apr_psprintf(r->pool,
"<D:supported-method D:name=\"%s\"/>"
DEBUG_CR,
name);
apr_text_append(r->pool, body, s);
}
}
}
}
apr_text_append(r->pool, body, "</D:supported-method-set>" DEBUG_CR);
return NULL;
}
/* generate DAV:supported-live-property-set OPTIONS response */
static dav_error *dav_gen_supported_live_props(request_rec *r,
const dav_resource *resource,
const apr_xml_elem *elem,
apr_text_header *body)
{
dav_lockdb *lockdb;
dav_propdb *propdb;
apr_xml_elem *child;
apr_xml_attr *attr;
dav_error *err;
/* open lock database, to report on supported lock properties */
/* ### should open read-only */
if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) {
return dav_push_error(r->pool, err->status, 0,
"The lock database could not be opened, "
"preventing the reporting of supported lock "
"properties.",
err);
}
/* open the property database (readonly) for the resource */
if ((err = dav_open_propdb(r, lockdb, resource, 1, NULL,
&propdb)) != NULL) {
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
return dav_push_error(r->pool, err->status, 0,
"The property database could not be opened, "
"preventing report of supported properties.",
err);
}
apr_text_append(r->pool, body, "<D:supported-live-property-set>" DEBUG_CR);
if (elem->first_child == NULL) {
/* show all supported live properties */
dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED);
body->last->next = props.propstats;
while (body->last->next != NULL)
body->last = body->last->next;
}
else {
/* check for support of specific live property */
for (child = elem->first_child; child != NULL; child = child->next) {
if (child->ns == APR_XML_NS_DAV_ID
&& strcmp(child->name, "supported-live-property") == 0) {
const char *name = NULL;
const char *nmspace = NULL;
/* go through attributes to find name and namespace */
for (attr = child->attr; attr != NULL; attr = attr->next) {
if (attr->ns == APR_XML_NS_DAV_ID) {
if (strcmp(attr->name, "name") == 0)
name = attr->value;
else if (strcmp(attr->name, "namespace") == 0)
nmspace = attr->value;
}
}
if (name == NULL) {
err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"A DAV:supported-live-property "
"element does not have a \"name\" "
"attribute");
break;
}
/* default namespace to DAV: */
if (nmspace == NULL)
nmspace = "DAV:";
/* check for support of property */
dav_get_liveprop_supported(propdb, nmspace, name, body);
}
}
}
apr_text_append(r->pool, body, "</D:supported-live-property-set>" DEBUG_CR);
dav_close_propdb(propdb);
if (lockdb != NULL)
(*lockdb->hooks->close_lockdb)(lockdb);
return err;
}
/* generate DAV:supported-report-set OPTIONS response */
static dav_error *dav_gen_supported_reports(request_rec *r,
const dav_resource *resource,
const apr_xml_elem *elem,
const dav_hooks_vsn *vsn_hooks,
apr_text_header *body)
{
apr_xml_elem *child;
apr_xml_attr *attr;
dav_error *err;
char *s;
apr_text_append(r->pool, body, "<D:supported-report-set>" DEBUG_CR);
if (vsn_hooks != NULL) {
const dav_report_elem *reports;
const dav_report_elem *rp;
if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) {
return dav_push_error(r->pool, err->status, 0,
"DAV:supported-report-set could not be "
"determined due to a problem fetching the "
"available reports for this resource.",
err);
}
if (reports != NULL) {
if (elem->first_child == NULL) {
/* show all supported reports */
for (rp = reports; rp->nmspace != NULL; ++rp) {
/* Note: we presume reports->namespace is
* properly XML/URL quoted */
s = apr_psprintf(r->pool,
"<D:supported-report D:name=\"%s\" "
"D:namespace=\"%s\"/>" DEBUG_CR,
rp->name, rp->nmspace);
apr_text_append(r->pool, body, s);
}
}
else {
/* check for support of specific report */
for (child = elem->first_child; child != NULL; child = child->next) {
if (child->ns == APR_XML_NS_DAV_ID
&& strcmp(child->name, "supported-report") == 0) {
const char *name = NULL;
const char *nmspace = NULL;
/* go through attributes to find name and namespace */
for (attr = child->attr; attr != NULL; attr = attr->next) {
if (attr->ns == APR_XML_NS_DAV_ID) {
if (strcmp(attr->name, "name") == 0)
name = attr->value;
else if (strcmp(attr->name, "namespace") == 0)
nmspace = attr->value;
}
}
if (name == NULL) {
return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"A DAV:supported-report element "
"does not have a \"name\" attribute");
}
/* default namespace to DAV: */
if (nmspace == NULL)
nmspace = "DAV:";
for (rp = reports; rp->nmspace != NULL; ++rp) {
if (strcmp(name, rp->name) == 0
&& strcmp(nmspace, rp->nmspace) == 0) {
/* Note: we presume reports->nmspace is
* properly XML/URL quoted
*/
s = apr_psprintf(r->pool,
"<D:supported-report "
"D:name=\"%s\" "
"D:namespace=\"%s\"/>"
DEBUG_CR,
rp->name, rp->nmspace);
apr_text_append(r->pool, body, s);
break;
}
}
}
}
}
}
}
apr_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR);
return NULL;
}
/* handle the SEARCH method */
static int dav_method_search(request_rec *r)
{
const dav_hooks_search *search_hooks = DAV_GET_HOOKS_SEARCH(r);
dav_resource *resource;
dav_error *err;
dav_response *multi_status;
/* If no search provider, decline the request */
if (search_hooks == NULL)
return DECLINED;
/* This method should only be called when the resource is not
* visible to Apache. We will fetch the resource from the repository,
* then create a subrequest for Apache to handle.
*/
err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */,
&resource);
if (err != NULL)
return dav_handle_err(r, err, NULL);
if (!resource->exists) {
/* Apache will supply a default error for this. */
return HTTP_NOT_FOUND;
}
/* set up the HTTP headers for the response */
if ((err = (*resource->hooks->set_headers)(r, resource)) != NULL) {
err = dav_push_error(r->pool, err->status, 0,
"Unable to set up HTTP headers.",
err);
return dav_handle_err(r, err, NULL);
}
if (r->header_only) {
return DONE;
}
/* okay... time to search the content */
/* Let's validate XML and process walk function
* in the hook function
*/
if ((err = (*search_hooks->search_resource)(r, &multi_status)) != NULL) {
/* ### add a higher-level description? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -