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

📄 mod_negotiation.c

📁 最新apache的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
             !strcmp(sub_req->handler, "type-map"))) {            apr_dir_close(dirp);            neg->avail_vars->nelts = 0;            if (sub_req->status != HTTP_OK) {                return sub_req->status;            }            return read_type_map(NULL, neg, sub_req);        }        /* Have reasonable variant --- gather notes. */        mime_info.sub_req = sub_req;        mime_info.file_name = apr_pstrdup(neg->pool, dirent.name);        if (sub_req->content_encoding) {            mime_info.content_encoding = sub_req->content_encoding;        }        if (sub_req->content_languages) {            mime_info.content_languages = sub_req->content_languages;        }        get_entry(neg->pool, &accept_info, sub_req->content_type);        set_mime_fields(&mime_info, &accept_info);        new_var = apr_array_push(neg->avail_vars);        memcpy(new_var, (void *) &mime_info, sizeof(var_rec));        neg->count_multiviews_variants++;        clean_var_rec(&mime_info);    }    apr_dir_close(dirp);    /* We found some file names that matched.  None could be served.     * Rather than fall out to autoindex or some other mapper, this     * request must die.     */    if (anymatch && !neg->avail_vars->nelts) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                      "Negotiation: discovered file(s) matching request: %s"                      " (None could be negotiated).",                      r->filename);        return HTTP_NOT_FOUND;    }    set_vlist_validator(r, r);    /* Sort the variants into a canonical order.  The negotiation     * result sometimes depends on the order of the variants.  By     * sorting the variants into a canonical order, rather than using     * the order in which readdir() happens to return them, we ensure     * that the negotiation result will be consistent over filesystem     * backup/restores and over all mirror sites.     */    qsort((void *) neg->avail_vars->elts, neg->avail_vars->nelts,          sizeof(var_rec), (int (*)(const void *, const void *)) variantsortf);    return OK;}/***************************************************************** * And now for the code you've been waiting for... actually * finding a match to the client's requirements. *//* Matching MIME types ... the star/star and foo/star commenting conventions * are implemented here.  (You know what I mean by star/star, but just * try mentioning those three characters in a C comment).  Using strcmp() * is legit, because everything has already been smashed to lowercase. * * Note also that if we get an exact match on the media type, we update * level_matched for use in level_cmp below... * * We also give a value for mime_stars, which is used later. It should * be 1 for star/star, 2 for type/star and 3 for type/subtype. */static int mime_match(accept_rec *accept_r, var_rec *avail){    const char *accept_type = accept_r->name;    const char *avail_type = avail->mime_type;    int len = strlen(accept_type);    if (accept_type[0] == '*') {        /* Anything matches star/star */        if (avail->mime_stars < 1) {            avail->mime_stars = 1;        }        return 1;    }    else if ((accept_type[len - 1] == '*') &&             !strncmp(accept_type, avail_type, len - 2)) {        if (avail->mime_stars < 2) {            avail->mime_stars = 2;        }        return 1;    }    else if (!strcmp(accept_type, avail_type)             || (!strcmp(accept_type, "text/html")                 && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE)                     || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) {        if (accept_r->level >= avail->level) {            avail->level_matched = avail->level;            avail->mime_stars = 3;            return 1;        }    }    return OK;}/* This code implements a piece of the tie-breaking algorithm between * variants of equal quality.  This piece is the treatment of variants * of the same base media type, but different levels.  What we want to * return is the variant at the highest level that the client explicitly * claimed to accept. * * If all the variants available are at a higher level than that, or if * the client didn't say anything specific about this media type at all * and these variants just got in on a wildcard, we prefer the lowest * level, on grounds that that's the one that the client is least likely * to choke on. * * (This is all motivated by treatment of levels in HTML --- we only * want to give level 3 to browsers that explicitly ask for it; browsers * that don't, including HTTP/0.9 browsers that only get the implicit * "Accept: * / *" [space added to avoid confusing cpp --- no, that * syntax doesn't really work] should get HTML2 if available). * * (Note that this code only comes into play when we are choosing among * variants of equal quality, where the draft standard gives us a fair * bit of leeway about what to do.  It ain't specified by the standard; * rather, it is a choice made by this server about what to do in cases * where the standard does not specify a unique course of action). */static int level_cmp(var_rec *var1, var_rec *var2){    /* Levels are only comparable between matching media types */    if (var1->is_pseudo_html && !var2->is_pseudo_html) {        return 0;    }    if (!var1->is_pseudo_html && strcmp(var1->mime_type, var2->mime_type)) {        return 0;    }    /* The result of the above if statements is that, if we get to     * here, both variants have the same mime_type or both are     * pseudo-html.     */    /* Take highest level that matched, if either did match. */    if (var1->level_matched > var2->level_matched) {        return 1;    }    if (var1->level_matched < var2->level_matched) {        return -1;    }    /* Neither matched.  Take lowest level, if there's a difference. */    if (var1->level < var2->level) {        return 1;    }    if (var1->level > var2->level) {        return -1;    }    /* Tied */    return 0;}/* Finding languages.  The main entry point is set_language_quality() * which is called for each variant. It sets two elements in the * variant record: *    language_quality  - the 'q' value of the 'best' matching language *                        from Accept-Language: header (HTTP/1.1) *    lang_index    -     Non-negotiated language priority, using *                        position of language on the Accept-Language: *                        header, if present, else LanguagePriority *                        directive order. * * When we do the variant checking for best variant, we use language * quality first, and if a tie, language_index next (this only applies * when _not_ using the RVSA/1.0 algorithm). If using the RVSA/1.0 * algorithm, lang_index is never used. * * set_language_quality() calls find_lang_index() and find_default_index() * to set lang_index. */static int find_lang_index(apr_array_header_t *accept_langs, char *lang){    const char **alang;    int i;    if (!lang || !accept_langs) {        return -1;    }    alang = (const char **) accept_langs->elts;    for (i = 0; i < accept_langs->nelts; ++i) {        if (!strncmp(lang, *alang, strlen(*alang))) {            return i;        }        alang += (accept_langs->elt_size / sizeof(char*));    }    return -1;}/* set_default_lang_quality() sets the quality we apply to variants * which have no language assigned to them. If none of the variants * have a language, we are not negotiating on language, so all are * acceptable, and we set the default q value to 1.0. However if * some of the variants have languages, we set this default to 0.0001. * The value of this default will be applied to all variants with * no explicit language -- which will have the effect of making them * acceptable, but only if no variants with an explicit language * are acceptable. The default q value set here is assigned to variants * with no language type in set_language_quality(). * * Note that if using the RVSA/1.0 algorithm, we don't use this * fiddle. */static void set_default_lang_quality(negotiation_state *neg){    var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;    int j;    if (!neg->dont_fiddle_headers) {        for (j = 0; j < neg->avail_vars->nelts; ++j) {            var_rec *variant = &avail_recs[j];            if (variant->content_languages &&                variant->content_languages->nelts) {                neg->default_lang_quality = 0.0001f;                return;            }        }    }    neg->default_lang_quality = 1.0f;}/* Set the language_quality value in the variant record. Also * assigns lang_index for ForceLanguagePriority. * * To find the language_quality value, we look for the 'q' value * of the 'best' matching language on the Accept-Language * header. The 'best' match is the language on Accept-Language * header which matches the language of this variant either fully, * or as far as the prefix marker (-). If two or more languages * match, use the longest string from the Accept-Language header * (see HTTP/1.1 [14.4]) * * When a variant has multiple languages, we find the 'best' * match for each variant language tag as above, then select the * one with the highest q value. Because both the accept-header * and variant can have multiple languages, we now have a hairy * loop-within-a-loop here. * * If the variant has no language and we have no Accept-Language * items, leave the quality at 1.0 and return. * * If the variant has no language, we use the default as set by * set_default_lang_quality() (1.0 if we are not negotiating on * language, 0.001 if we are). * * Following the setting of the language quality, we drop through to * set the old 'lang_index'. This is set based on either the order * of the languages on the Accept-Language header, or the * order on the LanguagePriority directive. This is only used * in the negotiation if the language qualities tie. */static void set_language_quality(negotiation_state *neg, var_rec *variant){    int forcepriority = neg->conf->forcelangpriority;    if (forcepriority == FLP_UNDEF) {        forcepriority = FLP_DEFAULT;    }    if (!variant->content_languages || !variant->content_languages->nelts) {        /* This variant has no content-language, so use the default         * quality factor for variants with no content-language         * (previously set by set_default_lang_quality()).         * Leave the factor alone (it remains at 1.0) when we may not fiddle         * with the headers.         */        if (!neg->dont_fiddle_headers) {            variant->lang_quality = neg->default_lang_quality;        }        if (!neg->accept_langs) {            return;             /* no accept-language header */        }        return;    }    else {        /* Variant has one (or more) languages.  Look for the best         * match. We do this by going through each language on the         * variant description looking for a match on the         * Accept-Language header. The best match is the longest         * matching language on the header. The final result is the         * best q value from all the languages on the variant         * description.         */        if (!neg->accept_langs) {            /* no accept-language header makes the variant indefinite */            variant->definite = 0;        }        else {    /* There is an accept-language with 0 or more items */            accept_rec *accs = (accept_rec *) neg->accept_langs->elts;            accept_rec *best = NULL, *star = NULL;            accept_rec *bestthistag;            char *lang, *p;            float fiddle_q = 0.0f;            int any_match_on_star = 0;            int i, j;            apr_size_t alen, longest_lang_range_len;            for (j = 0; j < variant->content_languages->nelts; ++j) {                p = NULL;                bestthistag = NULL;                longest_lang_range_len = 0;                alen = 0;                /* lang is the variant's language-tag, which is the one                 * we are allowed to use the prefix of in HTTP/1.1                 */                lang = ((char **) (variant->content_languages->elts))[j];                /* now find the best (i.e. longest) matching                 * Accept-Language header language. We put the best match                 * for this tag in bestthistag. We cannot update the                 * overall best (based on q value) because the best match                 * for this tag is the longest language item on the accept                 * header, not necessarily the highest q.                 */                for (i = 0; i < neg->accept_langs->nelts; ++i) {                    if (!strcmp(accs[i].name, "*")) {                        if (!star) {                            star = &accs[i];                        }                        continue;                    }                    /* Find language. We match if either the variant                     * language tag exactly matches the language range                     * from the accept header, or a prefix of the variant                     * language tag up to a '-' character matches the                     * whole of the language range in the Accept-Language                     * header.  Note that HTTP/1.x allows any number of                     * '-' characters in a tag or range, currently only                     * tags with zero or one '-' characters are defined                     * for general use (see rfc1766).                     *                     * We only use language range in the Accept-Language                     * header the best match for the variant language tag                     * if it is longer than the previous best match.                     */                    alen = strlen(accs[i].name);                    if ((strlen(lang) >= alen) &&                        !strncmp(lang, accs[i].name, alen) &&                        ((lang[alen] == 0) || (lang[alen] == '-')) ) {                        if (alen > longest_lang_range_len) {                            longest_lang_range_len = alen;                            bestthistag = &accs[i];                        }                    }                    if (!bestthistag && !neg->dont_fiddle_headers) {                        /* The next bit is a fiddle. Some browsers might                         * be configured to send more specific language                         * ranges than desirable. For example, an                         * Accept-Language of en-US should never match                         * variants with languages en or en-GB. But US                         * English speakers might pick en-US as their                         * language choice.  So this fiddle checks if the                         * language range has a prefix, and if so, it                         * matches variants which match that prefix with a                         * priority of 0.001. So a request for en-US would

⌨️ 快捷键说明

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