1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
60 * mod_negotiation.c: keeps track of MIME types the client is willing to
61 * accept, and contains code to handle type arbitration.
67 #include "apr_strings.h"
68 #include "apr_file_io.h"
71 #include <stdio.h> /* for EOF */
74 #include "ap_config.h"
76 #include "http_config.h"
77 #include "http_request.h"
78 #include "http_protocol.h"
79 #include "http_core.h"
81 #include "util_script.h"
89 #define MAP_FILE_MAGIC_TYPE "application/x-type-map"
91 /* Commands --- configuring document caching on a per (virtual?)
96 apr_array_header_t *language_priority;
99 module AP_MODULE_DECLARE_DATA negotiation_module;
101 static void *create_neg_dir_config(apr_pool_t *p, char *dummy)
103 neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config));
105 new->language_priority = apr_make_array(p, 4, sizeof(char *));
109 static void *merge_neg_dir_configs(apr_pool_t *p, void *basev, void *addv)
111 neg_dir_config *base = (neg_dir_config *) basev;
112 neg_dir_config *add = (neg_dir_config *) addv;
113 neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config));
115 /* give priority to the config in the subdirectory */
116 new->language_priority = apr_append_arrays(p, add->language_priority,
117 base->language_priority);
121 static const char *set_language_priority(cmd_parms *cmd, void *n,
124 apr_array_header_t *arr = ((neg_dir_config *) n)->language_priority;
125 const char **langp = (const char **) apr_push_array(arr);
131 static const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy,
134 void *server_conf = cmd->server->module_config;
136 ap_set_module_config(server_conf, &negotiation_module,
137 (arg ? "Cache" : NULL));
141 static int do_cache_negotiated_docs(server_rec *s)
143 return (ap_get_module_config(s->module_config, &negotiation_module) != NULL);
146 static const command_rec negotiation_cmds[] =
148 AP_INIT_FLAG("CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF,
149 "Either 'on' or 'off' (default)"),
150 AP_INIT_ITERATE("LanguagePriority", set_language_priority, NULL, OR_FILEINFO,
151 "space-delimited list of MIME language abbreviations"),
156 * Record of available info on a media type specified by the client
157 * (we also use 'em for encodings and languages)
160 typedef struct accept_rec {
161 char *name; /* MUST be lowercase */
164 char *charset; /* for content-type only */
168 * Record of available info on a particular variant
170 * Note that a few of these fields are updated by the actual negotiation
173 * level_matched --- initialized to zero. Set to the value of level
174 * if the client actually accepts this media type at that
175 * level (and *not* if it got in on a wildcard). See level_cmp
177 * mime_stars -- initialized to zero. Set to the number of stars
178 * present in the best matching Accept header element.
179 * 1 for star/star, 2 for type/star and 3 for
182 * definite -- initialized to 1. Set to 0 if there is a match which
183 * makes the variant non-definite according to the rules
187 typedef struct var_rec {
188 request_rec *sub_req; /* May be NULL (is, for map files) */
189 char *mime_type; /* MUST be lowercase */
191 const char *content_encoding;
192 apr_array_header_t *content_languages; /* list of languages for this variant */
193 char *content_charset;
196 /* The next five items give the quality values for the dimensions
197 * of negotiation for this variant. They are obtained from the
198 * appropriate header lines, except for source_quality, which
199 * is obtained from the variant itself (the 'qs' parameter value
200 * from the variant's mime-type). Apart from source_quality,
201 * these values are set when we find the quality for each variant
202 * (see best_match()). source_quality is set from the 'qs' parameter
203 * of the variant description or mime type: see set_mime_fields().
205 float lang_quality; /* quality of this variant's language */
206 float encoding_quality; /* ditto encoding */
207 float charset_quality; /* ditto charset */
208 float mime_type_quality; /* ditto media type */
209 float source_quality; /* source quality for this variant */
211 /* Now some special values */
212 float level; /* Auxiliary to content-type... */
213 float bytes; /* content length, if known */
214 int lang_index; /* pre HTTP/1.1 language priority stuff */
215 int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
217 /* Above are all written-once properties of the variant. The
218 * three fields below are changed during negotiation:
226 /* Something to carry around the state of negotiation (and to keep
227 * all of this thread-safe)...
234 int accept_q; /* 1 if an Accept item has a q= param */
235 float default_lang_quality; /* fiddle lang q for variants with no lang */
237 /* the array pointers below are NULL if the corresponding accept
238 * headers are not present
240 apr_array_header_t *accepts; /* accept_recs */
241 apr_array_header_t *accept_encodings; /* accept_recs */
242 apr_array_header_t *accept_charsets; /* accept_recs */
243 apr_array_header_t *accept_langs; /* accept_recs */
245 apr_array_header_t *avail_vars; /* available variants */
247 int count_multiviews_variants; /* number of variants found on disk */
249 int is_transparent; /* 1 if this resource is trans. negotiable */
251 int dont_fiddle_headers; /* 1 if we may not fiddle with accept hdrs */
252 int ua_supports_trans; /* 1 if ua supports trans negotiation */
253 int send_alternates; /* 1 if we want to send an Alternates header */
254 int may_choose; /* 1 if we may choose a variant for the client */
255 int use_rvsa; /* 1 if we must use RVSA/1.0 negotiation algo */
258 /* A few functions to manipulate var_recs.
259 * Cleaning out the fields...
262 static void clean_var_rec(var_rec *mime_info)
264 mime_info->sub_req = NULL;
265 mime_info->mime_type = "";
266 mime_info->file_name = "";
267 mime_info->content_encoding = NULL;
268 mime_info->content_languages = NULL;
269 mime_info->content_charset = "";
270 mime_info->description = "";
272 mime_info->is_pseudo_html = 0;
273 mime_info->level = 0.0f;
274 mime_info->level_matched = 0.0f;
275 mime_info->bytes = 0.0f;
276 mime_info->lang_index = -1;
277 mime_info->mime_stars = 0;
278 mime_info->definite = 1;
280 mime_info->charset_quality = 1.0f;
281 mime_info->encoding_quality = 1.0f;
282 mime_info->lang_quality = 1.0f;
283 mime_info->mime_type_quality = 1.0f;
284 mime_info->source_quality = 0.0f;
287 /* Initializing the relevant fields of a variant record from the
288 * accept_info read out of its content-type, one way or another.
291 static void set_mime_fields(var_rec *var, accept_rec *mime_info)
293 var->mime_type = mime_info->name;
294 var->source_quality = mime_info->quality;
295 var->level = mime_info->level;
296 var->content_charset = mime_info->charset;
298 var->is_pseudo_html = (!strcmp(var->mime_type, "text/html")
299 || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE)
300 || !strcmp(var->mime_type, INCLUDES_MAGIC_TYPE3));
303 /* Create a variant list validator in r using info from vlistr. */
305 static void set_vlist_validator(request_rec *r, request_rec *vlistr)
307 /* Calculating the variant list validator is similar to
308 * calculating an etag for the source of the variant list
309 * information, so we use ap_make_etag(). Note that this
310 * validator can be 'weak' in extreme case.
312 ap_update_mtime(vlistr, vlistr->finfo.mtime);
313 r->vlist_validator = ap_make_etag(vlistr, 0);
315 /* ap_set_etag will later take r->vlist_validator into account
316 * when creating the etag header
321 /*****************************************************************
323 * Parsing (lists of) media types and their parameters, as seen in
324 * HTTPD header lines and elsewhere.
328 * Get a single mime type entry --- one media type and parameters;
329 * enter the values we recognize into the argument accept_rec
332 static const char *get_entry(apr_pool_t *p, accept_rec *result,
333 const char *accept_line)
335 result->quality = 1.0f;
336 result->level = 0.0f;
337 result->charset = "";
340 * Note that this handles what I gather is the "old format",
342 * Accept: text/html text/plain moo/zot
344 * without any compatibility kludges --- if the token after the
345 * MIME type begins with a semicolon, we know we're looking at parms,
346 * otherwise, we know we aren't. (So why all the pissing and moaning
347 * in the CERN server code? I must be missing something).
350 result->name = ap_get_token(p, &accept_line, 0);
351 ap_str_tolower(result->name); /* You want case insensitive,
352 * you'll *get* case insensitive.
355 /* KLUDGE!!! Default HTML to level 2.0 unless the browser
356 * *explicitly* says something else.
359 if (!strcmp(result->name, "text/html") && (result->level == 0.0)) {
360 result->level = 2.0f;
362 else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE)) {
363 result->level = 2.0f;
365 else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) {
366 result->level = 3.0f;
369 while (*accept_line == ';') {
377 parm = ap_get_token(p, &accept_line, 1);
379 /* Look for 'var = value' --- and make sure the var is in lcase. */
381 for (cp = parm; (*cp && !apr_isspace(*cp) && *cp != '='); ++cp) {
382 *cp = apr_tolower(*cp);
386 continue; /* No '='; just ignore it. */
389 *cp++ = '\0'; /* Delimit var */
390 while (*cp && (apr_isspace(*cp) || *cp == '=')) {
397 (*end && *end != '\n' && *end != '\r' && *end != '\"');
401 for (end = cp; (*end && !apr_isspace(*end)); end++);
404 *end = '\0'; /* strip ending quote or return */
409 && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) {
410 result->quality = atof(cp);
412 else if (parm[0] == 'l' && !strcmp(&parm[1], "evel")) {
413 result->level = atof(cp);
415 else if (!strcmp(parm, "charset")) {
416 result->charset = cp;
420 if (*accept_line == ',') {
427 /*****************************************************************
429 * Dealing with header lines ...
431 * Accept, Accept-Charset, Accept-Language and Accept-Encoding
432 * are handled by do_header_line() - they all have the same
433 * basic structure of a list of items of the format
434 * name; q=N; charset=TEXT
436 * where charset is only valid in Accept.
439 static apr_array_header_t *do_header_line(apr_pool_t *p, const char *accept_line)
441 apr_array_header_t *accept_recs;
447 accept_recs = apr_make_array(p, 40, sizeof(accept_rec));
449 while (*accept_line) {
450 accept_rec *new = (accept_rec *) apr_push_array(accept_recs);
451 accept_line = get_entry(p, new, accept_line);
457 /* Given the text of the Content-Languages: line from the var map file,
458 * return an array containing the languages of this variant
461 static apr_array_header_t *do_languages_line(apr_pool_t *p, const char **lang_line)
463 apr_array_header_t *lang_recs = apr_make_array(p, 2, sizeof(char *));
469 while (**lang_line) {
470 char **new = (char **) apr_push_array(lang_recs);
471 *new = ap_get_token(p, lang_line, 0);
472 ap_str_tolower(*new);
473 if (**lang_line == ',' || **lang_line == ';') {
481 /*****************************************************************
483 * Handling header lines from clients...
486 static negotiation_state *parse_accept_headers(request_rec *r)
488 negotiation_state *new =
489 (negotiation_state *) apr_pcalloc(r->pool, sizeof(negotiation_state));
491 apr_table_t *hdrs = r->headers_in;
496 new->dir_name = ap_make_dirstr_parent(r->pool, r->filename);
498 new->accepts = do_header_line(r->pool, apr_table_get(hdrs, "Accept"));
500 /* calculate new->accept_q value */
502 elts = (accept_rec *) new->accepts->elts;
504 for (i = 0; i < new->accepts->nelts; ++i) {
505 if (elts[i].quality < 1.0) {
511 new->accept_encodings =
512 do_header_line(r->pool, apr_table_get(hdrs, "Accept-Encoding"));
514 do_header_line(r->pool, apr_table_get(hdrs, "Accept-Language"));
515 new->accept_charsets =
516 do_header_line(r->pool, apr_table_get(hdrs, "Accept-Charset"));
518 new->avail_vars = apr_make_array(r->pool, 40, sizeof(var_rec));
524 static void parse_negotiate_header(request_rec *r, negotiation_state *neg)
526 const char *negotiate = apr_table_get(r->headers_in, "Negotiate");
529 /* First, default to no TCN, no Alternates, and the original Apache
530 * negotiation algorithm with fiddles for broken browser configs.
532 * To save network bandwidth, we do not configure to send an
533 * Alternates header to the user agent by default. User
534 * agents that want an Alternates header for agent-driven
535 * negotiation will have to request it by sending an
536 * appropriate Negotiate header.
538 neg->ua_supports_trans = 0;
539 neg->send_alternates = 0;
542 neg->dont_fiddle_headers = 0;
547 if (strcmp(negotiate, "trans") == 0) {
548 /* Lynx 2.7 and 2.8 send 'negotiate: trans' even though they
549 * do not support transparent content negotiation, so for Lynx we
550 * ignore the negotiate header when its contents are exactly "trans".
551 * If future versions of Lynx ever need to say 'negotiate: trans',
552 * they can send the equivalent 'negotiate: trans, trans' instead
553 * to avoid triggering the workaround below.
555 const char *ua = apr_table_get(r->headers_in, "User-Agent");
557 if (ua && (strncmp(ua, "Lynx", 4) == 0))
561 neg->may_choose = 0; /* An empty Negotiate would require 300 response */
563 while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) {
565 if (strcmp(tok, "trans") == 0 ||
566 strcmp(tok, "vlist") == 0 ||
567 strcmp(tok, "guess-small") == 0 ||
568 apr_isdigit(tok[0]) ||
569 strcmp(tok, "*") == 0) {
571 /* The user agent supports transparent negotiation */
572 neg->ua_supports_trans = 1;
574 /* Send-alternates could be configurable, but note
575 * that it must be 1 if we have 'vlist' in the
578 neg->send_alternates = 1;
580 if (strcmp(tok, "1.0") == 0) {
581 /* we may use the RVSA/1.0 algorithm, configure for it */
584 neg->dont_fiddle_headers = 1;
586 else if (tok[0] == '*') {
587 /* we may use any variant selection algorithm, configure
588 * to use the Apache algorithm
592 /* We disable header fiddles on the assumption that a
593 * client sending Negotiate knows how to send correct
594 * headers which don't need fiddling.
596 neg->dont_fiddle_headers = 1;
602 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
603 "dont_fiddle_headers=%d use_rvsa=%d ua_supports_trans=%d "
604 "send_alternates=%d, may_choose=%d",
605 neg->dont_fiddle_headers, neg->use_rvsa,
606 neg->ua_supports_trans, neg->send_alternates, neg->may_choose);
611 /* Sometimes clients will give us no Accept info at all; this routine sets
612 * up the standard default for that case, and also arranges for us to be
613 * willing to run a CGI script if we find one. (In fact, we set up to
614 * dramatically prefer CGI scripts in cases where that's appropriate,
615 * e.g., POST or when URI includes query args or extra path info).
617 static void maybe_add_default_accepts(negotiation_state *neg,
620 accept_rec *new_accept;
623 neg->accepts = apr_make_array(neg->pool, 4, sizeof(accept_rec));
625 new_accept = (accept_rec *) apr_push_array(neg->accepts);
627 new_accept->name = "*/*";
628 new_accept->quality = 1.0f;
629 new_accept->level = 0.0f;
632 new_accept = (accept_rec *) apr_push_array(neg->accepts);
634 new_accept->name = CGI_MAGIC_TYPE;
636 new_accept->quality = 0;
639 new_accept->quality = prefer_scripts ? 2.0f : 0.001f;
641 new_accept->level = 0.0f;
644 /*****************************************************************
646 * Parsing type-map files, in Roy's meta/http format augmented with
650 /* Reading RFC822-style header lines, ignoring #-comments and
651 * handling continuations.
655 header_eof, header_seen, header_sep
658 static enum header_state get_header_line(char *buffer, int len, apr_file_t *map)
660 char *buf_end = buffer + len;
664 /* Get a noncommented line */
667 if (apr_fgets(buffer, MAX_STRING_LEN, map) != APR_SUCCESS) {
670 } while (buffer[0] == '#');
672 /* If blank, just return it --- this ends information on this variant */
674 for (cp = buffer; (*cp && apr_isspace(*cp)); ++cp) {
682 /* If non-blank, go looking for header lines, but note that we still
683 * have to treat comments specially...
688 while (apr_getc(&c, map) != APR_EOF) {
691 while (apr_getc(&c, map) != EOF && c != '\n') {
695 else if (apr_isspace(c)) {
696 /* Leading whitespace. POSSIBLE continuation line
697 * Also, possibly blank --- if so, we ungetc() the final newline
698 * so that we will pick up the blank line the next time 'round.
701 while (c != '\n' && apr_isspace(c)) {
702 if(apr_getc(&c, map) != APR_SUCCESS)
709 return header_seen; /* Blank line */
714 while (cp < buf_end - 2 && (apr_getc(&c, map)) != EOF && c != '\n') {
723 /* Line beginning with something other than whitespace */
733 /* Stripping out RFC822 comments */
735 static void strip_paren_comments(char *hdr)
737 /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */
738 /* Nope, it isn't correct. Fails to handle backslash escape as well. */
742 hdr = strchr(hdr, '"');
748 else if (*hdr == '(') {
749 while (*hdr && *hdr != ')') {
763 /* Getting to a header body from the header */
765 static char *lcase_header_name_return_body(char *header, request_rec *r)
769 for ( ; *cp && *cp != ':' ; ++cp) {
770 *cp = apr_tolower(*cp);
774 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
775 "Syntax error in type map --- no ':': %s", r->filename);
781 } while (*cp && apr_isspace(*cp));
784 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
785 "Syntax error in type map --- no header body: %s",
793 static int read_type_map(negotiation_state *neg, request_rec *rr)
795 request_rec *r = neg->r;
796 apr_file_t *map = NULL;
798 char buffer[MAX_STRING_LEN];
799 enum header_state hstate;
800 struct var_rec mime_info;
803 /* We are not using multiviews */
804 neg->count_multiviews_variants = 0;
806 if ((status = apr_open(&map, rr->filename, APR_READ,
807 APR_OS_DEFAULT, neg->pool)) != APR_SUCCESS) {
808 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
809 "cannot access type map file: %s", rr->filename);
810 return HTTP_FORBIDDEN;
813 clean_var_rec(&mime_info);
817 hstate = get_header_line(buffer, MAX_STRING_LEN, map);
819 if (hstate == header_seen) {
820 char *body1 = lcase_header_name_return_body(buffer, neg->r);
824 return HTTP_INTERNAL_SERVER_ERROR;
827 strip_paren_comments(body1);
830 if (!strncmp(buffer, "uri:", 4)) {
831 mime_info.file_name = ap_get_token(neg->pool, &body, 0);
833 else if (!strncmp(buffer, "content-type:", 13)) {
834 struct accept_rec accept_info;
836 get_entry(neg->pool, &accept_info, body);
837 set_mime_fields(&mime_info, &accept_info);
840 else if (!strncmp(buffer, "content-length:", 15)) {
841 mime_info.bytes = atof(body);
844 else if (!strncmp(buffer, "content-language:", 17)) {
845 mime_info.content_languages = do_languages_line(neg->pool,
849 else if (!strncmp(buffer, "content-encoding:", 17)) {
850 mime_info.content_encoding = ap_get_token(neg->pool, &body, 0);
853 else if (!strncmp(buffer, "description:", 12)) {
854 char *desc = apr_pstrdup(neg->pool, body);
857 for (cp = desc; *cp; ++cp) {
858 if (*cp=='\n') *cp=' ';
860 if (cp>desc) *(cp-1)=0;
861 mime_info.description = desc;
865 if (*mime_info.file_name && has_content) {
866 void *new_var = apr_push_array(neg->avail_vars);
868 memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
871 clean_var_rec(&mime_info);
874 } while (hstate != header_eof);
878 set_vlist_validator(r, rr);
884 /* Sort function used by read_types_multi. */
885 static int variantsortf(var_rec *a, var_rec *b) {
887 /* First key is the source quality, sort in descending order. */
889 /* XXX: note that we currently implement no method of setting the
890 * source quality for multiviews variants, so we are always comparing
893 if (a->source_quality < b->source_quality)
895 if (a->source_quality > b->source_quality)
898 /* Second key is the variant name */
899 return strcmp(a->file_name, b->file_name);
902 /*****************************************************************
904 * Same as read_type_map, except we use a filtered directory listing
908 static int read_types_multi(negotiation_state *neg)
910 request_rec *r = neg->r;
916 struct var_rec mime_info;
917 struct accept_rec accept_info;
920 clean_var_rec(&mime_info);
922 if (!(filp = strrchr(r->filename, '/'))) {
923 return DECLINED; /* Weird... */
926 if (strncmp(r->filename, "proxy:", 6) == 0) {
931 prefix_len = strlen(filp);
933 if ((status = apr_dir_open(&dirp, neg->dir_name, neg->pool)) != APR_SUCCESS) {
934 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
935 "cannot read directory for multi: %s", neg->dir_name);
936 return HTTP_FORBIDDEN;
939 while (apr_readdir(dirp) == APR_SUCCESS) {
940 request_rec *sub_req;
943 apr_get_dir_filename(&d_name, dirp);
944 /* Do we have a match? */
946 if (strncmp(d_name, filp, prefix_len)) {
949 if (d_name[prefix_len] != '.') {
953 /* Yep. See if it's something which we have access to, and
954 * which has a known type and encoding (as opposed to something
955 * which we'll be slapping default_type on later).
958 sub_req = ap_sub_req_lookup_file(d_name, r, NULL);
960 /* If it has a handler, we'll pretend it's a CGI script,
961 * since that's a good indication of the sort of thing it
964 if (sub_req->handler && !sub_req->content_type) {
965 sub_req->content_type = CGI_MAGIC_TYPE;
968 if (sub_req->status != HTTP_OK || !sub_req->content_type) {
969 ap_destroy_sub_req(sub_req);
973 /* If it's a map file, we use that instead of the map
977 if (((sub_req->content_type) &&
978 !strcmp(sub_req->content_type, MAP_FILE_MAGIC_TYPE)) ||
979 ((sub_req->handler) &&
980 !strcmp(sub_req->handler, "type-map"))) {
983 neg->avail_vars->nelts = 0;
984 if (sub_req->status != HTTP_OK) {
985 return sub_req->status;
987 return read_type_map(neg, sub_req);
990 /* Have reasonable variant --- gather notes. */
992 mime_info.sub_req = sub_req;
993 mime_info.file_name = apr_pstrdup(neg->pool, d_name);
994 if (sub_req->content_encoding) {
995 mime_info.content_encoding = sub_req->content_encoding;
997 if (sub_req->content_languages) {
998 mime_info.content_languages = sub_req->content_languages;
1001 get_entry(neg->pool, &accept_info, sub_req->content_type);
1002 set_mime_fields(&mime_info, &accept_info);
1004 new_var = apr_push_array(neg->avail_vars);
1005 memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
1007 neg->count_multiviews_variants++;
1009 clean_var_rec(&mime_info);
1014 set_vlist_validator(r, r);
1016 /* Sort the variants into a canonical order. The negotiation
1017 * result sometimes depends on the order of the variants. By
1018 * sorting the variants into a canonical order, rather than using
1019 * the order in which readdir() happens to return them, we ensure
1020 * that the negotiation result will be consistent over filesystem
1021 * backup/restores and over all mirror sites.
1024 qsort((void *) neg->avail_vars->elts, neg->avail_vars->nelts,
1025 sizeof(var_rec), (int (*)(const void *, const void *)) variantsortf);
1031 /*****************************************************************
1032 * And now for the code you've been waiting for... actually
1033 * finding a match to the client's requirements.
1036 /* Matching MIME types ... the star/star and foo/star commenting conventions
1037 * are implemented here. (You know what I mean by star/star, but just
1038 * try mentioning those three characters in a C comment). Using strcmp()
1039 * is legit, because everything has already been smashed to lowercase.
1041 * Note also that if we get an exact match on the media type, we update
1042 * level_matched for use in level_cmp below...
1044 * We also give a value for mime_stars, which is used later. It should
1045 * be 1 for star/star, 2 for type/star and 3 for type/subtype.
1048 static int mime_match(accept_rec *accept_r, var_rec *avail)
1050 char *accept_type = accept_r->name;
1051 char *avail_type = avail->mime_type;
1052 int len = strlen(accept_type);
1054 if (accept_type[0] == '*') { /* Anything matches star/star */
1055 if (avail->mime_stars < 1) {
1056 avail->mime_stars = 1;
1060 else if ((accept_type[len - 1] == '*') &&
1061 !strncmp(accept_type, avail_type, len - 2)) {
1062 if (avail->mime_stars < 2) {
1063 avail->mime_stars = 2;
1067 else if (!strcmp(accept_type, avail_type)
1068 || (!strcmp(accept_type, "text/html")
1069 && (!strcmp(avail_type, INCLUDES_MAGIC_TYPE)
1070 || !strcmp(avail_type, INCLUDES_MAGIC_TYPE3)))) {
1071 if (accept_r->level >= avail->level) {
1072 avail->level_matched = avail->level;
1073 avail->mime_stars = 3;
1081 /* This code implements a piece of the tie-breaking algorithm between
1082 * variants of equal quality. This piece is the treatment of variants
1083 * of the same base media type, but different levels. What we want to
1084 * return is the variant at the highest level that the client explicitly
1085 * claimed to accept.
1087 * If all the variants available are at a higher level than that, or if
1088 * the client didn't say anything specific about this media type at all
1089 * and these variants just got in on a wildcard, we prefer the lowest
1090 * level, on grounds that that's the one that the client is least likely
1093 * (This is all motivated by treatment of levels in HTML --- we only
1094 * want to give level 3 to browsers that explicitly ask for it; browsers
1095 * that don't, including HTTP/0.9 browsers that only get the implicit
1096 * "Accept: * / *" [space added to avoid confusing cpp --- no, that
1097 * syntax doesn't really work] should get HTML2 if available).
1099 * (Note that this code only comes into play when we are choosing among
1100 * variants of equal quality, where the draft standard gives us a fair
1101 * bit of leeway about what to do. It ain't specified by the standard;
1102 * rather, it is a choice made by this server about what to do in cases
1103 * where the standard does not specify a unique course of action).
1106 static int level_cmp(var_rec *var1, var_rec *var2)
1108 /* Levels are only comparable between matching media types */
1110 if (var1->is_pseudo_html && !var2->is_pseudo_html) {
1114 if (!var1->is_pseudo_html && strcmp(var1->mime_type, var2->mime_type)) {
1117 /* The result of the above if statements is that, if we get to
1118 * here, both variants have the same mime_type or both are
1122 /* Take highest level that matched, if either did match. */
1124 if (var1->level_matched > var2->level_matched) {
1127 if (var1->level_matched < var2->level_matched) {
1131 /* Neither matched. Take lowest level, if there's a difference. */
1133 if (var1->level < var2->level) {
1136 if (var1->level > var2->level) {
1145 /* Finding languages. The main entry point is set_language_quality()
1146 * which is called for each variant. It sets two elements in the
1148 * language_quality - the 'q' value of the 'best' matching language
1149 * from Accept-Language: header (HTTP/1.1)
1150 * lang_index - Pre HTTP/1.1 language priority, using
1151 * position of language on the Accept-Language:
1152 * header, if present, else LanguagePriority
1155 * When we do the variant checking for best variant, we use language
1156 * quality first, and if a tie, language_index next (this only applies
1157 * when _not_ using the RVSA/1.0 algorithm). If using the RVSA/1.0
1158 * algorithm, lang_index is never used.
1160 * set_language_quality() calls find_lang_index() and find_default_index()
1161 * to set lang_index.
1164 static int find_lang_index(apr_array_header_t *accept_langs, char *lang)
1169 if (!lang || !accept_langs) {
1173 accs = (accept_rec *) accept_langs->elts;
1175 for (i = 0; i < accept_langs->nelts; ++i) {
1176 if (!strncmp(lang, accs[i].name, strlen(accs[i].name))) {
1184 /* This function returns the priority of a given language
1185 * according to LanguagePriority. It is used in case of a tie
1186 * between several languages.
1189 static int find_default_index(neg_dir_config *conf, char *lang)
1191 apr_array_header_t *arr;
1200 arr = conf->language_priority;
1202 elts = (char **) arr->elts;
1204 for (i = 0; i < nelts; ++i) {
1205 if (!strcasecmp(elts[i], lang)) {
1213 /* set_default_lang_quality() sets the quality we apply to variants
1214 * which have no language assigned to them. If none of the variants
1215 * have a language, we are not negotiating on language, so all are
1216 * acceptable, and we set the default q value to 1.0. However if
1217 * some of the variants have languages, we set this default to 0.001.
1218 * The value of this default will be applied to all variants with
1219 * no explicit language -- which will have the effect of making them
1220 * acceptable, but only if no variants with an explicit language
1221 * are acceptable. The default q value set here is assigned to variants
1222 * with no language type in set_language_quality().
1224 * Note that if using the RVSA/1.0 algorithm, we don't use this
1228 static void set_default_lang_quality(negotiation_state *neg)
1230 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
1233 if (!neg->dont_fiddle_headers) {
1234 for (j = 0; j < neg->avail_vars->nelts; ++j) {
1235 var_rec *variant = &avail_recs[j];
1236 if (variant->content_languages &&
1237 variant->content_languages->nelts) {
1238 neg->default_lang_quality = 0.001f;
1244 neg->default_lang_quality = 1.0f;
1247 /* Set the language_quality value in the variant record. Also
1248 * assigns lang_index for back-compat.
1250 * To find the language_quality value, we look for the 'q' value
1251 * of the 'best' matching language on the Accept-Language
1252 * header. The 'best' match is the language on Accept-Language
1253 * header which matches the language of this variant either fully,
1254 * or as far as the prefix marker (-). If two or more languages
1255 * match, use the longest string from the Accept-Language header
1256 * (see HTTP/1.1 [14.4])
1258 * When a variant has multiple languages, we find the 'best'
1259 * match for each variant language tag as above, then select the
1260 * one with the highest q value. Because both the accept-header
1261 * and variant can have multiple languages, we now have a hairy
1262 * loop-within-a-loop here.
1264 * If the variant has no language and we have no Accept-Language
1265 * items, leave the quality at 1.0 and return.
1267 * If the variant has no language, we use the default as set by
1268 * set_default_lang_quality() (1.0 if we are not negotiating on
1269 * language, 0.001 if we are).
1271 * Following the setting of the language quality, we drop through to
1272 * set the old 'lang_index'. This is set based on either the order
1273 * of the languages on the Accept-Language header, or the
1274 * order on the LanguagePriority directive. This is only used
1275 * in the negotiation if the language qualities tie.
1278 static void set_language_quality(negotiation_state *neg, var_rec *variant)
1283 if (!variant->content_languages || !variant->content_languages->nelts) {
1284 /* This variant has no content-language, so use the default
1285 * quality factor for variants with no content-language
1286 * (previously set by set_default_lang_quality()).
1287 * Leave the factor alone (it remains at 1.0) when we may not fiddle
1290 if (!neg->dont_fiddle_headers) {
1291 variant->lang_quality = neg->default_lang_quality;
1293 if (!neg->accept_langs) {
1294 return; /* no accept-language header */
1299 /* Variant has one (or more) languages. Look for the best
1300 * match. We do this by going through each language on the
1301 * variant description looking for a match on the
1302 * Accept-Language header. The best match is the longest
1303 * matching language on the header. The final result is the
1304 * best q value from all the languages on the variant
1308 if (!neg->accept_langs) {
1309 /* no accept-language header makes the variant indefinite */
1310 variant->definite = 0;
1312 else { /* There is an accept-language with 0 or more items */
1313 accept_rec *accs = (accept_rec *) neg->accept_langs->elts;
1314 accept_rec *best = NULL, *star = NULL;
1315 accept_rec *bestthistag;
1317 float fiddle_q = 0.0f;
1318 int any_match_on_star = 0;
1320 size_t alen, longest_lang_range_len;
1322 for (j = 0; j < variant->content_languages->nelts; ++j) {
1325 longest_lang_range_len = 0;
1328 /* lang is the variant's language-tag, which is the one
1329 * we are allowed to use the prefix of in HTTP/1.1
1331 lang = ((char **) (variant->content_languages->elts))[j];
1333 /* now find the best (i.e. longest) matching
1334 * Accept-Language header language. We put the best match
1335 * for this tag in bestthistag. We cannot update the
1336 * overall best (based on q value) because the best match
1337 * for this tag is the longest language item on the accept
1338 * header, not necessarily the highest q.
1340 for (i = 0; i < neg->accept_langs->nelts; ++i) {
1341 if (!strcmp(accs[i].name, "*")) {
1347 /* Find language. We match if either the variant
1348 * language tag exactly matches the language range
1349 * from the accept header, or a prefix of the variant
1350 * language tag up to a '-' character matches the
1351 * whole of the language range in the Accept-Language
1352 * header. Note that HTTP/1.x allows any number of
1353 * '-' characters in a tag or range, currently only
1354 * tags with zero or one '-' characters are defined
1355 * for general use (see rfc1766).
1357 * We only use language range in the Accept-Language
1358 * header the best match for the variant language tag
1359 * if it is longer than the previous best match.
1362 alen = strlen(accs[i].name);
1364 if ((strlen(lang) >= alen) &&
1365 !strncmp(lang, accs[i].name, alen) &&
1366 ((lang[alen] == 0) || (lang[alen] == '-')) ) {
1368 if (alen > longest_lang_range_len) {
1369 longest_lang_range_len = alen;
1370 bestthistag = &accs[i];
1374 if (!bestthistag && !neg->dont_fiddle_headers) {
1375 /* The next bit is a fiddle. Some browsers might
1376 * be configured to send more specific language
1377 * ranges than desirable. For example, an
1378 * Accept-Language of en-US should never match
1379 * variants with languages en or en-GB. But US
1380 * English speakers might pick en-US as their
1381 * language choice. So this fiddle checks if the
1382 * language range has a prefix, and if so, it
1383 * matches variants which match that prefix with a
1384 * priority of 0.001. So a request for en-US would
1385 * match variants of types en and en-GB, but at
1386 * much lower priority than matches of en-US
1387 * directly, or of any other language listed on
1388 * the Accept-Language header. Note that this
1389 * fiddle does not handle multi-level prefixes.
1391 if ((p = strchr(accs[i].name, '-'))) {
1392 int plen = p - accs[i].name;
1394 if (!strncmp(lang, accs[i].name, plen)) {
1400 /* Finished looking at Accept-Language headers, the best
1401 * (longest) match is in bestthistag, or NULL if no match
1404 (bestthistag && bestthistag->quality > best->quality)) {
1408 /* See if the tag matches on a * in the Accept-Language
1409 * header. If so, record this fact for later use
1411 if (!bestthistag && star) {
1412 any_match_on_star = 1;
1416 /* If one of the language tags of the variant matched on *, we
1417 * need to see if its q is better than that of any non-* match
1418 * on any other tag of the variant. If so the * match takes
1419 * precedence and the overall match is not definite.
1421 if ( any_match_on_star &&
1422 ((best && star->quality > best->quality) ||
1425 variant->definite = 0;
1428 variant->lang_quality = best ? best->quality : fiddle_q;
1432 /* Now set the old lang_index field. Since this is old
1433 * stuff anyway, don't bother with handling multiple languages
1434 * per variant, just use the first one assigned to it
1437 if (variant->content_languages && variant->content_languages->nelts) {
1438 firstlang = ((char **) variant->content_languages->elts)[0];
1443 if (!neg->accept_langs) { /* Client doesn't care */
1444 idx = find_default_index((neg_dir_config *) ap_get_module_config(
1445 neg->r->per_dir_config, &negotiation_module),
1448 else { /* Client has Accept-Language */
1449 idx = find_lang_index(neg->accept_langs, firstlang);
1451 variant->lang_index = idx;
1456 /* Determining the content length --- if the map didn't tell us,
1457 * we have to do a stat() and remember for next time.
1459 * Grump. For Apache, even the first stat here may well be
1460 * redundant (for multiviews) with a stat() done by the sub_req
1461 * machinery. At some point, that ought to be fixed.
1464 static float find_content_length(negotiation_state *neg, var_rec *variant)
1468 if (variant->bytes == 0) {
1469 char *fullname = ap_make_full_path(neg->pool, neg->dir_name,
1470 variant->file_name);
1472 if (apr_stat(&statb, fullname, neg->pool) == APR_SUCCESS) {
1473 /* Note, precision may be lost */
1474 variant->bytes = (float) statb.size;
1478 return variant->bytes;
1481 /* For a given variant, find the best matching Accept: header
1482 * and assign the Accept: header's quality value to the
1483 * mime_type_quality field of the variant, for later use in
1484 * determining the best matching variant.
1487 static void set_accept_quality(negotiation_state *neg, var_rec *variant)
1490 accept_rec *accept_recs;
1494 /* if no Accept: header, leave quality alone (will
1495 * remain at the default value of 1)
1497 * XXX: This if is currently never true because of the effect of
1498 * maybe_add_default_accepts().
1500 if (!neg->accepts) {
1501 if (variant->mime_type && *variant->mime_type)
1502 variant->definite = 0;
1506 accept_recs = (accept_rec *) neg->accepts->elts;
1509 * Go through each of the ranges on the Accept: header,
1510 * looking for the 'best' match with this variant's
1511 * content-type. We use the best match's quality
1512 * value (from the Accept: header) for this variant's
1513 * mime_type_quality field.
1515 * The best match is determined like this:
1516 * type/type is better than type/ * is better than * / *
1517 * if match is type/type, use the level mime param if available
1519 for (i = 0; i < neg->accepts->nelts; ++i) {
1521 accept_rec *type = &accept_recs[i];
1522 int prev_mime_stars;
1524 prev_mime_stars = variant->mime_stars;
1526 if (!mime_match(type, variant)) {
1527 continue; /* didn't match the content type at all */
1530 /* did match - see if there were less or more stars than
1533 if (prev_mime_stars == variant->mime_stars) {
1534 continue; /* more stars => not as good a match */
1538 /* If we are allowed to mess with the q-values
1539 * and have no explicit q= parameters in the accept header,
1540 * make wildcards very low, so we have a low chance
1541 * of ending up with them if there's something better.
1544 if (!neg->dont_fiddle_headers && !neg->accept_q &&
1545 variant->mime_stars == 1) {
1548 else if (!neg->dont_fiddle_headers && !neg->accept_q &&
1549 variant->mime_stars == 2) {
1556 q_definite = (variant->mime_stars == 3);
1558 variant->mime_type_quality = q;
1559 variant->definite = variant->definite && q_definite;
1563 /* For a given variant, find the 'q' value of the charset given
1564 * on the Accept-Charset line. If no charsets are listed,
1565 * assume value of '1'.
1567 static void set_charset_quality(negotiation_state *neg, var_rec *variant)
1570 accept_rec *accept_recs;
1571 char *charset = variant->content_charset;
1572 accept_rec *star = NULL;
1574 /* if no Accept-Charset: header, leave quality alone (will
1575 * remain at the default value of 1)
1577 if (!neg->accept_charsets) {
1578 if (charset && *charset)
1579 variant->definite = 0;
1583 accept_recs = (accept_rec *) neg->accept_charsets->elts;
1585 if (charset == NULL || !*charset) {
1586 /* Charset of variant not known */
1588 /* if not a text / * type, leave quality alone */
1589 if (!(!strncmp(variant->mime_type, "text/", 5)
1590 || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE)
1591 || !strcmp(variant->mime_type, INCLUDES_MAGIC_TYPE3)
1595 /* Don't go guessing if we are in strict header mode,
1596 * e.g. when running the rvsa, as any guess won't be reflected
1597 * in the variant list or content-location headers.
1599 if (neg->dont_fiddle_headers)
1602 charset = "iso-8859-1"; /* The default charset for HTTP text types */
1606 * Go through each of the items on the Accept-Charset header,
1607 * looking for a match with this variant's charset. If none
1608 * match, charset is unacceptable, so set quality to 0.
1610 for (i = 0; i < neg->accept_charsets->nelts; ++i) {
1612 accept_rec *type = &accept_recs[i];
1614 if (!strcmp(type->name, charset)) {
1615 variant->charset_quality = type->quality;
1618 else if (strcmp(type->name, "*") == 0) {
1622 /* No explicit match */
1624 variant->charset_quality = star->quality;
1625 variant->definite = 0;
1628 /* If this variant is in charset iso-8859-1, the default is 1.0 */
1629 if (strcmp(charset, "iso-8859-1") == 0) {
1630 variant->charset_quality = 1.0f;
1633 variant->charset_quality = 0.0f;
1638 /* is_identity_encoding is included for back-compat, but does anyone
1639 * use 7bit, 8bin or binary in their var files??
1642 static int is_identity_encoding(const char *enc)
1644 return (!enc || !enc[0] || !strcmp(enc, "7bit") || !strcmp(enc, "8bit")
1645 || !strcmp(enc, "binary"));
1649 * set_encoding_quality determines whether the encoding for a particular
1650 * variant is acceptable for the user-agent.
1652 * The rules for encoding are that if the user-agent does not supply
1653 * any Accept-Encoding header, then all encodings are allowed but a
1654 * variant with no encoding should be preferred.
1655 * If there is an empty Accept-Encoding header, then no encodings are
1656 * acceptable. If there is a non-empty Accept-Encoding header, then
1657 * any of the listed encodings are acceptable, as well as no encoding
1658 * unless the "identity" encoding is specifically excluded.
1660 static void set_encoding_quality(negotiation_state *neg, var_rec *variant)
1662 accept_rec *accept_recs;
1663 const char *enc = variant->content_encoding;
1664 accept_rec *star = NULL;
1665 float value_if_not_found = 0.0f;
1668 if (!neg->accept_encodings) {
1669 /* We had no Accept-Encoding header, assume that all
1670 * encodings are acceptable with a low quality,
1671 * but we prefer no encoding if available.
1673 if (!enc || is_identity_encoding(enc))
1674 variant->encoding_quality = 1.0f;
1676 variant->encoding_quality = 0.5f;
1681 if (!enc || is_identity_encoding(enc)) {
1683 value_if_not_found = 0.0001f;
1686 accept_recs = (accept_rec *) neg->accept_encodings->elts;
1688 /* Go through each of the encodings on the Accept-Encoding: header,
1689 * looking for a match with our encoding. x- prefixes are ignored.
1691 if (enc[0] == 'x' && enc[1] == '-') {
1694 for (i = 0; i < neg->accept_encodings->nelts; ++i) {
1696 char *name = accept_recs[i].name;
1698 if (name[0] == 'x' && name[1] == '-') {
1702 if (!strcmp(name, enc)) {
1703 variant->encoding_quality = accept_recs[i].quality;
1707 if (strcmp(name, "*") == 0) {
1708 star = &accept_recs[i];
1712 /* No explicit match */
1714 variant->encoding_quality = star->quality;
1718 /* Encoding not found on Accept-Encoding: header, so it is
1719 * _not_ acceptable unless it is the identity (no encoding)
1721 variant->encoding_quality = value_if_not_found;
1724 /*************************************************************
1725 * Possible results of the variant selection algorithm
1727 enum algorithm_results {
1728 alg_choice = 1, /* choose variant */
1729 alg_list /* list variants */
1732 /* Below is the 'best_match' function. It returns an int, which has
1733 * one of the two values alg_choice or alg_list, which give the result
1734 * of the variant selection algorithm. alg_list means that no best
1735 * variant was found by the algorithm, alg_choice means that a best
1736 * variant was found and should be returned. The list/choice
1737 * terminology comes from TCN (rfc2295), but is used in a more generic
1738 * way here. The best variant is returned in *pbest. best_match has
1739 * two possible algorithms for determining the best variant: the
1740 * RVSA/1.0 algorithm (from RFC2296), and the standard Apache
1741 * algorithm. These are split out into separate functions
1742 * (is_variant_better_rvsa() and is_variant_better()). Selection of
1743 * one is through the neg->use_rvsa flag.
1745 * The call to best_match also creates full information, including
1746 * language, charset, etc quality for _every_ variant. This is needed
1747 * for generating a correct Vary header, and can be used for the
1748 * Alternates header, the human-readable list responses and 406 errors.
1751 /* Firstly, the RVSA/1.0 (HTTP Remote Variant Selection Algorithm
1752 * v1.0) from rfc2296. This is the algorithm that goes together with
1753 * transparent content negotiation (TCN).
1755 static int is_variant_better_rvsa(negotiation_state *neg, var_rec *variant,
1756 var_rec *best, float *p_bestq)
1758 float bestq = *p_bestq, q;
1760 /* TCN does not cover negotiation on content-encoding. For now,
1761 * we ignore the encoding unless it was explicitly excluded.
1763 if (variant->encoding_quality == 0.0f)
1766 q = variant->mime_type_quality *
1767 variant->source_quality *
1768 variant->charset_quality *
1769 variant->lang_quality;
1771 /* RFC 2296 calls for the result to be rounded to 5 decimal places,
1772 * but we don't do that because it serves no useful purpose other
1773 * than to ensure that a remote algorithm operates on the same
1774 * precision as ours. That is silly, since what we obviously want
1775 * is for the algorithm to operate on the best available precision
1776 * regardless of who runs it. Since the above calculation may
1777 * result in significant variance at 1e-12, rounding would be bogus.
1781 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1782 "Variant: file=%s type=%s lang=%s sourceq=%1.3f "
1783 "mimeq=%1.3f langq=%1.3f charq=%1.3f encq=%1.3f "
1784 "q=%1.5f definite=%d",
1785 (variant->file_name ? variant->file_name : ""),
1786 (variant->mime_type ? variant->mime_type : ""),
1787 (variant->content_languages
1788 ? apr_array_pstrcat(neg->pool, variant->content_languages, ',')
1790 variant->source_quality,
1791 variant->mime_type_quality,
1792 variant->lang_quality,
1793 variant->charset_quality,
1794 variant->encoding_quality,
1807 /* If the best variant's encoding is of lesser quality than
1808 * this variant, then we prefer this variant
1810 if (variant->encoding_quality > best->encoding_quality) {
1818 /* Negotiation algorithm as used by previous versions of Apache
1822 static int is_variant_better(negotiation_state *neg, var_rec *variant,
1823 var_rec *best, float *p_bestq)
1825 float bestq = *p_bestq, q;
1828 /* For non-transparent negotiation, server can choose how
1829 * to handle the negotiation. We'll use the following in
1830 * order: content-type, language, content-type level, charset,
1831 * content encoding, content length.
1833 * For each check, we have three possible outcomes:
1834 * This variant is worse than current best: return 0
1835 * This variant is better than the current best:
1836 * assign this variant's q to *p_bestq, and return 1
1837 * This variant is just as desirable as the current best:
1838 * drop through to the next test.
1840 * This code is written in this long-winded way to allow future
1841 * customisation, either by the addition of additional
1842 * checks, or to allow the order of the checks to be determined
1843 * by configuration options (e.g. we might prefer to check
1844 * language quality _before_ content type).
1847 /* First though, eliminate this variant if it is not
1848 * acceptable by type, charset, encoding or language.
1852 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
1853 "Variant: file=%s type=%s lang=%s sourceq=%1.3f "
1854 "mimeq=%1.3f langq=%1.3f langidx=%d charq=%1.3f encq=%1.3f ",
1855 (variant->file_name ? variant->file_name : ""),
1856 (variant->mime_type ? variant->mime_type : ""),
1857 (variant->content_languages
1858 ? apr_array_pstrcat(neg->pool, variant->content_languages, ',')
1860 variant->source_quality,
1861 variant->mime_type_quality,
1862 variant->lang_quality,
1863 variant->lang_index,
1864 variant->charset_quality,
1865 variant->encoding_quality);
1868 if (variant->encoding_quality == 0.0f ||
1869 variant->lang_quality == 0.0f ||
1870 variant->source_quality == 0.0f ||
1871 variant->charset_quality == 0.0f ||
1872 variant->mime_type_quality == 0.0f) {
1873 return 0; /* don't consider unacceptables */
1876 q = variant->mime_type_quality * variant->source_quality;
1877 if (q == 0.0 || q < bestq) {
1880 if (q > bestq || !best) {
1886 if (variant->lang_quality < best->lang_quality) {
1889 if (variant->lang_quality > best->lang_quality) {
1894 /* if language qualities were equal, try the LanguagePriority stuff */
1895 if (best->lang_index != -1 &&
1896 (variant->lang_index == -1 || variant->lang_index > best->lang_index)) {
1899 if (variant->lang_index != -1 &&
1900 (best->lang_index == -1 || variant->lang_index < best->lang_index)) {
1905 /* content-type level (sometimes used with text/html, though we
1906 * support it on other types too)
1908 levcmp = level_cmp(variant, best);
1918 if (variant->charset_quality < best->charset_quality) {
1921 /* If the best variant's charset is ISO-8859-1 and this variant has
1922 * the same charset quality, then we prefer this variant
1925 if (variant->charset_quality > best->charset_quality ||
1926 ((variant->content_charset != NULL &&
1927 *variant->content_charset != '\0' &&
1928 strcmp(variant->content_charset, "iso-8859-1") != 0) &&
1929 (best->content_charset == NULL ||
1930 *best->content_charset == '\0' ||
1931 strcmp(best->content_charset, "iso-8859-1") == 0))) {
1936 /* Prefer the highest value for encoding_quality.
1938 if (variant->encoding_quality < best->encoding_quality) {
1941 if (variant->encoding_quality > best->encoding_quality) {
1946 /* content length if all else equal */
1947 if (find_content_length(neg, variant) >= find_content_length(neg, best)) {
1951 /* ok, to get here means every thing turned out equal, except
1952 * we have a shorter content length, so use this variant
1958 static int best_match(negotiation_state *neg, var_rec **pbest)
1961 var_rec *best = NULL;
1963 enum algorithm_results algorithm_result;
1965 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
1967 set_default_lang_quality(neg);
1970 * Find the 'best' variant
1973 for (j = 0; j < neg->avail_vars->nelts; ++j) {
1974 var_rec *variant = &avail_recs[j];
1976 /* Find all the relevant 'quality' values from the
1977 * Accept... headers, and store in the variant. This also
1978 * prepares for sending an Alternates header etc so we need to
1979 * do it even if we do not actually plan to find a best
1982 set_accept_quality(neg, variant);
1983 set_language_quality(neg, variant);
1984 set_encoding_quality(neg, variant);
1985 set_charset_quality(neg, variant);
1987 /* Only do variant selection if we may actually choose a
1988 * variant for the client
1990 if (neg->may_choose) {
1992 /* Now find out if this variant is better than the current
1993 * best, either using the RVSA/1.0 algorithm, or Apache's
1994 * internal server-driven algorithm. Presumably other
1995 * server-driven algorithms are possible, and could be
1999 if (neg->use_rvsa) {
2000 if (is_variant_better_rvsa(neg, variant, best, &bestq)) {
2005 if (is_variant_better(neg, variant, best, &bestq)) {
2012 /* We now either have a best variant, or no best variant */
2014 if (neg->use_rvsa) {
2015 /* calculate result for RVSA/1.0 algorithm:
2016 * only a choice response if the best variant has q>0
2019 algorithm_result = (best && best->definite) && (bestq > 0) ?
2020 alg_choice : alg_list;
2023 /* calculate result for Apache negotiation algorithm */
2024 algorithm_result = bestq > 0 ? alg_choice : alg_list;
2027 /* Returning a choice response with a non-neighboring variant is a
2028 * protocol security error in TCN (see rfc2295). We do *not*
2029 * verify here that the variant and URI are neighbors, even though
2030 * we may return alg_choice. We depend on the environment (the
2031 * caller) to only declare the resource transparently negotiable if
2032 * all variants are neighbors.
2035 return algorithm_result;
2038 /* Sets response headers for a negotiated response.
2039 * neg->is_transparent determines whether a transparently negotiated
2040 * response or a plain `server driven negotiation' response is
2041 * created. Applicable headers are Alternates, Vary, and TCN.
2043 * The Vary header we create is sometimes longer than is required for
2044 * the correct caching of negotiated results by HTTP/1.1 caches. For
2045 * example if we have 3 variants x.html, x.ps.en and x.ps.nl, and if
2046 * the Accept: header assigns a 0 quality to .ps, then the results of
2047 * the two server-side negotiation algorithms we currently implement
2048 * will never depend on Accept-Language so we could return `Vary:
2049 * negotiate, accept' instead of the longer 'Vary: negotiate, accept,
2050 * accept-language' which the code below will return. A routine for
2051 * computing the exact minimal Vary header would be a huge pain to code
2052 * and maintain though, especially because we need to take all possible
2053 * twiddles in the server-side negotiation algorithms into account.
2055 static void set_neg_headers(request_rec *r, negotiation_state *neg,
2059 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
2060 const char *sample_type = NULL;
2061 const char *sample_language = NULL;
2062 const char *sample_encoding = NULL;
2063 const char *sample_charset = NULL;
2068 apr_array_header_t *arr;
2069 int max_vlist_array = (neg->avail_vars->nelts * 21);
2070 int first_variant = 1;
2071 int vary_by_type = 0;
2072 int vary_by_language = 0;
2073 int vary_by_charset = 0;
2074 int vary_by_encoding = 0;
2077 /* In order to avoid O(n^2) memory copies in building Alternates,
2078 * we preallocate a apr_table_t with the maximum substrings possible,
2079 * fill it with the variant list, and then concatenate the entire array.
2080 * Note that if you change the number of substrings pushed, you also
2081 * need to change the calculation of max_vlist_array above.
2083 if (neg->send_alternates && neg->avail_vars->nelts)
2084 arr = apr_make_array(r->pool, max_vlist_array, sizeof(char *));
2088 /* Put headers into err_headers_out, since send_http_header()
2089 * outputs both headers_out and err_headers_out.
2091 hdrs = r->err_headers_out;
2093 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2094 var_rec *variant = &avail_recs[j];
2096 if (variant->content_languages && variant->content_languages->nelts) {
2097 lang = apr_array_pstrcat(r->pool, variant->content_languages, ',');
2103 /* Calculate Vary by looking for any difference between variants */
2105 if (first_variant) {
2106 sample_type = variant->mime_type;
2107 sample_charset = variant->content_charset;
2108 sample_language = lang;
2109 sample_encoding = variant->content_encoding;
2112 if (!vary_by_type &&
2113 strcmp(sample_type ? sample_type : "",
2114 variant->mime_type ? variant->mime_type : "")) {
2117 if (!vary_by_charset &&
2118 strcmp(sample_charset ? sample_charset : "",
2119 variant->content_charset ?
2120 variant->content_charset : "")) {
2121 vary_by_charset = 1;
2123 if (!vary_by_language &&
2124 strcmp(sample_language ? sample_language : "",
2125 lang ? lang : "")) {
2126 vary_by_language = 1;
2128 if (!vary_by_encoding &&
2129 strcmp(sample_encoding ? sample_encoding : "",
2130 variant->content_encoding ?
2131 variant->content_encoding : "")) {
2132 vary_by_encoding = 1;
2137 if (!neg->send_alternates)
2140 /* Generate the string components for this Alternates entry */
2142 *((const char **) apr_push_array(arr)) = "{\"";
2143 *((const char **) apr_push_array(arr)) = variant->file_name;
2144 *((const char **) apr_push_array(arr)) = "\" ";
2146 qstr = (char *) apr_palloc(r->pool, 6);
2147 apr_snprintf(qstr, 6, "%1.3f", variant->source_quality);
2149 /* Strip trailing zeros (saves those valuable network bytes) */
2150 if (qstr[4] == '0') {
2152 if (qstr[3] == '0') {
2154 if (qstr[2] == '0') {
2159 *((const char **) apr_push_array(arr)) = qstr;
2161 if (variant->mime_type && *variant->mime_type) {
2162 *((const char **) apr_push_array(arr)) = " {type ";
2163 *((const char **) apr_push_array(arr)) = variant->mime_type;
2164 *((const char **) apr_push_array(arr)) = "}";
2166 if (variant->content_charset && *variant->content_charset) {
2167 *((const char **) apr_push_array(arr)) = " {charset ";
2168 *((const char **) apr_push_array(arr)) = variant->content_charset;
2169 *((const char **) apr_push_array(arr)) = "}";
2172 *((const char **) apr_push_array(arr)) = " {language ";
2173 *((const char **) apr_push_array(arr)) = lang;
2174 *((const char **) apr_push_array(arr)) = "}";
2176 if (variant->content_encoding && *variant->content_encoding) {
2177 /* Strictly speaking, this is non-standard, but so is TCN */
2179 *((const char **) apr_push_array(arr)) = " {encoding ";
2180 *((const char **) apr_push_array(arr)) = variant->content_encoding;
2181 *((const char **) apr_push_array(arr)) = "}";
2184 /* Note that the Alternates specification (in rfc2295) does
2185 * not require that we include {length x}, so we could omit it
2186 * if determining the length is too expensive. We currently
2187 * always include it though. 22 bytes is enough for 2^64.
2189 * If the variant is a CGI script, find_content_length would
2190 * return the length of the script, not the output it
2191 * produces, so we check for the presence of a handler and if
2192 * there is one we don't add a length.
2194 * XXX: TODO: This check does not detect a CGI script if we
2195 * get the variant from a type map. This needs to be fixed
2196 * (without breaking things if the type map specifies a
2197 * content-length, which currently leads to the correct result).
2199 if (!(variant->sub_req && variant->sub_req->handler)
2200 && (len = find_content_length(neg, variant)) != 0) {
2202 lenstr = (char *) apr_palloc(r->pool, 22);
2203 apr_snprintf(lenstr, 22, "%ld", len);
2204 *((const char **) apr_push_array(arr)) = " {length ";
2205 *((const char **) apr_push_array(arr)) = lenstr;
2206 *((const char **) apr_push_array(arr)) = "}";
2209 *((const char **) apr_push_array(arr)) = "}";
2210 *((const char **) apr_push_array(arr)) = ", "; /* trimmed below */
2213 if (neg->send_alternates && neg->avail_vars->nelts) {
2214 arr->nelts--; /* remove last comma */
2215 apr_table_mergen(hdrs, "Alternates",
2216 apr_array_pstrcat(r->pool, arr, '\0'));
2219 if (neg->is_transparent || vary_by_type || vary_by_language ||
2220 vary_by_language || vary_by_charset || vary_by_encoding) {
2222 apr_table_mergen(hdrs, "Vary", 2 + apr_pstrcat(r->pool,
2223 neg->is_transparent ? ", negotiate" : "",
2224 vary_by_type ? ", accept" : "",
2225 vary_by_language ? ", accept-language" : "",
2226 vary_by_charset ? ", accept-charset" : "",
2227 vary_by_encoding ? ", accept-encoding" : "", NULL));
2230 if (neg->is_transparent) { /* Create TCN response header */
2231 apr_table_setn(hdrs, "TCN",
2232 alg_result == alg_list ? "list" : "choice");
2236 /**********************************************************************
2238 * Return an HTML list of variants. This is output as part of the
2239 * choice response or 406 status body.
2242 static char *make_variant_list(request_rec *r, negotiation_state *neg)
2244 apr_array_header_t *arr;
2246 int max_vlist_array = (neg->avail_vars->nelts * 15) + 2;
2248 /* In order to avoid O(n^2) memory copies in building the list,
2249 * we preallocate a apr_table_t with the maximum substrings possible,
2250 * fill it with the variant list, and then concatenate the entire array.
2252 arr = apr_make_array(r->pool, max_vlist_array, sizeof(char *));
2254 *((const char **) apr_push_array(arr)) = "Available variants:\n<ul>\n";
2256 for (i = 0; i < neg->avail_vars->nelts; ++i) {
2257 var_rec *variant = &((var_rec *) neg->avail_vars->elts)[i];
2258 char *filename = variant->file_name ? variant->file_name : "";
2259 apr_array_header_t *languages = variant->content_languages;
2260 char *description = variant->description ? variant->description : "";
2262 /* The format isn't very neat, and it would be nice to make
2263 * the tags human readable (eg replace 'language en' with 'English').
2264 * Note that if you change the number of substrings pushed, you also
2265 * need to change the calculation of max_vlist_array above.
2267 *((const char **) apr_push_array(arr)) = "<li><a href=\"";
2268 *((const char **) apr_push_array(arr)) = filename;
2269 *((const char **) apr_push_array(arr)) = "\">";
2270 *((const char **) apr_push_array(arr)) = filename;
2271 *((const char **) apr_push_array(arr)) = "</a> ";
2272 *((const char **) apr_push_array(arr)) = description;
2274 if (variant->mime_type && *variant->mime_type) {
2275 *((const char **) apr_push_array(arr)) = ", type ";
2276 *((const char **) apr_push_array(arr)) = variant->mime_type;
2278 if (languages && languages->nelts) {
2279 *((const char **) apr_push_array(arr)) = ", language ";
2280 *((const char **) apr_push_array(arr)) = apr_array_pstrcat(r->pool,
2283 if (variant->content_charset && *variant->content_charset) {
2284 *((const char **) apr_push_array(arr)) = ", charset ";
2285 *((const char **) apr_push_array(arr)) = variant->content_charset;
2287 if (variant->content_encoding) {
2288 *((const char **) apr_push_array(arr)) = ", encoding ";
2289 *((const char **) apr_push_array(arr)) = variant->content_encoding;
2291 *((const char **) apr_push_array(arr)) = "\n";
2293 *((const char **) apr_push_array(arr)) = "</ul>\n";
2295 return apr_array_pstrcat(r->pool, arr, '\0');
2298 static void store_variant_list(request_rec *r, negotiation_state *neg)
2300 if (r->main == NULL) {
2301 apr_table_setn(r->notes, "variant-list", make_variant_list(r, neg));
2304 apr_table_setn(r->main->notes, "variant-list",
2305 make_variant_list(r->main, neg));
2309 /* Called if we got a "Choice" response from the variant selection algorithm.
2310 * It checks the result of the chosen variant to see if it
2311 * is itself negotiated (if so, return error HTTP_VARIANT_ALSO_VARIES).
2312 * Otherwise, add the appropriate headers to the current response.
2315 static int setup_choice_response(request_rec *r, negotiation_state *neg,
2318 request_rec *sub_req;
2319 const char *sub_vary;
2321 if (!variant->sub_req) {
2324 sub_req = ap_sub_req_lookup_file(variant->file_name, r, NULL);
2325 status = sub_req->status;
2327 if (status != HTTP_OK &&
2328 !apr_table_get(sub_req->err_headers_out, "TCN")) {
2329 ap_destroy_sub_req(sub_req);
2332 variant->sub_req = sub_req;
2335 sub_req = variant->sub_req;
2338 /* The variant selection algorithm told us to return a "Choice"
2339 * response. This is the normal variant response, with
2340 * some extra headers. First, ensure that the chosen
2341 * variant did or will not itself engage in transparent negotiation.
2342 * If not, set the appropriate headers, and fall through to
2343 * the normal variant handling
2346 /* This catches the error that a transparent type map selects a
2347 * transparent multiviews resource as the best variant.
2349 * XXX: We do not signal an error if a transparent type map
2350 * selects a _non_transparent multiviews resource as the best
2351 * variant, because we can generate a legal negotiation response
2352 * in this case. In this case, the vlist_validator of the
2353 * nontransparent subrequest will be lost however. This could
2354 * lead to cases in which a change in the set of variants or the
2355 * negotiation algorithm of the nontransparent resource is never
2356 * propagated up to a HTTP/1.1 cache which interprets Vary. To be
2357 * completely on the safe side we should return HTTP_VARIANT_ALSO_VARIES
2358 * for this type of recursive negotiation too.
2360 if (neg->is_transparent &&
2361 apr_table_get(sub_req->err_headers_out, "TCN")) {
2362 return HTTP_VARIANT_ALSO_VARIES;
2365 /* This catches the error that a transparent type map recursively
2366 * selects, as the best variant, another type map which itself
2367 * causes transparent negotiation to be done.
2369 * XXX: Actually, we catch this error by catching all cases of
2370 * type map recursion. There are some borderline recursive type
2371 * map arrangements which would not produce transparent
2372 * negotiation protocol errors or lack of cache propagation
2373 * problems, but such arrangements are very hard to detect at this
2374 * point in the control flow, so we do not bother to single them
2377 * Recursive type maps imply a recursive arrangement of negotiated
2378 * resources which is visible to outside clients, and this is not
2379 * supported by the transparent negotiation caching protocols, so
2380 * if we are to have generic support for recursive type maps, we
2381 * have to create some configuration setting which makes all type
2382 * maps non-transparent when recursion is enabled. Also, if we
2383 * want recursive type map support which ensures propagation of
2384 * type map changes into HTTP/1.1 caches that handle Vary, we
2385 * would have to extend the current mechanism for generating
2386 * variant list validators.
2388 if (sub_req->handler && strcmp(sub_req->handler, "type-map") == 0) {
2389 return HTTP_VARIANT_ALSO_VARIES;
2392 /* This adds an appropriate Variant-Vary header if the subrequest
2393 * is a multiviews resource.
2395 * XXX: TODO: Note that this does _not_ handle any Vary header
2396 * returned by a CGI if sub_req is a CGI script, because we don't
2397 * see that Vary header yet at this point in the control flow.
2398 * This won't cause any cache consistency problems _unless_ the
2399 * CGI script also returns a Cache-Control header marking the
2400 * response as cachable. This needs to be fixed, also there are
2401 * problems if a CGI returns an Etag header which also need to be
2404 if ((sub_vary = apr_table_get(sub_req->err_headers_out, "Vary")) != NULL) {
2405 apr_table_setn(r->err_headers_out, "Variant-Vary", sub_vary);
2407 /* Move the subreq Vary header into the main request to
2408 * prevent having two Vary headers in the response, which
2409 * would be legal but strange.
2411 apr_table_setn(r->err_headers_out, "Vary", sub_vary);
2412 apr_table_unset(sub_req->err_headers_out, "Vary");
2415 apr_table_setn(r->err_headers_out, "Content-Location",
2416 apr_pstrdup(r->pool, variant->file_name));
2418 set_neg_headers(r, neg, alg_choice); /* add Alternates and Vary */
2420 /* Still to do by caller: add Expires */
2425 /****************************************************************
2430 static int do_negotiation(request_rec *r, negotiation_state *neg,
2431 var_rec **bestp, int prefer_scripts)
2433 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
2434 int alg_result; /* result of variant selection algorithm */
2438 /* Decide if resource is transparently negotiable */
2440 /* GET or HEAD? (HEAD has same method number as GET) */
2441 if (r->method_number == M_GET) {
2443 /* maybe this should be configurable, see also the comment
2444 * about recursive type maps in setup_choice_response()
2446 neg->is_transparent = 1;
2448 /* We can't be transparent if we are a map file in the middle
2449 * of the request URI.
2451 if (r->path_info && *r->path_info)
2452 neg->is_transparent = 0;
2454 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2455 var_rec *variant = &avail_recs[j];
2457 /* We can't be transparent, because of internal
2458 * assumptions in best_match(), if there is a
2459 * non-neighboring variant. We can have a non-neighboring
2460 * variant when processing a type map.
2462 if (strchr(variant->file_name, '/'))
2463 neg->is_transparent = 0;
2467 if (neg->is_transparent) {
2468 parse_negotiate_header(r, neg);
2470 else { /* configure negotiation on non-transparent resource */
2471 neg->may_choose = 1;
2474 maybe_add_default_accepts(neg, prefer_scripts);
2476 alg_result = best_match(neg, bestp);
2478 /* alg_result is one of
2479 * alg_choice: a best variant is chosen
2480 * alg_list: no best variant is chosen
2483 if (alg_result == alg_list) {
2484 /* send a list response or HTTP_NOT_ACCEPTABLE error response */
2486 neg->send_alternates = 1; /* always include Alternates header */
2487 set_neg_headers(r, neg, alg_result);
2488 store_variant_list(r, neg);
2490 if (neg->is_transparent && neg->ua_supports_trans) {
2491 /* XXX todo: expires? cachability? */
2493 /* Some HTTP/1.0 clients are known to choke when they get
2494 * a 300 (multiple choices) response without a Location
2495 * header. However the 300 code response we are are about
2496 * to generate will only reach 1.0 clients which support
2497 * transparent negotiation, and they should be OK. The
2498 * response should never reach older 1.0 clients, even if
2499 * we have CacheNegotiatedDocs enabled, because no 1.0
2500 * proxy cache (we know of) will cache and return 300
2501 * responses (they certainly won't if they conform to the
2502 * HTTP/1.0 specification).
2504 return HTTP_MULTIPLE_CHOICES;
2508 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2509 "no acceptable variant: %s", r->filename);
2510 return HTTP_NOT_ACCEPTABLE;
2514 /* Variant selection chose a variant */
2516 /* XXX todo: merge the two cases in the if statement below */
2517 if (neg->is_transparent) {
2519 if ((res = setup_choice_response(r, neg, *bestp)) != 0) {
2520 return res; /* return if error */
2524 set_neg_headers(r, neg, alg_result);
2527 /* Make sure caching works - Vary should handle HTTP/1.1, but for
2528 * HTTP/1.0, we can't allow caching at all.
2531 /* XXX: Note that we only set r->no_cache to 1, which causes
2532 * Expires: <now> to be added, when responding to a HTTP/1.0
2533 * client. If we return the response to a 1.1 client, we do not
2534 * add Expires <now>, because doing so would degrade 1.1 cache
2535 * performance by preventing re-use of the response without prior
2536 * revalidation. On the other hand, if the 1.1 client is a proxy
2537 * which was itself contacted by a 1.0 client, or a proxy cache
2538 * which can be contacted later by 1.0 clients, then we currently
2539 * rely on this 1.1 proxy to add the Expires: <now> when it
2540 * forwards the response.
2542 * XXX: TODO: Find out if the 1.1 spec requires proxies and
2543 * tunnels to add Expires: <now> when forwarding the response to
2544 * 1.0 clients. I (kh) recall it is rather vague on this point.
2545 * Testing actual 1.1 proxy implementations would also be nice. If
2546 * Expires: <now> is not added by proxies then we need to always
2547 * include Expires: <now> ourselves to ensure correct caching, but
2548 * this would degrade HTTP/1.1 cache efficiency unless we also add
2549 * Cache-Control: max-age=N, which we currently don't.
2551 * Roy: No, we are not going to screw over HTTP future just to
2552 * ensure that people who can't be bothered to upgrade their
2553 * clients will always receive perfect server-side negotiation.
2554 * Hell, those clients are sending bogus accept headers anyway.
2556 * Manual setting of cache-control/expires always overrides this
2557 * automated kluge, on purpose.
2560 if ((!do_cache_negotiated_docs(r->server)
2561 && (r->proto_num < HTTP_VERSION(1,1)))
2562 && neg->count_multiviews_variants != 1) {
2569 static int handle_map_file(request_rec *r)
2571 negotiation_state *neg;
2576 if(strcmp(r->handler,MAP_FILE_MAGIC_TYPE) && strcmp(r->handler,"type-map"))
2579 neg = parse_accept_headers(r);
2580 if ((res = read_type_map(neg, r))) {
2584 res = do_negotiation(r, neg, &best, 0);
2585 if (res != 0) return res;
2587 if (r->path_info && *r->path_info) {
2588 r->uri[ap_find_path_info(r->uri, r->path_info)] = '\0';
2590 udir = ap_make_dirstr_parent(r->pool, r->uri);
2591 udir = ap_escape_uri(r->pool, udir);
2592 ap_internal_redirect(apr_pstrcat(r->pool, udir, best->file_name,
2593 r->path_info, NULL), r);
2597 static int handle_multi(request_rec *r)
2599 negotiation_state *neg;
2600 var_rec *best, *avail_recs;
2601 request_rec *sub_req;
2605 if (r->finfo.protection != 0 || !(ap_allow_options(r) & OPT_MULTI)) {
2609 neg = parse_accept_headers(r);
2611 if ((res = read_types_multi(neg))) {
2613 /* free all allocated memory from subrequests */
2614 avail_recs = (var_rec *) neg->avail_vars->elts;
2615 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2616 var_rec *variant = &avail_recs[j];
2617 if (variant->sub_req) {
2618 ap_destroy_sub_req(variant->sub_req);
2623 if (neg->avail_vars->nelts == 0) {
2627 res = do_negotiation(r, neg, &best,
2628 (r->method_number != M_GET) || r->args ||
2629 (r->path_info && *r->path_info));
2631 goto return_from_multi;
2633 if (!(sub_req = best->sub_req)) {
2634 /* We got this out of a map file, so we don't actually have
2635 * a sub_req structure yet. Get one now.
2638 sub_req = ap_sub_req_lookup_file(best->file_name, r, NULL);
2639 if (sub_req->status != HTTP_OK) {
2640 res = sub_req->status;
2641 ap_destroy_sub_req(sub_req);
2642 goto return_from_multi;
2646 /* BLECH --- don't multi-resolve non-ordinary files */
2648 if (sub_req->finfo.filetype != APR_REG) {
2649 res = HTTP_NOT_FOUND;
2650 goto return_from_multi;
2653 /* Otherwise, use it. */
2655 /* now do a "fast redirect" ... promote the sub_req into the main req */
2656 /* We need to tell POOL_DEBUG that we're guaranteeing that sub_req->pool
2657 * will exist as long as r->pool. Otherwise we run into troubles because
2658 * some values in this request will be allocated in r->pool, and others in
2661 apr_pool_join(r->pool, sub_req->pool);
2662 r->mtime = 0; /* reset etag info for subrequest */
2663 r->filename = sub_req->filename;
2664 r->handler = sub_req->handler;
2665 r->content_type = sub_req->content_type;
2666 r->content_encoding = sub_req->content_encoding;
2667 r->content_languages = sub_req->content_languages;
2668 r->content_language = sub_req->content_language;
2669 r->finfo = sub_req->finfo;
2670 r->per_dir_config = sub_req->per_dir_config;
2671 /* copy output headers from subrequest, but leave negotiation headers */
2672 r->notes = apr_overlay_tables(r->pool, sub_req->notes, r->notes);
2673 r->headers_out = apr_overlay_tables(r->pool, sub_req->headers_out,
2675 r->err_headers_out = apr_overlay_tables(r->pool, sub_req->err_headers_out,
2676 r->err_headers_out);
2677 r->subprocess_env = apr_overlay_tables(r->pool, sub_req->subprocess_env,
2679 avail_recs = (var_rec *) neg->avail_vars->elts;
2680 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2681 var_rec *variant = &avail_recs[j];
2682 if (variant != best && variant->sub_req) {
2683 ap_destroy_sub_req(variant->sub_req);
2689 /**********************************************************************
2690 * There is a problem with content-encoding, as some clients send and
2691 * expect an x- token (e.g. x-gzip) while others expect the plain token
2692 * (i.e. gzip). To try and deal with this as best as possible we do
2693 * the following: if the client sent an Accept-Encoding header and it
2694 * contains a plain token corresponding to the content encoding of the
2695 * response, then set content encoding using the plain token. Else if
2696 * the A-E header contains the x- token use the x- token in the C-E
2697 * header. Else don't do anything.
2699 * Note that if no A-E header was sent, or it does not contain a token
2700 * compatible with the final content encoding, then the token in the
2701 * C-E header will be whatever was specified in the AddEncoding
2704 static int fix_encoding(request_rec *r)
2706 const char *enc = r->content_encoding;
2708 apr_array_header_t *accept_encodings;
2709 accept_rec *accept_recs;
2712 if (!enc || !*enc) {
2716 if (enc[0] == 'x' && enc[1] == '-') {
2720 if ((accept_encodings = do_header_line(r->pool,
2721 apr_table_get(r->headers_in, "Accept-Encoding"))) == NULL) {
2725 accept_recs = (accept_rec *) accept_encodings->elts;
2727 for (i = 0; i < accept_encodings->nelts; ++i) {
2728 char *name = accept_recs[i].name;
2730 if (!strcmp(name, enc)) {
2731 r->content_encoding = name;
2735 if (name[0] == 'x' && name[1] == '-' && !strcmp(name+2, enc)) {
2741 r->content_encoding = x_enc;
2748 static void register_hooks(void)
2750 ap_hook_fixups(fix_encoding,NULL,NULL,AP_HOOK_MIDDLE);
2751 ap_hook_type_checker(handle_multi,NULL,NULL,AP_HOOK_FIRST);
2752 ap_hook_handler(handle_map_file,NULL,NULL,AP_HOOK_MIDDLE);
2755 module AP_MODULE_DECLARE_DATA negotiation_module =
2757 STANDARD20_MODULE_STUFF,
2758 create_neg_dir_config, /* dir config creator */
2759 merge_neg_dir_configs, /* dir merger --- default is to override */
2760 NULL, /* server config */
2761 NULL, /* merge server config */
2762 negotiation_cmds, /* command apr_table_t */
2763 register_hooks /* register hooks */