From a439b730225764af709ed58d3dc326201023c750 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Malo?= Date: Tue, 28 Jan 2003 02:31:27 +0000 Subject: [PATCH] Introduce "prefer-language" environment variable, which allows to influence the negotiation process on request basis to prefer a certain language, e.g.: SetEnvIf Request_URI ^/manual/foo/ prefer-language=foo git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@98512 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 + modules/mappers/mod_negotiation.c | 137 ++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 43 deletions(-) diff --git a/CHANGES b/CHANGES index 092569a03c..10fb2f944d 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ Changes with Apache 2.1.0-dev [Remove entries to the current 2.0 section below, when backported] + *) mod_negotiation: Introduce "prefer-language" environment variable, + which allows to influence the negotiation process on request basis + to prefer a certain language. [André Malo] + *) Added AllowEncodedSlashes directive which permits request URIs to encode '/' as '%2f' and pass it to scripts in path-info without triggering the 'no encoded slashes anywhere' legacy rule. diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index 41ef479999..65dc860e8d 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -2185,74 +2185,125 @@ static int is_variant_better(negotiation_state *neg, var_rec *variant, return 1; } +/* figure out, whether a variant is in a specific language + * it returns also false, if the variant has no language. + */ +static int variant_has_language(var_rec *variant, const char *lang) +{ + int j, max; + + /* fast exit */ + if ( !lang + || !variant->content_languages + || !(max = variant->content_languages->nelts)) { + return 0; + } + + for (j = 0; j < max; ++j) { + if (!strcmp(lang, + ((char **) (variant->content_languages->elts))[j])) { + return 1; + } + } + + return 0; +} + static int best_match(negotiation_state *neg, var_rec **pbest) { int j; - var_rec *best = NULL; + var_rec *best; float bestq = 0.0f; enum algorithm_results algorithm_result; var_rec *avail_recs = (var_rec *) neg->avail_vars->elts; + const char *preferred_language = apr_table_get(neg->r->subprocess_env, + "prefer-language"); + set_default_lang_quality(neg); /* * Find the 'best' variant + * We run the loop possibly twice: if "prefer-language" + * environment variable is set but we did not find an appropriate + * best variant. In that case forget the preferred language and + * negotiate over all variants. */ - for (j = 0; j < neg->avail_vars->nelts; ++j) { - var_rec *variant = &avail_recs[j]; + do { + best = NULL; - /* Find all the relevant 'quality' values from the - * Accept... headers, and store in the variant. This also - * prepares for sending an Alternates header etc so we need to - * do it even if we do not actually plan to find a best - * variant. - */ - set_accept_quality(neg, variant); - set_language_quality(neg, variant); - set_encoding_quality(neg, variant); - set_charset_quality(neg, variant); + for (j = 0; j < neg->avail_vars->nelts; ++j) { + var_rec *variant = &avail_recs[j]; - /* Only do variant selection if we may actually choose a - * variant for the client - */ - if (neg->may_choose) { + /* if a language is preferred, but the current variant + * is not in that language, then drop it for now + */ + if ( preferred_language + && !variant_has_language(variant, preferred_language)) { + continue; + } + + /* Find all the relevant 'quality' values from the + * Accept... headers, and store in the variant. This also + * prepares for sending an Alternates header etc so we need to + * do it even if we do not actually plan to find a best + * variant. + */ + set_accept_quality(neg, variant); + set_language_quality(neg, variant); + set_encoding_quality(neg, variant); + set_charset_quality(neg, variant); - /* Now find out if this variant is better than the current - * best, either using the RVSA/1.0 algorithm, or Apache's - * internal server-driven algorithm. Presumably other - * server-driven algorithms are possible, and could be - * implemented here. + /* Only do variant selection if we may actually choose a + * variant for the client */ + if (neg->may_choose) { + + /* Now find out if this variant is better than the current + * best, either using the RVSA/1.0 algorithm, or Apache's + * internal server-driven algorithm. Presumably other + * server-driven algorithms are possible, and could be + * implemented here. + */ - if (neg->use_rvsa) { - if (is_variant_better_rvsa(neg, variant, best, &bestq)) { - best = variant; + if (neg->use_rvsa) { + if (is_variant_better_rvsa(neg, variant, best, &bestq)) { + best = variant; + } } - } - else { - if (is_variant_better(neg, variant, best, &bestq)) { - best = variant; + else { + if (is_variant_better(neg, variant, best, &bestq)) { + best = variant; + } } } } - } - /* We now either have a best variant, or no best variant */ + /* We now either have a best variant, or no best variant */ - if (neg->use_rvsa) { - /* calculate result for RVSA/1.0 algorithm: - * only a choice response if the best variant has q>0 - * and is definite - */ - algorithm_result = (best && best->definite) && (bestq > 0) ? - alg_choice : alg_list; - } - else { - /* calculate result for Apache negotiation algorithm */ - algorithm_result = bestq > 0 ? alg_choice : alg_list; - } + if (neg->use_rvsa) { + /* calculate result for RVSA/1.0 algorithm: + * only a choice response if the best variant has q>0 + * and is definite + */ + algorithm_result = (best && best->definite) && (bestq > 0) ? + alg_choice : alg_list; + } + else { + /* calculate result for Apache negotiation algorithm */ + algorithm_result = bestq > 0 ? alg_choice : alg_list; + } + + /* run the loop again, if the "prefer-language" got no clear result */ + if (preferred_language && (!best || algorithm_result != alg_choice)) { + preferred_language = NULL; + continue; + } + + break; + } while (1); /* Returning a choice response with a non-neighboring variant is a * protocol security error in TCN (see rfc2295). We do *not* -- 2.50.1