mod_negotiation.c revision 68f0e394246eba4bee73068632a54c9e29b003d3
97a9a944b5887e91042b019776c41d5dd74557aferikabele/* ====================================================================
97a9a944b5887e91042b019776c41d5dd74557aferikabele * The Apache Software License, Version 1.1
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * reserved.
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * Redistribution and use in source and binary forms, with or without
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * modification, are permitted provided that the following conditions
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * are met:
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * 1. Redistributions of source code must retain the above copyright
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * notice, this list of conditions and the following disclaimer.
2e545ce2450a9953665f701bb05350f0d3f26275nd * 2. Redistributions in binary form must reproduce the above copyright
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * notice, this list of conditions and the following disclaimer in
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * the documentation and/or other materials provided with the
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * distribution.
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * 3. The end-user documentation included with the redistribution,
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * if any, must include the following acknowledgment:
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * "This product includes software developed by the
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * Apache Software Foundation (http://www.apache.org/)."
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * Alternately, this acknowledgment may appear in the software itself,
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * if and wherever such third-party acknowledgments normally appear.
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * 4. The names "Apache" and "Apache Software Foundation" must
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * not be used to endorse or promote products derived from this
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * software without prior written permission. For written
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd * permission, please contact apache@apache.org.
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd * 5. Products derived from this software may not be called "Apache",
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * nor may "Apache" appear in their name, without prior written
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd * permission of the Apache Software Foundation.
f3f945b6f394da4d080082fae12da22b4989914and * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
cf663b70eeea0b51582be629e148a697aa2a116eminfrin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
cf663b70eeea0b51582be629e148a697aa2a116eminfrin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
8e0c9984e1432c934dacca53efc92cde30d0fe53rbowen * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
cf663b70eeea0b51582be629e148a697aa2a116eminfrin * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
cf663b70eeea0b51582be629e148a697aa2a116eminfrin * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1acae7fb634ac2b01682507175e072b168995e0dcolm * SUCH DAMAGE.
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * ====================================================================
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * This software consists of voluntary contributions made by many
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * individuals on behalf of the Apache Software Foundation. For more
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * information on the Apache Software Foundation, please see
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * Portions of this software are based upon public domain software
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * originally written at the National Center for Supercomputing Applications,
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * University of Illinois, Urbana-Champaign.
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * mod_negotiation.c: keeps track of MIME types the client is willing to
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * accept, and contains code to handle type arbitration.
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin/* Commands --- configuring document caching on a per (virtual?)
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin * server basis...
4624ec7c743a08f22e90521b97d612c9499ae7efminfrintypedef struct {
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin#define FLP_UNDEF 0 /* Same as FLP_NONE, but base overrides */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin#define FLP_NONE 1 /* Return 406, HTTP_NOT_ACCEPTABLE */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin#define FLP_PREFIX 2 /* Try xx(-.*) from language_priority */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin#define FLP_ANY 4 /* Try anything in language_priority */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin /* If both, tries FLP_PREFIX then FLP_ANY */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrinstatic void *create_neg_dir_config(apr_pool_t *p, char *dummy)
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config));
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin new->language_priority = apr_array_make(p, 4, sizeof(char *));
78f97ce162b66a0dbfd7af4dcd9984f162569b04minfrinstatic void *merge_neg_dir_configs(apr_pool_t *p, void *basev, void *addv)
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin neg_dir_config *new = (neg_dir_config *) apr_palloc(p, sizeof(neg_dir_config));
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin /* give priority to the config in the subdirectory */
4624ec7c743a08f22e90521b97d612c9499ae7efminfrin new->forcelangpriority = add->forcelangpriority ? add->forcelangpriority
0734f81384d5f2528bb119f89d135043a280d5b2minfrin new->language_priority = apr_array_append(p, add->language_priority,
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic const char *set_language_priority(cmd_parms *cmd, void *n,
2aff288113d772cedca6add888eb643afffe9fb1nd const char *lang)
b536777217c919cacb1a6f18eaeff001f3b3f13crbowen apr_array_header_t *arr = ((neg_dir_config *) n)->language_priority;
fe64b2ba25510d8c9dba5560a2d537763566cf40nd const char **langp = (const char **) apr_array_push(arr);
c44eeebd065e2c8cd028016b45c58afb480aaf8fdruggeristatic const char *set_force_priority(cmd_parms *cmd, void *n_, const char *w)
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin return apr_pstrcat(cmd->pool, "Illegal ForceLanguagePriority option ", w, NULL);
8305f030deafc6022193cff1cb11b6f69a2d4f3arbowenstatic const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy,
fe64b2ba25510d8c9dba5560a2d537763566cf40nd ap_set_module_config(cmd->server->module_config, &negotiation_module,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar return (ap_get_module_config(s->module_config, &negotiation_module) != NULL);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar AP_INIT_FLAG("CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "Either 'on' or 'off' (default)"),
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar AP_INIT_ITERATE("LanguagePriority", set_language_priority, NULL, OR_FILEINFO,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "space-delimited list of MIME language abbreviations"),
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar AP_INIT_TAKE1("ForceLanguagePriority", set_force_priority, NULL, OR_FILEINFO,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar "One of 'none', 'prefix', 'any', or 'full'"),
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Record of available info on a media type specified by the client
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * (we also use 'em for encodings and languages)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coartypedef struct accept_rec {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Record of available info on a particular variant
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Note that a few of these fields are updated by the actual negotiation
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * code. These are:
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * level_matched --- initialized to zero. Set to the value of level
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * if the client actually accepts this media type at that
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * level (and *not* if it got in on a wildcard). See level_cmp
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * mime_stars -- initialized to zero. Set to the number of stars
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * present in the best matching Accept header element.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * definite -- initialized to 1. Set to 0 if there is a match which
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * makes the variant non-definite according to the rules
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * in rfc2296.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coartypedef struct var_rec {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar request_rec *sub_req; /* May be NULL (is, for map files) */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *file_name; /* Set to 'this' (for map file body content) */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar apr_array_header_t *content_languages; /* list of languages for this variant */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar const char *description;
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* The next five items give the quality values for the dimensions
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * of negotiation for this variant. They are obtained from the
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * appropriate header lines, except for source_quality, which
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * is obtained from the variant itself (the 'qs' parameter value
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * from the variant's mime-type). Apart from source_quality,
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * these values are set when we find the quality for each variant
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * (see best_match()). source_quality is set from the 'qs' parameter
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * of the variant description or mime type: see set_mime_fields().
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar float lang_quality; /* quality of this variant's language */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar float source_quality; /* source quality for this variant */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Now some special values */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int lang_index; /* pre HTTP/1.1 language priority stuff */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Above are all written-once properties of the variant. The
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * three fields below are changed during negotiation:
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/* Something to carry around the state of negotiation (and to keep
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * all of this thread-safe)...
1f1b6bf13313fdd14a45e52e553d3ff28689b717coartypedef struct {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar float default_lang_quality; /* fiddle lang q for variants with no lang */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* the array pointers below are NULL if the corresponding accept
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * headers are not present
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar apr_array_header_t *accept_encodings; /* accept_recs */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar apr_array_header_t *avail_vars; /* available variants */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int count_multiviews_variants; /* number of variants found on disk */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int is_transparent; /* 1 if this resource is trans. negotiable */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int dont_fiddle_headers; /* 1 if we may not fiddle with accept hdrs */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int ua_supports_trans; /* 1 if ua supports trans negotiation */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int send_alternates; /* 1 if we want to send an Alternates header */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int may_choose; /* 1 if we may choose a variant for the client */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar int use_rvsa; /* 1 if we must use RVSA/1.0 negotiation algo */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/* A few functions to manipulate var_recs.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Cleaning out the fields...
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/* Initializing the relevant fields of a variant record from the
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * accept_info read out of its content-type, one way or another.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic void set_mime_fields(var_rec *var, accept_rec *mime_info)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar var->is_pseudo_html = (!strcmp(var->mime_type, "text/html")
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/* Create a variant list validator in r using info from vlistr. */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic void set_vlist_validator(request_rec *r, request_rec *vlistr)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* Calculating the variant list validator is similar to
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * calculating an etag for the source of the variant list
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * information, so we use ap_make_etag(). Note that this
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * validator can be 'weak' in extreme case.
aaed4ebc116f5862aff2610a809a9a9e9a28f50ecoar /* ap_set_etag will later take r->vlist_validator into account
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * when creating the etag header
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar/*****************************************************************
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * Parsing (lists of) media types and their parameters, as seen in
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * HTTPD header lines and elsewhere.
26ec660d801fc7f7dd96146cea051df0a9b4193eminfrin * Get a single mime type entry --- one media type and parameters;
f3f945b6f394da4d080082fae12da22b4989914and * enter the values we recognize into the argument accept_rec
9e16224e92151e6c142e63ec8e3d06591c61352dndstatic const char *get_entry(apr_pool_t *p, accept_rec *result,
9e16224e92151e6c142e63ec8e3d06591c61352dnd const char *accept_line)
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * Note that this handles what I gather is the "old format",
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * without any compatibility kludges --- if the token after the
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * MIME type begins with a semicolon, we know we're looking at parms,
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * otherwise, we know we aren't. (So why all the pissing and moaning
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * in the CERN server code? I must be missing something).
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen ap_str_tolower(result->name); /* You want case insensitive,
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * you'll *get* case insensitive.
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf /* KLUDGE!!! Default HTML to level 2.0 unless the browser
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * *explicitly* says something else.
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen if (!strcmp(result->name, "text/html") && (result->level == 0.0)) {
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen else if (!strcmp(result->name, INCLUDES_MAGIC_TYPE3)) {
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen /* Parameters ... */
fe64b2ba25510d8c9dba5560a2d537763566cf40nd /* Look for 'var = value' --- and make sure the var is in lcase. */
9ec258b293b038250ec81887da01318ccc350690minfrin for (cp = parm; (*cp && !apr_isspace(*cp) && *cp != '='); ++cp) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive continue; /* No '='; just ignore it. */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar (*end && *end != '\n' && *end != '\r' && *end != '\"');
9ec258b293b038250ec81887da01318ccc350690minfrin for (end = cp; (*end && !apr_isspace(*end)); end++);
8d36abdf61277cb8ffcecc763c8a86c28f11f8e9covener && (parm[1] == '\0' || (parm[1] == 's' && parm[2] == '\0'))) {
4fa837f85f8e371c2f495ac56fe5180fcece130eminfrin/*****************************************************************
4fa837f85f8e371c2f495ac56fe5180fcece130eminfrin * Dealing with header lines ...
4fa837f85f8e371c2f495ac56fe5180fcece130eminfrin * Accept, Accept-Charset, Accept-Language and Accept-Encoding
2aff288113d772cedca6add888eb643afffe9fb1nd * are handled by do_header_line() - they all have the same
9e16224e92151e6c142e63ec8e3d06591c61352dnd * basic structure of a list of items of the format
0734f81384d5f2528bb119f89d135043a280d5b2minfrin * name; q=N; charset=TEXT
0734f81384d5f2528bb119f89d135043a280d5b2minfrin * where charset is only valid in Accept.
9e16224e92151e6c142e63ec8e3d06591c61352dndstatic apr_array_header_t *do_header_line(apr_pool_t *p, const char *accept_line)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive accept_recs = apr_array_make(p, 40, sizeof(accept_rec));
4fa837f85f8e371c2f495ac56fe5180fcece130eminfrin accept_rec *new = (accept_rec *) apr_array_push(accept_recs);
1126fe9569c24b1ef2acb98df6b84d4d7d934c82minfrin/* Given the text of the Content-Languages: line from the var map file,
1126fe9569c24b1ef2acb98df6b84d4d7d934c82minfrin * return an array containing the languages of this variant
17ade6df5ec233536985eb1c130a906c725dd614humbedoohstatic apr_array_header_t *do_languages_line(apr_pool_t *p, const char **lang_line)
595ee65a4fefd1f5df0c6969a5ea88370751f9e4covener apr_array_header_t *lang_recs = apr_array_make(p, 2, sizeof(char *));
17ade6df5ec233536985eb1c130a906c725dd614humbedooh/*****************************************************************
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf * Handling header lines from clients...
89ebbccde2b87b469b9d6fdb606eeb943c12a824colmstatic negotiation_state *parse_accept_headers(request_rec *r)
8d36abdf61277cb8ffcecc763c8a86c28f11f8e9covener (negotiation_state *) apr_pcalloc(r->pool, sizeof(negotiation_state));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen new->dir_name = ap_make_dirstr_parent(r->pool, r->filename);
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen new->accepts = do_header_line(r->pool, apr_table_get(hdrs, "Accept"));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen /* calculate new->accept_q value */
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen do_header_line(r->pool, apr_table_get(hdrs, "Accept-Encoding"));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen do_header_line(r->pool, apr_table_get(hdrs, "Accept-Language"));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen do_header_line(r->pool, apr_table_get(hdrs, "Accept-Charset"));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen /* This is possibly overkill for some servers, heck, we have
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * only 33 index.html variants in docs/docroot (today).
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowen * Make this configurable?
4aa603e6448b99f9371397d439795c91a93637eand new->avail_vars = apr_array_make(r->pool, 40, sizeof(var_rec));
a547340d7d0f0e79c9ba921c7dec7b18d0c800ffrbowenstatic void parse_negotiate_header(request_rec *r, negotiation_state *neg)
fe64b2ba25510d8c9dba5560a2d537763566cf40nd const char *negotiate = apr_table_get(r->headers_in, "Negotiate");
cf2c758d9a7837808846a4bbf5611f268954c79dnd /* First, default to no TCN, no Alternates, and the original Apache
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * negotiation algorithm with fiddles for broken browser configs.
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * To save network bandwidth, we do not configure to send an
f3f945b6f394da4d080082fae12da22b4989914and * Alternates header to the user agent by default. User
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * agents that want an Alternates header for agent-driven
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * negotiation will have to request it by sending an
cf2c758d9a7837808846a4bbf5611f268954c79dnd * appropriate Negotiate header.
cf2c758d9a7837808846a4bbf5611f268954c79dnd /* Lynx 2.7 and 2.8 send 'negotiate: trans' even though they
cf2c758d9a7837808846a4bbf5611f268954c79dnd * do not support transparent content negotiation, so for Lynx we
cf2c758d9a7837808846a4bbf5611f268954c79dnd * ignore the negotiate header when its contents are exactly "trans".
cf2c758d9a7837808846a4bbf5611f268954c79dnd * If future versions of Lynx ever need to say 'negotiate: trans',
cf2c758d9a7837808846a4bbf5611f268954c79dnd * they can send the equivalent 'negotiate: trans, trans' instead
cf2c758d9a7837808846a4bbf5611f268954c79dnd * to avoid triggering the workaround below.
cf2c758d9a7837808846a4bbf5611f268954c79dnd const char *ua = apr_table_get(r->headers_in, "User-Agent");
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak neg->may_choose = 0; /* An empty Negotiate would require 300 response */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak while ((tok = ap_get_list_item(neg->pool, &negotiate)) != NULL) {
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* The user agent supports transparent negotiation */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* Send-alternates could be configurable, but note
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * that it must be 1 if we have 'vlist' in the
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * negotiate header.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* we may use the RVSA/1.0 algorithm, configure for it */
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* we may use any variant selection algorithm, configure
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * to use the Apache algorithm
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak /* We disable header fiddles on the assumption that a
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * client sending Negotiate knows how to send correct
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak * headers which don't need fiddling.
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "dont_fiddle_headers=%d use_rvsa=%d ua_supports_trans=%d "
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak "send_alternates=%d, may_choose=%d",
f21bea4c0f58e17aa1d9a0fac2c219852f89944amaczniak neg->ua_supports_trans, neg->send_alternates, neg->may_choose);
fe64b2ba25510d8c9dba5560a2d537763566cf40nd/* Sometimes clients will give us no Accept info at all; this routine sets
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * up the standard default for that case, and also arranges for us to be
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * willing to run a CGI script if we find one. (In fact, we set up to
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * dramatically prefer CGI scripts in cases where that's appropriate,
fe64b2ba25510d8c9dba5560a2d537763566cf40nd * e.g., POST or when URI includes query args or extra path info).
f3f945b6f394da4d080082fae12da22b4989914andstatic void maybe_add_default_accepts(negotiation_state *neg,
9e16224e92151e6c142e63ec8e3d06591c61352dnd neg->accepts = apr_array_make(neg->pool, 4, sizeof(accept_rec));
9e16224e92151e6c142e63ec8e3d06591c61352dnd new_accept = (accept_rec *) apr_array_push(neg->accepts);
17ade6df5ec233536985eb1c130a906c725dd614humbedooh new_accept = (accept_rec *) apr_array_push(neg->accepts);
90c99eca06310d91254dd3525e1f5e9fa612af71jim/*****************************************************************
90c99eca06310d91254dd3525e1f5e9fa612af71jim * Parsing type-map files, in Roy's meta/http format augmented with
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf * #-comments.
90c99eca06310d91254dd3525e1f5e9fa612af71jim/* Reading RFC822-style header lines, ignoring #-comments and
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf * handling continuations.
282b62d8e9a4edbc2da22ba2d876ec94afc48084ndstatic enum header_state get_header_line(char *buffer, int len, apr_file_t *map)
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd /* Get a noncommented line */
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd if (apr_file_gets(buffer, MAX_STRING_LEN, map) != APR_SUCCESS) {
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd /* If blank, just return it --- this ends information on this variant */
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd /* If non-blank, go looking for header lines, but note that we still
282b62d8e9a4edbc2da22ba2d876ec94afc48084nd * have to treat comments specially...
17ade6df5ec233536985eb1c130a906c725dd614humbedooh /* We need to shortcut the rest of this block following the Body:
20f499565e77defe9dab24dd85c02f38a1175855nd * tag - we will not look for continutation after this line.
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin if (c == '#') {
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin /* Comment line */
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin while (apr_file_getc(&c, map) != APR_EOF && c != '\n') {
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin else if (apr_isspace(c)) {
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin /* Leading whitespace. POSSIBLE continuation line
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin * Also, possibly blank --- if so, we ungetc() the final newline
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin * so that we will pick up the blank line the next time 'round.
4aa603e6448b99f9371397d439795c91a93637eand if (c == '\n') {
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin /* Continuation */
3dd3d010c0efae7d1d6926f0b1de2da17eec796eminfrin while (cp < buf_end - 2 && (apr_file_getc(&c, map)) != APR_EOF && c != '\n') {
fe64b2ba25510d8c9dba5560a2d537763566cf40nd /* Line beginning with something other than whitespace */
9e16224e92151e6c142e63ec8e3d06591c61352dndstatic apr_off_t get_body(char *buffer, apr_size_t *len, const char *tag,
9e16224e92151e6c142e63ec8e3d06591c61352dnd /* We are at the first character following a body:tag\n entry
9e16224e92151e6c142e63ec8e3d06591c61352dnd * Suck in the body, then backspace to the first char after the
9e16224e92151e6c142e63ec8e3d06591c61352dnd * closing tag entry. If we fail to read, find the tag or back
9e16224e92151e6c142e63ec8e3d06591c61352dnd * up then we have a hosed file, so give up already
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin /* Skip all the trailing cruft after the end tag to the next line */
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin if (apr_file_seek(map, APR_CUR, &pos) != APR_SUCCESS) {
17f88acd0b3fba7eddb6fd974927edf8f5dbe41dsf return -1;
4aa603e6448b99f9371397d439795c91a93637eand /* Give the caller back the actual body's offset and length */
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin/* Stripping out RFC822 comments */
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin /* Hmmm... is this correct? In Roy's latest draft, (comments) can nest! */
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin /* Nope, it isn't correct. Fails to handle backslash escape as well. */
c1fcddc76fd5db5ac4ccd7c6ae839d53d128f354minfrin/* Getting to a header body from the header */
17f88acd0b3fba7eddb6fd974927edf8f5dbe41dsfstatic char *lcase_header_name_return_body(char *header, request_rec *r)
fe64b2ba25510d8c9dba5560a2d537763566cf40nd "Syntax error in type map, no ':' in %s for header %s",
17ade6df5ec233536985eb1c130a906c725dd614humbedooh "Syntax error in type map --- no header body: %s for %s",
7ec4d5cc4aa574e3191bc5a612e68fd8f25ab7earpluemstatic int read_type_map(apr_file_t **map, negotiation_state *neg, request_rec *rr)
cf663b70eeea0b51582be629e148a697aa2a116eminfrin /* We are not using multiviews */
cf663b70eeea0b51582be629e148a697aa2a116eminfrin if ((status = apr_file_open(map, rr->filename, APR_READ | APR_BUFFERED,
cf663b70eeea0b51582be629e148a697aa2a116eminfrin hstate = get_header_line(buffer, MAX_STRING_LEN, *map);
cf663b70eeea0b51582be629e148a697aa2a116eminfrin char *body1 = lcase_header_name_return_body(buffer, neg->r);
cf663b70eeea0b51582be629e148a697aa2a116eminfrin const char *body;
17ade6df5ec233536985eb1c130a906c725dd614humbedooh mime_info.file_name = ap_get_token(neg->pool, &body, 0);
cf663b70eeea0b51582be629e148a697aa2a116eminfrin else if (!strncmp(buffer, "content-language:", 17)) {
cf663b70eeea0b51582be629e148a697aa2a116eminfrin mime_info.content_languages = do_languages_line(neg->pool,
e80f65dadea03d04ee5b9e2d3de8c5fcef9e6714minfrin else if (!strncmp(buffer, "content-encoding:", 17)) {
e80f65dadea03d04ee5b9e2d3de8c5fcef9e6714minfrin mime_info.content_encoding = ap_get_token(neg->pool, &body, 0);
e80f65dadea03d04ee5b9e2d3de8c5fcef9e6714minfrin if ((mime_info.body = get_body(buffer, &len, tag, *map)) < 0) {
e80f65dadea03d04ee5b9e2d3de8c5fcef9e6714minfrin ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
8305f030deafc6022193cff1cb11b6f69a2d4f3arbowen "Syntax error in type map, no end tag '%s'"
8305f030deafc6022193cff1cb11b6f69a2d4f3arbowen "found in %s for Body: content.",
8305f030deafc6022193cff1cb11b6f69a2d4f3arbowen memcpy(new_var, (void *) &mime_info, sizeof(var_rec));
26ec660d801fc7f7dd96146cea051df0a9b4193eminfrin/* Sort function used by read_types_multi. */
cf2c758d9a7837808846a4bbf5611f268954c79dnd /* First key is the source quality, sort in descending order. */
cf2c758d9a7837808846a4bbf5611f268954c79dnd /* XXX: note that we currently implement no method of setting the
12a677ce91b7bd5aa918271de5d725635638f4edrbowen * source quality for multiviews variants, so we are always comparing
12a677ce91b7bd5aa918271de5d725635638f4edrbowen * 1.0 to 1.0 for now
cf2c758d9a7837808846a4bbf5611f268954c79dnd /* Second key is the variant name */
cf2c758d9a7837808846a4bbf5611f268954c79dnd/*****************************************************************
cf2c758d9a7837808846a4bbf5611f268954c79dnd * Same as read_type_map, except we use a filtered directory listing
cf2c758d9a7837808846a4bbf5611f268954c79dnd * as the map...
20f499565e77defe9dab24dd85c02f38a1175855nd /* XXX this should be more general, and quit using 'specials' */
cf2c758d9a7837808846a4bbf5611f268954c79dnd if ((status = apr_dir_open(&dirp, neg->dir_name, neg->pool)) != APR_SUCCESS) {
fe64b2ba25510d8c9dba5560a2d537763566cf40nd while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
3e6b8c7840a46cdccd46b7a4b1902c2bc82f6cc2gryzor /* Do we have a match? */
0d0ba3a410038e179b695446bb149cce6264e0abnd /* Ok, something's here. Maybe nothing useful. Remember that
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh * we tried, if we completely fail, so we can reject the request!
727872d18412fc021f03969b8641810d8896820bhumbedooh /* Yep. See if it's something which we have access to, and
0d0ba3a410038e179b695446bb149cce6264e0abnd * which has a known type and encoding (as opposed to something
0d0ba3a410038e179b695446bb149cce6264e0abnd * which we'll be slapping default_type on later).
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen sub_req = ap_sub_req_lookup_dirent(&dirent, r, NULL);
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd /* BLECH --- don't multi-resolve non-ordinary files */
* readme.txt and readme.foo, we will throw away .foo if
if (!exception_list) {
* A test of index.html.foo will match index.foo or index.html.foo,
* but it will never transpose the segments and allow index.foo.html
#ifdef CASE_BLIND_FILESYSTEM
--nexcept;
++cur_except;
if (!saveend)
if (nexcept) {
r->filename);
return HTTP_NOT_FOUND;
set_vlist_validator(r, r);
return OK;
return OK;
int nelts;
char **elts;
if (!lang) {
for (i = 0; i < nelts; ++i) {
char *firstlang;
int idx;
char *lang, *p;
int any_match_on_star = 0;
p = NULL;
alen = 0;
if (!star) {
if (!best ||
if ( any_match_on_star &&
(!best)) ) {
idx = 0;
int prev_mime_stars;
if (star) {
if (star) {
enum algorithm_results {
#ifdef NEG_DEBUG
if (q > bestq) {
*p_bestq = q;
if (q == bestq) {
*p_bestq = q;
int levcmp;
#ifdef NEG_DEBUG
*p_bestq = q;
*p_bestq = q;
*p_bestq = q;
*p_bestq = q;
*p_bestq = q;
*p_bestq = q;
*p_bestq = q;
return algorithm_result;
* example if we have 3 variants x.html, x.ps.en and x.ps.nl, and if
int alg_result)
char *lang;
char *qstr;
char *lenstr;
int vary_by_type = 0;
int vary_by_language = 0;
int vary_by_charset = 0;
int vary_by_encoding = 0;
if (first_variant) {
if (!vary_by_type &&
if (!vary_by_charset &&
if (!vary_by_language &&
if (!vary_by_encoding &&
first_variant = 0;
if (lang) {
const char *sub_vary;
int status;
return status;
return HTTP_VARIANT_ALSO_VARIES;
return HTTP_VARIANT_ALSO_VARIES;
int res;
return HTTP_MULTIPLE_CHOICES;
if (!*bestp) {
return HTTP_NOT_ACCEPTABLE;
* Manual setting of cache-control/expires always overrides this
return OK;
int res;
char *udir;
return DECLINED;
return res;
apr_bucket *e;
return res;
return HTTP_METHOD_NOT_ALLOWED;
return res;
e = apr_bucket_eos_create();
* viewcvs.cgi.xx, all serving the same repository.)
return OK;
int res;
return DECLINED;
return res;
return DECLINED;
if (res != 0)
goto return_from_multi;
goto return_from_multi;
r->mtime = 0;
return OK;
return DECLINED;
return DECLINED;
return OK;
if (x_enc) {
return OK;
return DECLINED;