📄 mod_negotiation.c
字号:
* 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. Note that this * fiddle does not handle multi-level prefixes. */ if ((p = strchr(accs[i].name, '-'))) { int plen = p - accs[i].name; if (!strncmp(lang, accs[i].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; } /* See if the tag matches on a * in the Accept-Language * header. If so, record this fact for later use */ if (!bestthistag && star) { any_match_on_star = 1; } } /* If one of the language tags of the variant matched on *, we * need to see if its q is better than that of any non-* match * on any other tag of the variant. If so the * match takes * precedence and the overall match is not definite. */ if ( any_match_on_star && ((best && star->quality > best->quality) || (!best)) ) { best = star; variant->definite = 0; } variant->lang_quality = best ? best->quality : fiddle_q; } } /* Handle the ForceDefaultLanguage overrides, based on the best match * to LanguagePriority order. The best match is the lowest index of * any LanguagePriority match. */ if (((forcepriority & FLP_PREFER) && (variant->lang_index < 0)) || ((forcepriority & FLP_FALLBACK) && !variant->lang_quality)) { int bestidx = -1; int j; for (j = 0; j < variant->content_languages->nelts; ++j) { /* lang is the variant's language-tag, which is the one * we are allowed to use the prefix of in HTTP/1.1 */ char *lang = ((char **) (variant->content_languages->elts))[j]; int idx = -1; /* If we wish to fallback or * we use our own LanguagePriority index. */ idx = find_lang_index(neg->conf->language_priority, lang); if ((idx >= 0) && ((bestidx == -1) || (idx < bestidx))) { bestidx = idx; } } if (bestidx >= 0) { if (variant->lang_quality) { if (forcepriority & FLP_PREFER) { variant->lang_index = bestidx; } } else { if (forcepriority & FLP_FALLBACK) { variant->lang_index = bestidx; variant->lang_quality = .0001f; variant->definite = 0; } } } } return;}/* Determining the content length --- if the map didn't tell us, * we have to do a stat() and remember for next time. */static apr_off_t find_content_length(negotiation_state *neg, var_rec *variant){ apr_finfo_t statb; if (variant->bytes < 0) { if ( variant->sub_req && (variant->sub_req->finfo.valid & APR_FINFO_SIZE)) { variant->bytes = variant->sub_req->finfo.size; } else { char *fullname = ap_make_full_path(neg->pool, neg->dir_name, variant->file_name); if (apr_stat(&statb, fullname, APR_FINFO_SIZE, neg->pool) == APR_SUCCESS) { variant->bytes = statb.size; } } } return variant->bytes;}/* For a given variant, find the best matching Accept: header * and assign the Accept: header's quality value to the * mime_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; float q = 0.0f; int q_definite = 1; /* if no Accept: header, leave quality alone (will * remain at the default value of 1) * * XXX: This if is currently never true because of the effect of * maybe_add_default_accepts(). */ if (!neg->accepts) { if (variant->mime_type && *variant->mime_type) variant->definite = 0; return; } accept_recs = (accept_rec *) neg->accepts->elts; /* * 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 * mime_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 */ } } /* If we are allowed to mess with the q-values * and have no explicit q= parameters in the accept header, * make wildcards very low, so we have a low chance * of ending up with them if there's something better. */ if (!neg->dont_fiddle_headers && !neg->accept_q && variant->mime_stars == 1) { q = 0.01f; } else if (!neg->dont_fiddle_headers && !neg->accept_q && variant->mime_stars == 2) { q = 0.02f; } else { q = type->quality; } q_definite = (variant->mime_stars == 3); } variant->mime_type_quality = q; variant->definite = variant->definite && q_definite;}/* For a given variant, find the 'q' value of the charset given * on the Accept-Charset line. If no charsets are listed, * assume value of '1'. */static void set_charset_quality(negotiation_state *neg, var_rec *variant){ int i; accept_rec *accept_recs; const 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) { if (charset && *charset) variant->definite = 0; return; } accept_recs = (accept_rec *) neg->accept_charsets->elts; if (charset == NULL || !*charset) { /* Charset of variant not known */ /* if not a text / * type, leave quality alone */ if (!(!strncmp(variant->mime_type, "text/", 5) || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE) || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE3) )) return; /* Don't go guessing if we are in strict header mode, * e.g. when running the rvsa, as any guess won't be reflected * in the variant list or content-location headers. */ if (neg->dont_fiddle_headers) return; charset = "iso-8859-1"; /* The default charset for HTTP text types */ } /* * 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->name, charset)) { variant->charset_quality = type->quality; return; } else if (strcmp(type->name, "*") == 0) { star = type; } } /* No explicit match */ if (star) { variant->charset_quality = star->quality; variant->definite = 0; 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; }}/* 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"));}/* * set_encoding_quality determines whether the encoding for a particular * variant is acceptable for the user-agent. * * The rules for encoding are that if the user-agent does not supply * any Accept-Encoding header, then all encodings are allowed but a * variant with no encoding should be preferred. * If there is an empty Accept-Encoding header, then no encodings are * acceptable. If there is a non-empty Accept-Encoding header, then * any of the listed encodings are acceptable, as well as no encoding * unless the "identity" encoding is specifically excluded. */static void set_encoding_quality(negotiation_state *neg, var_rec *variant){ accept_rec *accept_recs; const char *enc = variant->content_encoding; accept_rec *star = NULL; float value_if_not_found = 0.0f; int i; if (!neg->accept_encodings) { /* We had no Accept-Encoding header, assume that all * encodings are acceptable with a low quality, * but we prefer no encoding if available. */ if (!enc || is_identity_encoding(enc)) variant->encoding_quality = 1.0f; else variant->encoding_quality = 0.5f; return; } if (!enc || is_identity_encoding(enc)) { enc = "identity"; value_if_not_found = 0.0001f; } accept_recs = (accept_rec *) neg->accept_encodings->elts; /* 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].name; if (name[0] == 'x' && name[1] == '-') { name += 2; } if (!strcmp(name, enc)) { variant->encoding_quality = accept_recs[i].quality; return; } if (strcmp(name, "*") == 0) { star = &accept_recs[i]; } } /* No explicit match */ if (star) { variant->encoding_quality = star->quality; return; } /* Encoding not found on Accept-Encoding: header, so it is * _not_ acceptable unless it is the identity (no encoding) */ variant->encoding_quality = value_if_not_found;}/************************************************************* * Possible results of the variant selection algorithm */enum algorithm_results { alg_choice = 1, /* choose variant */ alg_list /* list variants */};/* Below is the 'best_match' function. It returns an int, which has * one of the two values alg_choice or alg_list, which give the result * of the variant selection algorithm. alg_list means that no best * variant was found by the algorithm, alg_choice means that a best * variant was found and should be returned. The list/choice * terminology comes from TCN (rfc2295), but is used in a more generic * way here. The best variant is returned in *pbest. best_match has * two possible algorithms for determining the best variant: the * RVSA/1.0 algorithm (from RFC2296), and the standard Apache * algorithm. These are split out into separate functions * (is_variant_better_rvsa() and is_variant_better()). Selection of * one is through the neg->use_rvsa flag. * * The call to best_match also creates full information, including * language, charset, etc quality for _every_ variant. This is needed * for generating a correct Vary header, and can be used for the * Alte
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -