📄 mod_negotiation.c
字号:
{ int i; accept_rec *accept_recs; 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 * Alternates header, the human-readable list responses and 406 errors. *//* Firstly, the RVSA/1.0 (HTTP Remote Variant Selection Algorithm * v1.0) from rfc2296. This is the algorithm that goes together with * transparent content negotiation (TCN). */static int is_variant_better_rvsa(negotiation_state *neg, var_rec *variant, var_rec *best, float *p_bestq){ float bestq = *p_bestq, q; /* TCN does not cover negotiation on content-encoding. For now, * we ignore the encoding unless it was explicitly excluded. */ if (variant->encoding_quality == 0.0f) return 0; q = variant->mime_type_quality * variant->source_quality * variant->charset_quality * variant->lang_quality; /* RFC 2296 calls for the result to be rounded to 5 decimal places, * but we don't do that because it serves no useful purpose other * than to ensure that a remote algorithm operates on the same * precision as ours. That is silly, since what we obviously want * is for the algorithm to operate on the best available precision * regardless of who runs it. Since the above calculation may * result in significant variance at 1e-12, rounding would be bogus. */#ifdef NEG_DEBUG fprintf(stderr, "Variant: file=%s type=%s lang=%s sourceq=%1.3f " "mimeq=%1.3f langq=%1.3f charq=%1.3f encq=%1.3f " "q=%1.5f definite=%d\n", (variant->file_name ? variant->file_name : ""), (variant->mime_type ? variant->mime_type : ""), (variant->content_languages ? ap_array_pstrcat(neg->pool, variant->content_languages, ',') : ""), variant->source_quality, variant->mime_type_quality, variant->lang_quality, variant->charset_quality, variant->encoding_quality, q, variant->definite);#endif if (q <= 0.0f) { return 0; } if (q > bestq) { *p_bestq = q; return 1; } if (q == bestq) { /* If the best variant's encoding is of lesser quality than * this variant, then we prefer this variant */ if (variant->encoding_quality > best->encoding_quality) { *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 encoding, content length. * * For each check, we have three possible outcomes: * This variant is worse than current best: return 0 * This variant is better than the current best: * assign this variant's q to *p_bestq, and return 1 * This variant is just as desirable as the current best: * drop through to the next test. * * This code is written in this long-winded way to allow future * customisation, either by the addition of additional * checks, or to allow the order of the checks to be determined * by configuration options (e.g. we might prefer to check * language quality _before_ content type). */ /* First though, eliminate this variant if it is not * acceptable by type, charset, encoding or language. */#ifdef NEG_DEBUG fprintf(stderr, "Variant: file=%s type=%s lang=%s sourceq=%1.3f " "mimeq=%1.3f langq=%1.3f langidx=%d charq=%1.3f encq=%1.3f \n", (variant->file_name ? variant->file_name : ""), (variant->mime_type ? variant->mime_type : ""), (variant->content_languages ? ap_array_pstrcat(neg->pool, variant->content_languages, ',') : ""), variant->source_quality, variant->mime_type_quality, variant->lang_quality, variant->lang_index, variant->charset_quality, variant->encoding_quality);#endif if (variant->encoding_quality == 0.0f || variant->lang_quality == 0.0f || variant->source_quality == 0.0f || variant->charset_quality == 0.0f || variant->mime_type_quality == 0.0f) { return 0; /* don't consider unacceptables */ } q = variant->mime_type_quality * variant->source_quality; if (q == 0.0 || q < bestq) { return 0; } if (q > bestq || !best) { *p_bestq = q; return 1; } /* language */ if (variant->lang_quality < best->lang_quality) { return 0; } if (variant->lang_quality > best->lang_quality) { *p_bestq = q; return 1; } /* if language qualities were equal, try the LanguagePriority stuff */ if (best->lang_index != -1 && (variant->lang_index == -1 || variant->lang_index > best->lang_index)) { return 0; } if (variant->lang_index != -1 && (best->lang_index == -1 || variant->lang_index < best->lang_index)) { *p_bestq = q; return 1; } /* content-type level (sometimes used with text/html, though we * support it on other types too) */ levcmp = level_cmp(variant, best); if (levcmp == -1) { return 0; } if (levcmp == 1) { *p_bestq = q; return 1; } /* charset */ if (variant->charset_quality < best->charset_quality) { return 0; } /* 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; } /* Prefer the highest value for encoding_quality. */ if (variant->encoding_quality < best->encoding_quality) { return 0; } if (variant->encoding_quality > best->encoding_quality) { *p_bestq = q; return 1; } /* content length if all else equal */ if (find_content_length(neg, variant) >= find_content_length(neg, best)) { return 0; } /* ok, to get here means every thing turned out equal, except * we have a shorter content length, so use this variant */ *p_bestq = q; return 1;}static int best_match(negotiation_state *neg, var_rec **pbest){ int j; var_rec *best = NULL; float bestq = 0.0f; enum algorithm_results algorithm_r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -