📄 util.c
字号:
new_sl->type = t; if (t == dav_if_opaquelock) { dav_error *err; if ((err = (*locks_hooks->parse_locktoken)(p, state_token, &new_sl->locktoken)) != NULL) { /* ### maybe add a higher-level description */ return err; } } else new_sl->etag = state_token; new_sl->next = ih->state; ih->state = new_sl; return NULL;}/* fetch_next_token returns the substring from str+1 * to the next occurence of char term, or \0, whichever * occurs first. Leading whitespace is ignored. */static char *dav_fetch_next_token(char **str, char term){ char *sp; char *token; token = *str + 1; while (*token && (*token == ' ' || *token == '\t')) token++; if ((sp = strchr(token, term)) == NULL) return NULL; *sp = '\0'; *str = sp; return token;}/* dav_process_if_header: * * If NULL (no error) is returned, then **if_header points to the * "If" productions structure (or NULL if "If" is not present). * * ### this part is bogus: * If an error is encountered, the error is logged. Parent should * return err->status. */static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih){ dav_error *err; char *str; char *list; const char *state_token; const char *uri = NULL; /* scope of current production; NULL=no-tag */ size_t uri_len = 0; dav_if_header *ih = NULL; uri_components parsed_uri; const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); enum {no_tagged, tagged, unknown} list_type = unknown; int condition; *p_ih = NULL; if ((str = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "If"))) == NULL) return NULL; while (*str) { switch(*str) { case '<': /* Tagged-list production - following states apply to this uri */ if (list_type == no_tagged || ((uri = dav_fetch_next_token(&str, '>')) == NULL)) { return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_TAGGED, "Invalid If-header: unclosed \"<\" or " "unexpected tagged-list production."); } /* 2518 specifies this must be an absolute URI; just take the * relative part for later comparison against r->uri */ if (ap_parse_uri_components(r->pool, uri, &parsed_uri) != HTTP_OK) { return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_TAGGED, "Invalid URI in tagged If-header."); } /* note that parsed_uri.path is allocated; we can trash it */ /* clean up the URI a bit */ ap_getparents(parsed_uri.path); uri_len = strlen(parsed_uri.path); if (uri_len > 1 && parsed_uri.path[uri_len - 1] == '/') parsed_uri.path[--uri_len] = '\0'; uri = parsed_uri.path; list_type = tagged; break; case '(': /* List production */ /* If a uri has not been encountered, this is a No-Tagged-List */ if (list_type == unknown) list_type = no_tagged; if ((list = dav_fetch_next_token(&str, ')')) == NULL) { return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_UNCLOSED_PAREN, "Invalid If-header: unclosed \"(\"."); } if ((ih = dav_add_if_resource(r->pool, ih, uri, uri_len)) == NULL) { /* ### dav_add_if_resource() should return an error for us! */ return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_PARSE, "Internal server error parsing \"If:\" " "header."); } condition = DAV_IF_COND_NORMAL; while (*list) { /* List is the entire production (in a uri scope) */ switch (*list) { case '<': if ((state_token = dav_fetch_next_token(&list, '>')) == NULL) { /* ### add a description to this error */ return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_PARSE, NULL); } if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_opaquelock, condition, locks_hooks)) != NULL) { /* ### maybe add a higher level description */ return err; } condition = DAV_IF_COND_NORMAL; break; case '[': if ((state_token = dav_fetch_next_token(&list, ']')) == NULL) { /* ### add a description to this error */ return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_PARSE, NULL); } if ((err = dav_add_if_state(r->pool, ih, state_token, dav_if_etag, condition, locks_hooks)) != NULL) { /* ### maybe add a higher level description */ return err; } condition = DAV_IF_COND_NORMAL; break; case 'N': if (list[1] == 'o' && list[2] == 't') { if (condition != DAV_IF_COND_NORMAL) { return dav_new_error(r->pool, HTTP_BAD_REQUEST, DAV_ERR_IF_MULTIPLE_NOT, "Invalid \"If:\" header: " "Multiple \"not\" entries " "for the same state."); } condition = DAV_IF_COND_NOT; } list += 2; 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').", *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';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -