📄 util.c
字号:
dav_buffer work_buf = { 0 };
dav_response *new_response;
#if DAV_DEBUG
if (depth && response == NULL) {
/*
** ### bleck. we can't return errors for other URIs unless we have
** ### a "response" ptr.
*/
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"DESIGN ERROR: dav_validate_request called "
"with depth>0, but no response ptr.");
}
#endif
if (response != NULL)
*response = NULL;
/* Do the standard checks for conditional requests using
* If-..-Since, If-Match etc */
if ((result = ap_meets_conditions(r)) != OK) {
/* ### fix this up... how? */
return dav_new_error(r->pool, result, 0, NULL);
}
/* always parse (and later process) the If: header */
if ((err = dav_process_if_header(r, &if_header)) != NULL) {
/* ### maybe add higher-level description */
return err;
}
/* If a locktoken was specified, create a dummy if_header with which
* to validate resources. In the interim, figure out why DAV uses
* locktokens in an if-header without a Lock-Token header to refresh
* locks, but a Lock-Token header without an if-header to remove them.
*/
if (locktoken != NULL) {
dav_if_header *ifhdr_new;
ifhdr_new = apr_pcalloc(r->pool, sizeof(*ifhdr_new));
ifhdr_new->uri = resource->uri;
ifhdr_new->uri_len = strlen(resource->uri);
ifhdr_new->dummy_header = 1;
ifhdr_new->state = apr_pcalloc(r->pool, sizeof(*ifhdr_new->state));
ifhdr_new->state->type = dav_if_opaquelock;
ifhdr_new->state->condition = DAV_IF_COND_NORMAL;
ifhdr_new->state->locktoken = locktoken;
ifhdr_new->next = if_header;
if_header = ifhdr_new;
}
/*
** If necessary, open the lock database (read-only, lazily);
** the validation process may need to retrieve or update lock info.
** Otherwise, assume provided lockdb is valid and opened rw.
*/
if (lockdb == NULL) {
if (locks_hooks != NULL) {
if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, &lockdb)) != NULL) {
/* ### maybe insert higher-level comment */
return err;
}
lock_db_opened_locally = 1;
}
}
/* (1) Validate the specified resource, at the specified depth */
if (resource->exists && depth > 0) {
dav_walker_ctx ctx = { { 0 } };
dav_response *multi_status;
ctx.w.walk_type = DAV_WALKTYPE_NORMAL;
ctx.w.func = dav_validate_walker;
ctx.w.walk_ctx = &ctx;
ctx.w.pool = r->pool;
ctx.w.root = resource;
ctx.if_header = if_header;
ctx.r = r;
ctx.flags = flags;
if (lockdb != NULL) {
ctx.w.lockdb = lockdb;
ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL;
}
err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
if (err == NULL) {
*response = multi_status;;
}
/* else: implies a 5xx status code occurred. */
}
else {
err = dav_validate_resource_state(r->pool, resource, lockdb,
if_header, flags, &work_buf, r);
}
/* (2) Validate the parent resource if requested */
if (err == NULL && (flags & DAV_VALIDATE_PARENT)) {
dav_resource *parent_resource;
err = (*repos_hooks->get_parent_resource)(resource, &parent_resource);
if (err == NULL && parent_resource == NULL) {
err = dav_new_error(r->pool, HTTP_FORBIDDEN, 0,
"Cannot access parent of repository root.");
}
else if (err == NULL) {
err = dav_validate_resource_state(r->pool, parent_resource, lockdb,
if_header,
flags | DAV_VALIDATE_IS_PARENT,
&work_buf, r);
/*
** This error occurred on the parent resource. This implies that
** we have to create a multistatus response (to report the error
** against a URI other than the Request-URI). "Convert" this error
** into a multistatus response.
*/
if (err != NULL) {
new_response = apr_pcalloc(r->pool, sizeof(*new_response));
new_response->href = parent_resource->uri;
new_response->status = err->status;
new_response->desc =
"A validation error has occurred on the parent resource, "
"preventing the operation on the resource specified by "
"the Request-URI.";
if (err->desc != NULL) {
new_response->desc = apr_pstrcat(r->pool,
new_response->desc,
" The error was: ",
err->desc, NULL);
}
/* assert: DAV_VALIDATE_PARENT implies response != NULL */
new_response->next = *response;
*response = new_response;
err = NULL;
}
}
}
if (lock_db_opened_locally)
(*locks_hooks->close_lockdb)(lockdb);
/*
** If we don't have a (serious) error, and we have multistatus responses,
** then we need to construct an "error". This error will be the overall
** status returned, and the multistatus responses will go into its body.
**
** For certain methods, the overall error will be a 424. The default is
** to construct a standard 207 response.
*/
if (err == NULL && response != NULL && *response != NULL) {
apr_text *propstat = NULL;
if ((flags & DAV_VALIDATE_USE_424) != 0) {
/* manufacture a 424 error to hold the multistatus response(s) */
return dav_new_error(r->pool, HTTP_FAILED_DEPENDENCY, 0,
"An error occurred on another resource, "
"preventing the requested operation on "
"this resource.");
}
/*
** Whatever caused the error, the Request-URI should have a 424
** associated with it since we cannot complete the method.
**
** For a LOCK operation, insert an empty DAV:lockdiscovery property.
** For other methods, return a simple 424.
*/
if ((flags & DAV_VALIDATE_ADD_LD) != 0) {
propstat = apr_pcalloc(r->pool, sizeof(*propstat));
propstat->text =
"<D:propstat>" DEBUG_CR
"<D:prop><D:lockdiscovery/></D:prop>" DEBUG_CR
"<D:status>HTTP/1.1 424 Failed Dependency</D:status>" DEBUG_CR
"</D:propstat>" DEBUG_CR;
}
/* create the 424 response */
new_response = apr_pcalloc(r->pool, sizeof(*new_response));
new_response->href = resource->uri;
new_response->status = HTTP_FAILED_DEPENDENCY;
new_response->propresult.propstats = propstat;
new_response->desc =
"An error occurred on another resource, preventing the "
"requested operation on this resource.";
new_response->next = *response;
*response = new_response;
/* manufacture a 207 error for the multistatus response(s) */
return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
"Error(s) occurred on resources during the "
"validation process.");
}
return err;
}
/* dav_get_locktoken_list:
*
* Sets ltl to a locktoken_list of all positive locktokens in header,
* else NULL if no If-header, or no positive locktokens.
*/
DAV_DECLARE(dav_error *) dav_get_locktoken_list(request_rec *r,
dav_locktoken_list **ltl)
{
dav_error *err;
dav_if_header *if_header;
dav_if_state_list *if_state;
dav_locktoken_list *lock_token = NULL;
*ltl = NULL;
if ((err = dav_process_if_header(r, &if_header)) != NULL) {
/* ### add a higher-level description? */
return err;
}
while (if_header != NULL) {
if_state = if_header->state; /* Begining of the if_state linked list */
while (if_state != NULL) {
if (if_state->condition == DAV_IF_COND_NORMAL
&& if_state->type == dav_if_opaquelock) {
lock_token = apr_pcalloc(r->pool, sizeof(dav_locktoken_list));
lock_token->locktoken = if_state->locktoken;
lock_token->next = *ltl;
*ltl = lock_token;
}
if_state = if_state->next;
}
if_header = if_header->next;
}
if (*ltl == NULL) {
/* No nodes added */
return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_ABSENT,
"No locktokens were specified in the \"If:\" "
"header, so the refresh could not be performed.");
}
return NULL;
}
#if 0 /* not needed right now... */
static const char *strip_white(const char *s, apr_pool_t *pool)
{
apr_size_t idx;
/* trim leading whitespace */
while (apr_isspace(*s)) /* assume: return false for '\0' */
++s;
/* trim trailing whitespace */
idx = strlen(s) - 1;
if (apr_isspace(s[idx])) {
char *s2 = apr_pstrdup(pool, s);
while (apr_isspace(s2[idx]) && idx > 0)
--idx;
s2[idx + 1] = '\0';
return s2;
}
return s;
}
#endif
#define DAV_LABEL_HDR "Label"
/* dav_add_vary_header
*
* If there were any headers in the request which require a Vary header
* in the response, add it.
*/
DAV_DECLARE(void) dav_add_vary_header(request_rec *in_req,
request_rec *out_req,
const dav_resource *resource)
{
const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(in_req);
/* ### this is probably all wrong... I think there is a function in
### the Apache API to add things to the Vary header. need to check */
/* Only versioning headers require a Vary response header,
* so only do this check if there is a versioning provider */
if (vsn_hooks != NULL) {
const char *target = apr_table_get(in_req->headers_in, DAV_LABEL_HDR);
const char *vary = apr_table_get(out_req->headers_out, "Vary");
/* If Target-Selector specified, add it to the Vary header */
if (target != NULL) {
if (vary == NULL)
vary = DAV_LABEL_HDR;
else
vary = apr_pstrcat(out_req->pool, vary, "," DAV_LABEL_HDR,
NULL);
apr_table_setn(out_req->headers_out, "Vary", vary);
}
}
}
/* dav_can_auto_checkout
*
* Determine whether auto-checkout is enabled for a resource.
* r - the request_rec
* resource - the resource
* auto_version - the value of the auto_versionable hook for the resource
* lockdb - pointer to lock database (opened if necessary)
* auto_checkout - set to 1 if auto-checkout enabled
*/
static dav_error * dav_can_auto_checkout(
request_rec *r,
dav_resource *resource,
dav_auto_version auto_version,
dav_lockdb **lockdb,
int *auto_checkout)
{
dav_error *err;
dav_lock *lock_list;
*auto_checkout = 0;
if (auto_version == DAV_AUTO_VERSION_ALWAYS) {
*auto_checkout = 1;
}
else if (auto_version == DAV_AUTO_VERSION_LOCKED) {
if (*lockdb == NULL) {
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
if (locks_hooks == NULL) {
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"Auto-checkout is only enabled for locked resources, "
"but there is no lock provider.");
}
if ((err = (*locks_hooks->open_lockdb)(r, 0, 0, lockdb)) != NULL) {
return dav_push_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"Cannot open lock database to determine "
"auto-versioning behavior.",
e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -