📄 util.c
字号:
goto state_list_failed;
}
else if (state_list->condition == DAV_IF_COND_NOT
&& !mismatch) {
/*
** The specified entity-tag DOES match the
** entity-tag on the resource. This state_list is
** not going to match. Bust outta here.
*/
reason =
"an entity-tag was specified using the \"Not\" form, "
"but the resource's actual ETag matches the provided "
"entity-tag.";
goto state_list_failed;
}
break;
}
case dav_if_opaquelock:
if (lockdb == NULL) {
if (state_list->condition == DAV_IF_COND_NOT) {
/* the locktoken is definitely not there! (success) */
continue;
}
/* condition == DAV_IF_COND_NORMAL */
/*
** If no lockdb is provided, then validation fails for
** this state_list (NORMAL means we were supposed to
** find the token, which we obviously cannot do without
** a lock database).
**
** Go and try the next state list.
*/
reason =
"a State-token was supplied, but a lock database "
"is not available for to provide the required lock.";
goto state_list_failed;
}
/* Resource validation 'fails' if:
* ANY of the lock->locktokens match
* a NOT state_list->locktoken,
* OR
* NONE of the lock->locktokens match
* a NORMAL state_list->locktoken.
*/
num_matched = 0;
for (lock = lock_list; lock != NULL; lock = lock->next) {
/*
DBG2("compare: rsrc=%s ifhdr=%s",
(*locks_hooks->format_locktoken)(p, lock->locktoken),
(*locks_hooks->format_locktoken)(p, state_list->locktoken));
*/
/* nothing to do if the locktokens do not match. */
if ((*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) {
continue;
}
/*
** We have now matched up one of the resource's locktokens
** to a locktoken in a State-token in the If: header.
** Note this fact, so that we can pass the overall
** requirement of seeing at least one of the resource's
** locktokens.
*/
seen_locktoken = 1;
if (state_list->condition == DAV_IF_COND_NOT) {
/*
** This state requires that the specified locktoken
** is NOT present on the resource. But we just found
** it. There is no way this state-list can now
** succeed, so go try another one.
*/
reason =
"a State-token was supplied, which used a "
"\"Not\" condition. The State-token was found "
"in the locks on this resource";
goto state_list_failed;
}
/* condition == DAV_IF_COND_NORMAL */
/* Validate auth_user: If an authenticated user created
** the lock, only the same user may submit that locktoken
** to manipulate a resource.
*/
if (lock->auth_user &&
(!r->user ||
strcmp(lock->auth_user, r->user))) {
const char *errmsg;
errmsg = apr_pstrcat(p, "User \"",
r->user,
"\" submitted a locktoken created "
"by user \"",
lock->auth_user, "\".", NULL);
return dav_new_error(p, HTTP_FORBIDDEN, 0, errmsg);
}
/*
** We just matched a specified State-Token to one of the
** resource's locktokens.
**
** Break out of the lock scan -- we only needed to find
** one match (actually, there shouldn't be any other
** matches in the lock list).
*/
num_matched = 1;
break;
}
if (num_matched == 0
&& state_list->condition == DAV_IF_COND_NORMAL) {
/*
** We had a NORMAL state, meaning that we should have
** found the State-Token within the locks on this
** resource. We didn't, so this state_list must fail.
*/
reason =
"a State-token was supplied, but it was not found "
"in the locks on this resource.";
goto state_list_failed;
}
break;
} /* switch */
} /* foreach ( state_list ) */
/*
** We've checked every state in this state_list and none of them
** have failed. Since all of them succeeded, then we have a matching
** state list and we may be done.
**
** The next requirement is that we have seen one of the resource's
** locktokens (if any). If we have, then we can just exit. If we
** haven't, then we need to keep looking.
*/
if (seen_locktoken) {
/* woo hoo! */
return NULL;
}
/*
** Haven't seen one. Let's break out of the search and just look
** for a matching locktoken.
*/
break;
/*
** This label is used when we detect that a state_list is not
** going to match this resource. We bust out and try the next
** state_list.
*/
state_list_failed:
;
} /* foreach ( ifhdr_scan ) */
/*
** The above loop exits for one of two reasons:
** 1) a state_list matched and seen_locktoken is false.
** 2) all if_header structures were scanned, without (1) occurring
*/
if (ifhdr_scan == NULL) {
/*
** We finished the loop without finding any matching state lists.
*/
/*
** If none of the state_lists apply to this resource, then we
** may have succeeded. Note that this scenario implies a
** tagged-list with no matching state_lists. If the If: header
** was a no-tag-list, then it would have applied to this resource.
**
** S9.4.2 states that when no state_lists apply, then the header
** should be ignored.
**
** If we saw one of the resource's locktokens, then we're done.
** If we did not see a locktoken, then we fail.
*/
if (num_that_apply == 0) {
if (seen_locktoken)
return NULL;
/*
** We may have aborted the scan before seeing the locktoken.
** Rescan the If: header to see if we can find the locktoken
** somewhere.
**
** Note that seen_locktoken == 0 implies lock_list != NULL
** which implies locks_hooks != NULL.
*/
if (dav_find_submitted_locktoken(if_header, lock_list,
locks_hooks)) {
/*
** We found a match! We're set... none of the If: header
** assertions apply (implicit success), and the If: header
** specified the locktoken somewhere. We're done.
*/
return NULL;
}
return dav_new_error(p, HTTP_LOCKED, 0 /* error_id */,
"This resource is locked and the \"If:\" "
"header did not specify one of the "
"locktokens for this resource's lock(s).");
}
/* else: one or more state_lists were applicable, but failed. */
/*
** If the dummy_header did not match, then they specified an
** incorrect token in the Lock-Token header. Forget whether the
** If: statement matched or not... we'll tell them about the
** bad Lock-Token first. That is considered a 400 (Bad Request).
*/
if (if_header->dummy_header) {
return dav_new_error(p, HTTP_BAD_REQUEST, 0,
"The locktoken specified in the "
"\"Lock-Token:\" header did not specify one "
"of this resource's locktoken(s).");
}
if (reason == NULL) {
return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
"The preconditions specified by the \"If:\" "
"header did not match this resource.");
}
return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
apr_psprintf(p,
"The precondition(s) specified by "
"the \"If:\" header did not match "
"this resource. At least one "
"failure is because: %s", reason));
}
/* assert seen_locktoken == 0 */
/*
** ifhdr_scan != NULL implies we found a matching state_list.
**
** Since we're still here, it also means that we have not yet found
** one the resource's locktokens in the If: header.
**
** Scan all the if_headers and states looking for one of this
** resource's locktokens. Note that we need to go back and scan them
** all -- we may have aborted a scan with a failure before we saw a
** matching token.
**
** Note that seen_locktoken == 0 implies lock_list != NULL which implies
** locks_hooks != NULL.
*/
if (dav_find_submitted_locktoken(if_header, lock_list, locks_hooks)) {
/*
** We found a match! We're set... we have a matching state list,
** and the If: header specified the locktoken somewhere. We're done.
*/
return NULL;
}
/*
** We had a matching state list, but the user agent did not specify one
** of this resource's locktokens. Tell them so.
**
** Note that we need to special-case the message on whether a "dummy"
** header exists. If it exists, yet we didn't see a needed locktoken,
** then that implies the dummy header (Lock-Token header) did NOT
** specify one of this resource's locktokens. (this implies something
** in the real If: header matched)
**
** We want to note the 400 (Bad Request) in favor of a 423 (Locked).
*/
if (if_header->dummy_header) {
return dav_new_error(p, HTTP_BAD_REQUEST, 0,
"The locktoken specified in the "
"\"Lock-Token:\" header did not specify one "
"of this resource's locktoken(s).");
}
return dav_new_error(p, HTTP_LOCKED, 1 /* error_id */,
"This resource is locked and the \"If:\" header "
"did not specify one of the "
"locktokens for this resource's lock(s).");
}
/* dav_validate_walker: Walker callback function to validate resource state */
static dav_error * dav_validate_walker(dav_walk_resource *wres, int calltype)
{
dav_walker_ctx *ctx = wres->walk_ctx;
dav_error *err;
if ((err = dav_validate_resource_state(ctx->w.pool, wres->resource,
ctx->w.lockdb,
ctx->if_header, ctx->flags,
&ctx->work_buf, ctx->r)) == NULL) {
/* There was no error, so just bug out. */
return NULL;
}
/*
** If we have a serious server error, or if the request itself failed,
** then just return error (not a multistatus).
*/
if (ap_is_HTTP_SERVER_ERROR(err->status)
|| (*wres->resource->hooks->is_same_resource)(wres->resource,
ctx->w.root)) {
/* ### maybe push a higher-level description? */
return err;
}
/* associate the error with the current URI */
dav_add_response(wres, err->status, NULL);
return NULL;
}
/*
** dav_validate_request: Validate if-headers (and check for locks) on:
** (1) r->filename @ depth;
** (2) Parent of r->filename if check_parent == 1
**
** The check of parent should be done when it is necessary to verify that
** the parent collection will accept a new member (ie current resource
** state is null).
**
** Return OK on successful validation.
** On error, return appropriate HTTP_* code, and log error. If a multi-stat
** error is necessary, response will point to it, else NULL.
*/
DAV_DECLARE(dav_error *) dav_validate_request(request_rec *r,
dav_resource *resource,
int depth,
dav_locktoken *locktoken,
dav_response **response,
int flags,
dav_lockdb *lockdb)
{
dav_error *err;
int result;
dav_if_header *if_header;
int lock_db_opened_locally = 0;
const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r);
const dav_hooks_repository *repos_hooks = resource->hooks;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -