Return-Path: Delivered-To: apmail-httpd-cvs-archive@httpd.apache.org Received: (qmail 63625 invoked by uid 500); 27 May 2003 20:35:48 -0000 Mailing-List: contact cvs-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list cvs@httpd.apache.org Received: (qmail 63614 invoked by uid 500); 27 May 2003 20:35:48 -0000 Delivered-To: apmail-httpd-2.0-cvs@apache.org Date: 27 May 2003 20:35:47 -0000 Message-ID: <20030527203547.75569.qmail@icarus.apache.org> From: nd@apache.org To: httpd-2.0-cvs@apache.org Subject: cvs commit: httpd-2.0/modules/mappers mod_negotiation.c X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N nd 2003/05/27 13:35:47 Modified: . Tag: APACHE_2_0_BRANCH CHANGES STATUS modules/mappers Tag: APACHE_2_0_BRANCH mod_negotiation.c Log: [Not sure whether this will be included in 2.0.46, adjust CHANGES if necessary] 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 Reviewed by: Jeff Trawick, Will Rowe, Erik Abele Revision Changes Path No revision No revision 1.988.2.111 +4 -0 httpd-2.0/CHANGES Index: CHANGES =================================================================== RCS file: /home/cvs/httpd-2.0/CHANGES,v retrieving revision 1.988.2.110 retrieving revision 1.988.2.111 diff -u -r1.988.2.110 -r1.988.2.111 --- CHANGES 21 May 2003 15:47:00 -0000 1.988.2.110 +++ CHANGES 27 May 2003 20:35:45 -0000 1.988.2.111 @@ -1,5 +1,9 @@ Changes with Apache 2.0.46 + *) mod_negotiation: Introduce "prefer-language" environment variable, + which allows to influence the negotiation process on request basis + to prefer a certain language. [Andr� Malo] + *) Fix for mod_dav. Call the 'can_be_activity' callback, if provided, when a MKACTIVITY request comes in. [Ben Collins-Sussman ] 1.751.2.316 +1 -25 httpd-2.0/STATUS Index: STATUS =================================================================== RCS file: /home/cvs/httpd-2.0/STATUS,v retrieving revision 1.751.2.315 retrieving revision 1.751.2.316 diff -u -r1.751.2.315 -r1.751.2.316 --- STATUS 27 May 2003 16:19:36 -0000 1.751.2.315 +++ STATUS 27 May 2003 20:35:46 -0000 1.751.2.316 @@ -105,30 +105,6 @@ modules/metadata/mod_setenvif.c r1.42 +1: nd - * port the "prefer-language" env variable. - there are docs online with explanations what it does: - - - (last paragraph) - This feature would allow us to set up a resaonable (and distributable) - config for our multilingual documentation with crosslinks between the - languages, such as: - Alias /manual /path/to/manual - Alias /manual/en /path/to/manual - Alias /manual/de /path/to/manual - SetEnvIf Request_URI ^/manual/en/ prefer-language=en - SetEnvIf Request_URI ^/manual/de/ prefer-language=de - : - (but with regexps, see the backport proposal above). We're going to - get a clever system for choosing the language either by user's choice - or language negotiation. If user's choice doesn't exist, it falls back - to negotiation again. - (There's a somewhat outdated example for such cross language links: - , done with mod_rewrite, waiting for - mod_negotiation enhancement ;-)) - modules/mappers/mod_negotiation.c r1.110,r1.115 - +1: nd, trawick, wrowe - * Allow mod_dav to do weak entity comparison functions. modules/dav/main/util.c: r1.45 [ This one is under review. Don't merge. ] No revision No revision 1.108.2.4 +105 -45 httpd-2.0/modules/mappers/mod_negotiation.c Index: mod_negotiation.c =================================================================== RCS file: /home/cvs/httpd-2.0/modules/mappers/mod_negotiation.c,v retrieving revision 1.108.2.3 retrieving revision 1.108.2.4 diff -u -r1.108.2.3 -r1.108.2.4 --- mod_negotiation.c 1 Mar 2003 21:36:19 -0000 1.108.2.3 +++ mod_negotiation.c 27 May 2003 20:35:47 -0000 1.108.2.4 @@ -2202,74 +2202,134 @@ 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 + * 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); - - /* 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. + for (j = 0; j < neg->avail_vars->nelts; ++j) { + var_rec *variant = &avail_recs[j]; + + /* 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; + } - if (neg->use_rvsa) { - if (is_variant_better_rvsa(neg, variant, best, &bestq)) { - best = variant; - } + /* 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); + /* accept the preferred language, even when it's not listed within + * the Accept-Language header + */ + if (preferred_language) { + variant->lang_quality = 1.0f; + variant->definite = 1; } else { - if (is_variant_better(neg, variant, best, &bestq)) { - best = variant; + set_language_quality(neg, variant); + } + set_encoding_quality(neg, variant); + set_charset_quality(neg, variant); + + /* 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; + } + } + 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*