mod_negotiation.c revision e68becff3c3ddc18723c9799b8cc2e6e9c3dbd66
3802a3d3d7af51ddff31943d5514382f01265770Lennart Poettering/* ====================================================================
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * The Apache Software License, Version 1.1
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Copyright (c) 2000 The Apache Software Foundation. All rights
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Redistribution and use in source and binary forms, with or without
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * modification, are permitted provided that the following conditions
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * 1. Redistributions of source code must retain the above copyright
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * 2. Redistributions in binary form must reproduce the above copyright
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * notice, this list of conditions and the following disclaimer in
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * the documentation and/or other materials provided with the
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * 3. The end-user documentation included with the redistribution,
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * if any, must include the following acknowledgment:
5de0ccffcc4a5a946102a14e0b0e681d964e3225Zbigniew Jędrzejewski-Szmek * "This product includes software developed by the
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Apache Software Foundation (http://www.apache.org/)."
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Alternately, this acknowledgment may appear in the software itself,
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * if and wherever such third-party acknowledgments normally appear.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * 4. The names "Apache" and "Apache Software Foundation" must
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * not be used to endorse or promote products derived from this
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * software without prior written permission. For written
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * permission, please contact apache@apache.org.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * 5. Products derived from this software may not be called "Apache",
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * nor may "Apache" appear in their name, without prior written
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * permission of the Apache Software Foundation.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * ====================================================================
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * This software consists of voluntary contributions made by many
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * individuals on behalf of the Apache Software Foundation. For more
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * information on the Apache Software Foundation, please see
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Portions of this software are based upon public domain software
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * originally written at the National Center for Supercomputing Applications,
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * University of Illinois, Urbana-Champaign.
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * mod_negotiation.c: keeps track of MIME types the client is willing to
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * accept, and contains code to handle type arbitration.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek#define MAP_FILE_MAGIC_TYPE "application/x-type-map"
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek/* Commands --- configuring document caching on a per (virtual?)
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * server basis...
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *language_priority;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringmodule MODULE_VAR_EXPORT negotiation_module;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringstatic void *create_neg_dir_config(ap_pool_t *p, char *dummy)
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering neg_dir_config *new = (neg_dir_config *) ap_palloc(p, sizeof(neg_dir_config));
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering new->language_priority = ap_make_array(p, 4, sizeof(char *));
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringstatic void *merge_neg_dir_configs(ap_pool_t *p, void *basev, void *addv)
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering neg_dir_config *base = (neg_dir_config *) basev;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering neg_dir_config *add = (neg_dir_config *) addv;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering neg_dir_config *new = (neg_dir_config *) ap_palloc(p, sizeof(neg_dir_config));
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering /* give priority to the config in the subdirectory */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering new->language_priority = ap_append_arrays(p, add->language_priority,
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmekstatic const char *set_language_priority(cmd_parms *cmd, void *n, char *lang)
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering ap_array_header_t *arr = ((neg_dir_config *) n)->language_priority;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering char **langp = (char **) ap_push_array(arr);
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmekstatic const char *cache_negotiated_docs(cmd_parms *cmd, void *dummy,
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering void *server_conf = cmd->server->module_config;
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering ap_set_module_config(server_conf, &negotiation_module,
7f3fdb7f19a109fa3d1be92926bfe4cea1817da5Jakub Wilkstatic int do_cache_negotiated_docs(server_rec *s)
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering return (ap_get_module_config(s->module_config, &negotiation_module) != NULL);
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringstatic const command_rec negotiation_cmds[] =
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering {"CacheNegotiatedDocs", cache_negotiated_docs, NULL, RSRC_CONF, FLAG,
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering "Either 'on' or 'off' (default)"},
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering {"LanguagePriority", set_language_priority, NULL, OR_FILEINFO, ITERATE,
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering "space-delimited list of MIME language abbreviations"},
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * Record of available info on a media type specified by the client
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * (we also use 'em for encodings and languages)
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringtypedef struct accept_rec {
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering char *charset; /* for content-type only */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * Record of available info on a particular variant
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * Note that a few of these fields are updated by the actual negotiation
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * code. These are:
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * level_matched --- initialized to zero. Set to the value of level
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * if the client actually accepts this media type at that
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * level (and *not* if it got in on a wildcard). See level_cmp
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * mime_stars -- initialized to zero. Set to the number of stars
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * present in the best matching Accept header element.
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * 1 for star/star, 2 for type/star and 3 for
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * definite -- initialized to 1. Set to 0 if there is a match which
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * makes the variant non-definite according to the rules
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek request_rec *sub_req; /* May be NULL (is, for map files) */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek char *mime_type; /* MUST be lowercase */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *content_languages; /* list of languages for this variant */
cc98b3025eeb89addb76a27390cb2baca4eab8b9Torstein Husebø /* The next five items give the quality values for the dimensions
f131770b1465fbf423881f16ba85523a05f846feVeres Lajos * of negotiation for this variant. They are obtained from the
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * appropriate header lines, except for source_quality, which
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * is obtained from the variant itself (the 'qs' parameter value
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * from the variant's mime-type). Apart from source_quality,
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * these values are set when we find the quality for each variant
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * (see best_match()). source_quality is set from the 'qs' parameter
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * of the variant description or mime type: see set_mime_fields().
8474b70c3a3842cdf3d51f331dd117ab6421f6d0Zbigniew Jędrzejewski-Szmek float lang_quality; /* quality of this variant's language */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek float encoding_quality; /* ditto encoding */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering float mime_type_quality; /* ditto media type */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek float source_quality; /* source quality for this variant */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek /* Now some special values */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek float level; /* Auxiliary to content-type... */
8474b70c3a3842cdf3d51f331dd117ab6421f6d0Zbigniew Jędrzejewski-Szmek float bytes; /* content length, if known */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int lang_index; /* pre HTTP/1.1 language priority stuff */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int is_pseudo_html; /* text/html, *or* the INCLUDES_MAGIC_TYPEs */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek /* Above are all written-once properties of the variant. The
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * three fields below are changed during negotiation:
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering/* Something to carry around the state of negotiation (and to keep
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering * all of this thread-safe)...
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poetteringtypedef struct {
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int accept_q; /* 1 if an Accept item has a q= param */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering float default_lang_quality; /* fiddle lang q for variants with no lang */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek /* the array pointers below are NULL if the corresponding accept
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek * headers are not present
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *accepts; /* accept_recs */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *accept_encodings; /* accept_recs */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *accept_charsets; /* accept_recs */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek ap_array_header_t *accept_langs; /* accept_recs */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering ap_array_header_t *avail_vars; /* available variants */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int count_multiviews_variants; /* number of variants found on disk */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering int is_transparent; /* 1 if this resource is trans. negotiable */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering int dont_fiddle_headers; /* 1 if we may not fiddle with accept hdrs */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering int ua_supports_trans; /* 1 if ua supports trans negotiation */
dc83f27a7cf03757dec11a69ec18504ad4ea8f89Lennart Poettering int send_alternates; /* 1 if we want to send an Alternates header */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int may_choose; /* 1 if we may choose a variant for the client */
edf2573743b25273bee020230a60f1a054b8ec60Zbigniew Jędrzejewski-Szmek int use_rvsa; /* 1 if we must use RVSA/1.0 negotiation algo */
const char *accept_line)
char *parm;
char *cp;
char *end;
++accept_line;
if (!*cp) {
++cp;
++cp;
end++);
if (*end) {
++accept_line;
return accept_line;
if (!accept_line) {
return NULL;
while (*accept_line) {
return accept_recs;
if (!lang_line) {
return lang_recs;
while (**lang_line) {
++(*lang_line);
return lang_recs;
new->r = r;
return new;
char *tok;
if (!negotiate)
#ifdef NEG_DEBUG
int prefer_scripts)
enum header_state {
char *cp;
return header_eof;
return header_sep;
else if (ap_isspace(c)) {
*cp++ = c;
return header_seen;
return header_seen;
while (*hdr) {
++hdr;
if (*hdr) {
++hdr;
if (!*cp) {
return NULL;
++cp;
if (!*cp) {
r->filename);
return NULL;
return cp;
int has_content;
return HTTP_FORBIDDEN;
has_content = 0;
const char *body;
return SERVER_ERROR;
&body);
char *cp;
has_content = 0;
return OK;
char *filp;
int prefix_len;
void *new_var;
return DECLINED;
++filp;
return HTTP_FORBIDDEN;
char *d_name;
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;
long len;
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 VARIANT_ALSO_VARIES;
return VARIANT_ALSO_VARIES;
int res;
return MULTIPLE_CHOICES;
if (!*bestp) {
return NOT_ACCEPTABLE;
* Manual setting of cache-control/expires always overrides this
return OK;
int res;
char *udir;
return res;
return OK;
int res;
return DECLINED;
return res;
return DECLINED;
if (res != 0)
goto return_from_multi;
goto return_from_multi;
goto return_from_multi;
r->headers_out);
r->err_headers_out);
r->subprocess_env);
return OK;
return DECLINED;
return DECLINED;
return OK;
if (x_enc) {
return OK;
return DECLINED;
{NULL}
static void register_hooks(void)