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