Blame modules/http/mod_mime.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * http_mime.c: Sends/gets MIME headers for requests
Packit 90a5c9
 *
Packit 90a5c9
 * Rob McCool
Packit 90a5c9
 *
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "apr.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "apr_lib.h"
Packit 90a5c9
#include "apr_hash.h"
Packit 90a5c9
Packit 90a5c9
#define APR_WANT_STRFUNC
Packit 90a5c9
#include "apr_want.h"
Packit 90a5c9
Packit 90a5c9
#include "ap_config.h"
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_config.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_request.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
Packit 90a5c9
/* XXXX - fix me / EBCDIC
Packit 90a5c9
 *        there was a cludge here which would use its
Packit 90a5c9
 *        own version apr_isascii(). Indicating that
Packit 90a5c9
 *        on some platforms that might be needed.
Packit 90a5c9
 *
Packit 90a5c9
 *        #define OS_ASC(c) (c)             -- for mere mortals
Packit 90a5c9
 *     or
Packit 90a5c9
 *        #define OS_ASC(c) (ebcdic2ascii[c]) -- for dino's
Packit 90a5c9
 *
Packit 90a5c9
 *        #define apr_isascii(c) ((OS_ASC(c) & 0x80) == 0)
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* XXXXX - fix me - See note with NOT_PROXY
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
typedef struct attrib_info {
Packit 90a5c9
    char *name;
Packit 90a5c9
    int   offset;
Packit 90a5c9
} attrib_info;
Packit 90a5c9
Packit 90a5c9
/* Information to which an extension can be mapped
Packit 90a5c9
 */
Packit 90a5c9
typedef struct extension_info {
Packit 90a5c9
    char *forced_type;                /* Additional AddTyped stuff */
Packit 90a5c9
    char *encoding_type;              /* Added with AddEncoding... */
Packit 90a5c9
    char *language_type;              /* Added with AddLanguage... */
Packit 90a5c9
    char *handler;                    /* Added with AddHandler... */
Packit 90a5c9
    char *charset_type;               /* Added with AddCharset... */
Packit 90a5c9
    char *input_filters;              /* Added with AddInputFilter... */
Packit 90a5c9
    char *output_filters;             /* Added with AddOutputFilter... */
Packit 90a5c9
} extension_info;
Packit 90a5c9
Packit 90a5c9
#define MULTIMATCH_UNSET      0
Packit 90a5c9
#define MULTIMATCH_ANY        1
Packit 90a5c9
#define MULTIMATCH_NEGOTIATED 2
Packit 90a5c9
#define MULTIMATCH_HANDLERS   4
Packit 90a5c9
#define MULTIMATCH_FILTERS    8
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    apr_hash_t *extension_mappings;  /* Map from extension name to
Packit 90a5c9
                                      * extension_info structure */
Packit 90a5c9
Packit 90a5c9
    apr_array_header_t *remove_mappings; /* A simple list, walked once */
Packit 90a5c9
Packit 90a5c9
    char *default_language;     /* Language if no AddLanguage ext found */
Packit 90a5c9
Packit 90a5c9
    int multimatch;       /* Extensions to include in multiview matching
Packit 90a5c9
                           * for filenames, e.g. Filters and Handlers
Packit 90a5c9
                           */
Packit 90a5c9
    int use_path_info;    /* If set to 0, only use filename.
Packit 90a5c9
                           * If set to 1, append PATH_INFO to filename for
Packit 90a5c9
                           *   lookups.
Packit 90a5c9
                           * If set to 2, this value is unset and is
Packit 90a5c9
                           *   effectively 0.
Packit 90a5c9
                           */
Packit 90a5c9
} mime_dir_config;
Packit 90a5c9
Packit 90a5c9
typedef struct param_s {
Packit 90a5c9
    char *attr;
Packit 90a5c9
    char *val;
Packit 90a5c9
    struct param_s *next;
Packit 90a5c9
} param;
Packit 90a5c9
Packit 90a5c9
typedef struct {
Packit 90a5c9
    const char *type;
Packit 90a5c9
    apr_size_t type_len;
Packit 90a5c9
    const char *subtype;
Packit 90a5c9
    apr_size_t subtype_len;
Packit 90a5c9
    param *param;
Packit 90a5c9
} content_type;
Packit 90a5c9
Packit 90a5c9
static char tspecial[] = {
Packit 90a5c9
    '(', ')', '<', '>', '@', ',', ';', ':',
Packit 90a5c9
    '\\', '"', '/', '[', ']', '?', '=',
Packit 90a5c9
    '\0'
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
module AP_MODULE_DECLARE_DATA mime_module;
Packit 90a5c9
Packit 90a5c9
static void *create_mime_dir_config(apr_pool_t *p, char *dummy)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
Packit 90a5c9
Packit 90a5c9
    new->extension_mappings = NULL;
Packit 90a5c9
    new->remove_mappings = NULL;
Packit 90a5c9
Packit 90a5c9
    new->default_language = NULL;
Packit 90a5c9
Packit 90a5c9
    new->multimatch = MULTIMATCH_UNSET;
Packit 90a5c9
Packit 90a5c9
    new->use_path_info = 2;
Packit 90a5c9
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
/*
Packit 90a5c9
 * Overlay one hash table of extension_mappings onto another
Packit 90a5c9
 */
Packit 90a5c9
static void *overlay_extension_mappings(apr_pool_t *p,
Packit 90a5c9
                                        const void *key,
Packit 90a5c9
                                        apr_ssize_t klen,
Packit 90a5c9
                                        const void *overlay_val,
Packit 90a5c9
                                        const void *base_val,
Packit 90a5c9
                                        const void *data)
Packit 90a5c9
{
Packit 90a5c9
    const extension_info *overlay_info = (const extension_info *)overlay_val;
Packit 90a5c9
    const extension_info *base_info = (const extension_info *)base_val;
Packit 90a5c9
    extension_info *new_info = apr_pmemdup(p, base_info, sizeof(extension_info));
Packit 90a5c9
Packit 90a5c9
    if (overlay_info->forced_type) {
Packit 90a5c9
        new_info->forced_type = overlay_info->forced_type;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->encoding_type) {
Packit 90a5c9
        new_info->encoding_type = overlay_info->encoding_type;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->language_type) {
Packit 90a5c9
        new_info->language_type = overlay_info->language_type;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->handler) {
Packit 90a5c9
        new_info->handler = overlay_info->handler;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->charset_type) {
Packit 90a5c9
        new_info->charset_type = overlay_info->charset_type;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->input_filters) {
Packit 90a5c9
        new_info->input_filters = overlay_info->input_filters;
Packit 90a5c9
    }
Packit 90a5c9
    if (overlay_info->output_filters) {
Packit 90a5c9
        new_info->output_filters = overlay_info->output_filters;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return new_info;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Member is the offset within an extension_info of the pointer to reset
Packit 90a5c9
 */
Packit 90a5c9
static void remove_items(apr_pool_t *p, apr_array_header_t *remove,
Packit 90a5c9
                         apr_hash_t *mappings)
Packit 90a5c9
{
Packit 90a5c9
    attrib_info *suffix = (attrib_info *) remove->elts;
Packit 90a5c9
    int i;
Packit 90a5c9
    for (i = 0; i < remove->nelts; i++) {
Packit 90a5c9
        extension_info *exinfo = apr_hash_get(mappings,
Packit 90a5c9
                                              suffix[i].name,
Packit 90a5c9
                                              APR_HASH_KEY_STRING);
Packit 90a5c9
        if (exinfo && *(const char**)((char *)exinfo + suffix[i].offset)) {
Packit 90a5c9
            extension_info *copyinfo = exinfo;
Packit 90a5c9
            exinfo = apr_pmemdup(p, copyinfo, sizeof(*exinfo));
Packit 90a5c9
            apr_hash_set(mappings, suffix[i].name,
Packit 90a5c9
                         APR_HASH_KEY_STRING, exinfo);
Packit 90a5c9
Packit 90a5c9
            *(const char**)((char *)exinfo + suffix[i].offset) = NULL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *base = (mime_dir_config *)basev;
Packit 90a5c9
    mime_dir_config *add = (mime_dir_config *)addv;
Packit 90a5c9
    mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
Packit 90a5c9
Packit 90a5c9
    if (base->extension_mappings && add->extension_mappings) {
Packit 90a5c9
        new->extension_mappings = apr_hash_merge(p, add->extension_mappings,
Packit 90a5c9
                                                 base->extension_mappings,
Packit 90a5c9
                                                 overlay_extension_mappings,
Packit 90a5c9
                                                 NULL);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        if (base->extension_mappings == NULL) {
Packit 90a5c9
            new->extension_mappings = add->extension_mappings;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            new->extension_mappings = base->extension_mappings;
Packit 90a5c9
        }
Packit 90a5c9
        /* We may not be merging the tables, but if we potentially will change
Packit 90a5c9
         * an exinfo member, then we are about to trounce it anyways.
Packit 90a5c9
         * We must have a copy for safety.
Packit 90a5c9
         */
Packit 90a5c9
        if (new->extension_mappings && add->remove_mappings) {
Packit 90a5c9
            new->extension_mappings =
Packit 90a5c9
                apr_hash_copy(p, new->extension_mappings);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (new->extension_mappings) {
Packit 90a5c9
        if (add->remove_mappings)
Packit 90a5c9
            remove_items(p, add->remove_mappings, new->extension_mappings);
Packit 90a5c9
    }
Packit 90a5c9
    new->remove_mappings = NULL;
Packit 90a5c9
Packit 90a5c9
    new->default_language = add->default_language ?
Packit 90a5c9
        add->default_language : base->default_language;
Packit 90a5c9
Packit 90a5c9
    new->multimatch = (add->multimatch != MULTIMATCH_UNSET) ?
Packit 90a5c9
        add->multimatch : base->multimatch;
Packit 90a5c9
Packit 90a5c9
    if ((add->use_path_info & 2) == 0) {
Packit 90a5c9
        new->use_path_info = add->use_path_info;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        new->use_path_info = base->use_path_info;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *add_extension_info(cmd_parms *cmd, void *m_,
Packit 90a5c9
                                      const char *value_, const char* ext)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *m=m_;
Packit 90a5c9
    extension_info *exinfo;
Packit 90a5c9
    int offset = (int) (long) cmd->info;
Packit 90a5c9
    char *key = apr_pstrdup(cmd->temp_pool, ext);
Packit 90a5c9
    char *value = apr_pstrdup(cmd->pool, value_);
Packit 90a5c9
    ap_str_tolower(value);
Packit 90a5c9
    ap_str_tolower(key);
Packit 90a5c9
Packit 90a5c9
    if (*key == '.') {
Packit 90a5c9
        ++key;
Packit 90a5c9
    }
Packit 90a5c9
    if (!m->extension_mappings) {
Packit 90a5c9
        m->extension_mappings = apr_hash_make(cmd->pool);
Packit 90a5c9
        exinfo = NULL;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        exinfo = (extension_info*)apr_hash_get(m->extension_mappings, key,
Packit 90a5c9
                                               APR_HASH_KEY_STRING);
Packit 90a5c9
    }
Packit 90a5c9
    if (!exinfo) {
Packit 90a5c9
        exinfo = apr_pcalloc(cmd->pool, sizeof(extension_info));
Packit 90a5c9
        key = apr_pstrdup(cmd->pool, key);
Packit 90a5c9
        apr_hash_set(m->extension_mappings, key, APR_HASH_KEY_STRING, exinfo);
Packit 90a5c9
    }
Packit 90a5c9
    *(const char**)((char *)exinfo + offset) = value;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * As RemoveType should also override the info from TypesConfig, we add an
Packit 90a5c9
 * empty string as type instead of actually removing the type.
Packit 90a5c9
 */
Packit 90a5c9
static const char *remove_extension_type(cmd_parms *cmd, void *m_,
Packit 90a5c9
                                         const char *ext)
Packit 90a5c9
{
Packit 90a5c9
    return add_extension_info(cmd, m_, "", ext);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Note handler names are un-added with each per_dir_config merge.
Packit 90a5c9
 * This keeps the association from being inherited, but not
Packit 90a5c9
 * from being re-added at a subordinate level.
Packit 90a5c9
 */
Packit 90a5c9
static const char *remove_extension_info(cmd_parms *cmd, void *m_,
Packit 90a5c9
                                         const char *ext)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *m = (mime_dir_config *) m_;
Packit 90a5c9
    attrib_info *suffix;
Packit 90a5c9
    if (*ext == '.') {
Packit 90a5c9
        ++ext;
Packit 90a5c9
    }
Packit 90a5c9
    if (!m->remove_mappings) {
Packit 90a5c9
        m->remove_mappings = apr_array_make(cmd->pool, 4, sizeof(*suffix));
Packit 90a5c9
    }
Packit 90a5c9
    suffix = (attrib_info *)apr_array_push(m->remove_mappings);
Packit 90a5c9
    suffix->name = apr_pstrdup(cmd->pool, ext);
Packit 90a5c9
    ap_str_tolower(suffix->name);
Packit 90a5c9
    suffix->offset = (int) (long) cmd->info;
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* The sole bit of server configuration that the MIME module has is
Packit 90a5c9
 * the name of its config file, so...
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static const char *set_types_config(cmd_parms *cmd, void *dummy,
Packit 90a5c9
                                    const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    ap_set_module_config(cmd->server->module_config, &mime_module,
Packit 90a5c9
                         (void *)arg);
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *multiviews_match(cmd_parms *cmd, void *m_,
Packit 90a5c9
                                    const char *include)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *m = (mime_dir_config *) m_;
Packit 90a5c9
    const char *errmsg;
Packit 90a5c9
Packit 90a5c9
    errmsg = ap_check_cmd_context(cmd, NOT_IN_LOCATION);
Packit 90a5c9
    if (errmsg != NULL) {
Packit 90a5c9
        return errmsg;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (strcasecmp(include, "Any") == 0) {
Packit 90a5c9
        if (m->multimatch && (m->multimatch & ~MULTIMATCH_ANY)) {
Packit 90a5c9
            return "Any is incompatible with NegotiatedOnly, "
Packit 90a5c9
                   "Filters and Handlers";
Packit 90a5c9
        }
Packit 90a5c9
        m->multimatch |= MULTIMATCH_ANY;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcasecmp(include, "NegotiatedOnly") == 0) {
Packit 90a5c9
        if (m->multimatch && (m->multimatch & ~MULTIMATCH_NEGOTIATED)) {
Packit 90a5c9
            return "NegotiatedOnly is incompatible with Any, "
Packit 90a5c9
                   "Filters and Handlers";
Packit 90a5c9
        }
Packit 90a5c9
        m->multimatch |= MULTIMATCH_NEGOTIATED;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcasecmp(include, "Filters") == 0) {
Packit 90a5c9
        if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
Packit 90a5c9
                                             | MULTIMATCH_ANY))) {
Packit 90a5c9
            return "Filters is incompatible with Any and NegotiatedOnly";
Packit 90a5c9
        }
Packit 90a5c9
        m->multimatch |= MULTIMATCH_FILTERS;
Packit 90a5c9
    }
Packit 90a5c9
    else if (strcasecmp(include, "Handlers") == 0) {
Packit 90a5c9
        if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
Packit 90a5c9
                                             | MULTIMATCH_ANY))) {
Packit 90a5c9
            return "Handlers is incompatible with Any and NegotiatedOnly";
Packit 90a5c9
        }
Packit 90a5c9
        m->multimatch |= MULTIMATCH_HANDLERS;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return apr_psprintf(cmd->pool, "Unrecognized option '%s'", include);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const command_rec mime_cmds[] =
Packit 90a5c9
{
Packit 90a5c9
    AP_INIT_ITERATE2("AddCharset", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
Packit 90a5c9
        "a charset (e.g., iso-2022-jp), followed by one or more "
Packit 90a5c9
        "file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddEncoding", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
Packit 90a5c9
        "an encoding (e.g., gzip), followed by one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddHandler", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
Packit 90a5c9
        "a handler name followed by one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddInputFilter", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
Packit 90a5c9
        "input filter name (or ; delimited names) followed by one or "
Packit 90a5c9
        "more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddLanguage", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
Packit 90a5c9
        "a language (e.g., fr), followed by one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddOutputFilter", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
Packit 90a5c9
        "output filter name (or ; delimited names) followed by one or "
Packit 90a5c9
        "more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE2("AddType", add_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
Packit 90a5c9
        "a mime type followed by one or more file extensions"),
Packit 90a5c9
    AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot,
Packit 90a5c9
        (void*)APR_OFFSETOF(mime_dir_config, default_language), OR_FILEINFO,
Packit 90a5c9
        "language to use for documents with no other language file extension"),
Packit 90a5c9
    AP_INIT_ITERATE("MultiviewsMatch", multiviews_match, NULL, OR_FILEINFO,
Packit 90a5c9
        "NegotiatedOnly (default), Handlers and/or Filters, or Any"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveCharset", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveEncoding", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveHandler", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveInputFilter", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveLanguage", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveOutputFilter", remove_extension_info,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_ITERATE("RemoveType", remove_extension_type,
Packit 90a5c9
        (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
Packit 90a5c9
        "one or more file extensions"),
Packit 90a5c9
    AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF,
Packit 90a5c9
        "the MIME types config file"),
Packit 90a5c9
    AP_INIT_FLAG("ModMimeUsePathInfo", ap_set_flag_slot,
Packit 90a5c9
        (void *)APR_OFFSETOF(mime_dir_config, use_path_info), ACCESS_CONF,
Packit 90a5c9
        "Set to 'yes' to allow mod_mime to use path info for type checking"),
Packit 90a5c9
    {NULL}
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static apr_hash_t *mime_type_extensions;
Packit 90a5c9
Packit 90a5c9
static int mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    ap_configfile_t *f;
Packit 90a5c9
    char l[MAX_STRING_LEN];
Packit 90a5c9
    const char *types_confname = ap_get_module_config(s->module_config,
Packit 90a5c9
                                                      &mime_module);
Packit 90a5c9
    apr_status_t status;
Packit 90a5c9
Packit 90a5c9
    if (!types_confname) {
Packit 90a5c9
        types_confname = AP_TYPES_CONFIG_FILE;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    types_confname = ap_server_root_relative(p, types_confname);
Packit 90a5c9
    if (!types_confname) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, APLOGNO(01596)
Packit 90a5c9
                     "Invalid mime types config path %s",
Packit 90a5c9
                     (const char *)ap_get_module_config(s->module_config,
Packit 90a5c9
                                                        &mime_module));
Packit 90a5c9
        return HTTP_INTERNAL_SERVER_ERROR;
Packit 90a5c9
    }
Packit 90a5c9
    if ((status = ap_pcfg_openfile(&f, ptemp, types_confname))
Packit 90a5c9
                != APR_SUCCESS) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_ERR, status, s, APLOGNO(01597)
Packit 90a5c9
                     "could not open mime types config file %s.",
Packit 90a5c9
                     types_confname);
Packit 90a5c9
        return HTTP_INTERNAL_SERVER_ERROR;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    mime_type_extensions = apr_hash_make(p);
Packit 90a5c9
Packit 90a5c9
    while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
Packit 90a5c9
        const char *ll = l, *ct;
Packit 90a5c9
Packit 90a5c9
        if (l[0] == '#') {
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
        ct = ap_getword_conf(p, &ll);
Packit 90a5c9
Packit 90a5c9
        while (ll[0]) {
Packit 90a5c9
            char *ext = ap_getword_conf(p, &ll);
Packit 90a5c9
            ap_str_tolower(ext);
Packit 90a5c9
            apr_hash_set(mime_type_extensions, ext, APR_HASH_KEY_STRING, ct);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    ap_cfg_closefile(f);
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char *zap_sp(const char *s)
Packit 90a5c9
{
Packit 90a5c9
    if (s == NULL) {
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    if (*s == '\0') {
Packit 90a5c9
        return (s);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* skip prefixed white space */
Packit 90a5c9
    for (; *s == ' ' || *s == '\t' || *s == '\n'; s++)
Packit 90a5c9
        ;
Packit 90a5c9
Packit 90a5c9
    return (s);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char *zap_sp_and_dup(apr_pool_t *p, const char *start,
Packit 90a5c9
                            const char *end, apr_size_t *len)
Packit 90a5c9
{
Packit 90a5c9
    while ((start < end) && apr_isspace(*start)) {
Packit 90a5c9
        start++;
Packit 90a5c9
    }
Packit 90a5c9
    while ((end > start) && apr_isspace(*(end - 1))) {
Packit 90a5c9
        end--;
Packit 90a5c9
    }
Packit 90a5c9
    if (len) {
Packit 90a5c9
        *len = end - start;
Packit 90a5c9
    }
Packit 90a5c9
    return apr_pstrmemdup(p, start, end - start);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int is_token(char c)
Packit 90a5c9
{
Packit 90a5c9
    int res;
Packit 90a5c9
Packit 90a5c9
    res = (apr_isascii(c) && apr_isgraph(c)
Packit 90a5c9
           && (strchr(tspecial, c) == NULL)) ? 1 : -1;
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int is_qtext(char c)
Packit 90a5c9
{
Packit 90a5c9
    int res;
Packit 90a5c9
Packit 90a5c9
    res = (apr_isascii(c) && (c != '"') && (c != '\\') && (c != '\n'))
Packit 90a5c9
        ? 1 : -1;
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int is_quoted_pair(const char *s)
Packit 90a5c9
{
Packit 90a5c9
    int res = -1;
Packit 90a5c9
    int c;
Packit 90a5c9
Packit 90a5c9
    if (*s == '\\') {
Packit 90a5c9
        c = (int) *(s + 1);
Packit 90a5c9
        if (c && apr_isascii(c)) {
Packit 90a5c9
            res = 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return (res);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static content_type *analyze_ct(request_rec *r, const char *s)
Packit 90a5c9
{
Packit 90a5c9
    const char *cp, *mp;
Packit 90a5c9
    char *attribute, *value;
Packit 90a5c9
    int quoted = 0;
Packit 90a5c9
    server_rec * ss = r->server;
Packit 90a5c9
    apr_pool_t * p = r->pool;
Packit 90a5c9
Packit 90a5c9
    content_type *ctp;
Packit 90a5c9
    param *pp, *npp;
Packit 90a5c9
Packit 90a5c9
    /* initialize ctp */
Packit 90a5c9
    ctp = (content_type *)apr_palloc(p, sizeof(content_type));
Packit 90a5c9
    ctp->type = NULL;
Packit 90a5c9
    ctp->subtype = NULL;
Packit 90a5c9
    ctp->param = NULL;
Packit 90a5c9
Packit 90a5c9
    mp = s;
Packit 90a5c9
Packit 90a5c9
    /* getting a type */
Packit 90a5c9
    cp = mp;
Packit 90a5c9
    while (apr_isspace(*cp)) {
Packit 90a5c9
        cp++;
Packit 90a5c9
    }
Packit 90a5c9
    if (!*cp) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01598)
Packit 90a5c9
                     "mod_mime: analyze_ct: cannot get media type from '%s'",
Packit 90a5c9
                     (const char *) mp);
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    ctp->type = cp;
Packit 90a5c9
    do {
Packit 90a5c9
        cp++;
Packit 90a5c9
    } while (*cp && (*cp != '/') && !apr_isspace(*cp) && (*cp != ';'));
Packit 90a5c9
    if (!*cp || (*cp == ';')) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01599)
Packit 90a5c9
                     "Cannot get media type from '%s'",
Packit 90a5c9
                     (const char *) mp);
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    while (apr_isspace(*cp)) {
Packit 90a5c9
        cp++;
Packit 90a5c9
    }
Packit 90a5c9
    if (*cp != '/') {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01600)
Packit 90a5c9
                     "mod_mime: analyze_ct: cannot get media type from '%s'",
Packit 90a5c9
                     (const char *) mp);
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    ctp->type_len = cp - ctp->type;
Packit 90a5c9
Packit 90a5c9
    cp++; /* skip the '/' */
Packit 90a5c9
Packit 90a5c9
    /* getting a subtype */
Packit 90a5c9
    while (apr_isspace(*cp)) {
Packit 90a5c9
        cp++;
Packit 90a5c9
    }
Packit 90a5c9
    if (!*cp) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01601)
Packit 90a5c9
                     "Cannot get media subtype.");
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    ctp->subtype = cp;
Packit 90a5c9
    do {
Packit 90a5c9
        cp++;
Packit 90a5c9
    } while (*cp && !apr_isspace(*cp) && (*cp != ';'));
Packit 90a5c9
    ctp->subtype_len = cp - ctp->subtype;
Packit 90a5c9
    while (apr_isspace(*cp)) {
Packit 90a5c9
        cp++;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (*cp == '\0') {
Packit 90a5c9
        return (ctp);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* getting parameters */
Packit 90a5c9
    cp++; /* skip the ';' */
Packit 90a5c9
    cp = zap_sp(cp);
Packit 90a5c9
    if (cp == NULL || *cp == '\0') {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01602)
Packit 90a5c9
                     "Cannot get media parameter.");
Packit 90a5c9
        return (NULL);
Packit 90a5c9
    }
Packit 90a5c9
    mp = cp;
Packit 90a5c9
    attribute = NULL;
Packit 90a5c9
    value = NULL;
Packit 90a5c9
Packit 90a5c9
    while (cp != NULL && *cp != '\0') {
Packit 90a5c9
        if (attribute == NULL) {
Packit 90a5c9
            if (is_token(*cp) > 0) {
Packit 90a5c9
                cp++;
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
            else if (*cp == ' ' || *cp == '\t' || *cp == '\n') {
Packit 90a5c9
                cp++;
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
            else if (*cp == '=') {
Packit 90a5c9
                attribute = zap_sp_and_dup(p, mp, cp, NULL);
Packit 90a5c9
                if (attribute == NULL || *attribute == '\0') {
Packit 90a5c9
                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01603)
Packit 90a5c9
                                 "Cannot get media parameter.");
Packit 90a5c9
                    return (NULL);
Packit 90a5c9
                }
Packit 90a5c9
                cp++;
Packit 90a5c9
                cp = zap_sp(cp);
Packit 90a5c9
                if (cp == NULL || *cp == '\0') {
Packit 90a5c9
                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01604)
Packit 90a5c9
                                 "Cannot get media parameter.");
Packit 90a5c9
                    return (NULL);
Packit 90a5c9
                }
Packit 90a5c9
                mp = cp;
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01605)
Packit 90a5c9
                             "Cannot get media parameter.");
Packit 90a5c9
                return (NULL);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            if (mp == cp) {
Packit 90a5c9
                if (*cp == '"') {
Packit 90a5c9
                    quoted = 1;
Packit 90a5c9
                    cp++;
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    quoted = 0;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            if (quoted > 0) {
Packit 90a5c9
                while (quoted && *cp != '\0') {
Packit 90a5c9
                    if (is_qtext(*cp) > 0) {
Packit 90a5c9
                        cp++;
Packit 90a5c9
                    }
Packit 90a5c9
                    else if (is_quoted_pair(cp) > 0) {
Packit 90a5c9
                        cp += 2;
Packit 90a5c9
                    }
Packit 90a5c9
                    else if (*cp == '"') {
Packit 90a5c9
                        cp++;
Packit 90a5c9
                        while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
Packit 90a5c9
                            cp++;
Packit 90a5c9
                        }
Packit 90a5c9
                        if (*cp != ';' && *cp != '\0') {
Packit 90a5c9
                            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01606)
Packit 90a5c9
                                         "Cannot get media parameter.");
Packit 90a5c9
                            return(NULL);
Packit 90a5c9
                        }
Packit 90a5c9
                        quoted = 0;
Packit 90a5c9
                    }
Packit 90a5c9
                    else {
Packit 90a5c9
                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01607)
Packit 90a5c9
                                     "Cannot get media parameter.");
Packit 90a5c9
                        return (NULL);
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                while (1) {
Packit 90a5c9
                    if (is_token(*cp) > 0) {
Packit 90a5c9
                        cp++;
Packit 90a5c9
                    }
Packit 90a5c9
                    else if (*cp == '\0' || *cp == ';') {
Packit 90a5c9
                        break;
Packit 90a5c9
                    }
Packit 90a5c9
                    else {
Packit 90a5c9
                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01608)
Packit 90a5c9
                                     "Cannot get media parameter.");
Packit 90a5c9
                        return (NULL);
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            value = zap_sp_and_dup(p, mp, cp, NULL);
Packit 90a5c9
            if (value == NULL || *value == '\0') {
Packit 90a5c9
                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01609)
Packit 90a5c9
                             "Cannot get media parameter.");
Packit 90a5c9
                return (NULL);
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            pp = apr_palloc(p, sizeof(param));
Packit 90a5c9
            pp->attr = attribute;
Packit 90a5c9
            pp->val = value;
Packit 90a5c9
            pp->next = NULL;
Packit 90a5c9
Packit 90a5c9
            if (ctp->param == NULL) {
Packit 90a5c9
                ctp->param = pp;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                npp = ctp->param;
Packit 90a5c9
                while (npp->next) {
Packit 90a5c9
                    npp = npp->next;
Packit 90a5c9
                }
Packit 90a5c9
                npp->next = pp;
Packit 90a5c9
            }
Packit 90a5c9
            quoted = 0;
Packit 90a5c9
            attribute = NULL;
Packit 90a5c9
            value = NULL;
Packit 90a5c9
            if (*cp == '\0') {
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
            cp++;
Packit 90a5c9
            mp = cp;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return (ctp);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * find_ct is the hook routine for determining content-type and other
Packit 90a5c9
 * MIME-related metadata.  It assumes that r->filename has already been
Packit 90a5c9
 * set and stat has been called for r->finfo.  It also assumes that the
Packit 90a5c9
 * non-path base file name is not the empty string unless it is a dir.
Packit 90a5c9
 */
Packit 90a5c9
static int find_ct(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    mime_dir_config *conf;
Packit 90a5c9
    apr_array_header_t *exception_list;
Packit 90a5c9
    char *ext;
Packit 90a5c9
    const char *fn, *fntmp, *type, *charset = NULL, *resource_name;
Packit 90a5c9
    int found_metadata = 0;
Packit 90a5c9
Packit 90a5c9
    if (r->finfo.filetype == APR_DIR) {
Packit 90a5c9
        ap_set_content_type(r, DIR_MAGIC_TYPE);
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!r->filename) {
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    conf = (mime_dir_config *)ap_get_module_config(r->per_dir_config,
Packit 90a5c9
                                                   &mime_module);
Packit 90a5c9
    exception_list = apr_array_make(r->pool, 2, sizeof(char *));
Packit 90a5c9
Packit 90a5c9
    /* If use_path_info is explicitly set to on (value & 1 == 1), append. */
Packit 90a5c9
    if (conf->use_path_info & 1) {
Packit 90a5c9
        resource_name = apr_pstrcat(r->pool, r->filename, r->path_info, NULL);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        resource_name = r->filename;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Always drop the path leading up to the file name.
Packit 90a5c9
     */
Packit 90a5c9
    if ((fn = ap_strrchr_c(resource_name, '/')) == NULL) {
Packit 90a5c9
        fn = resource_name;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        ++fn;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
    /* The exception list keeps track of those filename components that
Packit 90a5c9
     * are not associated with extensions indicating metadata.
Packit 90a5c9
     * The base name is always the first exception (i.e., "txt.html" has
Packit 90a5c9
     * a basename of "txt" even though it might look like an extension).
Packit 90a5c9
     * Leading dots are considered to be part of the base name (a file named
Packit 90a5c9
     * ".png" is likely not a png file but just a hidden file called png).
Packit 90a5c9
     */
Packit 90a5c9
    fntmp = fn;
Packit 90a5c9
    while (*fntmp == '.')
Packit 90a5c9
        fntmp++;
Packit 90a5c9
    fntmp = ap_strchr_c(fntmp, '.');
Packit 90a5c9
    if (fntmp) {
Packit 90a5c9
        ext = apr_pstrmemdup(r->pool, fn, fntmp - fn);
Packit 90a5c9
        fn = fntmp + 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        ext = apr_pstrdup(r->pool, fn);
Packit 90a5c9
        fn += strlen(fn);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *((const char **)apr_array_push(exception_list)) = ext;
Packit 90a5c9
Packit 90a5c9
    /* Parse filename extensions which can be in any order
Packit 90a5c9
     */
Packit 90a5c9
    while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) {
Packit 90a5c9
        const extension_info *exinfo = NULL;
Packit 90a5c9
        int found;
Packit 90a5c9
        char *extcase;
Packit 90a5c9
Packit 90a5c9
        if (*ext == '\0') {  /* ignore empty extensions "bad..html" */
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        found = 0;
Packit 90a5c9
Packit 90a5c9
        /* Save the ext in extcase before converting it to lower case.
Packit 90a5c9
         */
Packit 90a5c9
        extcase = apr_pstrdup(r->pool, ext);
Packit 90a5c9
        ap_str_tolower(ext);
Packit 90a5c9
Packit 90a5c9
        if (conf->extension_mappings != NULL) {
Packit 90a5c9
            exinfo = (extension_info*)apr_hash_get(conf->extension_mappings,
Packit 90a5c9
                                                   ext, APR_HASH_KEY_STRING);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (exinfo == NULL || !exinfo->forced_type) {
Packit 90a5c9
            if ((type = apr_hash_get(mime_type_extensions, ext,
Packit 90a5c9
                                     APR_HASH_KEY_STRING)) != NULL) {
Packit 90a5c9
                ap_set_content_type(r, (char*) type);
Packit 90a5c9
                found = 1;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (exinfo != NULL) {
Packit 90a5c9
Packit 90a5c9
            /* empty string is treated as special case for RemoveType */
Packit 90a5c9
            if (exinfo->forced_type && *exinfo->forced_type) {
Packit 90a5c9
                ap_set_content_type(r, exinfo->forced_type);
Packit 90a5c9
                found = 1;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            if (exinfo->charset_type) {
Packit 90a5c9
                charset = exinfo->charset_type;
Packit 90a5c9
                found = 1;
Packit 90a5c9
            }
Packit 90a5c9
            if (exinfo->language_type) {
Packit 90a5c9
                if (!r->content_languages) {
Packit 90a5c9
                    r->content_languages = apr_array_make(r->pool, 2,
Packit 90a5c9
                                                          sizeof(char *));
Packit 90a5c9
                }
Packit 90a5c9
                *((const char **)apr_array_push(r->content_languages))
Packit 90a5c9
                    = exinfo->language_type;
Packit 90a5c9
                found = 1;
Packit 90a5c9
            }
Packit 90a5c9
            if (exinfo->encoding_type) {
Packit 90a5c9
                if (!r->content_encoding) {
Packit 90a5c9
                    r->content_encoding = exinfo->encoding_type;
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    /* XXX should eliminate duplicate entities
Packit 90a5c9
                     *
Packit 90a5c9
                     * ah no. Order is important and double encoding is neither
Packit 90a5c9
                     * forbidden nor impossible. -- nd
Packit 90a5c9
                     */
Packit 90a5c9
                    r->content_encoding = apr_pstrcat(r->pool,
Packit 90a5c9
                                                      r->content_encoding,
Packit 90a5c9
                                                      ", ",
Packit 90a5c9
                                                      exinfo->encoding_type,
Packit 90a5c9
                                                      NULL);
Packit 90a5c9
                }
Packit 90a5c9
                found = 1;
Packit 90a5c9
            }
Packit 90a5c9
            /* The following extensions are not 'Found'.  That is, they don't
Packit 90a5c9
             * make any contribution to metadata negotiation, so they must have
Packit 90a5c9
             * been explicitly requested by name.
Packit 90a5c9
             */
Packit 90a5c9
            if (exinfo->handler && r->proxyreq == PROXYREQ_NONE) {
Packit 90a5c9
                r->handler = exinfo->handler;
Packit 90a5c9
                if (conf->multimatch & MULTIMATCH_HANDLERS) {
Packit 90a5c9
                    found = 1;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            /* XXX Two significant problems; 1, we don't check to see if we are
Packit 90a5c9
             * setting redundant filters.    2, we insert these in the types
Packit 90a5c9
             * config hook, which may be too early (dunno.)
Packit 90a5c9
             */
Packit 90a5c9
            if (exinfo->input_filters) {
Packit 90a5c9
                const char *filter, *filters = exinfo->input_filters;
Packit 90a5c9
                while (*filters
Packit 90a5c9
                    && (filter = ap_getword(r->pool, &filters, ';'))) {
Packit 90a5c9
                    ap_add_input_filter(filter, NULL, r, r->connection);
Packit 90a5c9
                }
Packit 90a5c9
                if (conf->multimatch & MULTIMATCH_FILTERS) {
Packit 90a5c9
                    found = 1;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            if (exinfo->output_filters) {
Packit 90a5c9
                const char *filter, *filters = exinfo->output_filters;
Packit 90a5c9
                while (*filters
Packit 90a5c9
                    && (filter = ap_getword(r->pool, &filters, ';'))) {
Packit 90a5c9
                    ap_add_output_filter(filter, NULL, r, r->connection);
Packit 90a5c9
                }
Packit 90a5c9
                if (conf->multimatch & MULTIMATCH_FILTERS) {
Packit 90a5c9
                    found = 1;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (found || (conf->multimatch & MULTIMATCH_ANY)) {
Packit 90a5c9
            found_metadata = 1;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *((const char **) apr_array_push(exception_list)) = extcase;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * Need to set a notes entry on r for unrecognized elements.
Packit 90a5c9
     * Somebody better claim them!  If we did absolutely nothing,
Packit 90a5c9
     * skip the notes to alert mod_negotiation we are clueless.
Packit 90a5c9
     */
Packit 90a5c9
    if (found_metadata) {
Packit 90a5c9
        apr_table_setn(r->notes, "ap-mime-exceptions-list",
Packit 90a5c9
                       (void *)exception_list);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (r->content_type) {
Packit 90a5c9
        content_type *ctp;
Packit 90a5c9
        int override = 0;
Packit 90a5c9
Packit 90a5c9
        if ((ctp = analyze_ct(r, r->content_type))) {
Packit 90a5c9
            param *pp = ctp->param;
Packit 90a5c9
            char *base_content_type = apr_palloc(r->pool, ctp->type_len +
Packit 90a5c9
                                                 ctp->subtype_len +
Packit 90a5c9
                                                 sizeof("/"));
Packit 90a5c9
            char *tmp = base_content_type;
Packit 90a5c9
            memcpy(tmp, ctp->type, ctp->type_len);
Packit 90a5c9
            tmp += ctp->type_len;
Packit 90a5c9
            *tmp++ = '/';
Packit 90a5c9
            memcpy(tmp, ctp->subtype, ctp->subtype_len);
Packit 90a5c9
            tmp += ctp->subtype_len;
Packit 90a5c9
            *tmp = 0;
Packit 90a5c9
            ap_set_content_type(r, base_content_type);
Packit 90a5c9
            while (pp != NULL) {
Packit 90a5c9
                if (charset && !strcmp(pp->attr, "charset")) {
Packit 90a5c9
                    if (!override) {
Packit 90a5c9
                        ap_set_content_type(r,
Packit 90a5c9
                                            apr_pstrcat(r->pool,
Packit 90a5c9
                                                        r->content_type,
Packit 90a5c9
                                                        "; charset=",
Packit 90a5c9
                                                        charset,
Packit 90a5c9
                                                        NULL));
Packit 90a5c9
                        override = 1;
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    ap_set_content_type(r,
Packit 90a5c9
                                        apr_pstrcat(r->pool,
Packit 90a5c9
                                                    r->content_type,
Packit 90a5c9
                                                    "; ", pp->attr,
Packit 90a5c9
                                                    "=", pp->val,
Packit 90a5c9
                                                    NULL));
Packit 90a5c9
                }
Packit 90a5c9
                pp = pp->next;
Packit 90a5c9
            }
Packit 90a5c9
            if (charset && !override) {
Packit 90a5c9
                ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type,
Packit 90a5c9
                                                   "; charset=", charset,
Packit 90a5c9
                                                   NULL));
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Set default language, if none was specified by the extensions
Packit 90a5c9
     * and we have a DefaultLanguage setting in force
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    if (!r->content_languages && conf->default_language) {
Packit 90a5c9
        const char **new;
Packit 90a5c9
Packit 90a5c9
        if (!r->content_languages) {
Packit 90a5c9
            r->content_languages = apr_array_make(r->pool, 2, sizeof(char *));
Packit 90a5c9
        }
Packit 90a5c9
        new = (const char **)apr_array_push(r->content_languages);
Packit 90a5c9
        *new = conf->default_language;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!r->content_type) {
Packit 90a5c9
        return DECLINED;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void register_hooks(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    ap_hook_post_config(mime_post_config,NULL,NULL,APR_HOOK_MIDDLE);
Packit 90a5c9
    ap_hook_type_checker(find_ct,NULL,NULL,APR_HOOK_MIDDLE);
Packit 90a5c9
    /*
Packit 90a5c9
     * this hook seems redundant ... is there any reason a type checker isn't
Packit 90a5c9
     * allowed to do this already?  I'd think that fixups in general would be
Packit 90a5c9
     * the last opportunity to get the filters right.
Packit 90a5c9
     * ap_hook_insert_filter(mime_insert_filters,NULL,NULL,APR_HOOK_MIDDLE);
Packit 90a5c9
     */
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_MODULE(mime) = {
Packit 90a5c9
    STANDARD20_MODULE_STUFF,
Packit 90a5c9
    create_mime_dir_config,     /* create per-directory config structure */
Packit 90a5c9
    merge_mime_dir_configs,     /* merge per-directory config structures */
Packit 90a5c9
    NULL,                       /* create per-server config structure */
Packit 90a5c9
    NULL,                       /* merge per-server config structures */
Packit 90a5c9
    mime_cmds,                  /* command apr_table_t */
Packit 90a5c9
    register_hooks              /* register hooks */
Packit 90a5c9
};