/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* * http_mime.c: Sends/gets MIME headers for requests * * Rob McCool *
*/
/* XXXX - fix me / EBCDIC * there was a cludge here which would use its * own version apr_isascii(). Indicating that * on some platforms that might be needed. * * #define OS_ASC(c) (c) -- for mere mortals * or * #define OS_ASC(c) (ebcdic2ascii[c]) -- for dino's * * #define apr_isascii(c) ((OS_ASC(c) & 0x80) == 0)
*/
/* XXXXX - fix me - See note with NOT_PROXY
*/
typedefstruct attrib_info { char *name; int offset;
} attrib_info;
/* Information to which an extension can be mapped
*/ typedefstruct extension_info { char *forced_type; /* Additional AddTyped stuff */ char *encoding_type; /* Added with AddEncoding... */ char *language_type; /* Added with AddLanguage... */ char *handler; /* Added with AddHandler... */ char *charset_type; /* Added with AddCharset... */ char *input_filters; /* Added with AddInputFilter... */ char *output_filters; /* Added with AddOutputFilter... */
} extension_info;
typedefstruct {
apr_hash_t *extension_mappings; /* Map from extension name to
* extension_info structure */
apr_array_header_t *remove_mappings; /* A simple list, walked once */
char *default_language; /* Language if no AddLanguage ext found */
int multimatch; /* Extensions to include in multiview matching * for filenames, e.g. Filters and Handlers
*/ int use_path_info; /* If set to 0, only use filename. * If set to 1, append PATH_INFO to filename for * lookups. * If set to 2, this value is unset and is * effectively 0.
*/
} mime_dir_config;
if (base->extension_mappings && add->extension_mappings) {
new->extension_mappings = apr_hash_merge(p, add->extension_mappings,
base->extension_mappings,
overlay_extension_mappings,
NULL);
} else { if (base->extension_mappings == NULL) {
new->extension_mappings = add->extension_mappings;
} else {
new->extension_mappings = base->extension_mappings;
} /* We may not be merging the tables, but if we potentially will change * an exinfo member, then we are about to trounce it anyways. * We must have a copy for safety.
*/ if (new->extension_mappings && add->remove_mappings) {
new->extension_mappings =
apr_hash_copy(p, new->extension_mappings);
}
}
if (new->extension_mappings) { if (add->remove_mappings)
remove_items(p, add->remove_mappings, new->extension_mappings);
}
new->remove_mappings = NULL;
/* * As RemoveType should also override the info from TypesConfig, we add an * empty string as type instead of actually removing the type.
*/ staticconstchar *remove_extension_type(cmd_parms *cmd, void *m_, constchar *ext)
{ return add_extension_info(cmd, m_, "", ext);
}
/* * Note handler names are un-added with each per_dir_config merge. * This keeps the association from being inherited, but not * from being re-added at a subordinate level.
*/ staticconstchar *remove_extension_info(cmd_parms *cmd, void *m_, constchar *ext)
{
mime_dir_config *m = (mime_dir_config *) m_;
attrib_info *suffix; if (*ext == '.') {
++ext;
} if (!m->remove_mappings) {
m->remove_mappings = apr_array_make(cmd->pool, 4, sizeof(*suffix));
}
suffix = (attrib_info *)apr_array_push(m->remove_mappings);
suffix->name = apr_pstrdup(cmd->pool, ext);
ap_str_tolower(suffix->name);
suffix->offset = (int) (long) cmd->info; return NULL;
}
/* The sole bit of server configuration that the MIME module has is * the name of its config file, so...
*/
if (strcasecmp(include, "Any") == 0) { if (m->multimatch && (m->multimatch & ~MULTIMATCH_ANY)) { return"Any is incompatible with NegotiatedOnly, " "Filters and Handlers";
}
m->multimatch |= MULTIMATCH_ANY;
} elseif (strcasecmp(include, "NegotiatedOnly") == 0) { if (m->multimatch && (m->multimatch & ~MULTIMATCH_NEGOTIATED)) { return"NegotiatedOnly is incompatible with Any, " "Filters and Handlers";
}
m->multimatch |= MULTIMATCH_NEGOTIATED;
} elseif (strcasecmp(include, "Filters") == 0) { if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
| MULTIMATCH_ANY))) { return"Filters is incompatible with Any and NegotiatedOnly";
}
m->multimatch |= MULTIMATCH_FILTERS;
} elseif (strcasecmp(include, "Handlers") == 0) { if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
| MULTIMATCH_ANY))) { return"Handlers is incompatible with Any and NegotiatedOnly";
}
m->multimatch |= MULTIMATCH_HANDLERS;
} else { return apr_psprintf(cmd->pool, "Unrecognized option '%s'", include);
}
return NULL;
}
staticconst command_rec mime_cmds[] =
{
AP_INIT_ITERATE2("AddCharset", add_extension_info,
(void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO, "a charset (e.g., iso-2022-jp), followed by one or more " "file extensions"),
AP_INIT_ITERATE2("AddEncoding", add_extension_info,
(void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO, "an encoding (e.g., gzip), followed by one or more file extensions"),
AP_INIT_ITERATE2("AddHandler", add_extension_info,
(void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO, "a handler name followed by one or more file extensions"),
AP_INIT_ITERATE2("AddInputFilter", add_extension_info,
(void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO, "input filter name (or ; delimited names) followed by one or " "more file extensions"),
AP_INIT_ITERATE2("AddLanguage", add_extension_info,
(void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO, "a language (e.g., fr), followed by one or more file extensions"),
AP_INIT_ITERATE2("AddOutputFilter", add_extension_info,
(void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO, "output filter name (or ; delimited names) followed by one or " "more file extensions"),
AP_INIT_ITERATE2("AddType", add_extension_info,
(void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO, "a mime type followed by one or more file extensions"),
AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot,
(void*)APR_OFFSETOF(mime_dir_config, default_language), OR_FILEINFO, "language to use for documents with no other language file extension"),
AP_INIT_ITERATE("MultiviewsMatch", multiviews_match, NULL, OR_FILEINFO, "NegotiatedOnly (default), Handlers and/or Filters, or Any"),
AP_INIT_ITERATE("RemoveCharset", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveEncoding", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveHandler", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveInputFilter", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveLanguage", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveOutputFilter", remove_extension_info,
(void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO, "one or more file extensions"),
AP_INIT_ITERATE("RemoveType", remove_extension_type,
(void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO, "one or more file extensions"),
AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF, "the MIME types config file"),
AP_INIT_FLAG("ModMimeUsePathInfo", ap_set_flag_slot,
(void *)APR_OFFSETOF(mime_dir_config, use_path_info), ACCESS_CONF, "Set to 'yes' to allow mod_mime to use path info for type checking"),
{NULL}
};
/* * 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.
*/ staticint find_ct(request_rec *r)
{
mime_dir_config *conf;
apr_array_header_t *exception_list; char *ext; constchar *fn, *fntmp, *type, *charset = NULL, *resource_name, *qm; int found_metadata = 0;
/* If use_path_info is explicitly set to on (value & 1 == 1), append. */ if (conf->use_path_info & 1) {
resource_name = apr_pstrcat(r->pool, r->filename, r->path_info, NULL);
} /* * In the reverse proxy case r->filename might contain a query string if * the nocanon option was used with ProxyPass. * If this is the case cut off the query string as the last parameter in * this query string might end up on an extension we take care about, but * we only want to match against path components not against query * parameters.
*/ elseif ((r->proxyreq == PROXYREQ_REVERSE)
&& (apr_table_get(r->notes, "proxy-nocanon"))
&& ((qm = ap_strchr_c(r->filename, '?')) != NULL)) {
resource_name = apr_pstrmemdup(r->pool, r->filename, qm - r->filename);
} else {
resource_name = r->filename;
}
/* Always drop the path leading up to the file name.
*/ if ((fn = ap_strrchr_c(resource_name, '/')) == NULL) {
fn = resource_name;
} 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). * Leading dots are considered to be part of the base name (a file named * ".png" is likely not a png file but just a hidden file called png).
*/
fntmp = fn; while (*fntmp == '.')
fntmp++;
fntmp = ap_strchr_c(fntmp, '.'); if (fntmp) {
ext = apr_pstrmemdup(r->pool, fn, fntmp - fn);
fn = fntmp + 1;
} else {
ext = apr_pstrdup(r->pool, fn);
fn += strlen(fn);
}
/* Parse filename extensions which can be in any order
*/ while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) { const extension_info *exinfo = NULL; int found; char *extcase;
if (exinfo == NULL || !exinfo->forced_type) { if ((type = apr_hash_get(mime_type_extensions, ext,
APR_HASH_KEY_STRING)) != NULL) {
ap_set_content_type_ex(r, (char*) type, 1);
found = 1;
}
}
if (exinfo != NULL) {
/* empty string is treated as special case for RemoveType */ if (exinfo->forced_type && *exinfo->forced_type) {
ap_set_content_type_ex(r, exinfo->forced_type, 1);
found = 1;
}
if (exinfo->charset_type) {
charset = exinfo->charset_type;
found = 1;
} if (exinfo->language_type) { if (!r->content_languages) {
r->content_languages = apr_array_make(r->pool, 2, sizeof(char *));
}
*((constchar **)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 * * ah no. Order is important and double encoding is neither * forbidden nor impossible. -- nd
*/
r->content_encoding = apr_pstrcat(r->pool,
r->content_encoding, ", ",
exinfo->encoding_type,
NULL);
}
found = 1;
} /* The following extensions are not 'Found'. That is, they don't * make any contribution to metadata negotiation, so they must have * been explicitly requested by name.
*/ if (exinfo->handler && r->proxyreq == PROXYREQ_NONE) {
r->handler = exinfo->handler; if (conf->multimatch & MULTIMATCH_HANDLERS) {
found = 1;
}
} /* XXX Two significant problems; 1, we don't check to see if we are * setting redundant filters. 2, we insert these in the types * config hook, which may be too early (dunno.)
*/ if (exinfo->input_filters) { constchar *filter, *filters = exinfo->input_filters; while (*filters
&& (filter = ap_getword(r->pool, &filters, ';'))) {
ap_add_input_filter(filter, NULL, r, r->connection);
} if (conf->multimatch & MULTIMATCH_FILTERS) {
found = 1;
}
} if (exinfo->output_filters) { constchar *filter, *filters = exinfo->output_filters; while (*filters
&& (filter = ap_getword(r->pool, &filters, ';'))) {
ap_add_output_filter(filter, NULL, r, r->connection);
} if (conf->multimatch & MULTIMATCH_FILTERS) {
found = 1;
}
}
}
/* * 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; int override = 0;
staticvoid register_hooks(apr_pool_t *p)
{
ap_hook_post_config(mime_post_config,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_type_checker(find_ct,NULL,NULL,APR_HOOK_MIDDLE); /* * this hook seems redundant ... is there any reason a type checker isn't * allowed to do this already? I'd think that fixups in general would be * the last opportunity to get the filters right. * ap_hook_insert_filter(mime_insert_filters,NULL,NULL,APR_HOOK_MIDDLE);
*/
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.