]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
[Not sure whether this will be included in 2.0.46, adjust CHANGES if necessary]
authorAndré Malo <nd@apache.org>
Tue, 27 May 2003 20:35:47 +0000 (20:35 +0000)
committerAndré Malo <nd@apache.org>
Tue, 27 May 2003 20:35:47 +0000 (20:35 +0000)
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

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/APACHE_2_0_BRANCH@100045 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
STATUS
modules/mappers/mod_negotiation.c

diff --git a/CHANGES b/CHANGES
index e2d2a21aef0fe42f7dcab8d5694061ce43a5a0c1..cd23322203a53e6391fc66f72ec1e0f49d21f820 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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 <sussman@collab.net>]
diff --git a/STATUS b/STATUS
index 41d63b1a37fd2d0b249bd74e690fffd9083763ce..ffda18650e15badd1298da81f15b635a26e73033 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -1,5 +1,5 @@
 APACHE 2.0 STATUS:                                              -*-text-*-
-Last modified at [$Date: 2003/05/27 16:19:36 $]
+Last modified at [$Date: 2003/05/27 20:35:46 $]
 
 Release:
 
@@ -105,30 +105,6 @@ PATCHES TO PORT FROM 2.1
       modules/metadata/mod_setenvif.c r1.42
       +1: nd
 
-    * port the "prefer-language" env variable.
-      there are docs online with explanations what it does:
-      <http://httpd.apache.org/docs-2.1/env.html#prefer-language>
-      <http://httpd.apache.org/docs-2.1/content-negotiation.html#exceptions>
-        (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:
-       <http://test.perlig.de/manual/>, 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.  ]
index 8f2670ca93798fbf1cc24af9fff2df054837a426..b486d6ee781b0fa0bd28171d3539a3737382061a 100644 (file)
@@ -2202,74 +2202,134 @@ 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
+     * 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];
-
-        /* 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);
+    do {
+        best = NULL;
 
-        /* Only do variant selection if we may actually choose a
-         * variant for the client
-         */
-        if (neg->may_choose) {
+        for (j = 0; j < neg->avail_vars->nelts; ++j) {
+            var_rec *variant = &avail_recs[j];
 
-            /* 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 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*