You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by nd...@apache.org on 2003/01/28 03:31:28 UTC

cvs commit: httpd-2.0/modules/mappers mod_negotiation.c

nd          2003/01/27 18:31:27

  Modified:    .        CHANGES
               modules/mappers mod_negotiation.c
  Log:
  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
  
  Revision  Changes    Path
  1.1039    +4 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.1038
  retrieving revision 1.1039
  diff -u -r1.1038 -r1.1039
  --- CHANGES	27 Jan 2003 17:49:03 -0000	1.1038
  +++ CHANGES	28 Jan 2003 02:31:24 -0000	1.1039
  @@ -2,6 +2,10 @@
   
     [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.
  
  
  
  1.110     +96 -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.109
  retrieving revision 1.110
  diff -u -r1.109 -r1.110
  --- mod_negotiation.c	25 Nov 2002 19:02:44 -0000	1.109
  +++ mod_negotiation.c	28 Jan 2003 02:31:27 -0000	1.110
  @@ -2185,74 +2185,125 @@
       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;
  +
  +        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;
  +            }
  +
  +            /* 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);
   
  -        /* 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.
  +            /* 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*