mod_mime.c revision 50e228f0b8429c27e411611f4863fafaba403b47
f743002678eb67b99bbc29fee116b65d9530fec0wrowe/* ====================================================================
80833bb9a1bf25dcf19e814438a4b311d2e1f4cffuankg * The Apache Software License, Version 1.1
cc5a4a08dc9783fcbc52ce86f11e01c281a43810minfrin *
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * reserved.
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza *
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * Redistribution and use in source and binary forms, with or without
56589be3d7a3e9343370df240010c6928cc78b39jkaluza * modification, are permitted provided that the following conditions
56589be3d7a3e9343370df240010c6928cc78b39jkaluza * are met:
56589be3d7a3e9343370df240010c6928cc78b39jkaluza *
8c4967445b49a1612b3f98c1dada65e597ecfe26trawick * 1. Redistributions of source code must retain the above copyright
8c4967445b49a1612b3f98c1dada65e597ecfe26trawick * notice, this list of conditions and the following disclaimer.
8c4967445b49a1612b3f98c1dada65e597ecfe26trawick *
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * 2. Redistributions in binary form must reproduce the above copyright
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * notice, this list of conditions and the following disclaimer in
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * the documentation and/or other materials provided with the
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * distribution.
6001d914962deabb83a46251001612e969bdf67ajim *
6001d914962deabb83a46251001612e969bdf67ajim * 3. The end-user documentation included with the redistribution,
6001d914962deabb83a46251001612e969bdf67ajim * if any, must include the following acknowledgment:
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * "This product includes software developed by the
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * Apache Software Foundation (http://www.apache.org/)."
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * Alternately, this acknowledgment may appear in the software itself,
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * if and wherever such third-party acknowledgments normally appear.
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener *
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * 4. The names "Apache" and "Apache Software Foundation" must
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * not be used to endorse or promote products derived from this
f4db898517ccc6ef1a403630de56918286d3a47eminfrin * software without prior written permission. For written
f4db898517ccc6ef1a403630de56918286d3a47eminfrin * permission, please contact apache@apache.org.
f4db898517ccc6ef1a403630de56918286d3a47eminfrin *
28a723b775c7666281298eab813c63ac42270f95humbedooh * 5. Products derived from this software may not be called "Apache",
28a723b775c7666281298eab813c63ac42270f95humbedooh * nor may "Apache" appear in their name, without prior written
28a723b775c7666281298eab813c63ac42270f95humbedooh * permission of the Apache Software Foundation.
067698ad30941e38ef5d7f95f1c2736c2ebc5cb9humbedooh *
067698ad30941e38ef5d7f95f1c2736c2ebc5cb9humbedooh * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
067698ad30941e38ef5d7f95f1c2736c2ebc5cb9humbedooh * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
7a437ce535a5fac890296402ba483c2f41bb6500trawick * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7a437ce535a5fac890296402ba483c2f41bb6500trawick * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
7a437ce535a5fac890296402ba483c2f41bb6500trawick * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d8a6de5eec06d4136839c8f7a56a6ab5acd2d3behumbedooh * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6e1e45624d6f32110383bb0bd06c254c1dba8123humbedooh * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
921d32d80d8271da08f12fc374a69cb36d1d63b3covener * SUCH DAMAGE.
921d32d80d8271da08f12fc374a69cb36d1d63b3covener * ====================================================================
921d32d80d8271da08f12fc374a69cb36d1d63b3covener *
3e097af23e40c45aa32602545155f0964ab5c69dcovener * This software consists of voluntary contributions made by many
3e097af23e40c45aa32602545155f0964ab5c69dcovener * individuals on behalf of the Apache Software Foundation. For more
3e097af23e40c45aa32602545155f0964ab5c69dcovener * information on the Apache Software Foundation, please see
faea99bb676ec50ece38da6b1879aa37546483a2covener * <http://www.apache.org/>.
faea99bb676ec50ece38da6b1879aa37546483a2covener *
faea99bb676ec50ece38da6b1879aa37546483a2covener * Portions of this software are based upon public domain software
86a5604df726638a2b8085e993b4b79c4b3a5262covener * originally written at the National Center for Supercomputing Applications,
faea99bb676ec50ece38da6b1879aa37546483a2covener * University of Illinois, Urbana-Champaign.
344f755169e100ea8ce51e847a0bf30a13b46917covener */
344f755169e100ea8ce51e847a0bf30a13b46917covener
344f755169e100ea8ce51e847a0bf30a13b46917covener/*
fcd5c4e9e126e867eb270ed2d4138348cb1e46e5trawick * http_mime.c: Sends/gets MIME headers for requests
fcd5c4e9e126e867eb270ed2d4138348cb1e46e5trawick *
fcd5c4e9e126e867eb270ed2d4138348cb1e46e5trawick * Rob McCool
50cfe8bbbaf4279375802531268e2bf0155215fetrawick *
50cfe8bbbaf4279375802531268e2bf0155215fetrawick */
50cfe8bbbaf4279375802531268e2bf0155215fetrawick
50cfe8bbbaf4279375802531268e2bf0155215fetrawick#include "apr.h"
5cb0075c38fc868730c4981e346845dad6c7ea58chrisd#include "apr_strings.h"
5cb0075c38fc868730c4981e346845dad6c7ea58chrisd#include "apr_lib.h"
5cb0075c38fc868730c4981e346845dad6c7ea58chrisd#include "apr_hash.h"
5cb0075c38fc868730c4981e346845dad6c7ea58chrisd
ffaa9771884a8664f0e6267efbe9d26b40000461trawick#define APR_WANT_STRFUNC
ffaa9771884a8664f0e6267efbe9d26b40000461trawick#include "apr_want.h"
ffaa9771884a8664f0e6267efbe9d26b40000461trawick
ffaa9771884a8664f0e6267efbe9d26b40000461trawick#include "ap_config.h"
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick#include "httpd.h"
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick#include "http_config.h"
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick#include "http_log.h"
4d12805e6c18253040223ea637acd6b3b3c18f60jorton#include "http_request.h"
4d12805e6c18253040223ea637acd6b3b3c18f60jorton
4d12805e6c18253040223ea637acd6b3b3c18f60jorton
4d12805e6c18253040223ea637acd6b3b3c18f60jorton/* XXXX - fix me / EBCDIC
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * there was a cludge here which would use its
e5d909f2b06bd880fb3675cd49363df981caa631trawick * own version apr_isascii(). Indicating that
a4df2cd1e1391575a327c2a90ba4315f805a0a78covener * on some platforms that might be needed.
a4df2cd1e1391575a327c2a90ba4315f805a0a78covener *
a4df2cd1e1391575a327c2a90ba4315f805a0a78covener * #define OS_ASC(c) (c) -- for mere mortals
cb666b29f81df1d11d65002250153353568021fccovener * or
cb666b29f81df1d11d65002250153353568021fccovener * #define OS_ASC(c) (ebcdic2ascii[c]) -- for dino's
cb666b29f81df1d11d65002250153353568021fccovener *
6a80c3c6f4b8ea7ba5e89402b8b779b09ce020e0covener * #define apr_isascii(c) ((OS_ASC(c) & 0x80) == 0)
1c2cab00d988fc48cbe59032cf76cc0bab20d6f7covener */
6a80c3c6f4b8ea7ba5e89402b8b779b09ce020e0covener
75a230a728338d84dcfe81edd375352f34de22d0covener/* XXXXX - fix me - See note with NOT_PROXY
75a230a728338d84dcfe81edd375352f34de22d0covener */
75a230a728338d84dcfe81edd375352f34de22d0covener
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covenertypedef struct attrib_info {
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener char *name;
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener} attrib_info;
63a5ea80bddcc84a462e40f402b4f330e0e05411covener
63a5ea80bddcc84a462e40f402b4f330e0e05411covener/* Information to which an extension can be mapped
63a5ea80bddcc84a462e40f402b4f330e0e05411covener */
63a5ea80bddcc84a462e40f402b4f330e0e05411covenertypedef struct extension_info {
986f3ea2c314d4d4b3b937149853a0f23f6119aaminfrin char *forced_type; /* Additional AddTyped stuff */
986f3ea2c314d4d4b3b937149853a0f23f6119aaminfrin char *encoding_type; /* Added with AddEncoding... */
986f3ea2c314d4d4b3b937149853a0f23f6119aaminfrin char *language_type; /* Added with AddLanguage... */
65a4e663b82f8bce28ac22ab2edfd7502de36998sf char *handler; /* Added with AddHandler... */
65a4e663b82f8bce28ac22ab2edfd7502de36998sf char *charset_type; /* Added with AddCharset... */
65a4e663b82f8bce28ac22ab2edfd7502de36998sf} extension_info;
65a4e663b82f8bce28ac22ab2edfd7502de36998sf
c7de1955eb0eaeabf7042902476397692672d549sftypedef struct {
509622419be000045d461ef38fb97df778fdf81djailletc apr_hash_t *extension_mappings; /* Map from extension name to
509622419be000045d461ef38fb97df778fdf81djailletc * extension_info structure */
509622419be000045d461ef38fb97df778fdf81djailletc
509622419be000045d461ef38fb97df778fdf81djailletc apr_array_header_t *charsets_remove; /* List of charsets to remove */
0b9de55d178312ec929dbe417dd61199b269991djailletc apr_array_header_t *encodings_remove; /* List of encodings to remove */
0b9de55d178312ec929dbe417dd61199b269991djailletc apr_array_header_t *handlers_remove; /* List of handlers to remove */
0b9de55d178312ec929dbe417dd61199b269991djailletc apr_array_header_t *languages_remove; /* List of languages to remove */
0b9de55d178312ec929dbe417dd61199b269991djailletc apr_array_header_t *types_remove; /* List of MIME types to remove */
74e7f6c55fd67b10cb400b3f6d1dc718a303d944minfrin
74e7f6c55fd67b10cb400b3f6d1dc718a303d944minfrin char *type; /* Type forced with ForceType */
74e7f6c55fd67b10cb400b3f6d1dc718a303d944minfrin char *handler; /* Handler forced with SetHandler */
74e7f6c55fd67b10cb400b3f6d1dc718a303d944minfrin char *default_language; /* Language if no AddLanguage ext found */
a511a29faf2ff7ead3b67680154a624effb31aafminfrin /* Due to the FUD about JS and charsets
a511a29faf2ff7ead3b67680154a624effb31aafminfrin * default_charset is actually in src/main */
a511a29faf2ff7ead3b67680154a624effb31aafminfrin} mime_dir_config;
a511a29faf2ff7ead3b67680154a624effb31aafminfrin
a511a29faf2ff7ead3b67680154a624effb31aafminfrintypedef struct param_s {
63921358ef93fcb41bc71d9894221ba3d7fbb87bminfrin char *attr;
63921358ef93fcb41bc71d9894221ba3d7fbb87bminfrin char *val;
63921358ef93fcb41bc71d9894221ba3d7fbb87bminfrin struct param_s *next;
deec48c67d4786bc77112ffbf3a4e70b931097edminfrin} param;
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrin
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrintypedef struct {
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrin char *type;
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrin char *subtype;
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esf param *param;
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esf} content_type;
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esf
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esfstatic char tspecial[] = {
2c487ac43b583db869e743772a7a10b278aa2bcfminfrin '(', ')', '<', '>', '@', ',', ';', ':',
684e0cfc200f66287a93bbd1708d1dd8a92a7eefcovener '\\', '"', '/', '[', ']', '?', '=',
684e0cfc200f66287a93bbd1708d1dd8a92a7eefcovener '\0'
5c43d2fb853f84497b5ece2d414ef9484aa87e5fsf};
05a5a9c3e16f21566e1b61f4bd68025ce1b741ccjoes
05a5a9c3e16f21566e1b61f4bd68025ce1b741ccjoesmodule AP_MODULE_DECLARE_DATA mime_module;
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq
26c5829347f6a355c00f1ba0301d575056b69536niqstatic void *create_mime_dir_config(apr_pool_t *p, char *dummy)
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq{
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq mime_dir_config *new =
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config));
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq new->extension_mappings = NULL;
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq
413ee814748f37be168ff12407fa6dba0ceeabe6trawick new->charsets_remove = NULL;
c12917da693bae4028a1d5a5e8224bceed8c739dsf new->encodings_remove = NULL;
c12917da693bae4028a1d5a5e8224bceed8c739dsf new->handlers_remove = NULL;
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf new->languages_remove = NULL;
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf new->types_remove = NULL;
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf new->type = NULL;
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf new->handler = NULL;
d7ffd2da16d58b1a0de212e4d56f7aebb72bef26sf new->default_language = NULL;
d7ffd2da16d58b1a0de212e4d56f7aebb72bef26sf
d7ffd2da16d58b1a0de212e4d56f7aebb72bef26sf return new;
4576c1a9ef54cd1e5555ee07d016a7f559f80338sf}
4576c1a9ef54cd1e5555ee07d016a7f559f80338sf/*
4576c1a9ef54cd1e5555ee07d016a7f559f80338sf * Overlay one hash table of extension_mappings onto another
9811aed12bbc71783d2e544ccb5fecd193843eadsf */
9811aed12bbc71783d2e544ccb5fecd193843eadsfstatic void overlay_extension_mappings(apr_pool_t *p,
9811aed12bbc71783d2e544ccb5fecd193843eadsf apr_hash_t *overlay, apr_hash_t *base)
1366443dc565c33e7b449ae428bbfc4c86f33935drh{
1366443dc565c33e7b449ae428bbfc4c86f33935drh apr_hash_index_t *index;
88fac54d9d64f85bbdab5d7010816f4377f95bd7rjung for (index = apr_hash_first(p, overlay); index;
88fac54d9d64f85bbdab5d7010816f4377f95bd7rjung index = apr_hash_next(index)) {
bd3f5647b96d378d9c75c954e3f13582af32c643sf char *key;
bd3f5647b96d378d9c75c954e3f13582af32c643sf apr_ssize_t klen;
bd3f5647b96d378d9c75c954e3f13582af32c643sf extension_info *overlay_info, *base_info;
bd3f5647b96d378d9c75c954e3f13582af32c643sf
bd3f5647b96d378d9c75c954e3f13582af32c643sf apr_hash_this(index, (const void**)&key, &klen, (void**)&overlay_info);
2a7beea91d46beb41f043a84eaad060047ee04aafabien
2a7beea91d46beb41f043a84eaad060047ee04aafabien base_info = (extension_info*)apr_hash_get(base, key, klen);
2a7beea91d46beb41f043a84eaad060047ee04aafabien
2a7beea91d46beb41f043a84eaad060047ee04aafabien if (base_info) {
584a85dd4047e38d3ed3a29b6662fcc9d100ae4csf extension_info *copyinfo = base_info;
584a85dd4047e38d3ed3a29b6662fcc9d100ae4csf base_info = (extension_info*)apr_palloc(p, sizeof(*base_info));
584a85dd4047e38d3ed3a29b6662fcc9d100ae4csf apr_hash_set(base, key, klen, base_info);
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sf memcpy(base_info, copyinfo, sizeof(*base_info));
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sf
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sf if (overlay_info->forced_type) {
f6b9c755a0b793e8a3a3aebd327ca20a86478117sf base_info->forced_type = overlay_info->forced_type;
f6b9c755a0b793e8a3a3aebd327ca20a86478117sf }
f6b9c755a0b793e8a3a3aebd327ca20a86478117sf if (overlay_info->encoding_type) {
132ee6ac1c26d6e8953836316ba50734eefab47bsf base_info->encoding_type = overlay_info->encoding_type;
132ee6ac1c26d6e8953836316ba50734eefab47bsf }
132ee6ac1c26d6e8953836316ba50734eefab47bsf if (overlay_info->language_type) {
85eacfc96a04547ef25aabbc06440039715084c2jorton base_info->language_type = overlay_info->language_type;
85eacfc96a04547ef25aabbc06440039715084c2jorton }
85eacfc96a04547ef25aabbc06440039715084c2jorton if (overlay_info->handler) {
536d2e7cd1fdec1255b8c3bdf41fdc714c506a54trawick base_info->handler = overlay_info->handler;
536d2e7cd1fdec1255b8c3bdf41fdc714c506a54trawick }
536d2e7cd1fdec1255b8c3bdf41fdc714c506a54trawick if (overlay_info->charset_type) {
536d2e7cd1fdec1255b8c3bdf41fdc714c506a54trawick base_info->charset_type = overlay_info->charset_type;
70caa242e6b90e0d6f0fabb56b8c5c2fb51717b3jorton }
985a4368b93c3e9171a57897ad9454c8dbf4cdf6jorton }
70caa242e6b90e0d6f0fabb56b8c5c2fb51717b3jorton else {
70caa242e6b90e0d6f0fabb56b8c5c2fb51717b3jorton apr_hash_set(base, key, klen, overlay_info);
79c5787b92ac5f0e1cc82393816c77a006399316trawick }
79c5787b92ac5f0e1cc82393816c77a006399316trawick }
79c5787b92ac5f0e1cc82393816c77a006399316trawick}
79c5787b92ac5f0e1cc82393816c77a006399316trawick
c967bf3bc89e8aa60dbd30d9da388e448ddc1cc4trawick/* Member is the offset within an extension_info of the pointer to reset
79c5787b92ac5f0e1cc82393816c77a006399316trawick */
79c5787b92ac5f0e1cc82393816c77a006399316trawickstatic void remove_items(apr_pool_t *p, apr_array_header_t *remove,
79c5787b92ac5f0e1cc82393816c77a006399316trawick apr_hash_t *mappings, void *member)
79c5787b92ac5f0e1cc82393816c77a006399316trawick{
79c5787b92ac5f0e1cc82393816c77a006399316trawick attrib_info *suffix = (attrib_info *) remove->elts;
7b395e4e878c28a4784919cfd2e704ddd14a3390jorton int i;
7b395e4e878c28a4784919cfd2e704ddd14a3390jorton for (i = 0; i < remove->nelts; i++) {
7b395e4e878c28a4784919cfd2e704ddd14a3390jorton extension_info *exinfo =
7b395e4e878c28a4784919cfd2e704ddd14a3390jorton (extension_info*)apr_hash_get(mappings,
536e48c08d674acac5d44929318f2ad928edc361jorton suffix[i].name,
536e48c08d674acac5d44929318f2ad928edc361jorton APR_HASH_KEY_STRING);
e81785da447b469da66f218b3f0244aab507958djorton if (exinfo && *((void **)((char*)&exinfo + (apr_size_t)member))) {
e81785da447b469da66f218b3f0244aab507958djorton extension_info *copyinfo = exinfo;
3e4e54d4e3fc0123c63d57aa84ac7ad7a8c73ff8jorton exinfo = (extension_info*)apr_palloc(p, sizeof(*exinfo));
3e4e54d4e3fc0123c63d57aa84ac7ad7a8c73ff8jorton apr_hash_set(mappings, suffix[i].name,
3e4e54d4e3fc0123c63d57aa84ac7ad7a8c73ff8jorton APR_HASH_KEY_STRING, exinfo);
53e9b27aba029b18be814df40bcf6f0428771d1efuankg memcpy(exinfo, copyinfo, sizeof(*exinfo));
53e9b27aba029b18be814df40bcf6f0428771d1efuankg *(void **)((char*)exinfo + (apr_size_t)member) = NULL;
53e9b27aba029b18be814df40bcf6f0428771d1efuankg }
53e9b27aba029b18be814df40bcf6f0428771d1efuankg }
53e9b27aba029b18be814df40bcf6f0428771d1efuankg}
6bb524f1895f30265a1431afc460977d391cb36bsf
6bb524f1895f30265a1431afc460977d391cb36bsfstatic void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
ca61ccd0c306c2c72df153688ba1b49f3eceed80sf{
6bb524f1895f30265a1431afc460977d391cb36bsf mime_dir_config *base = (mime_dir_config *) basev;
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrin mime_dir_config *add = (mime_dir_config *) addv;
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrin mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrin
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrin if (base->extension_mappings && add->extension_mappings) {
23f1535d6a60817d2846bac0aea230ea475d7dccminfrin new->extension_mappings = apr_hash_make(p);
23f1535d6a60817d2846bac0aea230ea475d7dccminfrin overlay_extension_mappings(p, base->extension_mappings,
23f1535d6a60817d2846bac0aea230ea475d7dccminfrin new->extension_mappings);
23f1535d6a60817d2846bac0aea230ea475d7dccminfrin overlay_extension_mappings(p, add->extension_mappings,
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung new->extension_mappings);
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung }
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung else {
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung if (base->extension_mappings == NULL) {
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung new->extension_mappings = add->extension_mappings;
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung }
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung else {
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung new->extension_mappings = base->extension_mappings;
6249dfa569d3b4f1f539665b979a80c6e335d93etrawick }
6249dfa569d3b4f1f539665b979a80c6e335d93etrawick if (new->extension_mappings && (add->handlers_remove
0827cb14e550f6f65018431c22c2c913631c8f25kbrand || add->types_remove
6249dfa569d3b4f1f539665b979a80c6e335d93etrawick || add->encodings_remove)) {
ae600ca541efc686b34f8b1f21bd3d0741d37674covener apr_hash_t *copyhash = new->extension_mappings;
6249dfa569d3b4f1f539665b979a80c6e335d93etrawick new->extension_mappings = apr_hash_make(p);
cfa64348224b66dd1c9979b809406c4d15b1c137fielding overlay_extension_mappings(p, copyhash, new->extension_mappings);
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim }
cfa64348224b66dd1c9979b809406c4d15b1c137fielding }
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim
cfa64348224b66dd1c9979b809406c4d15b1c137fielding if (new->extension_mappings) {
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim if (add->charsets_remove)
cfa64348224b66dd1c9979b809406c4d15b1c137fielding remove_items(p, add->charsets_remove, new->extension_mappings,
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim &(*(extension_info*)NULL).charset_type);
cfa64348224b66dd1c9979b809406c4d15b1c137fielding
if (add->encodings_remove)
remove_items(p, add->encodings_remove, new->extension_mappings,
&(*(extension_info*)NULL).encoding_type);
if (add->languages_remove)
remove_items(p, add->languages_remove, new->extension_mappings,
&(*(extension_info*)NULL).language_type);
if (add->handlers_remove)
remove_items(p, add->handlers_remove, new->extension_mappings,
&(*(extension_info*)NULL).handler);
if (add->types_remove)
remove_items(p, add->types_remove, new->extension_mappings,
&(*(extension_info*)NULL).forced_type);
}
new->charsets_remove = NULL;
new->encodings_remove = NULL;
new->handlers_remove = NULL;
new->languages_remove = NULL;
new->types_remove = NULL;
new->type = add->type ? add->type : base->type;
new->handler = add->handler ? add->handler : base->handler;
new->default_language = add->default_language ?
add->default_language : base->default_language;
return new;
}
static extension_info *add_extension_info(cmd_parms *cmd, void *m_,
const char* ext)
{
mime_dir_config *m=m_;
extension_info *exinfo;
char *key = apr_pstrdup(cmd->temp_pool, ext);
#ifdef CASE_BLIND_FILESYSTEM
ap_str_tolower(key);
#endif
if (*key == '.')
++key;
if (!m->extension_mappings) {
m->extension_mappings = apr_hash_make(cmd->pool);
exinfo = NULL;
}
else
exinfo = (extension_info*)apr_hash_get(m->extension_mappings, key,
APR_HASH_KEY_STRING);
if (!exinfo) {
exinfo = apr_pcalloc(cmd->pool, sizeof(extension_info));
key = apr_pstrdup(cmd->pool, key);
apr_hash_set(m->extension_mappings, key,
APR_HASH_KEY_STRING, exinfo);
}
return exinfo;
}
static const char *add_charset(cmd_parms *cmd, void *m, const char *value,
const char *ext)
{
extension_info* exinfo = add_extension_info(cmd, m, ext);
char *charset = apr_pstrdup(cmd->pool, value);
ap_str_tolower(charset);
exinfo->charset_type = charset;
return NULL;
}
static const char *add_encoding(cmd_parms *cmd, void *m, const char *value,
const char *ext)
{
extension_info* exinfo = add_extension_info(cmd, m, ext);
char *enc = apr_pstrdup(cmd->pool, value);
ap_str_tolower(enc);
exinfo->encoding_type = enc;
return NULL;
}
static const char *add_handler(cmd_parms *cmd, void *m, const char *value,
const char *ext)
{
extension_info* exinfo = add_extension_info(cmd, m, ext);
char *hdlr = apr_pstrdup(cmd->pool, value);
ap_str_tolower(hdlr);
exinfo->handler = hdlr;
return NULL;
}
static const char *add_language(cmd_parms *cmd, void *m, const char *value,
const char *ext)
{
extension_info* exinfo = add_extension_info(cmd, m, ext);
char *lang = apr_pstrdup(cmd->pool, value);
ap_str_tolower(lang);
exinfo->language_type = lang;
return NULL;
}
static const char *add_type(cmd_parms *cmd, void *m, const char *value,
const char *ext)
{
extension_info* exinfo = add_extension_info(cmd, m, ext);
char *ct = apr_pstrdup(cmd->pool, value);
ap_str_tolower(ct);
exinfo->forced_type = ct;
return NULL;
}
/*
* Note handler names that should be un-added for this location. This
* will keep the association from being inherited, as well, but not
* from being re-added at a subordinate level.
*/
static void remove_extension_info(cmd_parms *cmd,
apr_array_header_t **m_array,
const char* ext)
{
attrib_info *suffix;
if (*ext == '.')
++ext;
if (*m_array == NULL) {
*m_array = apr_array_make(cmd->pool, 4, sizeof(*suffix));
}
suffix = (attrib_info *) apr_array_push(*m_array);
suffix->name = apr_pstrdup(cmd->pool, ext);
#ifdef CASE_BLIND_FILESYSTEM
ap_str_tolower(suffix->name);
#endif
}
static const char *remove_charset(cmd_parms *cmd, void *m_, const char *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
remove_extension_info(cmd, &m->charsets_remove, ext);
return NULL;
}
static const char *remove_encoding(cmd_parms *cmd, void *m_, const char *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
remove_extension_info(cmd, &m->encodings_remove, ext);
return NULL;
}
static const char *remove_handler(cmd_parms *cmd, void *m_, const char *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
remove_extension_info(cmd, &m->handlers_remove, ext);
return NULL;
}
static const char *remove_language(cmd_parms *cmd, void *m_, const char *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
remove_extension_info(cmd, &m->languages_remove, ext);
return NULL;
}
static const char *remove_type(cmd_parms *cmd, void *m_, const char *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
remove_extension_info(cmd, &m->types_remove, ext);
return NULL;
}
/* The sole bit of server configuration that the MIME module has is
* the name of its config file, so...
*/
static const char *set_types_config(cmd_parms *cmd, void *dummy,
const char *arg)
{
ap_set_module_config(cmd->server->module_config, &mime_module,
(void *)arg);
return NULL;
}
static const command_rec mime_cmds[] =
{
AP_INIT_ITERATE2("AddCharset", add_charset, NULL, OR_FILEINFO,
"a charset (e.g., iso-2022-jp), followed by one or more file extensions"),
AP_INIT_ITERATE2("AddEncoding", add_encoding, NULL, OR_FILEINFO,
"an encoding (e.g., gzip), followed by one or more file extensions"),
AP_INIT_ITERATE2("AddHandler", add_handler, NULL, OR_FILEINFO,
"a handler name followed by one or more file extensions"),
AP_INIT_ITERATE2("AddLanguage", add_language, NULL, OR_FILEINFO,
"a language (e.g., fr), followed by one or more file extensions"),
AP_INIT_ITERATE2("AddType", add_type, NULL, OR_FILEINFO,
"a mime type followed by one or more file extensions"),
AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot,
(void*)XtOffsetOf(mime_dir_config, default_language), OR_FILEINFO,
"language to use for documents with no other language file extension"),
AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
(void *)XtOffsetOf(mime_dir_config, type), OR_FILEINFO,
"a media type"),
AP_INIT_ITERATE("RemoveCharset", remove_charset, NULL, OR_FILEINFO,
"one or more file extensions"),
AP_INIT_ITERATE("RemoveEncoding", remove_encoding, NULL, OR_FILEINFO,
"one or more file extensions"),
AP_INIT_ITERATE("RemoveHandler", remove_handler, NULL, OR_FILEINFO,
"one or more file extensions"),
AP_INIT_ITERATE("RemoveLanguage", remove_language, NULL, OR_FILEINFO,
"one or more file extensions"),
AP_INIT_ITERATE("RemoveType", remove_type, NULL, OR_FILEINFO,
"one or more file extensions"),
AP_INIT_TAKE1("SetHandler", ap_set_string_slot_lower,
(void *)XtOffsetOf(mime_dir_config, handler), OR_FILEINFO,
"a handler name"),
AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF,
"the MIME types config file"),
{NULL}
};
static apr_hash_t *mime_type_extensions;
static void mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
ap_configfile_t *f;
char l[MAX_STRING_LEN];
const char *types_confname = ap_get_module_config(s->module_config, &mime_module);
apr_status_t status;
if (!types_confname)
types_confname = AP_TYPES_CONFIG_FILE;
types_confname = ap_server_root_relative(p, types_confname);
if ((status = ap_pcfg_openfile(&f, ptemp, types_confname)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
"could not open mime types config file %s.", types_confname);
exit(1);
}
mime_type_extensions = apr_hash_make(p);
while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
const char *ll = l, *ct;
if (l[0] == '#')
continue;
ct = ap_getword_conf(p, &ll);
while (ll[0]) {
char *ext = ap_getword_conf(p, &ll);
ap_str_tolower(ext); /* ??? */
apr_hash_set(mime_type_extensions, ext, APR_HASH_KEY_STRING, ct);
}
}
ap_cfg_closefile(f);
}
static char *zap_sp(char *s)
{
char *tp;
if (s == NULL) {
return (NULL);
}
if (*s == '\0') {
return (s);
}
/* delete prefixed white space */
for (; *s == ' ' || *s == '\t' || *s == '\n'; s++);
/* delete postfixed white space */
for (tp = s; *tp != '\0'; tp++);
for (tp--; tp != s && (*tp == ' ' || *tp == '\t' || *tp == '\n'); tp--) {
*tp = '\0';
}
return (s);
}
static int is_token(char c)
{
int res;
res = (apr_isascii(c) && apr_isgraph(c)
&& (strchr(tspecial, c) == NULL)) ? 1 : -1;
return res;
}
static int is_qtext(char c)
{
int res;
res = (apr_isascii(c) && (c != '"') && (c != '\\') && (c != '\n'))
? 1 : -1;
return res;
}
static int is_quoted_pair(char *s)
{
int res = -1;
int c;
if (((s + 1) != NULL) && (*s == '\\')) {
c = (int) *(s + 1);
if (apr_isascii(c)) {
res = 1;
}
}
return (res);
}
static content_type *analyze_ct(request_rec *r, char *s)
{
char *tp, *mp, *cp;
char *attribute, *value;
int quoted = 0;
server_rec * ss = r->server;
apr_pool_t * p = r->pool;
content_type *ctp;
param *pp, *npp;
/* initialize ctp */
ctp = (content_type *) apr_palloc(p, sizeof(content_type));
ctp->type = NULL;
ctp->subtype = NULL;
ctp->param = NULL;
tp = apr_pstrdup(p, s);
mp = tp;
cp = mp;
/* getting a type */
if (!(cp = strchr(mp, '/'))) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"mod_mime: analyze_ct: cannot get media type from '%s'",
(const char *) mp);
return (NULL);
}
ctp->type = apr_pstrndup(p, mp, cp - mp);
ctp->type = zap_sp(ctp->type);
if (ctp->type == NULL || *(ctp->type) == '\0' ||
strchr(ctp->type, ';') || strchr(ctp->type, ' ') ||
strchr(ctp->type, '\t')) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media subtype.");
return (NULL);
}
/* getting a subtype */
cp++;
mp = cp;
for (; *cp != ';' && *cp != '\0'; cp++)
continue;
ctp->subtype = apr_pstrndup(p, mp, cp - mp);
ctp->subtype = zap_sp(ctp->subtype);
if ((ctp->subtype == NULL) || (*(ctp->subtype) == '\0') ||
strchr(ctp->subtype, ' ') || strchr(ctp->subtype, '\t')) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media subtype.");
return (NULL);
}
cp = zap_sp(cp);
if (cp == NULL || *cp == '\0') {
return (ctp);
}
/* getting parameters */
cp++;
cp = zap_sp(cp);
if (cp == NULL || *cp == '\0') {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
mp = cp;
attribute = NULL;
value = NULL;
while (cp != NULL && *cp != '\0') {
if (attribute == NULL) {
if (is_token(*cp) > 0) {
cp++;
continue;
}
else if (*cp == ' ' || *cp == '\t' || *cp == '\n') {
cp++;
continue;
}
else if (*cp == '=') {
attribute = apr_pstrndup(p, mp, cp - mp);
attribute = zap_sp(attribute);
if (attribute == NULL || *attribute == '\0') {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
cp++;
cp = zap_sp(cp);
if (cp == NULL || *cp == '\0') {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
mp = cp;
continue;
}
else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
}
else {
if (mp == cp) {
if (*cp == '"') {
quoted = 1;
cp++;
}
else {
quoted = 0;
}
}
if (quoted > 0) {
while (quoted && *cp != '\0') {
if (is_qtext(*cp) > 0) {
cp++;
}
else if (is_quoted_pair(cp) > 0) {
cp += 2;
}
else if (*cp == '"') {
cp++;
while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
cp++;
}
if (*cp != ';' && *cp != '\0') {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return(NULL);
}
quoted = 0;
}
else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
}
}
else {
while (1) {
if (is_token(*cp) > 0) {
cp++;
}
else if (*cp == '\0' || *cp == ';') {
break;
}
else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
}
}
value = apr_pstrndup(p, mp, cp - mp);
value = zap_sp(value);
if (value == NULL || *value == '\0') {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
"Cannot get media parameter.");
return (NULL);
}
pp = apr_palloc(p, sizeof(param));
pp->attr = attribute;
pp->val = value;
pp->next = NULL;
if (ctp->param == NULL) {
ctp->param = pp;
}
else {
npp = ctp->param;
while (npp->next) {
npp = npp->next;
}
npp->next = pp;
}
quoted = 0;
attribute = NULL;
value = NULL;
if (*cp == '\0') {
break;
}
cp++;
mp = cp;
}
}
return (ctp);
}
/*
* find_ct is the hook routine for determining content-type and other
* MIME-related metadata. It assumes that r->filename has already been
* set and stat has been called for r->finfo. It also assumes that the
* non-path base file name is not the empty string unless it is a dir.
*/
static int find_ct(request_rec *r)
{
mime_dir_config *conf;
apr_array_header_t *exception_list;
char *ext;
const char *fn, *type, *charset = NULL;
int found_metadata = 0;
if (r->finfo.filetype == APR_DIR) {
r->content_type = DIR_MAGIC_TYPE;
return OK;
}
conf = (mime_dir_config *) ap_get_module_config(r->per_dir_config,
&mime_module);
exception_list = apr_array_make(r->pool, 2, sizeof(char *));
/* Always drop the path leading up to the file name.
*/
if ((fn = strrchr(r->filename, '/')) == NULL)
fn = r->filename;
else
++fn;
/* The exception list keeps track of those filename components that
* are not associated with extensions indicating metadata.
* The base name is always the first exception (i.e., "txt.html" has
* a basename of "txt" even though it might look like an extension).
*/
ext = ap_getword(r->pool, &fn, '.');
*((const char **) apr_array_push(exception_list)) = ext;
/* Parse filename extensions which can be in any order
*/
while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) {
extension_info *exinfo;
int found;
if (*ext == '\0') /* ignore empty extensions "bad..html" */
continue;
found = 0;
#ifdef CASE_BLIND_FILESYSTEM
/* We have a basic problem that folks on case-crippled systems
* expect anything and everything to succeed
*/
ap_str_tolower(ext);
#endif
exinfo = (extension_info*) apr_hash_get(conf->extension_mappings,
ext, APR_HASH_KEY_STRING);
if (exinfo == NULL) {
if ((type = apr_hash_get(mime_type_extensions, ext,
APR_HASH_KEY_STRING)) != NULL) {
r->content_type = type;
found = 1;
}
}
else {
if (exinfo->forced_type) {
r->content_type = exinfo->forced_type;
found = 1;
}
if (exinfo->charset_type) {
charset = exinfo->charset_type;
found = 1;
}
if (exinfo->language_type) {
r->content_language = exinfo->language_type; /* back compat. */
if (!r->content_languages)
r->content_languages = apr_array_make(r->pool, 2,
sizeof(char *));
*((const char **) apr_array_push(r->content_languages)) =
exinfo->language_type;
found = 1;
}
if (exinfo->encoding_type) {
if (!r->content_encoding)
r->content_encoding = exinfo->encoding_type;
else {
/* XXX should eliminate duplicate entities */
r->content_encoding = apr_pstrcat(r->pool,
r->content_encoding,
", ",
exinfo->encoding_type,
NULL);
}
found = 1;
}
if (exinfo->handler && r->proxyreq == PROXYREQ_NONE) {
r->handler = exinfo->handler;
found = 1;
}
}
if (found)
found_metadata = 1;
else
*((const char **) apr_array_push(exception_list)) = ext;
}
/*
* Need to set a notes entry on r for unrecognized elements.
* Somebody better claim them! If we did absolutely nothing,
* skip the notes to alert mod_negotiation we are clueless.
*/
if (found_metadata) {
apr_table_setn(r->notes, "ap-mime-exceptions-list",
(void *)exception_list);
}
if (r->content_type) {
content_type *ctp;
char *ct;
int override = 0;
ct = (char *) apr_palloc(r->pool,
sizeof(char) * (strlen(r->content_type) + 1));
strcpy(ct, r->content_type);
if ((ctp = analyze_ct(r, ct))) {
param *pp = ctp->param;
r->content_type = apr_pstrcat(r->pool, ctp->type, "/",
ctp->subtype, NULL);
while (pp != NULL) {
if (charset && !strcmp(pp->attr, "charset")) {
if (!override) {
r->content_type = apr_pstrcat(r->pool, r->content_type,
"; charset=", charset,
NULL);
override = 1;
}
}
else {
r->content_type = apr_pstrcat(r->pool, r->content_type,
"; ", pp->attr,
"=", pp->val,
NULL);
}
pp = pp->next;
}
if (charset && !override) {
r->content_type = apr_pstrcat(r->pool, r->content_type,
"; charset=", charset,
NULL);
}
}
}
/* Set default language, if none was specified by the extensions
* and we have a DefaultLanguage setting in force
*/
if (!r->content_languages && conf->default_language) {
const char **new;
r->content_language = conf->default_language; /* back compat. only */
if (!r->content_languages)
r->content_languages = apr_array_make(r->pool, 2, sizeof(char *));
new = (const char **) apr_array_push(r->content_languages);
*new = conf->default_language;
}
/* Check for overrides with ForceType/SetHandler */
if (conf->type && strcmp(conf->type, "none"))
r->content_type = conf->type;
if (conf->handler && strcmp(conf->handler, "none"))
r->handler = conf->handler;
if (!r->content_type)
return DECLINED;
return OK;
}
static void register_hooks(apr_pool_t *p)
{
ap_hook_type_checker(find_ct,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_post_config(mime_post_config,NULL,NULL,APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA mime_module = {
STANDARD20_MODULE_STUFF,
create_mime_dir_config, /* create per-directory config structure */
merge_mime_dir_configs, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
mime_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};