123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008 |
- /* 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
- *
- */
- #include "apr.h"
- #include "apr_strings.h"
- #include "apr_lib.h"
- #include "apr_hash.h"
- #define APR_WANT_STRFUNC
- #include "apr_want.h"
- #include "ap_config.h"
- #include "httpd.h"
- #include "http_config.h"
- #include "http_log.h"
- #include "http_request.h"
- #include "http_protocol.h"
- /* 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
- */
- typedef struct attrib_info {
- char *name;
- int offset;
- } attrib_info;
- /* Information to which an extension can be mapped
- */
- typedef struct 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;
- #define MULTIMATCH_UNSET 0
- #define MULTIMATCH_ANY 1
- #define MULTIMATCH_NEGOTIATED 2
- #define MULTIMATCH_HANDLERS 4
- #define MULTIMATCH_FILTERS 8
- typedef struct {
- 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;
- typedef struct param_s {
- char *attr;
- char *val;
- struct param_s *next;
- } param;
- typedef struct {
- const char *type;
- apr_size_t type_len;
- const char *subtype;
- apr_size_t subtype_len;
- param *param;
- } content_type;
- static char tspecial[] = {
- '(', ')', '<', '>', '@', ',', ';', ':',
- '\\', '"', '/', '[', ']', '?', '=',
- '\0'
- };
- module AP_MODULE_DECLARE_DATA mime_module;
- static void *create_mime_dir_config(apr_pool_t *p, char *dummy)
- {
- mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
- new->extension_mappings = NULL;
- new->remove_mappings = NULL;
- new->default_language = NULL;
- new->multimatch = MULTIMATCH_UNSET;
- new->use_path_info = 2;
- return new;
- }
- /*
- * Overlay one hash table of extension_mappings onto another
- */
- static void *overlay_extension_mappings(apr_pool_t *p,
- const void *key,
- apr_ssize_t klen,
- const void *overlay_val,
- const void *base_val,
- const void *data)
- {
- const extension_info *overlay_info = (const extension_info *)overlay_val;
- const extension_info *base_info = (const extension_info *)base_val;
- extension_info *new_info = apr_pmemdup(p, base_info, sizeof(extension_info));
- if (overlay_info->forced_type) {
- new_info->forced_type = overlay_info->forced_type;
- }
- if (overlay_info->encoding_type) {
- new_info->encoding_type = overlay_info->encoding_type;
- }
- if (overlay_info->language_type) {
- new_info->language_type = overlay_info->language_type;
- }
- if (overlay_info->handler) {
- new_info->handler = overlay_info->handler;
- }
- if (overlay_info->charset_type) {
- new_info->charset_type = overlay_info->charset_type;
- }
- if (overlay_info->input_filters) {
- new_info->input_filters = overlay_info->input_filters;
- }
- if (overlay_info->output_filters) {
- new_info->output_filters = overlay_info->output_filters;
- }
- return new_info;
- }
- /* Member is the offset within an extension_info of the pointer to reset
- */
- static void remove_items(apr_pool_t *p, apr_array_header_t *remove,
- apr_hash_t *mappings)
- {
- attrib_info *suffix = (attrib_info *) remove->elts;
- int i;
- for (i = 0; i < remove->nelts; i++) {
- extension_info *exinfo = apr_hash_get(mappings,
- suffix[i].name,
- APR_HASH_KEY_STRING);
- if (exinfo && *(const char**)((char *)exinfo + suffix[i].offset)) {
- extension_info *copyinfo = exinfo;
- exinfo = (extension_info*)apr_palloc(p, sizeof(*exinfo));
- apr_hash_set(mappings, suffix[i].name,
- APR_HASH_KEY_STRING, exinfo);
- memcpy(exinfo, copyinfo, sizeof(*exinfo));
- *(const char**)((char *)exinfo + suffix[i].offset) = NULL;
- }
- }
- }
- static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
- {
- mime_dir_config *base = (mime_dir_config *)basev;
- mime_dir_config *add = (mime_dir_config *)addv;
- mime_dir_config *new = apr_palloc(p, sizeof(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;
- new->default_language = add->default_language ?
- add->default_language : base->default_language;
- new->multimatch = (add->multimatch != MULTIMATCH_UNSET) ?
- add->multimatch : base->multimatch;
- if ((add->use_path_info & 2) == 0) {
- new->use_path_info = add->use_path_info;
- }
- else {
- new->use_path_info = base->use_path_info;
- }
- return new;
- }
- static const char *add_extension_info(cmd_parms *cmd, void *m_,
- const char *value_, const char* ext)
- {
- mime_dir_config *m=m_;
- extension_info *exinfo;
- int offset = (int) (long) cmd->info;
- char *key = apr_pstrdup(cmd->temp_pool, ext);
- char *value = apr_pstrdup(cmd->pool, value_);
- ap_str_tolower(value);
- ap_str_tolower(key);
- 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);
- }
- *(const char**)((char *)exinfo + offset) = value;
- return NULL;
- }
- /*
- * As RemoveType should also override the info from TypesConfig, we add an
- * empty string as type instead of actually removing the type.
- */
- static const char *remove_extension_type(cmd_parms *cmd, void *m_,
- const char *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.
- */
- static const char *remove_extension_info(cmd_parms *cmd, void *m_,
- const char *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...
- */
- 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 char *multiviews_match(cmd_parms *cmd, void *m_,
- const char *include)
- {
- mime_dir_config *m = (mime_dir_config *) m_;
- const char *errmsg;
- errmsg = ap_check_cmd_context(cmd, NOT_IN_LOCATION);
- if (errmsg != NULL) {
- return errmsg;
- }
- 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;
- }
- else if (strcasecmp(include, "NegotiatedOnly") == 0) {
- if (m->multimatch && (m->multimatch & ~MULTIMATCH_NEGOTIATED)) {
- return "NegotiatedOnly is incompatible with Any, "
- "Filters and Handlers";
- }
- m->multimatch |= MULTIMATCH_NEGOTIATED;
- }
- else if (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;
- }
- else if (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;
- }
- static const 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}
- };
- static apr_hash_t *mime_type_extensions;
- static int 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 (!types_confname) {
- ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
- "Invalid mime types config path %s",
- (const char *)ap_get_module_config(s->module_config,
- &mime_module));
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- 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);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- 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);
- return OK;
- }
- static const char *zap_sp(const char *s)
- {
- if (s == NULL) {
- return (NULL);
- }
- if (*s == '\0') {
- return (s);
- }
- /* skip prefixed white space */
- for (; *s == ' ' || *s == '\t' || *s == '\n'; s++)
- ;
- return (s);
- }
- static char *zap_sp_and_dup(apr_pool_t *p, const char *start,
- const char *end, apr_size_t *len)
- {
- while ((start < end) && apr_isspace(*start)) {
- start++;
- }
- while ((end > start) && apr_isspace(*(end - 1))) {
- end--;
- }
- if (len) {
- *len = end - start;
- }
- return apr_pstrmemdup(p, start, end - start);
- }
- 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(const 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, const char *s)
- {
- const char *cp, *mp;
- 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;
- mp = s;
- /* getting a type */
- cp = mp;
- while (apr_isspace(*cp)) {
- cp++;
- }
- if (!*cp) {
- 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 = cp;
- do {
- cp++;
- } while (*cp && (*cp != '/') && !apr_isspace(*cp) && (*cp != ';'));
- if (!*cp || (*cp == ';')) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
- "Cannot get media type from '%s'",
- (const char *) mp);
- return (NULL);
- }
- while (apr_isspace(*cp)) {
- cp++;
- }
- if (*cp != '/') {
- 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_len = cp - ctp->type;
- cp++; /* skip the '/' */
- /* getting a subtype */
- while (apr_isspace(*cp)) {
- cp++;
- }
- if (!*cp) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
- "Cannot get media subtype.");
- return (NULL);
- }
- ctp->subtype = cp;
- do {
- cp++;
- } while (*cp && !apr_isspace(*cp) && (*cp != ';'));
- ctp->subtype_len = cp - ctp->subtype;
- while (apr_isspace(*cp)) {
- cp++;
- }
- if (*cp == '\0') {
- return (ctp);
- }
- /* getting parameters */
- cp++; /* skip the ';' */
- 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 = zap_sp_and_dup(p, mp, cp, NULL);
- 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 = zap_sp_and_dup(p, mp, cp, NULL);
- 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, *resource_name;
- int found_metadata = 0;
- if (r->finfo.filetype == APR_DIR) {
- ap_set_content_type(r, DIR_MAGIC_TYPE);
- return OK;
- }
- if (!r->filename) {
- return DECLINED;
- }
- conf = (mime_dir_config *)ap_get_module_config(r->per_dir_config,
- &mime_module);
- exception_list = apr_array_make(r->pool, 2, sizeof(char *));
- /* 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);
- }
- 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).
- */
- 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, '.'))) {
- const extension_info *exinfo = NULL;
- int found;
- if (*ext == '\0') { /* ignore empty extensions "bad..html" */
- continue;
- }
- found = 0;
- ap_str_tolower(ext);
- if (conf->extension_mappings != NULL) {
- exinfo = (extension_info*)apr_hash_get(conf->extension_mappings,
- ext, APR_HASH_KEY_STRING);
- }
- if (exinfo == NULL || !exinfo->forced_type) {
- if ((type = apr_hash_get(mime_type_extensions, ext,
- APR_HASH_KEY_STRING)) != NULL) {
- ap_set_content_type(r, (char*) type);
- 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(r, exinfo->forced_type);
- 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 *));
- }
- *((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
- *
- * 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 negotation, 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 && r->proxyreq == PROXYREQ_NONE) {
- const char *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 && r->proxyreq == PROXYREQ_NONE) {
- const char *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;
- }
- }
- }
- if (found || (conf->multimatch & MULTIMATCH_ANY)) {
- 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;
- int override = 0;
- if ((ctp = analyze_ct(r, r->content_type))) {
- param *pp = ctp->param;
- char *base_content_type = apr_palloc(r->pool, ctp->type_len +
- ctp->subtype_len +
- sizeof("/"));
- char *tmp = base_content_type;
- memcpy(tmp, ctp->type, ctp->type_len);
- tmp += ctp->type_len;
- *tmp++ = '/';
- memcpy(tmp, ctp->subtype, ctp->subtype_len);
- tmp += ctp->subtype_len;
- *tmp = 0;
- ap_set_content_type(r, base_content_type);
- while (pp != NULL) {
- if (charset && !strcmp(pp->attr, "charset")) {
- if (!override) {
- ap_set_content_type(r,
- apr_pstrcat(r->pool,
- r->content_type,
- "; charset=",
- charset,
- NULL));
- override = 1;
- }
- }
- else {
- ap_set_content_type(r,
- apr_pstrcat(r->pool,
- r->content_type,
- "; ", pp->attr,
- "=", pp->val,
- NULL));
- }
- pp = pp->next;
- }
- if (charset && !override) {
- ap_set_content_type(r, 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;
- 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;
- }
- if (!r->content_type) {
- return DECLINED;
- }
- return OK;
- }
- static void 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);
- */
- }
- 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 */
- };
|