home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / modules / standard / mod_negotiation.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-03  |  94.6 KB  |  2,791 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * mod_negotiation.c: keeps track of MIME types the client is willing to
  60.  * accept, and contains code to handle type arbitration.
  61.  *
  62.  * rst
  63.  */
  64.  
  65. #include "httpd.h"
  66. #include "http_config.h"
  67. #include "http_request.h"
  68. #include "http_protocol.h"
  69. #include "http_core.h"
  70. #include "http_log.h"
  71. #include "util_script.h"
  72.  
  73. /* Commands --- configuring document caching on a per (virtual?)
  74.  * server basis... 
  75.  */
  76.  
  77. typedef struct {
  78.     array_header *language_priority;
  79. } neg_dir_config;
  80.  
  81. module MODULE_VAR_EXPORT negotiation_module;
  82.  
  83. static void *create_neg_dir_config(pool *p, char *dummy)
  84. {
  85.     neg_dir_config *new = (neg_dir_config *) ap_palloc(p, sizeof(neg_dir_config));
  86.  
  87.     new->language_priority = ap_make_array(p, 4, sizeof(char *));
  88.     return new;
  89. }
  90.  
  91. static void *merge_neg_dir_configs(pool *p, void *basev, void *addv)
  92. {
  93.     neg_dir_config *base = (neg_dir_config *) basev;
  94.     neg_dir_config *add = (neg_dir_config *) addv;
  95.     neg_dir_config *new = (neg_dir_config *) ap_palloc(p, sizeof(neg_dir_config));
  96.  
  97.     /* give priority to the config in the subdirectory */
  98.     new->language_priority = ap_append_arrays(p, add->language_priority,
  99.                                            base->language_priority);
  100.     return new;
  101. }
  102.  
  103. static const char *set_language_priority(cmd_parms *cmd, void *n, char *lang)
  104. {
  105.     array_header *arr = ((neg_dir_config *) n)->language_priority;
  106.     char **langp = (char **) ap_push_array(arr);
  107.  
  108.     *langp = lang;
  109.     return NULL;
  110. }
  111.  
  112. static const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy,
  113.                                          char *dummy2)
  114. {
  115.     void *server_conf = cmd->server->module_config;
  116.  
  117.     ap_set_module_config(server_conf, &negotiation_module, "Cache");
  118.     return NULL;
  119. }
  120.  
  121. static int do_cache_negotiated_docs(server_rec *s)
  122. {
  123.     return (ap_get_module_config(s->module_config, &negotiation_module) != NULL);
  124. }
  125.  
  126. static const command_rec negotiation_cmds[] =
  127. {
  128.     {"CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, NO_ARGS,
  129.      "no arguments (either present or absent)"},
  130.     {"LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE,
  131.      "space-delimited list of MIME language abbreviations"},
  132.     {NULL}
  133. };
  134.  
  135. /*
  136.  * Record of available info on a media type specified by the client
  137.  * (we also use 'em for encodings and languages)
  138.  */
  139.  
  140. typedef struct accept_rec {
  141.     char *name;                 /* MUST be lowercase */
  142.     float quality;
  143.     float max_bytes;
  144.     float level;
  145.     char *charset;              /* for content-type only */
  146. } accept_rec;
  147.  
  148. /*
  149.  * Record of available info on a particular variant
  150.  *
  151.  * Note that a few of these fields are updated by the actual negotiation
  152.  * code.  These are:
  153.  *
  154.  * level_matched --- initialized to zero.  Set to the value of level
  155.  *             if the client actually accepts this media type at that
  156.  *             level (and *not* if it got in on a wildcard).  See level_cmp
  157.  *             below.
  158.  * mime_stars -- initialized to zero.  Set to the number of stars
  159.  *               present in the best matching Accept header element.
  160.  *               1 for star/star, 2 for type/star and 3 for
  161.  *               type/subtype.
  162.  *
  163.  * definite -- initialized to 1.  Set to 0 if there is a match which
  164.  *             makes the variant non-definite according to the rules
  165.  *             in rfc2296.
  166.  */
  167.  
  168. typedef struct var_rec {
  169.     request_rec *sub_req;       /* May be NULL (is, for map files) */
  170.     char *mime_type;            /* MUST be lowercase */
  171.     char *file_name;
  172.     const char *content_encoding;
  173.     array_header *content_languages;   /* list of languages for this variant */
  174.     char *content_charset;
  175.     char *description;
  176.  
  177.     /* The next five items give the quality values for the dimensions
  178.      * of negotiation for this variant. They are obtained from the
  179.      * appropriate header lines, except for source_quality, which
  180.      * is obtained from the variant itself (the 'qs' parameter value
  181.      * from the variant's mime-type). Apart from source_quality,
  182.      * these values are set when we find the quality for each variant
  183.      * (see best_match()). source_quality is set from the 'qs' parameter
  184.      * of the variant description or mime type: see set_mime_fields().
  185.      */
  186.     float lang_quality;         /* quality of this variant's language */
  187.     float encoding_quality;     /* ditto encoding */
  188.     float charset_quality;      /* ditto charset */
  189.     float mime_type_quality;    /* ditto media type */
  190.     float source_quality;       /* source quality for this variant */
  191.  
  192.     /* Now some special values */
  193.     float level;                /* Auxiliary to content-type... */
  194.     float bytes;                /* content length, if known */
  195.     int lang_index;             /* pre HTTP/1.1 language priority stuff */
  196.     int is_pseudo_html;         /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
  197.  
  198.     /* Above are all written-once properties of the variant.  The
  199.      * three fields below are changed during negotiation:
  200.      */
  201.  
  202.     float level_matched;
  203.     int mime_stars;
  204.     int definite;
  205. } var_rec;
  206.  
  207. /* Something to carry around the state of negotiation (and to keep
  208.  * all of this thread-safe)...
  209.  */
  210.  
  211. typedef struct {
  212.     pool *pool;
  213.     request_rec *r;
  214.     char *dir_name;
  215.     int accept_q;               /* 1 if an Accept item has a q= param */
  216.     float default_lang_quality; /* fiddle lang q for variants with no lang */
  217.  
  218.     /* the array pointers below are NULL if the corresponding accept
  219.      * headers are not present
  220.      */
  221.     array_header *accepts;            /* accept_recs */
  222.     array_header *accept_encodings;   /* accept_recs */
  223.     array_header *accept_charsets;    /* accept_recs */
  224.     array_header *accept_langs;       /* accept_recs */
  225.  
  226.     array_header *avail_vars;         /* available variants */
  227.  
  228.     int count_multiviews_variants;    /* number of variants found on disk */
  229.  
  230.     int is_transparent;       /* 1 if this resource is trans. negotiable */
  231.  
  232.     int dont_fiddle_headers;  /* 1 if we may not fiddle with accept hdrs */
  233.     int ua_supports_trans;    /* 1 if ua supports trans negotiation */
  234.     int send_alternates;      /* 1 if we want to send an Alternates header */
  235.     int may_choose;           /* 1 if we may choose a variant for the client */
  236.     int use_rvsa;             /* 1 if we must use RVSA/1.0 negotiation algo */
  237. } negotiation_state;
  238.  
  239. /* A few functions to manipulate var_recs.
  240.  * Cleaning out the fields...
  241.  */
  242.  
  243. static void clean_var_rec(var_rec *mime_info)
  244. {
  245.     mime_info->sub_req = NULL;
  246.     mime_info->mime_type = "";
  247.     mime_info->file_name = "";
  248.     mime_info->content_encoding = NULL;
  249.     mime_info->content_languages = NULL;
  250.     mime_info->content_charset = "";
  251.     mime_info->description = "";
  252.  
  253.     mime_info->is_pseudo_html = 0;
  254.     mime_info->level = 0.0f;
  255.     mime_info->level_matched = 0.0f;
  256.     mime_info->bytes = 0.0f;
  257.     mime_info->lang_index = -1;
  258.     mime_info->mime_stars = 0;
  259.     mime_info->definite = 1;
  260.  
  261.     mime_info->charset_quality = 1.0f;
  262.     mime_info->encoding_quality = 1.0f;
  263.     mime_info->lang_quality = 1.0f;
  264.     mime_info->mime_type_quality = 1.0f;
  265.     mime_info->source_quality = 0.0f;
  266. }
  267.  
  268. /* Initializing the relevant fields of a variant record from the
  269.  * accept_info read out of its content-type, one way or another.
  270.  */
  271.  
  272. static void set_mime_fields(var_rec *var, accept_rec *mime_info)
  273. {
  274.     var->mime_type = mime_info->name;
  275.     var->source_quality = mime_info->quality;
  276.     var->level = mime_info->level;
  277.     var->content_charset = mime_info->charset;
  278.  
  279.     var->is_pseudo_html = (!strcmp(var->mime_type, "text/html")
  280.                            || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE)
  281.                            || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE3));
  282. }
  283.  
  284. /* Create a variant list validator in r using info from vlistr. */
  285.  
  286. static void set_vlist_validator(request_rec *r, request_rec *vlistr)
  287. {
  288.     /* Calculating the variant list validator is similar to
  289.      * calculating an etag for the source of the variant list
  290.      * information, so we use ap_make_etag().  Note that this
  291.      * validator can be 'weak' in extreme case.
  292.      */
  293.  
  294.     ap_update_mtime (vlistr, vlistr->finfo.st_mtime);
  295.     r->vlist_validator = ap_make_etag(vlistr, 0);
  296.  
  297.     /* ap_set_etag will later take r->vlist_validator into account
  298.      * when creating the etag header
  299.      */
  300. }
  301.  
  302.  
  303. /*****************************************************************
  304.  *
  305.  * Parsing (lists of) media types and their parameters, as seen in
  306.  * HTTPD header lines and elsewhere.
  307.  */
  308.  
  309. /*
  310.  * Get a single mime type entry --- one media type and parameters;
  311.  * enter the values we recognize into the argument accept_rec
  312.  */
  313.  
  314. static const char *get_entry(pool *p, accept_rec *result,
  315.                              const char *accept_line)
  316. {
  317.     result->quality = 1.0f;
  318.     result->max_bytes = 0.0f;
  319.     result->level = 0.0f;
  320.     result->charset = "";
  321.  
  322.     /*
  323.      * Note that this handles what I gather is the "old format",
  324.      *
  325.      *    Accept: text/html text/plain moo/zot
  326.      *
  327.      * without any compatibility kludges --- if the token after the
  328.      * MIME type begins with a semicolon, we know we're looking at parms,
  329.      * otherwise, we know we aren't.  (So why all the pissing and moaning
  330.      * in the CERN server code?  I must be missing something).
  331.      */
  332.  
  333.     result->name = ap_get_token(p, &accept_line, 0);
  334.     ap_str_tolower(result->name);     /* You want case-insensitive,
  335.                                        * you'll *get* case-insensitive.
  336.                                        */
  337.  
  338.     /* KLUDGE!!! Default HTML to level 2.0 unless the browser
  339.      * *explicitly* says something else.
  340.      */
  341.  
  342.     if (!strcmp(result->name, "text/html") && (result->level == 0.0)) {
  343.         result->level = 2.0f;
  344.     }
  345.     else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE)) {
  346.         result->level = 2.0f;
  347.     }
  348.     else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) {
  349.         result->level = 3.0f;
  350.     }
  351.  
  352.     while (*accept_line == ';') {
  353.         /* Parameters ... */
  354.  
  355.         char *parm;
  356.         char *cp;
  357.         char *end;
  358.  
  359.         ++accept_line;
  360.         parm = ap_get_token(p, &accept_line, 1);
  361.  
  362.         /* Look for 'var = value' --- and make sure the var is in lcase. */
  363.  
  364.         for (cp = parm; (*cp && !ap_isspace(*cp) && *cp != '='); ++cp) {
  365.             *cp = ap_tolower(*cp);
  366.         }
  367.  
  368.         if (!*cp) {
  369.             continue;           /* No '='; just ignore it. */
  370.         }
  371.  
  372.         *cp++ = '\0';           /* Delimit var */
  373.         while (*cp && (ap_isspace(*cp) || *cp == '=')) {
  374.             ++cp;
  375.         }
  376.  
  377.         if (*cp == '"') {
  378.             ++cp;
  379.             for (end = cp;
  380.                  (*end && *end != '\n' && *end != '\r' && *end != '\"');
  381.                  end++);
  382.         }
  383.         else {
  384.             for (end = cp; (*end && !ap_isspace(*end)); end++);
  385.         }
  386.         if (*end) {
  387.             *end = '\0';        /* strip ending quote or return */
  388.         }
  389.         ap_str_tolower(cp);
  390.  
  391.         if (parm[0] == 'q'
  392.             && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) {
  393.             result->quality = atof(cp);
  394.         }
  395.         else if (parm[0] == 'm' && parm[1] == 'x' &&
  396.                  parm[2] == 'b' && parm[3] == '\0') {
  397.             result->max_bytes = atof(cp);
  398.         }
  399.         else if (parm[0] == 'l' && !strcmp(&parm[1], "evel")) {
  400.             result->level = atof(cp);
  401.         }
  402.         else if (!strcmp(parm, "charset")) {
  403.             result->charset = cp;
  404.         }
  405.     }
  406.  
  407.     if (*accept_line == ',') {
  408.         ++accept_line;
  409.     }
  410.  
  411.     return accept_line;
  412. }
  413.  
  414. /*****************************************************************
  415.  *
  416.  * Dealing with header lines ...
  417.  *
  418.  * Accept, Accept-Charset, Accept-Language and Accept-Encoding
  419.  * are handled by do_header_line() - they all have the same
  420.  * basic structure of a list of items of the format
  421.  *    name; q=N; charset=TEXT
  422.  *
  423.  * where charset is only valid in Accept.
  424.  */
  425.  
  426. static array_header *do_header_line(pool *p, const char *accept_line)
  427. {
  428.     array_header *accept_recs;
  429.  
  430.     if (!accept_line) {
  431.         return NULL;
  432.     }
  433.  
  434.     accept_recs = ap_make_array(p, 40, sizeof(accept_rec));
  435.  
  436.     while (*accept_line) {
  437.         accept_rec *new = (accept_rec *) ap_push_array(accept_recs);
  438.         accept_line = get_entry(p, new, accept_line);
  439.     }
  440.  
  441.     return accept_recs;
  442. }
  443.  
  444. /* Given the text of the Content-Languages: line from the var map file,
  445.  * return an array containing the languages of this variant
  446.  */
  447.  
  448. static array_header *do_languages_line(pool *p, const char **lang_line)
  449. {
  450.     array_header *lang_recs = ap_make_array(p, 2, sizeof(char *));
  451.  
  452.     if (!lang_line) {
  453.         return lang_recs;
  454.     }
  455.  
  456.     while (**lang_line) {
  457.         char **new = (char **) ap_push_array(lang_recs);
  458.         *new = ap_get_token(p, lang_line, 0);
  459.         ap_str_tolower(*new);
  460.         if (**lang_line == ',' || **lang_line == ';') {
  461.             ++(*lang_line);
  462.         }
  463.     }
  464.  
  465.     return lang_recs;
  466. }
  467.  
  468. /*****************************************************************
  469.  *
  470.  * Handling header lines from clients...
  471.  */
  472.  
  473. static negotiation_state *parse_accept_headers(request_rec *r)
  474. {
  475.     negotiation_state *new =
  476.         (negotiation_state *) ap_pcalloc(r->pool, sizeof(negotiation_state));
  477.     accept_rec *elts;
  478.     table *hdrs = r->headers_in;
  479.     int i;
  480.  
  481.     new->pool = r->pool;
  482.     new->r = r;
  483.     new->dir_name = ap_make_dirstr_parent(r->pool, r->filename);
  484.  
  485.     new->accepts = do_header_line(r->pool, ap_table_get(hdrs, "Accept"));
  486.  
  487.     /* calculate new->accept_q value */
  488.     if (new->accepts) {
  489.         elts = (accept_rec *) new->accepts->elts;
  490.  
  491.         for (i = 0; i < new->accepts->nelts; ++i) {
  492.             if (elts[i].quality < 1.0) {
  493.                 new->accept_q = 1;
  494.             }
  495.         }
  496.     }
  497.  
  498.     new->accept_encodings =
  499.         do_header_line(r->pool, ap_table_get(hdrs, "Accept-Encoding"));
  500.     new->accept_langs =
  501.         do_header_line(r->pool, ap_table_get(hdrs, "Accept-Language"));
  502.     new->accept_charsets =
  503.         do_header_line(r->pool, ap_table_get(hdrs, "Accept-Charset"));
  504.  
  505.     new->avail_vars = ap_make_array(r->pool, 40, sizeof(var_rec));
  506.  
  507.     return new;
  508. }
  509.  
  510.  
  511. static void parse_negotiate_header(request_rec *r, negotiation_state *neg)
  512. {
  513.     const char *negotiate = ap_table_get(r->headers_in, "Negotiate");
  514.     
  515.     if (negotiate) {
  516.         /* Negotiate: header tells us UA does transparent negotiation */
  517.  
  518.         /* sending Alternates on non-transparent resources is allowed,
  519.          * and may even be useful, but we don't for now, also
  520.          * because it could clash with an Alternates header set by
  521.          * a sub- or super- request on a transparent resource.
  522.          */
  523.  
  524.         while (*negotiate) {
  525.             char *tok = ap_get_token(neg->pool, &negotiate, 1);
  526.             char *cp;
  527.  
  528.             for (cp = tok; (*cp && !ap_isspace(*cp) && *cp != '='); ++cp) {
  529.                 *cp = ap_tolower(*cp);
  530.             }
  531.             *cp = 0;
  532.             
  533.             if (strcmp(tok, "trans") == 0 ||
  534.                 strcmp(tok, "vlist") == 0 ||
  535.                 strcmp(tok, "guess-small") == 0 ||
  536.                 ap_isdigit(tok[0]) ||
  537.                 strcmp(tok, "*") == 0) {
  538.  
  539.                 /* The user agent supports transparent negotiation */
  540.                 neg->ua_supports_trans = 1;
  541.  
  542.                 /* Send-alternates could be configurable, but note
  543.                  * that it must be 1 if we have 'vlist' in the
  544.                  * negotiate header.
  545.                  */
  546.                 neg->send_alternates = 1;
  547.  
  548.                 if (strcmp(tok, "1.0") == 0) {
  549.                     /* we may use the RVSA/1.0 algorithm, configure for it */
  550.                     neg->may_choose = 1;
  551.                     neg->use_rvsa = 1;
  552.                     neg->dont_fiddle_headers = 1;
  553.                 }
  554.                 else if (strcmp(tok, "*") == 0) {
  555.                     /* we may use any variant selection algorithm, configure
  556.                      * to use the Apache algorithm
  557.                      */
  558.                     neg->may_choose = 1;
  559.                     
  560.                     /* We disable header fiddles on the assumption that a
  561.                      * client sending Negotiate knows how to send correct
  562.                      * headers which don't need fiddling.
  563.                      */
  564.                     neg->dont_fiddle_headers = 1; 
  565.                 }
  566.             }
  567.  
  568.             if (*negotiate)
  569.                 negotiate++; /* skip over , */
  570.         }
  571.     }
  572.  
  573.     if (!neg->ua_supports_trans) {
  574.         /* User agent does not support transparent negotiation,
  575.          * configure to do server-driven negotiation with the Apache
  576.          * algorithm.
  577.          */
  578.         neg->may_choose = 1;
  579.  
  580.         /* To save network bandwidth, we do not configure to send an
  581.          * Alternates header to the user agent in this case.  User
  582.          * agents which want an Alternates header for agent-driven
  583.          * negotiation will have to request it by sending an
  584.          * appropriate Negotiate header.
  585.          */
  586.     }
  587.  
  588. #if NEG_DEBUG
  589.     fprintf(stderr, "dont_fiddle_headers=%d use_rvsa=%d ua_supports_trans=%d "
  590.             "send_alternates=%d, may_choose=%d\n",
  591.             neg->dont_fiddle_headers, neg->use_rvsa,  
  592.             neg->ua_supports_trans, neg->send_alternates, neg->may_choose);
  593. #endif
  594.  
  595. }
  596.  
  597. /* Sometimes clients will give us no Accept info at all; this routine sets
  598.  * up the standard default for that case, and also arranges for us to be
  599.  * willing to run a CGI script if we find one.  (In fact, we set up to
  600.  * dramatically prefer CGI scripts in cases where that's appropriate,
  601.  * e.g., POST or when URI includes query args or extra path info).
  602.  */
  603. static void maybe_add_default_accepts(negotiation_state *neg, 
  604.                                       int prefer_scripts)
  605. {
  606.     accept_rec *new_accept;
  607.  
  608.     if (!neg->accepts) {
  609.         neg->accepts = ap_make_array(neg->pool, 4, sizeof(accept_rec));
  610.  
  611.         new_accept = (accept_rec *) ap_push_array(neg->accepts);
  612.         
  613.         new_accept->name = "*/*";
  614.         new_accept->quality = 1.0f;
  615.         new_accept->level = 0.0f;
  616.         new_accept->max_bytes = 0.0f;
  617.     }    
  618.  
  619.     new_accept = (accept_rec *) ap_push_array(neg->accepts);
  620.  
  621.     new_accept->name = CGI_MAGIC_TYPE;
  622.     if (neg->use_rvsa) {
  623.         new_accept->quality = 0;
  624.     }
  625.     else {
  626.         new_accept->quality = prefer_scripts ? 2.0f : 0.001f;
  627.     }
  628.     new_accept->level = 0.0f;
  629.     new_accept->max_bytes = 0.0f;
  630. }
  631.  
  632. /*****************************************************************
  633.  *
  634.  * Parsing type-map files, in Roy's meta/http format augmented with
  635.  * #-comments.
  636.  */
  637.  
  638. /* Reading RFC822-style header lines, ignoring #-comments and
  639.  * handling continuations.
  640.  */
  641.  
  642. enum header_state {
  643.     header_eof, header_seen, header_sep
  644. };
  645.  
  646. static enum header_state get_header_line(char *buffer, int len, FILE *map)
  647. {
  648.     char *buf_end = buffer + len;
  649.     char *cp;
  650.     int c;
  651.  
  652.     /* Get a noncommented line */
  653.  
  654.     do {
  655.         if (fgets(buffer, MAX_STRING_LEN, map) == NULL) {
  656.             return header_eof;
  657.         }
  658.     } while (buffer[0] == '#');
  659.  
  660.     /* If blank, just return it --- this ends information on this variant */
  661.  
  662.     for (cp = buffer; (*cp && ap_isspace(*cp)); ++cp) {
  663.         continue;
  664.     }
  665.  
  666.     if (*cp == '\0') {
  667.         return header_sep;
  668.     }
  669.  
  670.     /* If non-blank, go looking for header lines, but note that we still
  671.      * have to treat comments specially...
  672.      */
  673.  
  674.     cp += strlen(cp);
  675.  
  676.     while ((c = getc(map)) != EOF) {
  677.         if (c == '#') {
  678.             /* Comment line */
  679.             while ((c = getc(map)) != EOF && c != '\n') {
  680.                 continue;
  681.             }
  682.         }
  683.         else if (ap_isspace(c)) {
  684.             /* Leading whitespace.  POSSIBLE continuation line
  685.              * Also, possibly blank --- if so, we ungetc() the final newline
  686.              * so that we will pick up the blank line the next time 'round.
  687.              */
  688.  
  689.             while (c != EOF && c != '\n' && ap_isspace(c)) {
  690.                 c = getc(map);
  691.             }
  692.  
  693.             ungetc(c, map);
  694.  
  695.             if (c == '\n') {
  696.                 return header_seen;     /* Blank line */
  697.             }
  698.  
  699.             /* Continuation */
  700.  
  701.             while (cp < buf_end - 2 && (c = getc(map)) != EOF && c != '\n') {
  702.                 *cp++ = c;
  703.             }
  704.  
  705.             *cp++ = '\n';
  706.             *cp = '\0';
  707.         }
  708.         else {
  709.  
  710.             /* Line beginning with something other than whitespace */
  711.  
  712.             ungetc(c, map);
  713.             return header_seen;
  714.         }
  715.     }
  716.  
  717.     return header_seen;
  718. }
  719.  
  720. /* Stripping out RFC822 comments */
  721.  
  722. static void strip_paren_comments(char *hdr)
  723. {
  724.     /* Hmmm... is this correct?  In Roy's latest draft, (comments) can nest! */
  725.     /* Nope, it isn't correct.  Fails to handle backslash escape as well.    */
  726.  
  727.     while (*hdr) {
  728.         if (*hdr == '"') {
  729.             hdr = strchr(hdr, '"');
  730.             if (hdr == NULL) {
  731.                 return;
  732.             }
  733.             ++hdr;
  734.         }
  735.         else if (*hdr == '(') {
  736.             while (*hdr && *hdr != ')') {
  737.                 *hdr++ = ' ';
  738.             }
  739.  
  740.             if (*hdr) {
  741.                 *hdr++ = ' ';
  742.             }
  743.         }
  744.         else {
  745.             ++hdr;
  746.         }
  747.     }
  748. }
  749.  
  750. /* Getting to a header body from the header */
  751.  
  752. static char *lcase_header_name_return_body(char *header, request_rec *r)
  753. {
  754.     char *cp = header;
  755.  
  756.     for ( ; *cp && *cp != ':' ; ++cp) {
  757.         *cp = ap_tolower(*cp);
  758.     }
  759.  
  760.     if (!*cp) {
  761.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  762.                       "Syntax error in type map --- no ':': %s", r->filename);
  763.         return NULL;
  764.     }
  765.  
  766.     do {
  767.         ++cp;
  768.     } while (*cp && ap_isspace(*cp));
  769.  
  770.     if (!*cp) {
  771.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  772.                       "Syntax error in type map --- no header body: %s",
  773.                       r->filename);
  774.         return NULL;
  775.     }
  776.  
  777.     return cp;
  778. }
  779.  
  780. static int read_type_map(negotiation_state *neg, request_rec *rr)
  781. {
  782.     request_rec *r = neg->r;
  783.     FILE *map;
  784.     char buffer[MAX_STRING_LEN];
  785.     enum header_state hstate;
  786.     struct var_rec mime_info;
  787.     int has_content;
  788.  
  789.     /* We are not using multiviews */
  790.     neg->count_multiviews_variants = 0;
  791.  
  792.     map = ap_pfopen(neg->pool, rr->filename, "r");
  793.     if (map == NULL) {
  794.         ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  795.                       "cannot access type map file: %s", rr->filename);
  796.         return HTTP_FORBIDDEN;
  797.     }
  798.  
  799.     clean_var_rec(&mime_info);
  800.     has_content = 0;
  801.  
  802.     do {
  803.         hstate = get_header_line(buffer, MAX_STRING_LEN, map);
  804.  
  805.         if (hstate == header_seen) {
  806.             char *body1 = lcase_header_name_return_body(buffer, neg->r);
  807.             const char *body;
  808.  
  809.             if (body1 == NULL) {
  810.                 return SERVER_ERROR;
  811.             }
  812.  
  813.             strip_paren_comments(body1);
  814.             body = body1;
  815.  
  816.             if (!strncmp(buffer, "uri:", 4)) {
  817.                 mime_info.file_name = ap_get_token(neg->pool, &body, 0);
  818.             }
  819.             else if (!strncmp(buffer, "content-type:", 13)) {
  820.                 struct accept_rec accept_info;
  821.  
  822.                 get_entry(neg->pool, &accept_info, body);
  823.                 set_mime_fields(&mime_info, &accept_info);
  824.                 has_content = 1;
  825.             }
  826.             else if (!strncmp(buffer, "content-length:", 15)) {
  827.                 mime_info.bytes = atof(body);
  828.                 has_content = 1;
  829.             }
  830.             else if (!strncmp(buffer, "content-language:", 17)) {
  831.                 mime_info.content_languages = do_languages_line(neg->pool,
  832.                                                                 &body);
  833.                 has_content = 1;
  834.             }
  835.             else if (!strncmp(buffer, "content-encoding:", 17)) {
  836.                 mime_info.content_encoding = ap_get_token(neg->pool, &body, 0);
  837.                 has_content = 1;
  838.             }
  839.             else if (!strncmp(buffer, "description:", 12)) {
  840.                 /* XXX: The possibility to set a description is
  841.                  * currently not documented.
  842.                  */
  843.                 char *desc = ap_pstrdup(neg->pool, body);
  844.                 char *cp;
  845.  
  846.                 for (cp = desc; *cp; ++cp) {
  847.                     if (*cp=='\n') *cp=' ';
  848.                 }
  849.                 if (cp>desc) *(cp-1)=0;
  850.                 mime_info.description = desc;
  851.             }
  852.         }
  853.         else {
  854.             if (*mime_info.file_name && has_content) {
  855.                 void *new_var = ap_push_array(neg->avail_vars);
  856.  
  857.                 memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
  858.             }
  859.  
  860.             clean_var_rec(&mime_info);
  861.             has_content = 0;
  862.         }
  863.     } while (hstate != header_eof);
  864.  
  865.     ap_pfclose(neg->pool, map);
  866.  
  867.     set_vlist_validator(r, rr);
  868.  
  869.     return OK;
  870. }
  871.  
  872.  
  873. /* Sort function used by read_types_multi. */
  874. static int variantsortf(var_rec *a, var_rec *b) {
  875.  
  876.     /* First key is the source quality, sort in descending order. */
  877.  
  878.     /* XXX: note that we currently implement no method of setting the
  879.      * source quality for multiviews variants, so we are always comparing
  880.      * 1.0 to 1.0 for now
  881.      */
  882.     if (a->source_quality < b->source_quality)
  883.         return 1;
  884.     if (a->source_quality > b->source_quality)
  885.         return -1;
  886.  
  887.     /* Second key is the variant name */
  888.     return strcmp(a->file_name, b->file_name);
  889. }
  890.  
  891. /*****************************************************************
  892.  *
  893.  * Same as read_type_map, except we use a filtered directory listing
  894.  * as the map...  
  895.  */
  896.  
  897. static int read_types_multi(negotiation_state *neg)
  898. {
  899.     request_rec *r = neg->r;
  900.  
  901.     char *filp;
  902.     int prefix_len;
  903.     DIR *dirp;
  904.     struct DIR_TYPE *dir_entry;
  905.     struct var_rec mime_info;
  906.     struct accept_rec accept_info;
  907.     void *new_var;
  908.  
  909.     clean_var_rec(&mime_info);
  910.  
  911.     if (!(filp = strrchr(r->filename, '/'))) {
  912.         return DECLINED;        /* Weird... */
  913.     }
  914.  
  915.     if (strncmp(r->filename, "proxy:", 6) == 0) {
  916.         return DECLINED;
  917.     }
  918.  
  919.     ++filp;
  920.     prefix_len = strlen(filp);
  921.  
  922.     dirp = ap_popendir(neg->pool, neg->dir_name);
  923.  
  924.     if (dirp == NULL) {
  925.         ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  926.                     "cannot read directory for multi: %s", neg->dir_name);
  927.         return HTTP_FORBIDDEN;
  928.     }
  929.  
  930.     while ((dir_entry = readdir(dirp))) {
  931.         request_rec *sub_req;
  932.  
  933.         /* Do we have a match? */
  934.  
  935.         if (strncmp(dir_entry->d_name, filp, prefix_len)) {
  936.             continue;
  937.         }
  938.         if (dir_entry->d_name[prefix_len] != '.') {
  939.             continue;
  940.         }
  941.  
  942.         /* Yep.  See if it's something which we have access to, and 
  943.          * which has a known type and encoding (as opposed to something
  944.          * which we'll be slapping default_type on later).
  945.          */
  946.  
  947.         sub_req = ap_sub_req_lookup_file(dir_entry->d_name, r);
  948.  
  949.         /* If it has a handler, we'll pretend it's a CGI script,
  950.          * since that's a good indication of the sort of thing it
  951.          * might be doing.
  952.          */
  953.         if (sub_req->handler && !sub_req->content_type) {
  954.             sub_req->content_type = CGI_MAGIC_TYPE;
  955.         }
  956.  
  957.         if (sub_req->status != HTTP_OK || !sub_req->content_type) {
  958.             ap_destroy_sub_req(sub_req);
  959.             continue;
  960.         }
  961.  
  962.         /* If it's a map file, we use that instead of the map
  963.          * we're building...
  964.          */
  965.  
  966.         if (((sub_req->content_type) &&
  967.              !strcmp(sub_req->content_type, MAP_FILE_MAGIC_TYPE)) ||
  968.             ((sub_req->handler) &&
  969.              !strcmp(sub_req->handler, "type-map"))) {
  970.  
  971.             ap_pclosedir(neg->pool, dirp);
  972.             neg->avail_vars->nelts = 0;
  973.             if (sub_req->status != HTTP_OK) {
  974.                 return sub_req->status;
  975.             }
  976.             return read_type_map(neg, sub_req);
  977.         }
  978.  
  979.         /* Have reasonable variant --- gather notes. */
  980.  
  981.         mime_info.sub_req = sub_req;
  982.         mime_info.file_name = ap_pstrdup(neg->pool, dir_entry->d_name);
  983.         if (sub_req->content_encoding) {
  984.             mime_info.content_encoding = sub_req->content_encoding;
  985.         }
  986.         if (sub_req->content_languages) {
  987.             mime_info.content_languages = sub_req->content_languages;
  988.         }
  989.  
  990.         get_entry(neg->pool, &accept_info, sub_req->content_type);
  991.         set_mime_fields(&mime_info, &accept_info);
  992.  
  993.         new_var = ap_push_array(neg->avail_vars);
  994.         memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
  995.  
  996.         neg->count_multiviews_variants++;
  997.  
  998.         clean_var_rec(&mime_info);
  999.     }
  1000.  
  1001.     ap_pclosedir(neg->pool, dirp);
  1002.  
  1003.     set_vlist_validator(r, r);
  1004.  
  1005.     /* Sort the variants into a canonical order.  The negotiation
  1006.      * result sometimes depends on the order of the variants.  By
  1007.      * sorting the variants into a canonical order, rather than using
  1008.      * the order in which readdir() happens to return them, we ensure
  1009.      * that the negotiation result will be consistent over filesystem
  1010.      * backup/restores and over all mirror sites.
  1011.      */
  1012.        
  1013.     qsort((void *) neg->avail_vars->elts, neg->avail_vars->nelts,
  1014.           sizeof(var_rec), (int (*)(const void *, const void *)) variantsortf);
  1015.  
  1016.     return OK;
  1017. }
  1018.  
  1019.  
  1020. /*****************************************************************
  1021.  * And now for the code you've been waiting for... actually
  1022.  * finding a match to the client's requirements.  
  1023.  */
  1024.  
  1025. /* Matching MIME types ... the star/star and foo/star commenting conventions
  1026.  * are implemented here.  (You know what I mean by star/star, but just
  1027.  * try mentioning those three characters in a C comment).  Using strcmp()
  1028.  * is legit, because everything has already been smashed to lowercase.
  1029.  *
  1030.  * Note also that if we get an exact match on the media type, we update
  1031.  * level_matched for use in level_cmp below...
  1032.  * 
  1033.  * We also give a value for mime_stars, which is used later. It should
  1034.  * be 1 for star/star, 2 for type/star and 3 for type/subtype.
  1035.  */
  1036.  
  1037. static int mime_match(accept_rec *accept_r, var_rec *avail)
  1038. {
  1039.     char *accept_type = accept_r->name;
  1040.     char *avail_type = avail->mime_type;
  1041.     int len = strlen(accept_type);
  1042.  
  1043.     if (accept_type[0] == '*') {        /* Anything matches star/star */
  1044.         if (avail->mime_stars < 1) {
  1045.             avail->mime_stars = 1;
  1046.         }
  1047.         return 1;
  1048.     }
  1049.     else if ((accept_type[len - 1] == '*') &&
  1050.              !strncmp(accept_type, avail_type, len - 2)) {
  1051.         if (avail->mime_stars < 2) {
  1052.             avail->mime_stars = 2;
  1053.         }
  1054.         return 1;
  1055.     }
  1056.     else if (!strcmp(accept_type, avail_type)
  1057.              || (!strcmp(accept_type, "text/html")
  1058.                  && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE)
  1059.                      || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) {
  1060.         if (accept_r->level >= avail->level) {
  1061.             avail->level_matched = avail->level;
  1062.             avail->mime_stars = 3;
  1063.             return 1;
  1064.         }
  1065.     }
  1066.  
  1067.     return OK;
  1068. }
  1069.  
  1070. /* This code implements a piece of the tie-breaking algorithm between
  1071.  * variants of equal quality.  This piece is the treatment of variants
  1072.  * of the same base media type, but different levels.  What we want to
  1073.  * return is the variant at the highest level that the client explicitly
  1074.  * claimed to accept.
  1075.  *
  1076.  * If all the variants available are at a higher level than that, or if
  1077.  * the client didn't say anything specific about this media type at all
  1078.  * and these variants just got in on a wildcard, we prefer the lowest
  1079.  * level, on grounds that that's the one that the client is least likely
  1080.  * to choke on.
  1081.  *
  1082.  * (This is all motivated by treatment of levels in HTML --- we only
  1083.  * want to give level 3 to browsers that explicitly ask for it; browsers
  1084.  * that don't, including HTTP/0.9 browsers that only get the implicit
  1085.  * "Accept: * / *" [space added to avoid confusing cpp --- no, that
  1086.  * syntax doesn't really work] should get HTML2 if available).
  1087.  *
  1088.  * (Note that this code only comes into play when we are choosing among
  1089.  * variants of equal quality, where the draft standard gives us a fair
  1090.  * bit of leeway about what to do.  It ain't specified by the standard;
  1091.  * rather, it is a choice made by this server about what to do in cases
  1092.  * where the standard does not specify a unique course of action).
  1093.  */
  1094.  
  1095. static int level_cmp(var_rec *var1, var_rec *var2)
  1096. {
  1097.     /* Levels are only comparable between matching media types */
  1098.  
  1099.     if (var1->is_pseudo_html && !var2->is_pseudo_html) {
  1100.         return 0;
  1101.     }
  1102.  
  1103.     if (!var1->is_pseudo_html && strcmp(var1->mime_type, var2->mime_type)) {
  1104.         return 0;
  1105.     }
  1106.     /* The result of the above if statements is that, if we get to
  1107.      * here, both variants have the same mime_type or both are
  1108.      * pseudo-html.
  1109.      */    
  1110.  
  1111.     /* Take highest level that matched, if either did match. */
  1112.  
  1113.     if (var1->level_matched > var2->level_matched) {
  1114.         return 1;
  1115.     }
  1116.     if (var1->level_matched < var2->level_matched) {
  1117.         return -1;
  1118.     }
  1119.  
  1120.     /* Neither matched.  Take lowest level, if there's a difference. */
  1121.  
  1122.     if (var1->level < var2->level) {
  1123.         return 1;
  1124.     }
  1125.     if (var1->level > var2->level) {
  1126.         return -1;
  1127.     }
  1128.  
  1129.     /* Tied */
  1130.  
  1131.     return 0;
  1132. }
  1133.  
  1134. /* Finding languages.  The main entry point is set_language_quality()
  1135.  * which is called for each variant. It sets two elements in the
  1136.  * variant record:
  1137.  *    language_quality  - the 'q' value of the 'best' matching language
  1138.  *                        from Accept-Language: header (HTTP/1.1)
  1139.  *    lang_index    -     Pre HTTP/1.1 language priority, using
  1140.  *                        position of language on the Accept-Language:
  1141.  *                        header, if present, else LanguagePriority
  1142.  *                        directive order.
  1143.  *
  1144.  * When we do the variant checking for best variant, we use language
  1145.  * quality first, and if a tie, language_index next (this only applies
  1146.  * when _not_ using the RVSA/1.0 algorithm). If using the RVSA/1.0
  1147.  * algorithm, lang_index is never used.
  1148.  *
  1149.  * set_language_quality() calls find_lang_index() and find_default_index()
  1150.  * to set lang_index.  
  1151.  */
  1152.  
  1153. static int find_lang_index(array_header *accept_langs, char *lang)
  1154. {
  1155.     accept_rec *accs;
  1156.     int i;
  1157.  
  1158.     if (!lang || !accept_langs) {
  1159.         return -1;
  1160.     }
  1161.  
  1162.     accs = (accept_rec *) accept_langs->elts;
  1163.  
  1164.     for (i = 0; i < accept_langs->nelts; ++i) {
  1165.         if (!strncmp(lang, accs[i].name, strlen(accs[i].name))) {
  1166.             return i;
  1167.         }
  1168.     }
  1169.  
  1170.     return -1;
  1171. }
  1172.  
  1173. /* This function returns the priority of a given language
  1174.  * according to LanguagePriority.  It is used in case of a tie
  1175.  * between several languages.
  1176.  */
  1177.  
  1178. static int find_default_index(neg_dir_config *conf, char *lang)
  1179. {
  1180.     array_header *arr;
  1181.     int nelts;
  1182.     char **elts;
  1183.     int i;
  1184.  
  1185.     if (!lang) {
  1186.         return -1;
  1187.     }
  1188.  
  1189.     arr = conf->language_priority;
  1190.     nelts = arr->nelts;
  1191.     elts = (char **) arr->elts;
  1192.  
  1193.     for (i = 0; i < nelts; ++i) {
  1194.         if (!strcasecmp(elts[i], lang)) {
  1195.             return i;
  1196.         }
  1197.     }
  1198.  
  1199.     return -1;
  1200. }
  1201.  
  1202. /* set_default_lang_quality() sets the quality we apply to variants
  1203.  * which have no language assigned to them. If none of the variants
  1204.  * have a language, we are not negotiating on language, so all are
  1205.  * acceptable, and we set the default q value to 1.0. However if
  1206.  * some of the variants have languages, we set this default to 0.001.
  1207.  * The value of this default will be applied to all variants with
  1208.  * no explicit language -- which will have the effect of making them
  1209.  * acceptable, but only if no variants with an explicit language
  1210.  * are acceptable. The default q value set here is assigned to variants
  1211.  * with no language type in set_language_quality().
  1212.  *
  1213.  * Note that if using the RVSA/1.0 algorithm, we don't use this
  1214.  * fiddle.  
  1215.  */
  1216.  
  1217. static void set_default_lang_quality(negotiation_state *neg)
  1218. {
  1219.     var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
  1220.     int j;
  1221.  
  1222.     if (!neg->dont_fiddle_headers) {
  1223.         for (j = 0; j < neg->avail_vars->nelts; ++j) {
  1224.             var_rec *variant = &avail_recs[j];
  1225.             if (variant->content_languages &&
  1226.                 variant->content_languages->nelts) {
  1227.                 neg->default_lang_quality = 0.001f;
  1228.                 return;
  1229.             }
  1230.         }
  1231.     }
  1232.  
  1233.     neg->default_lang_quality = 1.0f;
  1234. }
  1235.  
  1236. /* Set the language_quality value in the variant record. Also
  1237.  * assigns lang_index for back-compat. 
  1238.  *
  1239.  * To find the language_quality value, we look for the 'q' value
  1240.  * of the 'best' matching language on the Accept-Language
  1241.  * header. The 'best' match is the language on Accept-Language
  1242.  * header which matches the language of this variant either fully,
  1243.  * or as far as the prefix marker (-). If two or more languages
  1244.  * match, use the longest string from the Accept-Language header
  1245.  * (see HTTP/1.1 [14.4])
  1246.  *
  1247.  * When a variant has multiple languages, we find the 'best'
  1248.  * match for each variant language tag as above, then select the
  1249.  * one with the highest q value. Because both the accept-header
  1250.  * and variant can have multiple languages, we now have a hairy
  1251.  * loop-within-a-loop here.
  1252.  *
  1253.  * If the variant has no language and we have no Accept-Language
  1254.  * items, leave the quality at 1.0 and return.
  1255.  *
  1256.  * If the variant has no language, we use the default as set by
  1257.  * set_default_lang_quality() (1.0 if we are not negotiating on
  1258.  * language, 0.001 if we are).
  1259.  *
  1260.  * Following the setting of the language quality, we drop through to
  1261.  * set the old 'lang_index'. This is set based on either the order
  1262.  * of the languages on the Accept-Language header, or the
  1263.  * order on the LanguagePriority directive. This is only used
  1264.  * in the negotiation if the language qualities tie.
  1265.  */
  1266.  
  1267. static void set_language_quality(negotiation_state *neg, var_rec *variant)
  1268. {
  1269.     char *firstlang;
  1270.     int idx;
  1271.  
  1272.     if (!variant->content_languages || !variant->content_languages->nelts) {
  1273.         /* This variant has no content-language, so use the default
  1274.          * quality factor for variants with no content-language
  1275.          * (previously set by set_default_lang_quality()).
  1276.          * Leave the factor alone (it remains at 1.0) when we may not fiddle
  1277.          * with the headers.
  1278.          */
  1279.         if (!neg->dont_fiddle_headers) {
  1280.             variant->lang_quality = neg->default_lang_quality;
  1281.         }
  1282.         if (!neg->accept_langs) {
  1283.             return;             /* no accept-language header */
  1284.         }
  1285.  
  1286.     }
  1287.     else {
  1288.         /* Variant has one (or more) languages.  Look for the best
  1289.          * match. We do this by going through each language on the
  1290.          * variant description looking for a match on the
  1291.          * Accept-Language header. The best match is the longest
  1292.          * matching language on the header. The final result is the
  1293.          * best q value from all the languages on the variant
  1294.          * description.
  1295.          */
  1296.  
  1297.         if (!neg->accept_langs) {
  1298.             /* no accept-language header makes the variant indefinite */
  1299.             variant->definite = 0;
  1300.         }
  1301.         else {    /* There is an accept-language with 0 or more items */
  1302.             accept_rec *accs = (accept_rec *) neg->accept_langs->elts;
  1303.             accept_rec *best = NULL, *star = NULL;
  1304.             accept_rec *bestthistag;
  1305.             char *lang, *p;
  1306.             float fiddle_q = 0.0f;
  1307.             int any_match_on_star = 0;
  1308.             int i, j, alen, longest_lang_range_len;
  1309.             
  1310.             for (j = 0; j < variant->content_languages->nelts; ++j) {
  1311.                 p = NULL;
  1312.                 bestthistag = NULL;
  1313.                 longest_lang_range_len = 0;
  1314.                 alen = 0;
  1315.                 
  1316.                 /* lang is the variant's language-tag, which is the one
  1317.                  * we are allowed to use the prefix of in HTTP/1.1
  1318.                  */
  1319.                 lang = ((char **) (variant->content_languages->elts))[j];
  1320.                 
  1321.                 /* now find the best (i.e. longest) matching
  1322.                  * Accept-Language header language. We put the best match
  1323.                  * for this tag in bestthistag. We cannot update the
  1324.                  * overall best (based on q value) because the best match
  1325.                  * for this tag is the longest language item on the accept
  1326.                  * header, not necessarily the highest q.
  1327.                  */
  1328.                 for (i = 0; i < neg->accept_langs->nelts; ++i) {
  1329.                     if (!strcmp(accs[i].name, "*")) {
  1330.                         if (!star) {
  1331.                             star = &accs[i];
  1332.                         }
  1333.                         continue;
  1334.                     }
  1335.                     /* Find language. We match if either the variant
  1336.                      * language tag exactly matches the language range
  1337.                      * from the accept header, or a prefix of the variant
  1338.                      * language tag up to a '-' character matches the
  1339.                      * whole of the language range in the Accept-Language
  1340.                      * header.  Note that HTTP/1.x allows any number of
  1341.                      * '-' characters in a tag or range, currently only
  1342.                      * tags with zero or one '-' characters are defined
  1343.                      * for general use (see rfc1766).
  1344.                      *  
  1345.                      * We only use language range in the Accept-Language
  1346.                      * header the best match for the variant language tag
  1347.                      * if it is longer than the previous best match.
  1348.                      */
  1349.                     
  1350.                     alen = strlen(accs[i].name);
  1351.                     
  1352.                     if ((strlen(lang) >= alen) &&
  1353.                         !strncmp(lang, accs[i].name, alen) &&
  1354.                         ((lang[alen] == 0) || (lang[alen] == '-')) ) {
  1355.                         
  1356.                         if (alen > longest_lang_range_len) {
  1357.                             longest_lang_range_len = alen;
  1358.                             bestthistag = &accs[i];
  1359.                         }
  1360.                     }
  1361.                     
  1362.                     if (!bestthistag && !neg->dont_fiddle_headers) {
  1363.                         /* The next bit is a fiddle. Some browsers might
  1364.                          * be configured to send more specific language
  1365.                          * ranges than desirable. For example, an
  1366.                          * Accept-Language of en-US should never match
  1367.                          * variants with languages en or en-GB. But US
  1368.                          * English speakers might pick en-US as their
  1369.                          * language choice.  So this fiddle checks if the
  1370.                          * language range has a prefix, and if so, it
  1371.                          * matches variants which match that prefix with a
  1372.                          * priority of 0.001. So a request for en-US would
  1373.                          * match variants of types en and en-GB, but at
  1374.                          * much lower priority than matches of en-US
  1375.                          * directly, or of any other language listed on
  1376.                          * the Accept-Language header. Note that this
  1377.                          * fiddle does not handle multi-level prefixes.
  1378.                          */
  1379.                         if ((p = strchr(accs[i].name, '-'))) {
  1380.                             int plen = p - accs[i].name;
  1381.  
  1382.                             if (!strncmp(lang, accs[i].name, plen)) {
  1383.                                 fiddle_q = 0.001f;
  1384.                             }
  1385.                         }
  1386.                     }
  1387.                 }
  1388.                 /* Finished looking at Accept-Language headers, the best
  1389.                  * (longest) match is in bestthistag, or NULL if no match
  1390.                  */
  1391.                 if (!best ||
  1392.                     (bestthistag && bestthistag->quality > best->quality)) {
  1393.                     best = bestthistag;
  1394.                 }
  1395.                 
  1396.                 /* See if the tag matches on a * in the Accept-Language
  1397.                  * header. If so, record this fact for later use 
  1398.                  */
  1399.                 if (!bestthistag && star) {
  1400.                     any_match_on_star = 1;
  1401.                 }
  1402.             }
  1403.             
  1404.             /* If one of the language tags of the variant matched on *, we
  1405.              * need to see if its q is better than that of any non-* match
  1406.              * on any other tag of the variant.  If so the * match takes
  1407.              * precedence and the overall match is not definite.
  1408.              */
  1409.             if ( any_match_on_star &&
  1410.                 ((best && star->quality > best->quality) ||
  1411.                  (!best)) ) {
  1412.                 best = star;
  1413.                 variant->definite = 0;
  1414.             }
  1415.             
  1416.             variant->lang_quality = best ? best->quality : fiddle_q;
  1417.         }
  1418.     }
  1419.  
  1420.     /* Now set the old lang_index field. Since this is old 
  1421.      * stuff anyway, don't bother with handling multiple languages
  1422.      * per variant, just use the first one assigned to it 
  1423.      */
  1424.     idx = 0;
  1425.     if (variant->content_languages && variant->content_languages->nelts) {
  1426.         firstlang = ((char **) variant->content_languages->elts)[0];
  1427.     }
  1428.     else {
  1429.         firstlang = "";
  1430.     }
  1431.     if (!neg->accept_langs) {   /* Client doesn't care */
  1432.         idx = find_default_index((neg_dir_config *) ap_get_module_config(
  1433.                                   neg->r->per_dir_config, &negotiation_module),
  1434.                                  firstlang);
  1435.     }
  1436.     else {                      /* Client has Accept-Language */
  1437.         idx = find_lang_index(neg->accept_langs, firstlang);
  1438.     }
  1439.     variant->lang_index = idx;
  1440.  
  1441.     return;
  1442. }
  1443.  
  1444. /* Determining the content length --- if the map didn't tell us,
  1445.  * we have to do a stat() and remember for next time.
  1446.  *
  1447.  * Grump.  For Apache, even the first stat here may well be
  1448.  * redundant (for multiviews) with a stat() done by the sub_req
  1449.  * machinery.  At some point, that ought to be fixed.
  1450.  */
  1451.  
  1452. static float find_content_length(negotiation_state *neg, var_rec *variant)
  1453. {
  1454.     struct stat statb;
  1455.  
  1456.     if (variant->bytes == 0) {
  1457.         char *fullname = ap_make_full_path(neg->pool, neg->dir_name,
  1458.                                            variant->file_name);
  1459.  
  1460.         if (stat(fullname, &statb) >= 0) {
  1461.             /* Note, precision may be lost */
  1462.             variant->bytes = (float) statb.st_size;
  1463.         }
  1464.     }
  1465.  
  1466.     return variant->bytes;
  1467. }
  1468.  
  1469. /* For a given variant, find the best matching Accept: header
  1470.  * and assign the Accept: header's quality value to the
  1471.  * mime_type_quality field of the variant, for later use in
  1472.  * determining the best matching variant.
  1473.  */
  1474.  
  1475. static void set_accept_quality(negotiation_state *neg, var_rec *variant)
  1476. {
  1477.     int i;
  1478.     accept_rec *accept_recs;
  1479.     float q = 0.0f;
  1480.     int q_definite = 1;
  1481.  
  1482.     /* if no Accept: header, leave quality alone (will
  1483.      * remain at the default value of 1) 
  1484.      *
  1485.      * XXX: This if is currently never true because of the effect of
  1486.      * maybe_add_default_accepts().
  1487.      */
  1488.     if (!neg->accepts) {
  1489.         if (variant->mime_type && *variant->mime_type)
  1490.             variant->definite = 0;
  1491.         return;
  1492.     }
  1493.  
  1494.     accept_recs = (accept_rec *) neg->accepts->elts;
  1495.  
  1496.     /*
  1497.      * Go through each of the ranges on the Accept: header,
  1498.      * looking for the 'best' match with this variant's
  1499.      * content-type. We use the best match's quality
  1500.      * value (from the Accept: header) for this variant's
  1501.      * mime_type_quality field.
  1502.      *
  1503.      * The best match is determined like this:
  1504.      *    type/type is better than type/ * is better than * / *
  1505.      *    if match is type/type, use the level mime param if available
  1506.      */
  1507.     for (i = 0; i < neg->accepts->nelts; ++i) {
  1508.  
  1509.         accept_rec *type = &accept_recs[i];
  1510.         int prev_mime_stars;
  1511.  
  1512.         prev_mime_stars = variant->mime_stars;
  1513.  
  1514.         if (!mime_match(type, variant)) {
  1515.             continue;           /* didn't match the content type at all */
  1516.         }
  1517.         else {
  1518.             /* did match - see if there were less or more stars than
  1519.              * in previous match
  1520.              */
  1521.             if (prev_mime_stars == variant->mime_stars) {
  1522.                 continue;       /* more stars => not as good a match */
  1523.             }
  1524.         }
  1525.  
  1526.         /* Check maxbytes -- not in HTTP/1.1 or TCN */
  1527.  
  1528.         if (type->max_bytes > 0
  1529.             && (find_content_length(neg, variant) > type->max_bytes)) {
  1530.             continue;
  1531.         }
  1532.  
  1533.         /* If we are allowed to mess with the q-values
  1534.          * and have no explicit q= parameters in the accept header,
  1535.          * make wildcards very low, so we have a low chance
  1536.          * of ending up with them if there's something better.
  1537.          */
  1538.  
  1539.         if (!neg->dont_fiddle_headers && !neg->accept_q &&
  1540.             variant->mime_stars == 1) {
  1541.             q = 0.01f;
  1542.         }
  1543.         else if (!neg->dont_fiddle_headers && !neg->accept_q &&
  1544.                  variant->mime_stars == 2) {
  1545.             q = 0.02f;
  1546.         }
  1547.         else {
  1548.             q = type->quality;
  1549.         }
  1550.  
  1551.         q_definite = (variant->mime_stars == 3);
  1552.     }
  1553.     variant->mime_type_quality = q;
  1554.     variant->definite = variant->definite && q_definite;
  1555.  
  1556. }
  1557.  
  1558. /* For a given variant, find the 'q' value of the charset given
  1559.  * on the Accept-Charset line. If not charsets are listed,
  1560.  * assume value of '1'.
  1561.  */
  1562. static void set_charset_quality(negotiation_state *neg, var_rec *variant)
  1563. {
  1564.     int i;
  1565.     accept_rec *accept_recs;
  1566.     char *charset = variant->content_charset;
  1567.     accept_rec *star = NULL;
  1568.  
  1569.     /* if no Accept-Charset: header, leave quality alone (will
  1570.      * remain at the default value of 1)
  1571.      */
  1572.     if (!neg->accept_charsets) {
  1573.         if (charset && *charset)
  1574.             variant->definite = 0;
  1575.         return;
  1576.     }
  1577.  
  1578.     accept_recs = (accept_rec *) neg->accept_charsets->elts;
  1579.  
  1580.     if (charset == NULL || !*charset) {
  1581.         /* Charset of variant not known */
  1582.  
  1583.         /* if not a text / * type, leave quality alone */
  1584.         if (!(!strncmp(variant->mime_type, "text/", 5)
  1585.               || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE)
  1586.               || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE3) 
  1587.               ))
  1588.             return;
  1589.  
  1590.         /* Don't go guessing if we are in strict header mode,
  1591.          * e.g. when running the rvsa, as any guess won't be reflected
  1592.          * in the variant list or content-location headers.
  1593.          */
  1594.         if (neg->dont_fiddle_headers)
  1595.             return;
  1596.  
  1597.         charset = "iso-8859-1"; /* The default charset for HTTP text types */
  1598.     }
  1599.  
  1600.     /*
  1601.      * Go through each of the items on the Accept-Charset header,
  1602.      * looking for a match with this variant's charset. If none
  1603.      * match, charset is unacceptable, so set quality to 0.
  1604.      */
  1605.     for (i = 0; i < neg->accept_charsets->nelts; ++i) {
  1606.  
  1607.         accept_rec *type = &accept_recs[i];
  1608.  
  1609.         if (!strcmp(type->name, charset)) {
  1610.             variant->charset_quality = type->quality;
  1611.             return;
  1612.         }
  1613.         else if (strcmp(type->name, "*") == 0) {
  1614.             star = type;
  1615.         }
  1616.     }
  1617.     /* No explicit match */
  1618.     if (star) {
  1619.         variant->charset_quality = star->quality;
  1620.         variant->definite = 0;
  1621.         return;
  1622.     }
  1623.     /* If this variant is in charset iso-8859-1, the default is 1.0 */
  1624.     if (strcmp(charset, "iso-8859-1") == 0) {
  1625.         variant->charset_quality = 1.0f;
  1626.     }
  1627.     else {
  1628.         variant->charset_quality = 0.0f;
  1629.     }
  1630. }
  1631.  
  1632.  
  1633. /* is_identity_encoding is included for back-compat, but does anyone
  1634.  * use 7bit, 8bin or binary in their var files??
  1635.  */
  1636.  
  1637. static int is_identity_encoding(const char *enc)
  1638. {
  1639.     return (!enc || !enc[0] || !strcmp(enc, "7bit") || !strcmp(enc, "8bit")
  1640.             || !strcmp(enc, "binary"));
  1641. }
  1642.  
  1643. /*
  1644.  * set_encoding_quality determines whether the encoding for a particular
  1645.  * variant is acceptable for the user-agent.
  1646.  *
  1647.  * The rules for encoding are that if the user-agent does not supply
  1648.  * any Accept-Encoding header, then all encodings are allowed but a
  1649.  * variant with no encoding should be preferred.
  1650.  * If there is an empty Accept-Encoding header, then no encodings are 
  1651.  * acceptable. If there is a non-empty Accept-Encoding header, then
  1652.  * any of the listed encodings are acceptable, as well as no encoding
  1653.  * unless the "identity" encoding is specifically excluded.
  1654.  */
  1655. static void set_encoding_quality(negotiation_state *neg, var_rec *variant)
  1656. {
  1657.     accept_rec *accept_recs;
  1658.     const char *enc = variant->content_encoding;
  1659.     accept_rec *star = NULL;
  1660.     float value_if_not_found = 0.0f;
  1661.     int i;
  1662.  
  1663.     if (!neg->accept_encodings) {
  1664.         /* We had no Accept-Encoding header, assume that all
  1665.          * encodings are acceptable with a low quality,
  1666.          * but we prefer no encoding if available.
  1667.          */
  1668.         if (!enc || is_identity_encoding(enc))
  1669.             variant->encoding_quality = 1.0f;
  1670.         else
  1671.             variant->encoding_quality = 0.5f;
  1672.  
  1673.         return;
  1674.     }
  1675.  
  1676.     if (!enc || is_identity_encoding(enc)) {
  1677.         enc = "identity";
  1678.         value_if_not_found = 0.0001f;
  1679.     }
  1680.  
  1681.     accept_recs = (accept_rec *) neg->accept_encodings->elts;
  1682.  
  1683.     /* Go through each of the encodings on the Accept-Encoding: header,
  1684.      * looking for a match with our encoding. x- prefixes are ignored.
  1685.      */
  1686.     if (enc[0] == 'x' && enc[1] == '-') {
  1687.         enc += 2;
  1688.     }
  1689.     for (i = 0; i < neg->accept_encodings->nelts; ++i) {
  1690.  
  1691.         char *name = accept_recs[i].name;
  1692.  
  1693.         if (name[0] == 'x' && name[1] == '-') {
  1694.             name += 2;
  1695.         }
  1696.  
  1697.         if (!strcmp(name, enc)) {
  1698.             variant->encoding_quality = accept_recs[i].quality;
  1699.             return;
  1700.         }
  1701.  
  1702.         if (strcmp(name, "*") == 0) {
  1703.             star = &accept_recs[i];
  1704.         }
  1705.  
  1706.     }
  1707.     /* No explicit match */
  1708.     if (star) {
  1709.         variant->encoding_quality = star->quality;
  1710.         return;
  1711.     }
  1712.  
  1713.     /* Encoding not found on Accept-Encoding: header, so it is
  1714.      * _not_ acceptable unless it is the identity (no encoding)
  1715.      */
  1716.     variant->encoding_quality = value_if_not_found;
  1717. }
  1718.  
  1719. /************************************************************* 
  1720.  * Possible results of the variant selection algorithm 
  1721.  */
  1722. enum algorithm_results {
  1723.     alg_choice = 1,              /* choose variant */
  1724.     alg_list                     /* list variants */
  1725. };
  1726.  
  1727. /* Below is the 'best_match' function. It returns an int, which has
  1728.  * one of the two values alg_choice or alg_list, which give the result
  1729.  * of the variant selection algorithm.  alg_list means that no best
  1730.  * variant was found by the algorithm, alg_choice means that a best
  1731.  * variant was found and should be returned.  The list/choice
  1732.  * terminology comes from TCN (rfc2295), but is used in a more generic
  1733.  * way here.  The best variant is returned in *pbest. best_match has
  1734.  * two possible algorithms for determining the best variant: the
  1735.  * RVSA/1.0 algorithm (from RFC2296), and the standard Apache
  1736.  * algorithm. These are split out into separate functions
  1737.  * (is_variant_better_rvsa() and is_variant_better()).  Selection of
  1738.  * one is through the neg->use_rvsa flag.
  1739.  *
  1740.  * The call to best_match also creates full information, including
  1741.  * language, charset, etc quality for _every_ variant. This is needed
  1742.  * for generating a correct Vary header, and can be used for the
  1743.  * Alternates header, the human-readable list responses and 406 errors.
  1744.  */
  1745.  
  1746. /* Firstly, the RVSA/1.0 (HTTP Remote Variant Selection Algorithm
  1747.  * v1.0) from rfc2296.  This is the algorithm that goes together with
  1748.  * transparent content negotiation (TCN).
  1749.  */
  1750. static int is_variant_better_rvsa(negotiation_state *neg, var_rec *variant,
  1751.                                   var_rec *best, float *p_bestq)
  1752. {
  1753.     float bestq = *p_bestq, q;
  1754.  
  1755.     /* TCN does not cover negotiation on content-encoding.  For now,
  1756.      * we ignore the encoding unless it was explicitly excluded.
  1757.      */
  1758.     if (variant->encoding_quality == 0.0f)
  1759.         return 0;
  1760.     
  1761.     q = variant->mime_type_quality *
  1762.         variant->source_quality *
  1763.         variant->charset_quality *
  1764.         variant->lang_quality;
  1765.  
  1766.    /* Make sure that variants with a very low nonzero q value
  1767.     * do not get rounded down to 0
  1768.     */
  1769.    if (q <= 0.0f)
  1770.        q = 0.0f; 
  1771.    else if (q < 0.00001f)
  1772.        q = 0.00001f; 
  1773.  
  1774. #ifdef NEG_DEBUG
  1775.     fprintf(stderr, "Variant: file=%s type=%s lang=%s sourceq=%1.3f "
  1776.            "mimeq=%1.3f langq=%1.3f charq=%1.3f encq=%1.3f "
  1777.            "q=%1.5f definite=%d\n",            
  1778.             (variant->file_name ? variant->file_name : ""),
  1779.             (variant->mime_name ? variant->mime_name : ""),
  1780.             (variant->content_languages
  1781.              ? ap_array_pstrcat(neg->pool, variant->content_languages, ',')
  1782.              : ""),
  1783.             variant->source_quality,
  1784.             variant->mime_type_quality,
  1785.             variant->lang_quality,
  1786.             variant->charset_quality,
  1787.             variant->encoding_qual             q,
  1788.             variant->definite);
  1789. #endif
  1790.  
  1791.     if (q == 0.0f) {
  1792.         return 0;
  1793.     }
  1794.     if (q > bestq) {
  1795.         *p_bestq = q;
  1796.         return 1;
  1797.     }
  1798.     if (q == bestq) {
  1799.         /* If the best variant's encoding is of lesser quality than
  1800.          * this variant, then we prefer this variant
  1801.          */
  1802.         if (variant->encoding_quality > best->encoding_quality) {
  1803.             *p_bestq = q;
  1804.             return 1;
  1805.         }
  1806.         /* If the best variant's charset is ISO-8859-1 and this variant has
  1807.          * the same charset quality, then we prefer this variant
  1808.          */
  1809.         if (variant->charset_quality == best->charset_quality &&
  1810.             (variant->content_charset != NULL &&
  1811.              *variant->content_charset != '\0' &&
  1812.              strcmp(variant->content_charset, "iso-8859-1") != 0) &&
  1813.             (best->content_charset == NULL ||
  1814.              *best->content_charset == '\0' ||
  1815.              strcmp(best->content_charset, "iso-8859-1") == 0)) {
  1816.             *p_bestq = q;
  1817.             return 1;
  1818.         }
  1819.     }
  1820.     return 0;
  1821. }
  1822.  
  1823. /* Negotiation algorithm as used by previous versions of Apache
  1824.  * (just about). 
  1825.  */
  1826.  
  1827. static int is_variant_better(negotiation_state *neg, var_rec *variant,
  1828.                              var_rec *best, float *p_bestq)
  1829. {
  1830.     float bestq = *p_bestq, q;
  1831.     int levcmp;
  1832.  
  1833.     /* For non-transparent negotiation, server can choose how
  1834.      * to handle the negotiation. We'll use the following in
  1835.      * order: content-type, language, content-type level, charset,
  1836.      * content length.
  1837.      *
  1838.      * For each check, we have three possible outcomes:
  1839.      *   This variant is worse than current best: return 0
  1840.      *   This variant is better than the current best:
  1841.      *          assign this variant's q to *p_bestq, and return 1
  1842.      *   This variant is just as desirable as the current best:
  1843.      *          drop through to the next test.
  1844.      *
  1845.      * This code is written in this long-winded way to allow future
  1846.      * customisation, either by the addition of additional
  1847.      * checks, or to allow the order of the checks to be determined
  1848.      * by configuration options (e.g. we might prefer to check
  1849.      * language quality _before_ content type).
  1850.      */
  1851.  
  1852.     /* First though, eliminate this variant if it is not
  1853.      * acceptable by type, charset, encoding or language.
  1854.      */
  1855.  
  1856.     if (variant->encoding_quality == 0.0f ||
  1857.         variant->lang_quality == 0.0f ||
  1858.         variant->source_quality == 0.0f ||
  1859.         variant->charset_quality == 0.0f ||
  1860.         variant->mime_type_quality == 0.0f) {
  1861.         return 0;               /* don't consider unacceptables */
  1862.     }
  1863.  
  1864.     q = variant->mime_type_quality * variant->source_quality;
  1865.     if (q == 0.0 || q < bestq) {
  1866.         return 0;
  1867.     }
  1868.     if (q > bestq || !best) {
  1869.         *p_bestq = q;
  1870.         return 1;
  1871.     }
  1872.  
  1873.     /* language */
  1874.     if (variant->lang_quality < best->lang_quality) {
  1875.         return 0;
  1876.     }
  1877.     if (variant->lang_quality > best->lang_quality) {
  1878.         *p_bestq = q;
  1879.         return 1;
  1880.     }
  1881.  
  1882.     /* if language qualities were equal, try the LanguagePriority
  1883.      * stuff
  1884.      */
  1885.     /* XXX: TODO: there is a slight discrepancy between how this
  1886.      * behaves and how it described in the documentation
  1887.      */
  1888.     if (best->lang_index != -1 && variant->lang_index > best->lang_index) {
  1889.         return 0;
  1890.     }
  1891.     if (variant->lang_index != -1 &&
  1892.         (variant->lang_index < best->lang_index || best->lang_index == -1)) {
  1893.         *p_bestq = q;
  1894.         return 1;
  1895.     }
  1896.  
  1897.     /* content-type level (sometimes used with text/html, though we
  1898.      * support it on other types too)
  1899.      */
  1900.     levcmp = level_cmp(variant, best);
  1901.     if (levcmp == -1) {
  1902.         return 0;
  1903.     }
  1904.     if (levcmp == 1) {
  1905.         *p_bestq = q;
  1906.         return 1;
  1907.     }
  1908.  
  1909.     /* charset */
  1910.     if (variant->charset_quality < best->charset_quality) {
  1911.         return 0;
  1912.     }
  1913.     /* If the best variant's charset is ISO-8859-1 and this variant has
  1914.      * the same charset quality, then we prefer this variant
  1915.      */
  1916.     /* XXX: TODO: this specific tie-breaker is not described in the
  1917.      * documentation
  1918.      */
  1919.  
  1920.     if (variant->charset_quality > best->charset_quality ||
  1921.         ((variant->content_charset != NULL &&
  1922.           *variant->content_charset != '\0' &&
  1923.           strcmp(variant->content_charset, "iso-8859-1") != 0) &&
  1924.          (best->content_charset == NULL ||
  1925.           *best->content_charset == '\0' ||
  1926.           strcmp(best->content_charset, "iso-8859-1") == 0))) {
  1927.         *p_bestq = q;
  1928.         return 1;
  1929.     }
  1930.  
  1931.     /* Prefer the highest value for encoding_quality.
  1932.      */
  1933.     if (variant->encoding_quality < best->encoding_quality) {
  1934.        return 0;
  1935.     }
  1936.     if (variant->encoding_quality > best->encoding_quality) {
  1937.        *p_bestq = q;
  1938.        return 1;
  1939.     }
  1940.  
  1941.     /* content length if all else equal */
  1942.     if (find_content_length(neg, variant) >= find_content_length(neg, best)) {
  1943.         return 0;
  1944.     }
  1945.  
  1946.     /* ok, to get here means every thing turned out equal, except
  1947.      * we have a shorter content length, so use this variant
  1948.      */
  1949.     *p_bestq = q;
  1950.     return 1;
  1951. }
  1952.  
  1953. static int best_match(negotiation_state *neg, var_rec **pbest)
  1954. {
  1955.     int j;
  1956.     var_rec *best = NULL;
  1957.     float bestq = 0.0f;
  1958.     enum algorithm_results algorithm_result;
  1959.  
  1960.     var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
  1961.  
  1962.     set_default_lang_quality(neg);
  1963.  
  1964.     /*
  1965.      * Find the 'best' variant 
  1966.      */
  1967.  
  1968.     for (j = 0; j < neg->avail_vars->nelts; ++j) {
  1969.         var_rec *variant = &avail_recs[j];
  1970.  
  1971.         /* Find all the relevant 'quality' values from the
  1972.          * Accept... headers, and store in the variant.  This also
  1973.          * prepares for sending an Alternates header etc so we need to
  1974.          * do it even if we do not actually plan to find a best
  1975.          * variant.  
  1976.          */
  1977.         set_accept_quality(neg, variant);
  1978.         set_language_quality(neg, variant);
  1979.         set_encoding_quality(neg, variant);
  1980.         set_charset_quality(neg, variant);
  1981.  
  1982.         /* Only do variant selection if we may actually choose a
  1983.          * variant for the client 
  1984.          */
  1985.         if (neg->may_choose) {
  1986.  
  1987.             /* Now find out if this variant is better than the current
  1988.              * best, either using the RVSA/1.0 algorithm, or Apache's
  1989.              * internal server-driven algorithm. Presumably other
  1990.              * server-driven algorithms are possible, and could be
  1991.              * implemented here.
  1992.              */
  1993.      
  1994.             if (neg->use_rvsa) {
  1995.                 if (is_variant_better_rvsa(neg, variant, best, &bestq)) {
  1996.                     best = variant;
  1997.                 }
  1998.             }
  1999.             else {
  2000.                 if (is_variant_better(neg, variant, best, &bestq)) {
  2001.                     best = variant;
  2002.                 }
  2003.             }
  2004.         }
  2005.     }
  2006.  
  2007.     /* We now either have a best variant, or no best variant */
  2008.  
  2009.     if (neg->use_rvsa)    {
  2010.         /* calculate result for RVSA/1.0 algorithm:
  2011.          * only a choice response if the best variant has q>0
  2012.          * and is definite
  2013.          */
  2014.         algorithm_result = (best && best->definite) && (bestq > 0) ?
  2015.                            alg_choice : alg_list;
  2016.     }
  2017.     else {
  2018.         /* calculate result for Apache negotiation algorithm */
  2019.         algorithm_result = bestq > 0 ? alg_choice : alg_list;        
  2020.     }
  2021.  
  2022.     /* Returning a choice response with a non-neighboring variant is a
  2023.      * protocol security error in TCN (see rfc2295).  We do *not*
  2024.      * verify here that the variant and URI are neighbors, even though
  2025.      * we may return alg_choice.  We depend on the environment (the
  2026.      * caller) to only declare the resource transparently negotiable if
  2027.      * all variants are neighbors.
  2028.      */
  2029.     *pbest = best;
  2030.     return algorithm_result;
  2031. }
  2032.  
  2033. /* Sets response headers for a negotiated response.
  2034.  * neg->is_transparent determines whether a transparently negotiated
  2035.  * response or a plain `server driven negotiation' response is
  2036.  * created.   Applicable headers are Alternates, Vary, and TCN.
  2037.  *
  2038.  * The Vary header we create is sometimes longer than is required for
  2039.  * the correct caching of negotiated results by HTTP/1.1 caches.  For
  2040.  * example if we have 3 variants x.html, x.ps.en and x.ps.nl, and if
  2041.  * the Accept: header assigns a 0 quality to .ps, then the results of
  2042.  * the two server-side negotiation algorithms we currently implement
  2043.  * will never depend on Accept-Language so we could return `Vary:
  2044.  * negotiate, accept' instead of the longer 'Vary: negotiate, accept,
  2045.  * accept-language' which the code below will return.  A routine for
  2046.  * computing the exact minimal Vary header would be a huge pain to code
  2047.  * and maintain though, especially because we need to take all possible
  2048.  * twiddles in the server-side negotiation algorithms into account.
  2049.  */
  2050. static void set_neg_headers(request_rec *r, negotiation_state *neg,
  2051.                             int alg_result)
  2052. {
  2053.     table *hdrs;
  2054.     var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
  2055.     const char *sample_type = NULL;
  2056.     const char *sample_language = NULL;
  2057.     const char *sample_encoding = NULL;
  2058.     const char *sample_charset = NULL;
  2059.     char *lang;
  2060.     char *qstr;
  2061.     char *lenstr;
  2062.     long len;
  2063.     array_header *arr;
  2064.     int max_vlist_array = (neg->avail_vars->nelts * 21);
  2065.     int first_variant = 1;
  2066.     int vary_by_type = 0;
  2067.     int vary_by_language = 0;
  2068.     int vary_by_charset = 0;
  2069.     int vary_by_encoding = 0;
  2070.     int j;
  2071.  
  2072.     /* In order to avoid O(n^2) memory copies in building Alternates,
  2073.      * we preallocate a table with the maximum substrings possible,
  2074.      * fill it with the variant list, and then concatenate the entire array.
  2075.      * Note that if you change the number of substrings pushed, you also
  2076.      * need to change the calculation of max_vlist_array above.
  2077.      */
  2078.     if (neg->send_alternates && neg->avail_vars->nelts)
  2079.         arr = ap_make_array(r->pool, max_vlist_array, sizeof(char *));
  2080.     else
  2081.         arr = NULL;
  2082.  
  2083.     /* Put headers into err_headers_out, since send_http_header()
  2084.      * outputs both headers_out and err_headers_out.
  2085.      */
  2086.     hdrs = r->err_headers_out;
  2087.  
  2088.     for (j = 0; j < neg->avail_vars->nelts; ++j) {
  2089.         var_rec *variant = &avail_recs[j];
  2090.  
  2091.         if (variant->content_languages && variant->content_languages->nelts) {
  2092.             lang = ap_array_pstrcat(r->pool, variant->content_languages, ',');
  2093.         }
  2094.         else {
  2095.             lang = NULL;
  2096.         }
  2097.  
  2098.         /* Calculate Vary by looking for any difference between variants */
  2099.  
  2100.         if (first_variant) {
  2101.             sample_type     = variant->mime_type;
  2102.             sample_charset  = variant->content_charset;
  2103.             sample_language = lang;
  2104.             sample_encoding = variant->content_encoding;
  2105.         }
  2106.         else {
  2107.             if (!vary_by_type &&
  2108.                 strcmp(sample_type ? sample_type : "", 
  2109.                        variant->mime_type ? variant->mime_type : "")) {
  2110.                 vary_by_type = 1;
  2111.             }
  2112.             if (!vary_by_charset &&
  2113.                 strcmp(sample_charset ? sample_charset : "",
  2114.                        variant->content_charset ?
  2115.                        variant->content_charset : "")) {
  2116.                 vary_by_charset = 1;
  2117.             }
  2118.             if (!vary_by_language &&
  2119.                 strcmp(sample_language ? sample_language : "", 
  2120.                        lang ? lang : "")) {
  2121.                 vary_by_language = 1;
  2122.             }
  2123.             if (!vary_by_encoding &&
  2124.                 strcmp(sample_encoding ? sample_encoding : "",
  2125.                        variant->content_encoding ? 
  2126.                        variant->content_encoding : "")) {
  2127.                 vary_by_encoding = 1;
  2128.             }
  2129.         }
  2130.         first_variant = 0;
  2131.  
  2132.         if (!neg->send_alternates)
  2133.             continue;
  2134.  
  2135.         /* Generate the string components for this Alternates entry */
  2136.  
  2137.         *((const char **) ap_push_array(arr)) = "{\"";
  2138.         *((const char **) ap_push_array(arr)) = variant->file_name;
  2139.         *((const char **) ap_push_array(arr)) = "\" ";
  2140.  
  2141.         qstr = (char *) ap_palloc(r->pool, 6);
  2142.         ap_snprintf(qstr, 6, "%1.3f", variant->source_quality);
  2143.  
  2144.         /* Strip trailing zeros (saves those valuable network bytes) */
  2145.         if (qstr[4] == '0') {
  2146.             qstr[4] = '\0';
  2147.             if (qstr[3] == '0') {
  2148.                 qstr[3] = '\0';
  2149.                 if (qstr[2] == '0') {
  2150.                     qstr[1] = '\0';
  2151.                 }
  2152.             }
  2153.         }
  2154.         *((const char **) ap_push_array(arr)) = qstr;
  2155.  
  2156.         if (variant->mime_type && *variant->mime_type) {
  2157.             *((const char **) ap_push_array(arr)) = " {type ";
  2158.             *((const char **) ap_push_array(arr)) = variant->mime_type;
  2159.             *((const char **) ap_push_array(arr)) = "}";
  2160.         }
  2161.         if (variant->content_charset && *variant->content_charset) {
  2162.             *((const char **) ap_push_array(arr)) = " {charset ";
  2163.             *((const char **) ap_push_array(arr)) = variant->content_charset;
  2164.             *((const char **) ap_push_array(arr)) = "}";
  2165.         }
  2166.         if (lang) {
  2167.             *((const char **) ap_push_array(arr)) = " {language ";
  2168.             *((const char **) ap_push_array(arr)) = lang;
  2169.             *((const char **) ap_push_array(arr)) = "}";
  2170.         }
  2171.         if (variant->content_encoding && *variant->content_encoding) {
  2172.             /* Strictly speaking, this is non-standard, but so is TCN */
  2173.  
  2174.             *((const char **) ap_push_array(arr)) = " {encoding ";
  2175.             *((const char **) ap_push_array(arr)) = variant->content_encoding;
  2176.             *((const char **) ap_push_array(arr)) = "}";
  2177.         }
  2178.  
  2179.         /* Note that the Alternates specification (in rfc2295) does
  2180.          * not require that we include {length x}, so we could omit it
  2181.          * if determining the length is too expensive.  We currently
  2182.          * always include it though.  22 bytes is enough for 2^64.
  2183.          *
  2184.          * If the variant is a CGI script, find_content_length would
  2185.          * return the length of the script, not the output it
  2186.          * produces, so we check for the presence of a handler and if
  2187.          * there is one we don't add a length.
  2188.          * 
  2189.          * XXX: TODO: This check does not detect a CGI script if we
  2190.          * get the variant from a type map.  This needs to be fixed
  2191.          * (without breaking things if the type map specifies a
  2192.          * content-length, which currently leads to the correct result).
  2193.          */
  2194.         if (!(variant->sub_req && variant->sub_req->handler)
  2195.             && (len = find_content_length(neg, variant)) != 0) {
  2196.  
  2197.             lenstr = (char *) ap_palloc(r->pool, 22);
  2198.             ap_snprintf(lenstr, 22, "%ld", len);
  2199.             *((const char **) ap_push_array(arr)) = " {length ";
  2200.             *((const char **) ap_push_array(arr)) = lenstr;
  2201.             *((const char **) ap_push_array(arr)) = "}";
  2202.         }
  2203.       
  2204.         *((const char **) ap_push_array(arr)) = "}";
  2205.         *((const char **) ap_push_array(arr)) = ", "; /* trimmed below */
  2206.     }
  2207.  
  2208.     if (neg->send_alternates && neg->avail_vars->nelts) {
  2209.         arr->nelts--;                                 /* remove last comma */
  2210.         ap_table_mergen(hdrs, "Alternates",
  2211.                         ap_array_pstrcat(r->pool, arr, '\0'));
  2212.     } 
  2213.  
  2214.     /* Theoretically the negotiation result _always_ has a dependence on
  2215.      * the contents of the Accept header because we do 'mxb='
  2216.      * processing in set_accept_quality().  However, variations in mxb
  2217.      * only affect the relative quality of several acceptable variants,
  2218.      * so there is no reason to worry about an unacceptable variant
  2219.      * being mistakenly prioritized.  We therefore ignore mxb in deciding
  2220.      * whether or not to include Accept in the Vary field value.
  2221.      */
  2222.     if (neg->is_transparent || vary_by_type || vary_by_language ||
  2223.         vary_by_language || vary_by_charset || vary_by_encoding) {
  2224.  
  2225.         ap_table_mergen(hdrs, "Vary", 2 + ap_pstrcat(r->pool,
  2226.             neg->is_transparent ? ", negotiate"       : "",
  2227.             vary_by_type        ? ", accept"          : "",
  2228.             vary_by_language    ? ", accept-language" : "",
  2229.             vary_by_charset     ? ", accept-charset"  : "",
  2230.             vary_by_encoding    ? ", accept-encoding" : "", NULL));
  2231.     }
  2232.  
  2233.     if (neg->is_transparent) { /* Create TCN response header */
  2234.         ap_table_setn(hdrs, "TCN",
  2235.                       alg_result == alg_list ? "list" : "choice");
  2236.     }
  2237. }
  2238.  
  2239. /**********************************************************************
  2240.  *
  2241.  * Return an HTML list of variants. This is output as part of the
  2242.  * choice response or 406 status body.
  2243.  */
  2244.  
  2245. static char *make_variant_list(request_rec *r, negotiation_state *neg)
  2246. {
  2247.     array_header *arr;
  2248.     int i;
  2249.     int max_vlist_array = (neg->avail_vars->nelts * 15) + 2;
  2250.  
  2251.     /* In order to avoid O(n^2) memory copies in building the list,
  2252.      * we preallocate a table with the maximum substrings possible,
  2253.      * fill it with the variant list, and then concatenate the entire array.
  2254.      */
  2255.     arr = ap_make_array(r->pool, max_vlist_array, sizeof(char *));
  2256.  
  2257.     *((const char **) ap_push_array(arr)) = "Available variants:\n<ul>\n";
  2258.  
  2259.     for (i = 0; i < neg->avail_vars->nelts; ++i) {
  2260.         var_rec *variant = &((var_rec *) neg->avail_vars->elts)[i];
  2261.         char *filename = variant->file_name ? variant->file_name : "";
  2262.         array_header *languages = variant->content_languages;
  2263.         char *description = variant->description ? variant->description : "";
  2264.  
  2265.         /* The format isn't very neat, and it would be nice to make
  2266.          * the tags human readable (eg replace 'language en' with 'English').
  2267.          * Note that if you change the number of substrings pushed, you also
  2268.          * need to change the calculation of max_vlist_array above.
  2269.          */
  2270.         *((const char **) ap_push_array(arr)) = "<li><a href=\"";
  2271.         *((const char **) ap_push_array(arr)) = filename;
  2272.         *((const char **) ap_push_array(arr)) = "\">";
  2273.         *((const char **) ap_push_array(arr)) = filename;
  2274.         *((const char **) ap_push_array(arr)) = "</a> ";
  2275.         *((const char **) ap_push_array(arr)) = description;
  2276.  
  2277.         if (variant->mime_type && *variant->mime_type) {
  2278.             *((const char **) ap_push_array(arr)) = ", type ";
  2279.             *((const char **) ap_push_array(arr)) = variant->mime_type;
  2280.         }
  2281.         if (languages && languages->nelts) {
  2282.             *((const char **) ap_push_array(arr)) = ", language ";
  2283.             *((const char **) ap_push_array(arr)) = ap_array_pstrcat(r->pool,
  2284.                                                        languages, ',');
  2285.         }
  2286.         if (variant->content_charset && *variant->content_charset) {
  2287.             *((const char **) ap_push_array(arr)) = ", charset ";
  2288.             *((const char **) ap_push_array(arr)) = variant->content_charset;
  2289.         }
  2290.         if (variant->content_encoding) {
  2291.             *((const char **) ap_push_array(arr)) = ", encoding ";
  2292.             *((const char **) ap_push_array(arr)) = variant->content_encoding;
  2293.         }
  2294.         *((const char **) ap_push_array(arr)) = "\n";
  2295.     }
  2296.     *((const char **) ap_push_array(arr)) = "</ul>\n";
  2297.  
  2298.     return ap_array_pstrcat(r->pool, arr, '\0');
  2299. }
  2300.  
  2301. static void store_variant_list(request_rec *r, negotiation_state *neg)
  2302. {
  2303.     if (r->main == NULL) {
  2304.         ap_table_setn(r->notes, "variant-list", make_variant_list(r, neg));
  2305.     }
  2306.     else {
  2307.         ap_table_setn(r->main->notes, "variant-list",
  2308.                       make_variant_list(r->main, neg));
  2309.     }
  2310. }
  2311.  
  2312. /* Called if we got a "Choice" response from the variant selection algorithm.
  2313.  * It checks the result of the chosen variant to see if it
  2314.  * is itself negotiated (if so, return error VARIANT_ALSO_VARIES).
  2315.  * Otherwise, add the appropriate headers to the current response.
  2316.  */
  2317.  
  2318. static int setup_choice_response(request_rec *r, negotiation_state *neg,
  2319.                                  var_rec *variant)
  2320. {
  2321.     request_rec *sub_req;
  2322.     const char *sub_vary;
  2323.  
  2324.     if (!variant->sub_req) {
  2325.         int status;
  2326.  
  2327.         sub_req = ap_sub_req_lookup_file(variant->file_name, r);
  2328.         status = sub_req->status;
  2329.  
  2330.         if (status != HTTP_OK && 
  2331.             !ap_table_get(sub_req->err_headers_out, "TCN")) {
  2332.             ap_destroy_sub_req(sub_req);
  2333.             return status;
  2334.         }
  2335.         variant->sub_req = sub_req;
  2336.     }
  2337.     else {
  2338.         sub_req = variant->sub_req;
  2339.     }
  2340.  
  2341.     /* The variant selection algorithm told us to return a "Choice"
  2342.      * response. This is the normal variant response, with
  2343.      * some extra headers. First, ensure that the chosen
  2344.      * variant did or will not itself engage in transparent negotiation.
  2345.      * If not, set the appropriate headers, and fall through to
  2346.      * the normal variant handling 
  2347.      */
  2348.  
  2349.     /* This catches the error that a transparent type map selects a
  2350.      * transparent multiviews resource as the best variant.
  2351.      *
  2352.      * XXX: We do not signal an error if a transparent type map
  2353.      * selects a _non_transparent multiviews resource as the best
  2354.      * variant, because we can generate a legal negotiation response
  2355.      * in this case.  In this case, the vlist_validator of the
  2356.      * nontransparent subrequest will be lost however.  This could
  2357.      * lead to cases in which a change in the set of variants or the
  2358.      * negotiation algorithm of the nontransparent resource is never
  2359.      * propagated up to a HTTP/1.1 cache which interprets Vary.  To be
  2360.      * completely on the safe side we should return VARIANT_ALSO_VARIES
  2361.      * for this type of recursive negotiation too.
  2362.      */
  2363.     if (neg->is_transparent &&
  2364.         ap_table_get(sub_req->err_headers_out, "TCN")) {
  2365.         return VARIANT_ALSO_VARIES;
  2366.     }
  2367.  
  2368.     /* This catches the error that a transparent type map recursively
  2369.      * selects, as the best variant, another type map which itself
  2370.      * causes transparent negotiation to be done.
  2371.      *
  2372.      * XXX: Actually, we catch this error by catching all cases of
  2373.      * type map recursion.  There are some borderline recursive type
  2374.      * map arrangements which would not produce transparent
  2375.      * negotiation protocol errors or lack of cache propagation
  2376.      * problems, but such arrangements are very hard to detect at this
  2377.      * point in the control flow, so we do not bother to single them
  2378.      * out.
  2379.      *
  2380.      * Recursive type maps imply a recursive arrangement of negotiated
  2381.      * resources which is visible to outside clients, and this is not
  2382.      * supported by the transparent negotiation caching protocols, so
  2383.      * if we are to have generic support for recursive type maps, we
  2384.      * have to create some configuration setting which makes all type
  2385.      * maps non-transparent when recursion is enabled.  Also, if we
  2386.      * want recursive type map support which ensures propagation of
  2387.      * type map changes into HTTP/1.1 caches that handle Vary, we
  2388.      * would have to extend the current mechanism for generating
  2389.      * variant list validators.
  2390.      */
  2391.     if (sub_req->handler && strcmp(sub_req->handler, "type-map") == 0) {
  2392.         return VARIANT_ALSO_VARIES;
  2393.     }
  2394.  
  2395.     /* This adds an appropriate Variant-Vary header if the subrequest
  2396.      * is a multiviews resource.
  2397.      *
  2398.      * XXX: TODO: Note that this does _not_ handle any Vary header
  2399.      * returned by a CGI if sub_req is a CGI script, because we don't
  2400.      * see that Vary header yet at this point in the control flow.
  2401.      * This won't cause any cache consistency problems _unless_ the
  2402.      * CGI script also returns a Cache-Control header marking the
  2403.      * response as cachable.  This needs to be fixed, also there are
  2404.      * problems if a CGI returns an Etag header which also need to be
  2405.      * fixed.
  2406.      */
  2407.     if ((sub_vary = ap_table_get(sub_req->err_headers_out, "Vary")) != NULL) {
  2408.         ap_table_setn(r->err_headers_out, "Variant-Vary", sub_vary);
  2409.  
  2410.         /* Move the subreq Vary header into the main request to
  2411.          * prevent having two Vary headers in the response, which
  2412.          * would be legal but strange.
  2413.          */
  2414.         ap_table_setn(r->err_headers_out, "Vary", sub_vary);
  2415.         ap_table_unset(sub_req->err_headers_out, "Vary");
  2416.     }
  2417.     
  2418.     ap_table_setn(r->err_headers_out, "Content-Location",
  2419.                   ap_pstrdup(r->pool, variant->file_name));
  2420.  
  2421.     set_neg_headers(r, neg, alg_choice);         /* add Alternates and Vary */
  2422.  
  2423.     /* Still to do by caller: add Expires */
  2424.  
  2425.     return 0;
  2426. }
  2427.  
  2428. /****************************************************************
  2429.  *
  2430.  * Executive...
  2431.  */
  2432.  
  2433. static int do_negotiation(request_rec *r, negotiation_state *neg, 
  2434.                           var_rec **bestp, int prefer_scripts) 
  2435. {
  2436.     var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
  2437.     int alg_result;              /* result of variant selection algorithm */
  2438.     int res;
  2439.     int j;
  2440.     int unencoded_variants = 0;
  2441.  
  2442.     /* Decide if resource is transparently negotiable */
  2443.  
  2444.     /* GET or HEAD? (HEAD has same method number as GET) */
  2445.     if (r->method_number == M_GET) {
  2446.  
  2447.         /* maybe this should be configurable, see also the comment
  2448.          * about recursive type maps in setup_choice_response()
  2449.          */
  2450.         neg->is_transparent = 1;       
  2451.  
  2452.         /* We can't be transparent if we are a map file in the middle
  2453.          * of the request URI.
  2454.          */
  2455.         if (r->path_info && *r->path_info)
  2456.             neg->is_transparent = 0;
  2457.  
  2458.         for (j = 0; j < neg->avail_vars->nelts; ++j) {
  2459.             var_rec *variant = &avail_recs[j];
  2460.  
  2461.             /* We can't be transparent, because of internal
  2462.              * assumptions in best_match(), if there is a
  2463.              * non-neighboring variant.  We can have a non-neighboring
  2464.              * variant when processing a type map.  
  2465.              */
  2466.             if (strchr(variant->file_name, '/'))
  2467.                 neg->is_transparent = 0;
  2468.  
  2469.             if (!variant->content_encoding)
  2470.                 unencoded_variants++;
  2471.         }
  2472.         
  2473.         /* If there are less than 2 unencoded variants, we always
  2474.          * switch to server-driven negotiation, regardless of whether
  2475.          * we are contacted by a client capable of transparent
  2476.          * negotiation.  We do this because our current TCN
  2477.          * implementation does not deal well with the case of having 0
  2478.          * or 1 unencoded variants.
  2479.          */
  2480.         if (unencoded_variants < 2)
  2481.             neg->is_transparent = 0;
  2482.     }
  2483.  
  2484.     if (neg->is_transparent)  {
  2485.         parse_negotiate_header(r, neg);
  2486.     }
  2487.     else { /* configure negotiation on non-transparent resource */
  2488.         neg->may_choose = 1;
  2489.     }
  2490.  
  2491.     maybe_add_default_accepts(neg, prefer_scripts);
  2492.  
  2493.     alg_result = best_match(neg, bestp);
  2494.  
  2495.     /* alg_result is one of
  2496.      *   alg_choice: a best variant is chosen
  2497.      *   alg_list: no best variant is chosen
  2498.      */
  2499.  
  2500.     if (alg_result == alg_list) {
  2501.         /* send a list response or NOT_ACCEPTABLE error response  */
  2502.  
  2503.         neg->send_alternates = 1; /* always include Alternates header */
  2504.         set_neg_headers(r, neg, alg_result); 
  2505.         store_variant_list(r, neg);
  2506.  
  2507.         if (neg->is_transparent && neg->ua_supports_trans) {
  2508.             /* XXX todo: expires? cachability? */
  2509.             
  2510.             /* Some HTTP/1.0 clients are known to choke when they get
  2511.              * a 300 (multiple choices) response without a Location
  2512.              * header.  However the 300 code response we are are about
  2513.              * to generate will only reach 1.0 clients which support
  2514.              * transparent negotiation, and they should be OK. The
  2515.              * response should never reach older 1.0 clients, even if
  2516.              * we have CacheNegotiatedDocs enabled, because no 1.0
  2517.              * proxy cache (we know of) will cache and return 300
  2518.              * responses (they certainly won't if they conform to the
  2519.              * HTTP/1.0 specification).
  2520.              */
  2521.             return MULTIPLE_CHOICES;
  2522.         }
  2523.         
  2524.         if (!*bestp) {
  2525.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  2526.                           "no acceptable variant: %s", r->filename);
  2527.             return NOT_ACCEPTABLE;
  2528.         }
  2529.     }
  2530.  
  2531.     /* Variant selection chose a variant */
  2532.  
  2533.     /* XXX todo: merge the two cases in the if statement below */
  2534.     if (neg->is_transparent) {
  2535.  
  2536.         if ((res = setup_choice_response(r, neg, *bestp)) != 0) {
  2537.             return res; /* return if error */
  2538.         }
  2539.     }
  2540.     else {
  2541.         set_neg_headers(r, neg, alg_result);
  2542.     }
  2543.  
  2544.     /* Make sure caching works - Vary should handle HTTP/1.1, but for
  2545.      * HTTP/1.0, we can't allow caching at all.
  2546.      */
  2547.  
  2548.     /* XXX: Note that we only set r->no_cache to 1, which causes
  2549.      * Expires: <now> to be added, when responding to a HTTP/1.0
  2550.      * client.  If we return the response to a 1.1 client, we do not
  2551.      * add Expires <now>, because doing so would degrade 1.1 cache
  2552.      * performance by preventing re-use of the response without prior
  2553.      * revalidation.  On the other hand, if the 1.1 client is a proxy
  2554.      * which was itself contacted by a 1.0 client, or a proxy cache
  2555.      * which can be contacted later by 1.0 clients, then we currently
  2556.      * rely on this 1.1 proxy to add the Expires: <now> when it
  2557.      * forwards the response.
  2558.      *
  2559.      * XXX: TODO: Find out if the 1.1 spec requires proxies and
  2560.      * tunnels to add Expires: <now> when forwarding the response to
  2561.      * 1.0 clients.  I (kh) recall it is rather vague on this point.
  2562.      * Testing actual 1.1 proxy implementations would also be nice. If
  2563.      * Expires: <now> is not added by proxies then we need to always
  2564.      * include Expires: <now> ourselves to ensure correct caching, but
  2565.      * this would degrade HTTP/1.1 cache efficiency unless we also add
  2566.      * Cache-Control: max-age=N, which we currently don't.
  2567.      *
  2568.      * Roy: No, we are not going to screw over HTTP future just to
  2569.      *      ensure that people who can't be bothered to upgrade their
  2570.      *      clients will always receive perfect server-side negotiation.
  2571.      *      Hell, those clients are sending bogus accept headers anyway.
  2572.      *
  2573.      *      Manual setting of cache-control/expires always overrides this
  2574.      *      automated kluge, on purpose.
  2575.      */
  2576.     
  2577.     if ((!do_cache_negotiated_docs(r->server)
  2578.          && (r->proto_num < HTTP_VERSION(1,1)))        
  2579.          && neg->count_multiviews_variants != 1) {
  2580.         r->no_cache = 1;
  2581.     }
  2582.  
  2583.     return OK;
  2584. }
  2585.  
  2586. static int handle_map_file(request_rec *r)
  2587. {
  2588.     negotiation_state *neg = parse_accept_headers(r);
  2589.     var_rec *best;
  2590.     int res;
  2591.  
  2592.     char *udir;
  2593.  
  2594.     if ((res = read_type_map(neg, r))) {
  2595.         return res;
  2596.     }
  2597.  
  2598.     res = do_negotiation(r, neg, &best, 0);
  2599.     if (res != 0) return res;
  2600.  
  2601.     if (r->path_info && *r->path_info) {
  2602.         r->uri[ap_find_path_info(r->uri, r->path_info)] = '\0';
  2603.     }
  2604.     udir = ap_make_dirstr_parent(r->pool, r->uri);
  2605.     udir = ap_escape_uri(r->pool, udir);
  2606.     ap_internal_redirect(ap_pstrcat(r->pool, udir, best->file_name,
  2607.                                     r->path_info, NULL), r);
  2608.     return OK;
  2609. }
  2610.  
  2611. static int handle_multi(request_rec *r)
  2612. {
  2613.     negotiation_state *neg;
  2614.     var_rec *best, *avail_recs;
  2615.     request_rec *sub_req;
  2616.     int res;
  2617.     int j;
  2618.  
  2619.     if (r->finfo.st_mode != 0 || !(ap_allow_options(r) & OPT_MULTI)) {
  2620.         return DECLINED;
  2621.     }
  2622.  
  2623.     neg = parse_accept_headers(r);
  2624.  
  2625.     if ((res = read_types_multi(neg))) {
  2626.       return_from_multi:
  2627.         /* free all allocated memory from subrequests */
  2628.         avail_recs = (var_rec *) neg->avail_vars->elts;
  2629.         for (j = 0; j < neg->avail_vars->nelts; ++j) {
  2630.             var_rec *variant = &avail_recs[j];
  2631.             if (variant->sub_req) {
  2632.                 ap_destroy_sub_req(variant->sub_req);
  2633.             }
  2634.         }
  2635.         return res;
  2636.     }
  2637.     if (neg->avail_vars->nelts == 0) {
  2638.         return DECLINED;
  2639.     }
  2640.  
  2641.     res = do_negotiation(r, neg, &best,
  2642.                          (r->method_number != M_GET) || r->args ||
  2643.                          (r->path_info && *r->path_info));
  2644.     if (res != 0)
  2645.         goto return_from_multi;
  2646.  
  2647.     if (!(sub_req = best->sub_req)) {
  2648.         /* We got this out of a map file, so we don't actually have
  2649.          * a sub_req structure yet.  Get one now.
  2650.          */
  2651.  
  2652.         sub_req = ap_sub_req_lookup_file(best->file_name, r);
  2653.         if (sub_req->status != HTTP_OK) {
  2654.             res = sub_req->status;
  2655.             ap_destroy_sub_req(sub_req);
  2656.             goto return_from_multi;
  2657.         }
  2658.     }
  2659.  
  2660.     /* BLECH --- don't multi-resolve non-ordinary files */
  2661.  
  2662.     if (!S_ISREG(sub_req->finfo.st_mode)) {
  2663.         res = NOT_FOUND;
  2664.         goto return_from_multi;
  2665.     }
  2666.  
  2667.     /* Otherwise, use it. */
  2668.  
  2669.     /* now do a "fast redirect" ... promote the sub_req into the main req */
  2670.     /* We need to tell POOL_DEBUG that we're guaranteeing that sub_req->pool
  2671.      * will exist as long as r->pool.  Otherwise we run into troubles because
  2672.      * some values in this request will be allocated in r->pool, and others in
  2673.      * sub_req->pool.
  2674.      */
  2675.     ap_pool_join(r->pool, sub_req->pool);
  2676.     r->mtime = 0; /* reset etag info for subrequest */
  2677.     r->filename = sub_req->filename;
  2678.     r->handler = sub_req->handler;
  2679.     r->content_type = sub_req->content_type;
  2680.     r->content_encoding = sub_req->content_encoding;
  2681.     r->content_languages = sub_req->content_languages;
  2682.     r->content_language = sub_req->content_language;
  2683.     r->finfo = sub_req->finfo;
  2684.     r->per_dir_config = sub_req->per_dir_config;
  2685.     /* copy output headers from subrequest, but leave negotiation headers */
  2686.     r->notes = ap_overlay_tables(r->pool, sub_req->notes, r->notes);
  2687.     r->headers_out = ap_overlay_tables(r->pool, sub_req->headers_out,
  2688.                                     r->headers_out);
  2689.     r->err_headers_out = ap_overlay_tables(r->pool, sub_req->err_headers_out,
  2690.                                         r->err_headers_out);
  2691.     r->subprocess_env = ap_overlay_tables(r->pool, sub_req->subprocess_env,
  2692.                                        r->subprocess_env);
  2693.     avail_recs = (var_rec *) neg->avail_vars->elts;
  2694.     for (j = 0; j < neg->avail_vars->nelts; ++j) {
  2695.         var_rec *variant = &avail_recs[j];
  2696.         if (variant != best && variant->sub_req) {
  2697.             ap_destroy_sub_req(variant->sub_req);
  2698.         }
  2699.     }
  2700.     return OK;
  2701. }
  2702.  
  2703. /********************************************************************** 
  2704.  * There is a problem with content-encoding, as some clients send and
  2705.  * expect an x- token (e.g. x-gzip) while others expect the plain token
  2706.  * (i.e. gzip). To try and deal with this as best as possible we do
  2707.  * the following: if the client sent an Accept-Encoding header and it
  2708.  * contains a plain token corresponding to the content encoding of the
  2709.  * response, then set content encoding using the plain token. Else if
  2710.  * the A-E header contains the x- token use the x- token in the C-E
  2711.  * header. Else don't do anything.
  2712.  *
  2713.  * Note that if no A-E header was sent, or it does not contain a token
  2714.  * compatible with the final content encoding, then the token in the
  2715.  * C-E header will be whatever was specified in the AddEncoding
  2716.  * directive.
  2717.  */
  2718. static int fix_encoding(request_rec *r)
  2719. {
  2720.     const char *enc = r->content_encoding;
  2721.     char *x_enc = NULL;
  2722.     array_header *accept_encodings;
  2723.     accept_rec *accept_recs;
  2724.     int i;
  2725.  
  2726.     if (!enc || !*enc) {
  2727.         return DECLINED;
  2728.     }
  2729.  
  2730.     if (enc[0] == 'x' && enc[1] == '-') {
  2731.         enc += 2;
  2732.     }
  2733.  
  2734.     if ((accept_encodings = do_header_line(r->pool,
  2735.              ap_table_get(r->headers_in, "Accept-Encoding"))) == NULL) {
  2736.         return DECLINED;
  2737.     }
  2738.  
  2739.     accept_recs = (accept_rec *) accept_encodings->elts;
  2740.  
  2741.     for (i = 0; i < accept_encodings->nelts; ++i) {
  2742.         char *name = accept_recs[i].name;
  2743.  
  2744.         if (!strcmp(name, enc)) {
  2745.             r->content_encoding = name;
  2746.             return OK;
  2747.         }
  2748.  
  2749.         if (name[0] == 'x' && name[1] == '-' && !strcmp(name+2, enc)) {
  2750.             x_enc = name;
  2751.         }
  2752.     }
  2753.  
  2754.     if (x_enc) {
  2755.         r->content_encoding = x_enc;
  2756.         return OK;
  2757.     }
  2758.  
  2759.     return DECLINED;
  2760. }
  2761.  
  2762. static const handler_rec negotiation_handlers[] =
  2763. {
  2764.     {MAP_FILE_MAGIC_TYPE, handle_map_file},
  2765.     {"type-map", handle_map_file},
  2766.     {NULL}
  2767. };
  2768.  
  2769. module MODULE_VAR_EXPORT negotiation_module =
  2770. {
  2771.     STANDARD_MODULE_STUFF,
  2772.     NULL,                       /* initializer */
  2773.     create_neg_dir_config,      /* dir config creator */
  2774.     merge_neg_dir_configs,      /* dir merger --- default is to override */
  2775.     NULL,                       /* server config */
  2776.     NULL,                       /* merge server config */
  2777.     negotiation_cmds,           /* command table */
  2778.     negotiation_handlers,       /* handlers */
  2779.     NULL,                       /* filename translation */
  2780.     NULL,                       /* check_user_id */
  2781.     NULL,                       /* check auth */
  2782.     NULL,                       /* check access */
  2783.     handle_multi,               /* type_checker */
  2784.     fix_encoding,               /* fixups */
  2785.     NULL,                       /* logger */
  2786.     NULL,                       /* header parser */
  2787.     NULL,                       /* child_init */
  2788.     NULL,                       /* child_exit */
  2789.     NULL                        /* post read-request */
  2790. };
  2791.