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

📄 mod_negotiation.c

📁 apache简化版
💻 C
📖 第 1 页 / 共 5 页
字号:
                if (!strcmp(accs[i].type_name, "*")) {                    if (!star) {                        star = &accs[i];                    }                    continue;                }                /* Find language. We match if either the variant language                 * tag exactly matches, or the prefix of the tag up to the                 * '-' character matches the whole of the language in the                 * Accept-Language header. We only use this accept-language                 * item as the best match for the current tag if it                 * is longer than the previous best match */                if ((!strcmp(lang, accs[i].type_name) ||                     (prefixlen &&                      !strncmp(lang, accs[i].type_name, prefixlen) &&                      (accs[i].type_name[prefixlen] == '\0'))) &&                    ((len = strlen(accs[i].type_name)) >                     longest_lang_range_len)) {                    longest_lang_range_len = len;                    bestthistag = &accs[i];                }                if (!bestthistag) {                    /* 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                     * match variants of types en and en-GB, but at much                     * lower priority than matches of en-US directly, or                     * of any other language listed on the Accept-Language                     * header                     */                    if ((p = strchr(accs[i].type_name, '-'))) {                        int plen = p - accs[i].type_name;                        if (!strncmp(lang, accs[i].type_name, plen)) {                            fiddle_q = 0.001f;                        }                    }                }            }            /* Finished looking at Accept-Language headers, the best             * (longest) match is in bestthistag, or NULL if no match             */            if (!best ||                (bestthistag && bestthistag->quality > best->quality)) {                best = bestthistag;            }        }        variant->lang_quality = best            ? best->quality            : (star ? star->quality : fiddle_q);    }    /* Now set the old lang_index field. Since this is old      * stuff anyway, don't both with handling multiple languages     * per variant, just use the first one assigned to it     */    idx = 0;    if (variant->content_languages && variant->content_languages->nelts) {        firstlang = ((char **) variant->content_languages->elts)[0];    }    else {        firstlang = "";    }    if (naccept == 0) {         /* Client doesn't care */        idx = find_default_index(conf, firstlang);    }    else {                      /* Client has Accept-Language */        idx = find_lang_index(neg->accept_langs, firstlang);    }    variant->lang_index = idx;    return;}/* Determining the content length --- if the map didn't tell us, * we have to do a stat() and remember for next time. * * Grump.  For Apache, even the first stat here may well be * redundant (for multiviews) with a stat() done by the sub_req * machinery.  At some point, that ought to be fixed. */static float find_content_length(negotiation_state *neg, var_rec *variant){    struct stat statb;    if (variant->bytes == 0) {        char *fullname = ap_make_full_path(neg->pool, neg->dir_name,                                        variant->file_name);        if (stat(fullname, &statb) >= 0) {            /* Note, precision may be lost */            variant->bytes = (float) statb.st_size;        }    }    return variant->bytes;}/* For a given variant, find the best matching Accept: header * and assign the Accept: header's quality value to the * accept_type_quality field of the variant, for later use in * determining the best matching variant. */static void set_accept_quality(negotiation_state *neg, var_rec *variant){    int i;    accept_rec *accept_recs = (accept_rec *) neg->accepts->elts;    float q = 0.0f;    int q_definite = 1;    /* if no Accept: header, leave quality alone (will     * remain at the default value of 1) */    if (!neg->accepts || neg->accepts->nelts == 0) {        return;    }    /*     * Go through each of the ranges on the Accept: header,     * looking for the 'best' match with this variant's     * content-type. We use the best match's quality     * value (from the Accept: header) for this variant's     * accept_type_quality field.     *     * The best match is determined like this:     *    type/type is better than type/ * is better than * / *     *    if match is type/type, use the level mime param if available     */    for (i = 0; i < neg->accepts->nelts; ++i) {        accept_rec *type = &accept_recs[i];        int prev_mime_stars;        prev_mime_stars = variant->mime_stars;        if (!mime_match(type, variant)) {            continue;           /* didn't match the content type at all */        }        else {            /* did match - see if there were less or more stars than             * in previous match             */            if (prev_mime_stars == variant->mime_stars) {                continue;       /* more stars => not as good a match */            }        }        /* Check maxbytes -- not in HTTP/1.1 or Holtman */        if (type->max_bytes > 0            && (find_content_length(neg, variant) > type->max_bytes)) {            continue;        }        /* If we are allowed to mess with the q-values,         * make wildcards very low, so we have a low chance         * of ending up with them if there's something better.         */        if (!neg->accept_q && variant->mime_stars == 1) {            q = 0.01f;        }        else if (!neg->accept_q && variant->mime_stars == 2) {            q = 0.02f;        }        else {            q = type->quality;        }        q_definite = (variant->mime_stars == 3);    }    variant->accept_type_quality = q;    variant->definite = variant->definite && q_definite;    /* if the _best_ quality we got for this variant was 0.0,     * eliminate it now */}/* For a given variant, find the 'q' value of the charset given * on the Accept-Charset line. If not charsets are listed, * assume value of '1'. */static void set_charset_quality(negotiation_state *neg, var_rec *variant){    int i;    accept_rec *accept_recs = (accept_rec *) neg->accept_charsets->elts;    char *charset = variant->content_charset;    accept_rec *star = NULL;    /* if no Accept-Charset: header, leave quality alone (will     * remain at the default value of 1) */    if (!neg->accept_charsets || neg->accept_charsets->nelts == 0) {        return;    }    if (charset == NULL || !*charset) {        charset = "iso-8859-1";    }    /*     * Go through each of the items on the Accept-Charset: header,     * looking for a match with this variant's charset. If none     * match, charset is unacceptable, so set quality to 0.     */    for (i = 0; i < neg->accept_charsets->nelts; ++i) {        accept_rec *type = &accept_recs[i];        if (!strcmp(type->type_name, charset)) {            variant->charset_quality = type->quality;            return;        }        else if (strcmp(type->type_name, "*") == 0) {            star = type;        }    }    /* No explicit match */    if (star) {        variant->charset_quality = star->quality;        return;    }    /* If this variant is in charset iso-8859-1, the default is 1.0 */    if (strcmp(charset, "iso-8859-1") == 0) {        variant->charset_quality = 1.0f;    }    else {        variant->charset_quality = 0.0f;    }}/* For a given variant, find the best matching Accept: header * and assign the Accept: header's quality value to the * accept_type_quality field of the variant, for later use in * determining the best matching variant. *//* is_identity_encoding is included for back-compat, but does anyone * use 7bit, 8bin or binary in their var files?? */static int is_identity_encoding(const char *enc){    return (!enc || !enc[0] || !strcmp(enc, "7bit") || !strcmp(enc, "8bit")            || !strcmp(enc, "binary"));}static void set_encoding_quality(negotiation_state *neg, var_rec *variant){    int i;    accept_rec *accept_recs = (accept_rec *) neg->accept_encodings->elts;    const char *enc = variant->content_encoding;    if (!enc || is_identity_encoding(enc)) {        return;    }    /* if no Accept: header, leave quality alone (will     * remain at the default value of 1) */    if (neg->accept_encodings->nelts == 0) {        /* If we had an empty Accept-Encoding header, assume that         * no encodings are acceptable, else all encodings are ok */        variant->encoding_quality = neg->have_accept_header ? 0 : 1;        return;    }    /* Go through each of the encodings on the Accept-Encoding: header,     * looking for a match with our encoding. x- prefixes are ignored.     */    if (enc[0] == 'x' && enc[1] == '-') {        enc += 2;    }    for (i = 0; i < neg->accept_encodings->nelts; ++i) {        char *name = accept_recs[i].type_name;        if (name[0] == 'x' && name[1] == '-') {            name += 2;        }        if (!strcmp(name, enc)) {            variant->encoding_quality = 1;            return;        }    }    /* Encoding not found on Accept-Encoding: header, so it is     * _not_ acceptable */    variant->encoding_quality = 0;}/* Possible results of the network algorithm */enum algorithm_results {    na_not_applied = -1,        /* net algorithm not used */    na_choice = 1,              /* choose variant */    na_list                     /* list variants */};/* * This is a heavily-rewritten 'best_match' function. For a start, it * now returns an int, which has one of the three values: na_not_applied, * na_choice or na_list, which give the result of the network algorithm * (if it was not applied, the return value is na_not_applied). * The best variable is returned in *pbest. It also has two possible * algorithms for determining the best match: the network algorithm, * and the standard Apache algorithm. These are split out into * separate functions (is_variant_better_na() and is_variant_better()). * * Previously, best_match iterated first through the content_types * in the Accept: header, then checked each variant, and eliminated * those that didn't match the variant's type. We cannot do this because * we need full information, including language, charset, etc * quality for _every_ variant, for the Alternates: header, * and (possibly) the human-readable choice responses or 406 errors. * * After the 'best' (if any) is determined, the overall result of * the negotiation is obtained. If the network algorithm was not * in use, the result is na_not_applied. Else the result is * na_list if 'short accept header' is in use, else na_list * if _no_ best match was found, or na_choice if a best match * was found. *//* Firstly, the negotiation 'network algorithm' from Holtman. */static int is_variant_better_na(negotiation_state *neg, var_rec *variant,                                var_rec *best, float *p_bestq){    float bestq = *p_bestq, q;    /* Note: Encoding is not negotiated in the Holtman     * transparent neg draft, so we ignored it here. But     * it does mean we could return encodings the UA     * or proxy cannot handle. Eek. */    q = variant->accept_type_quality *        variant->type_quality *        variant->charset_quality *        variant->lang_quality;#ifdef NEG_DEBUG    fprintf(stderr, "Variant: file=%s type=%s lang=%s acceptq=%1.3f "            "langq=%1.3f typeq=%1.3f q=%1.3f definite=%d\n",            (variant->file_name ? variant->file_name : ""),            (variant->type_name ? variant->type_name : ""),            (variant->content_languages             ? merge_string_array(neg->pool, variant->content_languages, ",")             : ""),            variant->accept_type_quality,            variant->lang_quality,            variant->type_quality,            q,            variant->definite);#endif    if (q > bestq) {        *p_bestq = q;        return 1;    }    if (q == bestq) {        /* If the best variant's charset is ISO-8859-1 and this variant has         * the same charset quality, then we prefer this variant         */        if (variant->charset_quality == best->charset_quality &&            (variant->content_charset != NULL &&             *variant->content_charset != '\0' &&             strcmp(variant->content_charset, "iso-8859-1") != 0) &&            (best->content_charset == NULL ||             *best->content_charset == '\0' ||             strcmp(best->content_charset, "iso-8859-1") == 0)) {            *p_bestq = q;            return 1;        }    }    return 0;}/* Negotiation algorithm as used by previous versions of Apache * (just about).  */static int is_variant_better(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq){    float bestq = *p_bestq, q;    int levcmp;    /*     * For non-transparent negotiation, server can choose how     * to handle the negotiation. We'll use the following in     * order: content-type, language, content-type level, charset,     * content length.

⌨️ 快捷键说明

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