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