1 /* ====================================================================
2 * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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
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/)."
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
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.
30 * 6. Redistributions of any form whatsoever must retain the following
32 * "This product includes software developed by the Apache Group
33 * for use in the Apache HTTP server project (http://www.apache.org/)."
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 * ====================================================================
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/>.
59 * mod_negotiation.c: keeps track of MIME types the client is willing to
60 * accept, and contains code to handle type arbitration.
66 #include "http_config.h"
67 #include "http_request.h"
68 #include "http_protocol.h"
69 #include "http_core.h"
71 #include "util_script.h"
73 /* Commands --- configuring document caching on a per (virtual?)
78 ap_array_header_t *language_priority;
81 module MODULE_VAR_EXPORT negotiation_module;
83 static void *create_neg_dir_config(ap_context_t *p, char *dummy)
85 neg_dir_config *new = (neg_dir_config *) ap_palloc(p, sizeof(neg_dir_config));
87 new->language_priority = ap_make_array(p, 4, sizeof(char *));
91 static void *merge_neg_dir_configs(ap_context_t *p, void *basev, void *addv)
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));
97 /* give priority to the config in the subdirectory */
98 new->language_priority = ap_append_arrays(p, add->language_priority,
99 base->language_priority);
103 static const char *set_language_priority(cmd_parms *cmd, void *n, char *lang)
105 ap_array_header_t *arr = ((neg_dir_config *) n)->language_priority;
106 char **langp = (char **) ap_push_array(arr);
112 static const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy,
115 void *server_conf = cmd->server->module_config;
117 ap_set_module_config(server_conf, &negotiation_module, "Cache");
121 static int do_cache_negotiated_docs(server_rec *s)
123 return (ap_get_module_config(s->module_config, &negotiation_module) != NULL);
126 static const command_rec negotiation_cmds[] =
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"},
136 * Record of available info on a media type specified by the client
137 * (we also use 'em for encodings and languages)
140 typedef struct accept_rec {
141 char *name; /* MUST be lowercase */
144 char *charset; /* for content-type only */
148 * Record of available info on a particular variant
150 * Note that a few of these fields are updated by the actual negotiation
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
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
162 * definite -- initialized to 1. Set to 0 if there is a match which
163 * makes the variant non-definite according to the rules
167 typedef struct var_rec {
168 request_rec *sub_req; /* May be NULL (is, for map files) */
169 char *mime_type; /* MUST be lowercase */
171 const char *content_encoding;
172 ap_array_header_t *content_languages; /* list of languages for this variant */
173 char *content_charset;
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().
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 */
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 */
197 /* Above are all written-once properties of the variant. The
198 * three fields below are changed during negotiation:
206 /* Something to carry around the state of negotiation (and to keep
207 * all of this thread-safe)...
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 */
217 /* the array pointers below are NULL if the corresponding accept
218 * headers are not present
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 */
225 ap_array_header_t *avail_vars; /* available variants */
227 int count_multiviews_variants; /* number of variants found on disk */
229 int is_transparent; /* 1 if this resource is trans. negotiable */
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 */
238 /* A few functions to manipulate var_recs.
239 * Cleaning out the fields...
242 static void clean_var_rec(var_rec *mime_info)
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 = "";
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;
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;
267 /* Initializing the relevant fields of a variant record from the
268 * accept_info read out of its content-type, one way or another.
271 static void set_mime_fields(var_rec *var, accept_rec *mime_info)
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;
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));
283 /* Create a variant list validator in r using info from vlistr. */
285 static void set_vlist_validator(request_rec *r, request_rec *vlistr)
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.
293 ap_update_mtime (vlistr, vlistr->finfo.st_mtime);
294 r->vlist_validator = ap_make_etag(vlistr, 0);
296 /* ap_set_etag will later take r->vlist_validator into account
297 * when creating the etag header
302 /*****************************************************************
304 * Parsing (lists of) media types and their parameters, as seen in
305 * HTTPD header lines and elsewhere.
309 * Get a single mime type entry --- one media type and parameters;
310 * enter the values we recognize into the argument accept_rec
313 static const char *get_entry(ap_context_t *p, accept_rec *result,
314 const char *accept_line)
316 result->quality = 1.0f;
317 result->level = 0.0f;
318 result->charset = "";
321 * Note that this handles what I gather is the "old format",
323 * Accept: text/html text/plain moo/zot
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).
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.
336 /* KLUDGE!!! Default HTML to level 2.0 unless the browser
337 * *explicitly* says something else.
340 if (!strcmp(result->name, "text/html") && (result->level == 0.0)) {
341 result->level = 2.0f;
343 else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE)) {
344 result->level = 2.0f;
346 else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) {
347 result->level = 3.0f;
350 while (*accept_line == ';') {
358 parm = ap_get_token(p, &accept_line, 1);
360 /* Look for 'var = value' --- and make sure the var is in lcase. */
362 for (cp = parm; (*cp && !ap_isspace(*cp) && *cp != '='); ++cp) {
363 *cp = ap_tolower(*cp);
367 continue; /* No '='; just ignore it. */
370 *cp++ = '\0'; /* Delimit var */
371 while (*cp && (ap_isspace(*cp) || *cp == '=')) {
378 (*end && *end != '\n' && *end != '\r' && *end != '\"');
382 for (end = cp; (*end && !ap_isspace(*end)); end++);
385 *end = '\0'; /* strip ending quote or return */
390 && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) {
391 result->quality = atof(cp);
393 else if (parm[0] == 'l' && !strcmp(&parm[1], "evel")) {
394 result->level = atof(cp);
396 else if (!strcmp(parm, "charset")) {
397 result->charset = cp;
401 if (*accept_line == ',') {
408 /*****************************************************************
410 * Dealing with header lines ...
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
417 * where charset is only valid in Accept.
420 static ap_array_header_t *do_header_line(ap_context_t *p, const char *accept_line)
422 ap_array_header_t *accept_recs;
428 accept_recs = ap_make_array(p, 40, sizeof(accept_rec));
430 while (*accept_line) {
431 accept_rec *new = (accept_rec *) ap_push_array(accept_recs);
432 accept_line = get_entry(p, new, accept_line);
438 /* Given the text of the Content-Languages: line from the var map file,
439 * return an array containing the languages of this variant
442 static ap_array_header_t *do_languages_line(ap_context_t *p, const char **lang_line)
444 ap_array_header_t *lang_recs = ap_make_array(p, 2, sizeof(char *));
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 == ';') {
462 /*****************************************************************
464 * Handling header lines from clients...
467 static negotiation_state *parse_accept_headers(request_rec *r)
469 negotiation_state *new =
470 (negotiation_state *) ap_pcalloc(r->pool, sizeof(negotiation_state));
472 ap_table_t *hdrs = r->headers_in;
477 new->dir_name = ap_make_dirstr_parent(r->pool, r->filename);
479 new->accepts = do_header_line(r->pool, ap_table_get(hdrs, "Accept"));
481 /* calculate new->accept_q value */
483 elts = (accept_rec *) new->accepts->elts;
485 for (i = 0; i < new->accepts->nelts; ++i) {
486 if (elts[i].quality < 1.0) {
492 new->accept_encodings =
493 do_header_line(r->pool, ap_table_get(hdrs, "Accept-Encoding"));
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"));
499 new->avail_vars = ap_make_array(r->pool, 40, sizeof(var_rec));
505 static void parse_negotiate_header(request_rec *r, negotiation_state *neg)
507 const char *negotiate = ap_table_get(r->headers_in, "Negotiate");
510 /* First, default to no TCN, no Alternates, and the original Apache
511 * negotiation algorithm with fiddles for broken browser configs.
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.
519 neg->ua_supports_trans = 0;
520 neg->send_alternates = 0;
523 neg->dont_fiddle_headers = 0;
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.
536 const char *ua = ap_table_get(r->headers_in, "User-Agent");
538 if (ua && (strncmp(ua, "Lynx", 4) == 0))
542 neg->may_choose = 0; /* An empty Negotiate would require 300 response */
544 while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) {
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) {
552 /* The user agent supports transparent negotiation */
553 neg->ua_supports_trans = 1;
555 /* Send-alternates could be configurable, but note
556 * that it must be 1 if we have 'vlist' in the
559 neg->send_alternates = 1;
561 if (strcmp(tok, "1.0") == 0) {
562 /* we may use the RVSA/1.0 algorithm, configure for it */
565 neg->dont_fiddle_headers = 1;
567 else if (tok[0] == '*') {
568 /* we may use any variant selection algorithm, configure
569 * to use the Apache algorithm
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.
577 neg->dont_fiddle_headers = 1;
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);
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).
597 static void maybe_add_default_accepts(negotiation_state *neg,
600 accept_rec *new_accept;
603 neg->accepts = ap_make_array(neg->pool, 4, sizeof(accept_rec));
605 new_accept = (accept_rec *) ap_push_array(neg->accepts);
607 new_accept->name = "*/*";
608 new_accept->quality = 1.0f;
609 new_accept->level = 0.0f;
612 new_accept = (accept_rec *) ap_push_array(neg->accepts);
614 new_accept->name = CGI_MAGIC_TYPE;
616 new_accept->quality = 0;
619 new_accept->quality = prefer_scripts ? 2.0f : 0.001f;
621 new_accept->level = 0.0f;
624 /*****************************************************************
626 * Parsing type-map files, in Roy's meta/http format augmented with
630 /* Reading RFC822-style header lines, ignoring #-comments and
631 * handling continuations.
635 header_eof, header_seen, header_sep
638 static enum header_state get_header_line(char *buffer, int len, ap_file_t *map)
640 char *buf_end = buffer + len;
644 /* Get a noncommented line */
647 if (ap_fgets(buffer, MAX_STRING_LEN, map) != APR_SUCCESS) {
650 } while (buffer[0] == '#');
652 /* If blank, just return it --- this ends information on this variant */
654 for (cp = buffer; (*cp && ap_isspace(*cp)); ++cp) {
662 /* If non-blank, go looking for header lines, but note that we still
663 * have to treat comments specially...
668 while (ap_getc(&c, map) != APR_EOF) {
671 while (ap_getc(&c, map) != EOF && c != '\n') {
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.
681 while (c != '\n' && ap_isspace(c)) {
682 if(ap_getc(&c, map) != APR_SUCCESS)
689 return header_seen; /* Blank line */
694 while (cp < buf_end - 2 && (ap_getc(&c, map)) != EOF && c != '\n') {
703 /* Line beginning with something other than whitespace */
713 /* Stripping out RFC822 comments */
715 static void strip_paren_comments(char *hdr)
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. */
722 hdr = strchr(hdr, '"');
728 else if (*hdr == '(') {
729 while (*hdr && *hdr != ')') {
743 /* Getting to a header body from the header */
745 static char *lcase_header_name_return_body(char *header, request_rec *r)
749 for ( ; *cp && *cp != ':' ; ++cp) {
750 *cp = ap_tolower(*cp);
754 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
755 "Syntax error in type map --- no ':': %s", r->filename);
761 } while (*cp && ap_isspace(*cp));
764 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
765 "Syntax error in type map --- no header body: %s",
773 static int read_type_map(negotiation_state *neg, request_rec *rr)
775 request_rec *r = neg->r;
778 char buffer[MAX_STRING_LEN];
779 enum header_state hstate;
780 struct var_rec mime_info;
783 /* We are not using multiviews */
784 neg->count_multiviews_variants = 0;
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;
793 clean_var_rec(&mime_info);
797 hstate = get_header_line(buffer, MAX_STRING_LEN, map);
799 if (hstate == header_seen) {
800 char *body1 = lcase_header_name_return_body(buffer, neg->r);
807 strip_paren_comments(body1);
810 if (!strncmp(buffer, "uri:", 4)) {
811 mime_info.file_name = ap_get_token(neg->pool, &body, 0);
813 else if (!strncmp(buffer, "content-type:", 13)) {
814 struct accept_rec accept_info;
816 get_entry(neg->pool, &accept_info, body);
817 set_mime_fields(&mime_info, &accept_info);
820 else if (!strncmp(buffer, "content-length:", 15)) {
821 mime_info.bytes = atof(body);
824 else if (!strncmp(buffer, "content-language:", 17)) {
825 mime_info.content_languages = do_languages_line(neg->pool,
829 else if (!strncmp(buffer, "content-encoding:", 17)) {
830 mime_info.content_encoding = ap_get_token(neg->pool, &body, 0);
833 else if (!strncmp(buffer, "description:", 12)) {
834 char *desc = ap_pstrdup(neg->pool, body);
837 for (cp = desc; *cp; ++cp) {
838 if (*cp=='\n') *cp=' ';
840 if (cp>desc) *(cp-1)=0;
841 mime_info.description = desc;
845 if (*mime_info.file_name && has_content) {
846 void *new_var = ap_push_array(neg->avail_vars);
848 memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
851 clean_var_rec(&mime_info);
854 } while (hstate != header_eof);
858 set_vlist_validator(r, rr);
864 /* Sort function used by read_types_multi. */
865 static int variantsortf(var_rec *a, var_rec *b) {
867 /* First key is the source quality, sort in descending order. */
869 /* XXX: note that we currently implement no method of setting the
870 * source quality for multiviews variants, so we are always comparing
873 if (a->source_quality < b->source_quality)
875 if (a->source_quality > b->source_quality)
878 /* Second key is the variant name */
879 return strcmp(a->file_name, b->file_name);
882 /*****************************************************************
884 * Same as read_type_map, except we use a filtered directory listing
888 static int read_types_multi(negotiation_state *neg)
890 request_rec *r = neg->r;
896 struct var_rec mime_info;
897 struct accept_rec accept_info;
900 clean_var_rec(&mime_info);
902 if (!(filp = strrchr(r->filename, '/'))) {
903 return DECLINED; /* Weird... */
906 if (strncmp(r->filename, "proxy:", 6) == 0) {
911 prefix_len = strlen(filp);
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;
919 while (ap_readdir(dirp) == APR_SUCCESS) {
920 request_rec *sub_req;
923 ap_get_dir_filename(&d_name, dirp);
924 /* Do we have a match? */
926 if (strncmp(d_name, filp, prefix_len)) {
929 if (d_name[prefix_len] != '.') {
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).
938 sub_req = ap_sub_req_lookup_file(d_name, r);
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
944 if (sub_req->handler && !sub_req->content_type) {
945 sub_req->content_type = CGI_MAGIC_TYPE;
948 if (sub_req->status != HTTP_OK || !sub_req->content_type) {
949 ap_destroy_sub_req(sub_req);
953 /* If it's a map file, we use that instead of the map
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"))) {
963 neg->avail_vars->nelts = 0;
964 if (sub_req->status != HTTP_OK) {
965 return sub_req->status;
967 return read_type_map(neg, sub_req);
970 /* Have reasonable variant --- gather notes. */
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;
977 if (sub_req->content_languages) {
978 mime_info.content_languages = sub_req->content_languages;
981 get_entry(neg->pool, &accept_info, sub_req->content_type);
982 set_mime_fields(&mime_info, &accept_info);
984 new_var = ap_push_array(neg->avail_vars);
985 memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
987 neg->count_multiviews_variants++;
989 clean_var_rec(&mime_info);
994 set_vlist_validator(r, r);
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.
1004 qsort((void *) neg->avail_vars->elts, neg->avail_vars->nelts,
1005 sizeof(var_rec), (int (*)(const void *, const void *)) variantsortf);
1011 /*****************************************************************
1012 * And now for the code you've been waiting for... actually
1013 * finding a match to the client's requirements.
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.
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...
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.
1028 static int mime_match(accept_rec *accept_r, var_rec *avail)
1030 char *accept_type = accept_r->name;
1031 char *avail_type = avail->mime_type;
1032 int len = strlen(accept_type);
1034 if (accept_type[0] == '*') { /* Anything matches star/star */
1035 if (avail->mime_stars < 1) {
1036 avail->mime_stars = 1;
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;
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;
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.
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
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).
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).
1086 static int level_cmp(var_rec *var1, var_rec *var2)
1088 /* Levels are only comparable between matching media types */
1090 if (var1->is_pseudo_html && !var2->is_pseudo_html) {
1094 if (!var1->is_pseudo_html && strcmp(var1->mime_type, var2->mime_type)) {
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
1102 /* Take highest level that matched, if either did match. */
1104 if (var1->level_matched > var2->level_matched) {
1107 if (var1->level_matched < var2->level_matched) {
1111 /* Neither matched. Take lowest level, if there's a difference. */
1113 if (var1->level < var2->level) {
1116 if (var1->level > var2->level) {
1125 /* Finding languages. The main entry point is set_language_quality()
1126 * which is called for each variant. It sets two elements in the
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
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.
1140 * set_language_quality() calls find_lang_index() and find_default_index()
1141 * to set lang_index.
1144 static int find_lang_index(ap_array_header_t *accept_langs, char *lang)
1149 if (!lang || !accept_langs) {
1153 accs = (accept_rec *) accept_langs->elts;
1155 for (i = 0; i < accept_langs->nelts; ++i) {
1156 if (!strncmp(lang, accs[i].name, strlen(accs[i].name))) {
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.
1169 static int find_default_index(neg_dir_config *conf, char *lang)
1171 ap_array_header_t *arr;
1180 arr = conf->language_priority;
1182 elts = (char **) arr->elts;
1184 for (i = 0; i < nelts; ++i) {
1185 if (!strcasecmp(elts[i], lang)) {
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().
1204 * Note that if using the RVSA/1.0 algorithm, we don't use this
1208 static void set_default_lang_quality(negotiation_state *neg)
1210 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
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;
1224 neg->default_lang_quality = 1.0f;
1227 /* Set the language_quality value in the variant record. Also
1228 * assigns lang_index for back-compat.
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])
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.
1244 * If the variant has no language and we have no Accept-Language
1245 * items, leave the quality at 1.0 and return.
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).
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.
1258 static void set_language_quality(negotiation_state *neg, var_rec *variant)
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
1270 if (!neg->dont_fiddle_headers) {
1271 variant->lang_quality = neg->default_lang_quality;
1273 if (!neg->accept_langs) {
1274 return; /* no accept-language header */
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
1288 if (!neg->accept_langs) {
1289 /* no accept-language header makes the variant indefinite */
1290 variant->definite = 0;
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;
1297 float fiddle_q = 0.0f;
1298 int any_match_on_star = 0;
1299 int i, j, alen, longest_lang_range_len;
1301 for (j = 0; j < variant->content_languages->nelts; ++j) {
1304 longest_lang_range_len = 0;
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
1310 lang = ((char **) (variant->content_languages->elts))[j];
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.
1319 for (i = 0; i < neg->accept_langs->nelts; ++i) {
1320 if (!strcmp(accs[i].name, "*")) {
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).
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.
1341 alen = strlen(accs[i].name);
1343 if ((strlen(lang) >= alen) &&
1344 !strncmp(lang, accs[i].name, alen) &&
1345 ((lang[alen] == 0) || (lang[alen] == '-')) ) {
1347 if (alen > longest_lang_range_len) {
1348 longest_lang_range_len = alen;
1349 bestthistag = &accs[i];
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.
1370 if ((p = strchr(accs[i].name, '-'))) {
1371 int plen = p - accs[i].name;
1373 if (!strncmp(lang, accs[i].name, plen)) {
1379 /* Finished looking at Accept-Language headers, the best
1380 * (longest) match is in bestthistag, or NULL if no match
1383 (bestthistag && bestthistag->quality > best->quality)) {
1387 /* See if the tag matches on a * in the Accept-Language
1388 * header. If so, record this fact for later use
1390 if (!bestthistag && star) {
1391 any_match_on_star = 1;
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.
1400 if ( any_match_on_star &&
1401 ((best && star->quality > best->quality) ||
1404 variant->definite = 0;
1407 variant->lang_quality = best ? best->quality : fiddle_q;
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
1416 if (variant->content_languages && variant->content_languages->nelts) {
1417 firstlang = ((char **) variant->content_languages->elts)[0];
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),
1427 else { /* Client has Accept-Language */
1428 idx = find_lang_index(neg->accept_langs, firstlang);
1430 variant->lang_index = idx;
1435 /* Determining the content length --- if the map didn't tell us,
1436 * we have to do a stat() and remember for next time.
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.
1443 static float find_content_length(negotiation_state *neg, var_rec *variant)
1447 if (variant->bytes == 0) {
1448 char *fullname = ap_make_full_path(neg->pool, neg->dir_name,
1449 variant->file_name);
1451 if (stat(fullname, &statb) >= 0) {
1452 /* Note, precision may be lost */
1453 variant->bytes = (float) statb.st_size;
1457 return variant->bytes;
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.
1466 static void set_accept_quality(negotiation_state *neg, var_rec *variant)
1469 accept_rec *accept_recs;
1473 /* if no Accept: header, leave quality alone (will
1474 * remain at the default value of 1)
1476 * XXX: This if is currently never true because of the effect of
1477 * maybe_add_default_accepts().
1479 if (!neg->accepts) {
1480 if (variant->mime_type && *variant->mime_type)
1481 variant->definite = 0;
1485 accept_recs = (accept_rec *) neg->accepts->elts;
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.
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
1498 for (i = 0; i < neg->accepts->nelts; ++i) {
1500 accept_rec *type = &accept_recs[i];
1501 int prev_mime_stars;
1503 prev_mime_stars = variant->mime_stars;
1505 if (!mime_match(type, variant)) {
1506 continue; /* didn't match the content type at all */
1509 /* did match - see if there were less or more stars than
1512 if (prev_mime_stars == variant->mime_stars) {
1513 continue; /* more stars => not as good a match */
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.
1523 if (!neg->dont_fiddle_headers && !neg->accept_q &&
1524 variant->mime_stars == 1) {
1527 else if (!neg->dont_fiddle_headers && !neg->accept_q &&
1528 variant->mime_stars == 2) {
1535 q_definite = (variant->mime_stars == 3);
1537 variant->mime_type_quality = q;
1538 variant->definite = variant->definite && q_definite;
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'.
1546 static void set_charset_quality(negotiation_state *neg, var_rec *variant)
1549 accept_rec *accept_recs;
1550 char *charset = variant->content_charset;
1551 accept_rec *star = NULL;
1553 /* if no Accept-Charset: header, leave quality alone (will
1554 * remain at the default value of 1)
1556 if (!neg->accept_charsets) {
1557 if (charset && *charset)
1558 variant->definite = 0;
1562 accept_recs = (accept_rec *) neg->accept_charsets->elts;
1564 if (charset == NULL || !*charset) {
1565 /* Charset of variant not known */
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)
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.
1578 if (neg->dont_fiddle_headers)
1581 charset = "iso-8859-1"; /* The default charset for HTTP text types */
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.
1589 for (i = 0; i < neg->accept_charsets->nelts; ++i) {
1591 accept_rec *type = &accept_recs[i];
1593 if (!strcmp(type->name, charset)) {
1594 variant->charset_quality = type->quality;
1597 else if (strcmp(type->name, "*") == 0) {
1601 /* No explicit match */
1603 variant->charset_quality = star->quality;
1604 variant->definite = 0;
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;
1612 variant->charset_quality = 0.0f;
1617 /* is_identity_encoding is included for back-compat, but does anyone
1618 * use 7bit, 8bin or binary in their var files??
1621 static int is_identity_encoding(const char *enc)
1623 return (!enc || !enc[0] || !strcmp(enc, "7bit") || !strcmp(enc, "8bit")
1624 || !strcmp(enc, "binary"));
1628 * set_encoding_quality determines whether the encoding for a particular
1629 * variant is acceptable for the user-agent.
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.
1639 static void set_encoding_quality(negotiation_state *neg, var_rec *variant)
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;
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.
1652 if (!enc || is_identity_encoding(enc))
1653 variant->encoding_quality = 1.0f;
1655 variant->encoding_quality = 0.5f;
1660 if (!enc || is_identity_encoding(enc)) {
1662 value_if_not_found = 0.0001f;
1665 accept_recs = (accept_rec *) neg->accept_encodings->elts;
1667 /* Go through each of the encodings on the Accept-Encoding: header,
1668 * looking for a match with our encoding. x- prefixes are ignored.
1670 if (enc[0] == 'x' && enc[1] == '-') {
1673 for (i = 0; i < neg->accept_encodings->nelts; ++i) {
1675 char *name = accept_recs[i].name;
1677 if (name[0] == 'x' && name[1] == '-') {
1681 if (!strcmp(name, enc)) {
1682 variant->encoding_quality = accept_recs[i].quality;
1686 if (strcmp(name, "*") == 0) {
1687 star = &accept_recs[i];
1691 /* No explicit match */
1693 variant->encoding_quality = star->quality;
1697 /* Encoding not found on Accept-Encoding: header, so it is
1698 * _not_ acceptable unless it is the identity (no encoding)
1700 variant->encoding_quality = value_if_not_found;
1703 /*************************************************************
1704 * Possible results of the variant selection algorithm
1706 enum algorithm_results {
1707 alg_choice = 1, /* choose variant */
1708 alg_list /* list variants */
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.
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.
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).
1734 static int is_variant_better_rvsa(negotiation_state *neg, var_rec *variant,
1735 var_rec *best, float *p_bestq)
1737 float bestq = *p_bestq, q;
1739 /* TCN does not cover negotiation on content-encoding. For now,
1740 * we ignore the encoding unless it was explicitly excluded.
1742 if (variant->encoding_quality == 0.0f)
1745 q = variant->mime_type_quality *
1746 variant->source_quality *
1747 variant->charset_quality *
1748 variant->lang_quality;
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.
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, ',')
1768 variant->source_quality,
1769 variant->mime_type_quality,
1770 variant->lang_quality,
1771 variant->charset_quality,
1772 variant->encoding_quality,
1785 /* If the best variant's encoding is of lesser quality than
1786 * this variant, then we prefer this variant
1788 if (variant->encoding_quality > best->encoding_quality) {
1796 /* Negotiation algorithm as used by previous versions of Apache
1800 static int is_variant_better(negotiation_state *neg, var_rec *variant,
1801 var_rec *best, float *p_bestq)
1803 float bestq = *p_bestq, q;
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.
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.
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).
1825 /* First though, eliminate this variant if it is not
1826 * acceptable by type, charset, encoding or language.
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, ',')
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);
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 */
1853 q = variant->mime_type_quality * variant->source_quality;
1854 if (q == 0.0 || q < bestq) {
1857 if (q > bestq || !best) {
1863 if (variant->lang_quality < best->lang_quality) {
1866 if (variant->lang_quality > best->lang_quality) {
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)) {
1876 if (variant->lang_index != -1 &&
1877 (best->lang_index == -1 || variant->lang_index < best->lang_index)) {
1882 /* content-type level (sometimes used with text/html, though we
1883 * support it on other types too)
1885 levcmp = level_cmp(variant, best);
1895 if (variant->charset_quality < best->charset_quality) {
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
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))) {
1913 /* Prefer the highest value for encoding_quality.
1915 if (variant->encoding_quality < best->encoding_quality) {
1918 if (variant->encoding_quality > best->encoding_quality) {
1923 /* content length if all else equal */
1924 if (find_content_length(neg, variant) >= find_content_length(neg, best)) {
1928 /* ok, to get here means every thing turned out equal, except
1929 * we have a shorter content length, so use this variant
1935 static int best_match(negotiation_state *neg, var_rec **pbest)
1938 var_rec *best = NULL;
1940 enum algorithm_results algorithm_result;
1942 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
1944 set_default_lang_quality(neg);
1947 * Find the 'best' variant
1950 for (j = 0; j < neg->avail_vars->nelts; ++j) {
1951 var_rec *variant = &avail_recs[j];
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
1959 set_accept_quality(neg, variant);
1960 set_language_quality(neg, variant);
1961 set_encoding_quality(neg, variant);
1962 set_charset_quality(neg, variant);
1964 /* Only do variant selection if we may actually choose a
1965 * variant for the client
1967 if (neg->may_choose) {
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
1976 if (neg->use_rvsa) {
1977 if (is_variant_better_rvsa(neg, variant, best, &bestq)) {
1982 if (is_variant_better(neg, variant, best, &bestq)) {
1989 /* We now either have a best variant, or no best variant */
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
1996 algorithm_result = (best && best->definite) && (bestq > 0) ?
1997 alg_choice : alg_list;
2000 /* calculate result for Apache negotiation algorithm */
2001 algorithm_result = bestq > 0 ? alg_choice : alg_list;
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.
2012 return algorithm_result;
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.
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.
2032 static void set_neg_headers(request_rec *r, negotiation_state *neg,
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;
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;
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.
2060 if (neg->send_alternates && neg->avail_vars->nelts)
2061 arr = ap_make_array(r->pool, max_vlist_array, sizeof(char *));
2065 /* Put headers into err_headers_out, since send_http_header()
2066 * outputs both headers_out and err_headers_out.
2068 hdrs = r->err_headers_out;
2070 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2071 var_rec *variant = &avail_recs[j];
2073 if (variant->content_languages && variant->content_languages->nelts) {
2074 lang = ap_array_pstrcat(r->pool, variant->content_languages, ',');
2080 /* Calculate Vary by looking for any difference between variants */
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;
2089 if (!vary_by_type &&
2090 strcmp(sample_type ? sample_type : "",
2091 variant->mime_type ? variant->mime_type : "")) {
2094 if (!vary_by_charset &&
2095 strcmp(sample_charset ? sample_charset : "",
2096 variant->content_charset ?
2097 variant->content_charset : "")) {
2098 vary_by_charset = 1;
2100 if (!vary_by_language &&
2101 strcmp(sample_language ? sample_language : "",
2102 lang ? lang : "")) {
2103 vary_by_language = 1;
2105 if (!vary_by_encoding &&
2106 strcmp(sample_encoding ? sample_encoding : "",
2107 variant->content_encoding ?
2108 variant->content_encoding : "")) {
2109 vary_by_encoding = 1;
2114 if (!neg->send_alternates)
2117 /* Generate the string components for this Alternates entry */
2119 *((const char **) ap_push_array(arr)) = "{\"";
2120 *((const char **) ap_push_array(arr)) = variant->file_name;
2121 *((const char **) ap_push_array(arr)) = "\" ";
2123 qstr = (char *) ap_palloc(r->pool, 6);
2124 ap_snprintf(qstr, 6, "%1.3f", variant->source_quality);
2126 /* Strip trailing zeros (saves those valuable network bytes) */
2127 if (qstr[4] == '0') {
2129 if (qstr[3] == '0') {
2131 if (qstr[2] == '0') {
2136 *((const char **) ap_push_array(arr)) = qstr;
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)) = "}";
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)) = "}";
2149 *((const char **) ap_push_array(arr)) = " {language ";
2150 *((const char **) ap_push_array(arr)) = lang;
2151 *((const char **) ap_push_array(arr)) = "}";
2153 if (variant->content_encoding && *variant->content_encoding) {
2154 /* Strictly speaking, this is non-standard, but so is TCN */
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)) = "}";
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.
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.
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).
2176 if (!(variant->sub_req && variant->sub_req->handler)
2177 && (len = find_content_length(neg, variant)) != 0) {
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)) = "}";
2186 *((const char **) ap_push_array(arr)) = "}";
2187 *((const char **) ap_push_array(arr)) = ", "; /* trimmed below */
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'));
2196 if (neg->is_transparent || vary_by_type || vary_by_language ||
2197 vary_by_language || vary_by_charset || vary_by_encoding) {
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));
2207 if (neg->is_transparent) { /* Create TCN response header */
2208 ap_table_setn(hdrs, "TCN",
2209 alg_result == alg_list ? "list" : "choice");
2213 /**********************************************************************
2215 * Return an HTML list of variants. This is output as part of the
2216 * choice response or 406 status body.
2219 static char *make_variant_list(request_rec *r, negotiation_state *neg)
2221 ap_array_header_t *arr;
2223 int max_vlist_array = (neg->avail_vars->nelts * 15) + 2;
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.
2229 arr = ap_make_array(r->pool, max_vlist_array, sizeof(char *));
2231 *((const char **) ap_push_array(arr)) = "Available variants:\n<ul>\n";
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 : "";
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.
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;
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;
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,
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;
2264 if (variant->content_encoding) {
2265 *((const char **) ap_push_array(arr)) = ", encoding ";
2266 *((const char **) ap_push_array(arr)) = variant->content_encoding;
2268 *((const char **) ap_push_array(arr)) = "\n";
2270 *((const char **) ap_push_array(arr)) = "</ul>\n";
2272 return ap_array_pstrcat(r->pool, arr, '\0');
2275 static void store_variant_list(request_rec *r, negotiation_state *neg)
2277 if (r->main == NULL) {
2278 ap_table_setn(r->notes, "variant-list", make_variant_list(r, neg));
2281 ap_table_setn(r->main->notes, "variant-list",
2282 make_variant_list(r->main, neg));
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.
2292 static int setup_choice_response(request_rec *r, negotiation_state *neg,
2295 request_rec *sub_req;
2296 const char *sub_vary;
2298 if (!variant->sub_req) {
2301 sub_req = ap_sub_req_lookup_file(variant->file_name, r);
2302 status = sub_req->status;
2304 if (status != HTTP_OK &&
2305 !ap_table_get(sub_req->err_headers_out, "TCN")) {
2306 ap_destroy_sub_req(sub_req);
2309 variant->sub_req = sub_req;
2312 sub_req = variant->sub_req;
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
2323 /* This catches the error that a transparent type map selects a
2324 * transparent multiviews resource as the best variant.
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.
2337 if (neg->is_transparent &&
2338 ap_table_get(sub_req->err_headers_out, "TCN")) {
2339 return VARIANT_ALSO_VARIES;
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.
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
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.
2365 if (sub_req->handler && strcmp(sub_req->handler, "type-map") == 0) {
2366 return VARIANT_ALSO_VARIES;
2369 /* This adds an appropriate Variant-Vary header if the subrequest
2370 * is a multiviews resource.
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
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);
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.
2388 ap_table_setn(r->err_headers_out, "Vary", sub_vary);
2389 ap_table_unset(sub_req->err_headers_out, "Vary");
2392 ap_table_setn(r->err_headers_out, "Content-Location",
2393 ap_pstrdup(r->pool, variant->file_name));
2395 set_neg_headers(r, neg, alg_choice); /* add Alternates and Vary */
2397 /* Still to do by caller: add Expires */
2402 /****************************************************************
2407 static int do_negotiation(request_rec *r, negotiation_state *neg,
2408 var_rec **bestp, int prefer_scripts)
2410 var_rec *avail_recs = (var_rec *) neg->avail_vars->elts;
2411 int alg_result; /* result of variant selection algorithm */
2415 /* Decide if resource is transparently negotiable */
2417 /* GET or HEAD? (HEAD has same method number as GET) */
2418 if (r->method_number == M_GET) {
2420 /* maybe this should be configurable, see also the comment
2421 * about recursive type maps in setup_choice_response()
2423 neg->is_transparent = 1;
2425 /* We can't be transparent if we are a map file in the middle
2426 * of the request URI.
2428 if (r->path_info && *r->path_info)
2429 neg->is_transparent = 0;
2431 for (j = 0; j < neg->avail_vars->nelts; ++j) {
2432 var_rec *variant = &avail_recs[j];
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.
2439 if (strchr(variant->file_name, '/'))
2440 neg->is_transparent = 0;
2444 if (neg->is_transparent) {
2445 parse_negotiate_header(r, neg);
2447 else { /* configure negotiation on non-transparent resource */
2448 neg->may_choose = 1;
2451 maybe_add_default_accepts(neg, prefer_scripts);
2453 alg_result = best_match(neg, bestp);
2455 /* alg_result is one of
2456 * alg_choice: a best variant is chosen
2457 * alg_list: no best variant is chosen
2460 if (alg_result == alg_list) {
2461 /* send a list response or NOT_ACCEPTABLE error response */
2463 neg->send_alternates = 1; /* always include Alternates header */
2464 set_neg_headers(r, neg, alg_result);
2465 store_variant_list(r, neg);
2467 if (neg->is_transparent && neg->ua_supports_trans) {
2468 /* XXX todo: expires? cachability? */
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).
2481 return MULTIPLE_CHOICES;
2485 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
2486 "no acceptable variant: %s", r->filename);
2487 return NOT_ACCEPTABLE;
2491 /* Variant selection chose a variant */
2493 /* XXX todo: merge the two cases in the if statement below */
2494 if (neg->is_transparent) {
2496 if ((res = setup_choice_response(r, neg, *bestp)) != 0) {
2497 return res; /* return if error */
2501 set_neg_headers(r, neg, alg_result);
2504 /* Make sure caching works - Vary should handle HTTP/1.1, but for
2505 * HTTP/1.0, we can't allow caching at all.
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.
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.
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.
2533 * Manual setting of cache-control/expires always overrides this
2534 * automated kluge, on purpose.
2537 if ((!do_cache_negotiated_docs(r->server)
2538 && (r->proto_num < HTTP_VERSION(1,1)))
2539 && neg->count_multiviews_variants != 1) {
2546 static int handle_map_file(request_rec *r)
2548 negotiation_state *neg = parse_accept_headers(r);
2554 if ((res = read_type_map(neg, r))) {
2558 res = do_negotiation(r, neg, &best, 0);
2559 if (res != 0) return res;
2561 if (r->path_info && *r->path_info) {
2562 r->uri[ap_find_path_info(r->uri, r->path_info)] = '\0';
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);
2571 static int handle_multi(request_rec *r)
2573 negotiation_state *neg;
2574 var_rec *best, *avail_recs;
2575 request_rec *sub_req;
2579 if (r->finfo.st_mode != 0 || !(ap_allow_options(r) & OPT_MULTI)) {
2583 neg = parse_accept_headers(r);
2585 if ((res = read_types_multi(neg))) {
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);
2597 if (neg->avail_vars->nelts == 0) {
2601 res = do_negotiation(r, neg, &best,
2602 (r->method_number != M_GET) || r->args ||
2603 (r->path_info && *r->path_info));
2605 goto return_from_multi;
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.
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;
2620 /* BLECH --- don't multi-resolve non-ordinary files */
2622 if (!S_ISREG(sub_req->finfo.st_mode)) {
2624 goto return_from_multi;
2627 /* Otherwise, use it. */
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
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,
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,
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);
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.
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
2678 static int fix_encoding(request_rec *r)
2680 const char *enc = r->content_encoding;
2682 ap_array_header_t *accept_encodings;
2683 accept_rec *accept_recs;
2686 if (!enc || !*enc) {
2690 if (enc[0] == 'x' && enc[1] == '-') {
2694 if ((accept_encodings = do_header_line(r->pool,
2695 ap_table_get(r->headers_in, "Accept-Encoding"))) == NULL) {
2699 accept_recs = (accept_rec *) accept_encodings->elts;
2701 for (i = 0; i < accept_encodings->nelts; ++i) {
2702 char *name = accept_recs[i].name;
2704 if (!strcmp(name, enc)) {
2705 r->content_encoding = name;
2709 if (name[0] == 'x' && name[1] == '-' && !strcmp(name+2, enc)) {
2715 r->content_encoding = x_enc;
2722 static const handler_rec negotiation_handlers[] =
2724 {MAP_FILE_MAGIC_TYPE, handle_map_file},
2725 {"type-map", handle_map_file},
2729 static void register_hooks(void)
2731 ap_hook_fixups(fix_encoding,NULL,NULL,HOOK_MIDDLE);
2732 ap_hook_type_checker(handle_multi,NULL,NULL,HOOK_MIDDLE);
2735 module MODULE_VAR_EXPORT negotiation_module =
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 */