⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
                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';
        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:
            {
                int mismatch = strcmp(state_list->etag, 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.";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -