📄 util.c
字号:
"Invalid \"If:\" " "header: Unexpected " "character encountered " "(0x%02x, '%c').", *list, *list)); } list++; } break; case ' ': case '\t': break; default: return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_UNK_CHAR, apr_psprintf(r->pool, "Invalid \"If:\" header: " "Unexpected character " "encountered (0x%02x, '%c').", *str, *str)); } str++; } *p_ih = ih; return NULL;}static int dav_find_submitted_locktoken(const dav_if_header *if_header, const dav_lock *lock_list, const dav_hooks_locks *locks_hooks){ for (; if_header != NULL; if_header = if_header->next) { const dav_if_state_list *state_list; for (state_list = if_header->state; state_list != NULL; state_list = state_list->next) { if (state_list->type == dav_if_opaquelock) { const dav_lock *lock; /* given state_list->locktoken, match it */ /* ** The resource will have one or more lock tokens. We only ** need to match one of them against any token in the ** If: header. ** ** One token case: It is an exclusive or shared lock. Either ** way, we must find it. ** ** N token case: They are shared locks. By policy, we need ** to match only one. The resource's other ** tokens may belong to somebody else (so we ** shouldn't see them in the If: header anyway) */ for (lock = lock_list; lock != NULL; lock = lock->next) { if (!(*locks_hooks->compare_locktoken)(state_list->locktoken, lock->locktoken)) { return 1; } } } } } return 0;}/* dav_validate_resource_state: * Returns NULL if path/uri meets if-header and lock requirements */static dav_error * dav_validate_resource_state(apr_pool_t *p, const dav_resource *resource, dav_lockdb *lockdb, const dav_if_header *if_header, int flags, dav_buffer *pbuf, request_rec *r){ dav_error *err; const char *uri; const char *etag; const dav_hooks_locks *locks_hooks = (lockdb ? lockdb->hooks : NULL); const dav_if_header *ifhdr_scan; dav_if_state_list *state_list; dav_lock *lock_list; dav_lock *lock; int num_matched; int num_that_apply; int seen_locktoken; apr_size_t uri_len; const char *reason = NULL; /* DBG1("validate: <%s>", resource->uri); */ /* ** The resource will have one of three states: ** ** 1) No locks. We have no special requirements that the user supply ** specific locktokens. One of the state lists must match, and ** we're done. ** ** 2) One exclusive lock. The locktoken must appear *anywhere* in the ** If: header. Of course, asserting the token in a "Not" term will ** quickly fail that state list :-). If the locktoken appears in ** one of the state lists *and* one state list matches, then we're ** done. ** ** 3) One or more shared locks. One of the locktokens must appear ** *anywhere* in the If: header. If one of the locktokens appears, ** and we match one state list, then we are done. ** ** The <seen_locktoken> variable determines whether we have seen one ** of this resource's locktokens in the If: header. */ /* ** If this is a new lock request, <flags> will contain the requested ** lock scope. Three rules apply: ** ** 1) Do not require a (shared) locktoken to be seen (when we are ** applying another shared lock) ** 2) If the scope is exclusive and we see any locks, fail. ** 3) If the scope is shared and we see an exclusive lock, fail. */ if (lockdb == NULL) { /* we're in State 1. no locks. */ lock_list = NULL; } else { /* ** ### hrm... we don't need to have these fully ** ### resolved since we're only looking at the ** ### locktokens... ** ** ### use get_locks w/ calltype=PARTIAL */ if ((err = dav_lock_query(lockdb, resource, &lock_list)) != NULL) { return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "The locks could not be queried for " "verification against a possible \"If:\" " "header.", err); } /* lock_list now determines whether we're in State 1, 2, or 3. */ } /* ** For a new, exclusive lock: if any locks exist, fail. ** For a new, shared lock: if an exclusive lock exists, fail. ** else, do not require a token to be seen. */ if (flags & DAV_LOCKSCOPE_EXCLUSIVE) { if (lock_list != NULL) { return dav_new_error(p, HTTP_LOCKED, 0, "Existing lock(s) on the requested resource " "prevent an exclusive lock."); } /* ** There are no locks, so we can pretend that we've already met ** any requirement to find the resource's locks in an If: header. */ seen_locktoken = 1; } else if (flags & DAV_LOCKSCOPE_SHARED) { /* ** Strictly speaking, we don't need this loop. Either the first ** (and only) lock will be EXCLUSIVE, or none of them will be. */ for (lock = lock_list; lock != NULL; lock = lock->next) { if (lock->scope == DAV_LOCKSCOPE_EXCLUSIVE) { return dav_new_error(p, HTTP_LOCKED, 0, "The requested resource is already " "locked exclusively."); } } /* ** The locks on the resource (if any) are all shared. Set the ** <seen_locktoken> flag to indicate that we do not need to find ** the locks in an If: header. */ seen_locktoken = 1; } else { /* ** For methods other than LOCK: ** ** If we have no locks, then <seen_locktoken> can be set to true -- ** pretending that we've already met the requirement of seeing one ** of the resource's locks in the If: header. ** ** Otherwise, it must be cleared and we'll look for one. */ seen_locktoken = (lock_list == NULL); } /* ** If there is no If: header, then we can shortcut some logic: ** ** 1) if we do not need to find a locktoken in the (non-existent) If: ** header, then we are successful. ** ** 2) if we must find a locktoken in the (non-existent) If: header, then ** we fail. */ if (if_header == NULL) { if (seen_locktoken) return NULL; return dav_new_error(p, HTTP_LOCKED, 0, "This resource is locked and an \"If:\" header " "was not supplied to allow access to the " "resource."); } /* the If: header is present */ /* ** If a dummy header is present (because of a Lock-Token: header), then ** we are required to find that token in this resource's set of locks. ** If we have no locks, then we immediately fail. ** ** This is a 400 (Bad Request) since they should only submit a locktoken ** that actually exists. ** ** Don't issue this response if we're talking about the parent resource. ** It is okay for that resource to NOT have this locktoken. ** (in fact, it certainly will not: a dummy_header only occurs for the ** UNLOCK method, the parent is checked only for locknull resources, ** and the parent certainly does not have the (locknull's) locktoken) */ if (lock_list == NULL && if_header->dummy_header) { if (flags & DAV_VALIDATE_IS_PARENT) return NULL; return dav_new_error(p, HTTP_BAD_REQUEST, 0, "The locktoken specified in the \"Lock-Token:\" " "header is invalid because this resource has no " "outstanding locks."); } /* ** Prepare the input URI. We want the URI to never have a trailing slash. ** ** When URIs are placed into the dav_if_header structure, they are ** guaranteed to never have a trailing slash. If the URIs are equivalent, ** then it doesn't matter if they both lack a trailing slash -- they're ** still equivalent. ** ** Note: we could also ensure that a trailing slash is present on both ** URIs, but the majority of URIs provided to us via a resource walk ** will not contain that trailing slash. */ uri = resource->uri; uri_len = strlen(uri); if (uri[uri_len - 1] == '/') { dav_set_bufsize(p, pbuf, uri_len); memcpy(pbuf->buf, uri, uri_len); pbuf->buf[--uri_len] = '\0'; uri = pbuf->buf; } /* get the resource's etag; we may need it during the checks */ etag = (*resource->hooks->getetag)(resource); /* how many state_lists apply to this URI? */ num_that_apply = 0; /* If there are if-headers, fail if this resource * does not match at least one state_list. */ for (ifhdr_scan = if_header; ifhdr_scan != NULL; ifhdr_scan = ifhdr_scan->next) { /* DBG2("uri=<%s> if_uri=<%s>", uri, ifhdr_scan->uri ? ifhdr_scan->uri : "(no uri)"); */ if (ifhdr_scan->uri != NULL && (uri_len != ifhdr_scan->uri_len || memcmp(uri, ifhdr_scan->uri, uri_len) != 0)) { /* ** A tagged-list's URI doesn't match this resource's URI. ** Skip to the next state_list to see if it will match. */ continue; } /* this state_list applies to this resource */ /* ** ### only one state_list should ever apply! a no-tag, or a tagged ** ### where S9.4.2 states only one can match. ** ** ### revamp this code to loop thru ifhdr_scan until we find the ** ### matching state_list. process it. stop. */ ++num_that_apply; /* To succeed, resource must match *all* of the states * specified in the state_list. */ for (state_list = ifhdr_scan->state; state_list != NULL; state_list = state_list->next) { switch(state_list->type) { case dav_if_etag: { const char *given_etag, *current_etag; int mismatch; /* Do a weak entity comparison function as defined in * RFC 2616 13.3.3. */ if (state_list->etag[0] == 'W' && state_list->etag[1] == '/') { given_etag = state_list->etag + 2; } else { given_etag = state_list->etag; } if (etag[0] == 'W' && etag[1] == '/') { current_etag = etag + 2; } else { current_etag = etag; } mismatch = strcmp(given_etag, current_etag); if (state_list->condition == DAV_IF_COND_NORMAL && mismatch) { /* ** The specified entity-tag does not match the ** entity-tag on the resource. This state_list is ** not going to match. Bust outta here. */ reason = "an entity-tag was specified, but the resource's " "actual ETag does not match."; 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 "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -