1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
* contributor license agreements. See the NOTICE file distributed with
3
* this work for additional information regarding copyright ownership.
4
* The ASF licenses this file to You under the Apache License, Version 2.0
5
* (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
* http_mime.c: Sends/gets MIME headers for requests
25
#include "apr_strings.h"
29
#define APR_WANT_STRFUNC
32
#include "ap_config.h"
34
#include "http_config.h"
36
#include "http_request.h"
37
#include "http_protocol.h"
39
/* XXXX - fix me / EBCDIC
40
* there was a cludge here which would use its
41
* own version apr_isascii(). Indicating that
42
* on some platforms that might be needed.
44
* #define OS_ASC(c) (c) -- for mere mortals
46
* #define OS_ASC(c) (ebcdic2ascii[c]) -- for dino's
48
* #define apr_isascii(c) ((OS_ASC(c) & 0x80) == 0)
51
/* XXXXX - fix me - See note with NOT_PROXY
54
typedef struct attrib_info {
59
/* Information to which an extension can be mapped
61
typedef struct extension_info {
62
char *forced_type; /* Additional AddTyped stuff */
63
char *encoding_type; /* Added with AddEncoding... */
64
char *language_type; /* Added with AddLanguage... */
65
char *handler; /* Added with AddHandler... */
66
char *charset_type; /* Added with AddCharset... */
67
char *input_filters; /* Added with AddInputFilter... */
68
char *output_filters; /* Added with AddOutputFilter... */
71
#define MULTIMATCH_UNSET 0
72
#define MULTIMATCH_ANY 1
73
#define MULTIMATCH_NEGOTIATED 2
74
#define MULTIMATCH_HANDLERS 4
75
#define MULTIMATCH_FILTERS 8
78
apr_hash_t *extension_mappings; /* Map from extension name to
79
* extension_info structure */
81
apr_array_header_t *remove_mappings; /* A simple list, walked once */
83
char *default_language; /* Language if no AddLanguage ext found */
85
int multimatch; /* Extensions to include in multiview matching
86
* for filenames, e.g. Filters and Handlers
88
int use_path_info; /* If set to 0, only use filename.
89
* If set to 1, append PATH_INFO to filename for
91
* If set to 2, this value is unset and is
96
typedef struct param_s {
106
apr_size_t subtype_len;
110
static char tspecial[] = {
111
'(', ')', '<', '>', '@', ',', ';', ':',
112
'\\', '"', '/', '[', ']', '?', '=',
116
module AP_MODULE_DECLARE_DATA mime_module;
118
static void *create_mime_dir_config(apr_pool_t *p, char *dummy)
120
mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
122
new->extension_mappings = NULL;
123
new->remove_mappings = NULL;
125
new->default_language = NULL;
127
new->multimatch = MULTIMATCH_UNSET;
129
new->use_path_info = 2;
134
* Overlay one hash table of extension_mappings onto another
136
static void *overlay_extension_mappings(apr_pool_t *p,
139
const void *overlay_val,
140
const void *base_val,
143
extension_info *new_info = apr_palloc(p, sizeof(extension_info));
144
const extension_info *overlay_info = (const extension_info *)overlay_val;
145
const extension_info *base_info = (const extension_info *)base_val;
147
memcpy(new_info, base_info, sizeof(extension_info));
148
if (overlay_info->forced_type) {
149
new_info->forced_type = overlay_info->forced_type;
151
if (overlay_info->encoding_type) {
152
new_info->encoding_type = overlay_info->encoding_type;
154
if (overlay_info->language_type) {
155
new_info->language_type = overlay_info->language_type;
157
if (overlay_info->handler) {
158
new_info->handler = overlay_info->handler;
160
if (overlay_info->charset_type) {
161
new_info->charset_type = overlay_info->charset_type;
163
if (overlay_info->input_filters) {
164
new_info->input_filters = overlay_info->input_filters;
166
if (overlay_info->output_filters) {
167
new_info->output_filters = overlay_info->output_filters;
173
/* Member is the offset within an extension_info of the pointer to reset
175
static void remove_items(apr_pool_t *p, apr_array_header_t *remove,
176
apr_hash_t *mappings)
178
attrib_info *suffix = (attrib_info *) remove->elts;
180
for (i = 0; i < remove->nelts; i++) {
181
extension_info *exinfo = apr_hash_get(mappings,
183
APR_HASH_KEY_STRING);
184
if (exinfo && *(const char**)((char *)exinfo + suffix[i].offset)) {
185
extension_info *copyinfo = exinfo;
186
exinfo = (extension_info*)apr_palloc(p, sizeof(*exinfo));
187
apr_hash_set(mappings, suffix[i].name,
188
APR_HASH_KEY_STRING, exinfo);
189
memcpy(exinfo, copyinfo, sizeof(*exinfo));
190
*(const char**)((char *)exinfo + suffix[i].offset) = NULL;
195
static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
197
mime_dir_config *base = (mime_dir_config *)basev;
198
mime_dir_config *add = (mime_dir_config *)addv;
199
mime_dir_config *new = apr_palloc(p, sizeof(mime_dir_config));
201
if (base->extension_mappings && add->extension_mappings) {
202
new->extension_mappings = apr_hash_merge(p, add->extension_mappings,
203
base->extension_mappings,
204
overlay_extension_mappings,
208
if (base->extension_mappings == NULL) {
209
new->extension_mappings = add->extension_mappings;
212
new->extension_mappings = base->extension_mappings;
214
/* We may not be merging the tables, but if we potentially will change
215
* an exinfo member, then we are about to trounce it anyways.
216
* We must have a copy for safety.
218
if (new->extension_mappings && add->remove_mappings) {
219
new->extension_mappings =
220
apr_hash_copy(p, new->extension_mappings);
224
if (new->extension_mappings) {
225
if (add->remove_mappings)
226
remove_items(p, add->remove_mappings, new->extension_mappings);
228
new->remove_mappings = NULL;
230
new->default_language = add->default_language ?
231
add->default_language : base->default_language;
233
new->multimatch = (add->multimatch != MULTIMATCH_UNSET) ?
234
add->multimatch : base->multimatch;
236
if ((add->use_path_info & 2) == 0) {
237
new->use_path_info = add->use_path_info;
240
new->use_path_info = base->use_path_info;
246
static const char *add_extension_info(cmd_parms *cmd, void *m_,
247
const char *value_, const char* ext)
249
mime_dir_config *m=m_;
250
extension_info *exinfo;
251
int offset = (int) (long) cmd->info;
252
char *key = apr_pstrdup(cmd->temp_pool, ext);
253
char *value = apr_pstrdup(cmd->pool, value_);
254
ap_str_tolower(value);
260
if (!m->extension_mappings) {
261
m->extension_mappings = apr_hash_make(cmd->pool);
265
exinfo = (extension_info*)apr_hash_get(m->extension_mappings, key,
266
APR_HASH_KEY_STRING);
269
exinfo = apr_pcalloc(cmd->pool, sizeof(extension_info));
270
key = apr_pstrdup(cmd->pool, key);
271
apr_hash_set(m->extension_mappings, key, APR_HASH_KEY_STRING, exinfo);
273
*(const char**)((char *)exinfo + offset) = value;
278
* Note handler names are un-added with each per_dir_config merge.
279
* This keeps the association from being inherited, but not
280
* from being re-added at a subordinate level.
282
static const char *remove_extension_info(cmd_parms *cmd, void *m_,
285
mime_dir_config *m = (mime_dir_config *) m_;
290
if (!m->remove_mappings) {
291
m->remove_mappings = apr_array_make(cmd->pool, 4, sizeof(*suffix));
293
suffix = (attrib_info *)apr_array_push(m->remove_mappings);
294
suffix->name = apr_pstrdup(cmd->pool, ext);
295
ap_str_tolower(suffix->name);
296
suffix->offset = (int) (long) cmd->info;
300
/* The sole bit of server configuration that the MIME module has is
301
* the name of its config file, so...
304
static const char *set_types_config(cmd_parms *cmd, void *dummy,
307
ap_set_module_config(cmd->server->module_config, &mime_module,
312
static const char *multiviews_match(cmd_parms *cmd, void *m_,
315
mime_dir_config *m = (mime_dir_config *) m_;
317
if (strcasecmp(include, "Any") == 0) {
318
if (m->multimatch && (m->multimatch & ~MULTIMATCH_ANY)) {
319
return "Any is incompatible with NegotiatedOnly, "
320
"Filters and Handlers";
322
m->multimatch |= MULTIMATCH_ANY;
324
else if (strcasecmp(include, "NegotiatedOnly") == 0) {
325
if (m->multimatch && (m->multimatch & ~MULTIMATCH_NEGOTIATED)) {
326
return "NegotiatedOnly is incompatible with Any, "
327
"Filters and Handlers";
329
m->multimatch |= MULTIMATCH_NEGOTIATED;
331
else if (strcasecmp(include, "Filters") == 0) {
332
if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
333
| MULTIMATCH_ANY))) {
334
return "Filters is incompatible with Any and NegotiatedOnly";
336
m->multimatch |= MULTIMATCH_FILTERS;
338
else if (strcasecmp(include, "Handlers") == 0) {
339
if (m->multimatch && (m->multimatch & (MULTIMATCH_NEGOTIATED
340
| MULTIMATCH_ANY))) {
341
return "Handlers is incompatible with Any and NegotiatedOnly";
343
m->multimatch |= MULTIMATCH_HANDLERS;
346
return apr_psprintf(cmd->pool, "Unrecognized option '%s'", include);
352
static const command_rec mime_cmds[] =
354
AP_INIT_ITERATE2("AddCharset", add_extension_info,
355
(void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
356
"a charset (e.g., iso-2022-jp), followed by one or more "
358
AP_INIT_ITERATE2("AddEncoding", add_extension_info,
359
(void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
360
"an encoding (e.g., gzip), followed by one or more file extensions"),
361
AP_INIT_ITERATE2("AddHandler", add_extension_info,
362
(void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
363
"a handler name followed by one or more file extensions"),
364
AP_INIT_ITERATE2("AddInputFilter", add_extension_info,
365
(void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
366
"input filter name (or ; delimited names) followed by one or "
367
"more file extensions"),
368
AP_INIT_ITERATE2("AddLanguage", add_extension_info,
369
(void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
370
"a language (e.g., fr), followed by one or more file extensions"),
371
AP_INIT_ITERATE2("AddOutputFilter", add_extension_info,
372
(void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
373
"output filter name (or ; delimited names) followed by one or "
374
"more file extensions"),
375
AP_INIT_ITERATE2("AddType", add_extension_info,
376
(void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
377
"a mime type followed by one or more file extensions"),
378
AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot,
379
(void*)APR_OFFSETOF(mime_dir_config, default_language), OR_FILEINFO,
380
"language to use for documents with no other language file extension"),
381
AP_INIT_ITERATE("MultiviewsMatch", multiviews_match, NULL, OR_FILEINFO,
382
"NegotiatedOnly (default), Handlers and/or Filters, or Any"),
383
AP_INIT_ITERATE("RemoveCharset", remove_extension_info,
384
(void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
385
"one or more file extensions"),
386
AP_INIT_ITERATE("RemoveEncoding", remove_extension_info,
387
(void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
388
"one or more file extensions"),
389
AP_INIT_ITERATE("RemoveHandler", remove_extension_info,
390
(void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
391
"one or more file extensions"),
392
AP_INIT_ITERATE("RemoveInputFilter", remove_extension_info,
393
(void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
394
"one or more file extensions"),
395
AP_INIT_ITERATE("RemoveLanguage", remove_extension_info,
396
(void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
397
"one or more file extensions"),
398
AP_INIT_ITERATE("RemoveOutputFilter", remove_extension_info,
399
(void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
400
"one or more file extensions"),
401
AP_INIT_ITERATE("RemoveType", remove_extension_info,
402
(void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
403
"one or more file extensions"),
404
AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF,
405
"the MIME types config file"),
406
AP_INIT_FLAG("ModMimeUsePathInfo", ap_set_flag_slot,
407
(void *)APR_OFFSETOF(mime_dir_config, use_path_info), ACCESS_CONF,
408
"Set to 'yes' to allow mod_mime to use path info for type checking"),
412
static apr_hash_t *mime_type_extensions;
414
static int mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
417
char l[MAX_STRING_LEN];
418
const char *types_confname = ap_get_module_config(s->module_config,
422
if (!types_confname) {
423
types_confname = AP_TYPES_CONFIG_FILE;
426
types_confname = ap_server_root_relative(p, types_confname);
427
if (!types_confname) {
428
ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
429
"Invalid mime types config path %s",
430
(const char *)ap_get_module_config(s->module_config,
432
return HTTP_INTERNAL_SERVER_ERROR;
434
if ((status = ap_pcfg_openfile(&f, ptemp, types_confname))
436
ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
437
"could not open mime types config file %s.",
439
return HTTP_INTERNAL_SERVER_ERROR;
442
mime_type_extensions = apr_hash_make(p);
444
while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
445
const char *ll = l, *ct;
450
ct = ap_getword_conf(p, &ll);
453
char *ext = ap_getword_conf(p, &ll);
455
apr_hash_set(mime_type_extensions, ext, APR_HASH_KEY_STRING, ct);
462
static const char *zap_sp(const char *s)
471
/* skip prefixed white space */
472
for (; *s == ' ' || *s == '\t' || *s == '\n'; s++)
478
static char *zap_sp_and_dup(apr_pool_t *p, const char *start,
479
const char *end, apr_size_t *len)
481
while ((start < end) && apr_isspace(*start)) {
484
while ((end > start) && apr_isspace(*(end - 1))) {
490
return apr_pstrmemdup(p, start, end - start);
493
static int is_token(char c)
497
res = (apr_isascii(c) && apr_isgraph(c)
498
&& (strchr(tspecial, c) == NULL)) ? 1 : -1;
502
static int is_qtext(char c)
506
res = (apr_isascii(c) && (c != '"') && (c != '\\') && (c != '\n'))
511
static int is_quoted_pair(const char *s)
516
if (((s + 1) != NULL) && (*s == '\\')) {
518
if (apr_isascii(c)) {
525
static content_type *analyze_ct(request_rec *r, const char *s)
528
char *attribute, *value;
530
server_rec * ss = r->server;
531
apr_pool_t * p = r->pool;
537
ctp = (content_type *)apr_palloc(p, sizeof(content_type));
546
while (apr_isspace(*cp)) {
550
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
551
"mod_mime: analyze_ct: cannot get media type from '%s'",
558
} while (*cp && (*cp != '/') && !apr_isspace(*cp) && (*cp != ';'));
559
if (!*cp || (*cp == ';')) {
560
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
561
"Cannot get media type from '%s'",
565
while (apr_isspace(*cp)) {
569
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
570
"mod_mime: analyze_ct: cannot get media type from '%s'",
574
ctp->type_len = cp - ctp->type;
576
cp++; /* skip the '/' */
578
/* getting a subtype */
579
while (apr_isspace(*cp)) {
583
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
584
"Cannot get media subtype.");
590
} while (*cp && !apr_isspace(*cp) && (*cp != ';'));
591
ctp->subtype_len = cp - ctp->subtype;
592
while (apr_isspace(*cp)) {
600
/* getting parameters */
601
cp++; /* skip the ';' */
603
if (cp == NULL || *cp == '\0') {
604
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
605
"Cannot get media parameter.");
612
while (cp != NULL && *cp != '\0') {
613
if (attribute == NULL) {
614
if (is_token(*cp) > 0) {
618
else if (*cp == ' ' || *cp == '\t' || *cp == '\n') {
622
else if (*cp == '=') {
623
attribute = zap_sp_and_dup(p, mp, cp, NULL);
624
if (attribute == NULL || *attribute == '\0') {
625
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
626
"Cannot get media parameter.");
631
if (cp == NULL || *cp == '\0') {
632
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
633
"Cannot get media parameter.");
640
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
641
"Cannot get media parameter.");
656
while (quoted && *cp != '\0') {
657
if (is_qtext(*cp) > 0) {
660
else if (is_quoted_pair(cp) > 0) {
663
else if (*cp == '"') {
665
while (*cp == ' ' || *cp == '\t' || *cp == '\n') {
668
if (*cp != ';' && *cp != '\0') {
669
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
670
"Cannot get media parameter.");
676
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
677
"Cannot get media parameter.");
684
if (is_token(*cp) > 0) {
687
else if (*cp == '\0' || *cp == ';') {
691
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
692
"Cannot get media parameter.");
697
value = zap_sp_and_dup(p, mp, cp, NULL);
698
if (value == NULL || *value == '\0') {
699
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss,
700
"Cannot get media parameter.");
704
pp = apr_palloc(p, sizeof(param));
705
pp->attr = attribute;
709
if (ctp->param == NULL) {
733
* find_ct is the hook routine for determining content-type and other
734
* MIME-related metadata. It assumes that r->filename has already been
735
* set and stat has been called for r->finfo. It also assumes that the
736
* non-path base file name is not the empty string unless it is a dir.
738
static int find_ct(request_rec *r)
740
mime_dir_config *conf;
741
apr_array_header_t *exception_list;
743
const char *fn, *type, *charset = NULL, *resource_name;
744
int found_metadata = 0;
746
if (r->finfo.filetype == APR_DIR) {
747
ap_set_content_type(r, DIR_MAGIC_TYPE);
755
conf = (mime_dir_config *)ap_get_module_config(r->per_dir_config,
757
exception_list = apr_array_make(r->pool, 2, sizeof(char *));
759
/* If use_path_info is explicitly set to on (value & 1 == 1), append. */
760
if (conf->use_path_info & 1) {
761
resource_name = apr_pstrcat(r->pool, r->filename, r->path_info, NULL);
764
resource_name = r->filename;
767
/* Always drop the path leading up to the file name.
769
if ((fn = ap_strrchr_c(resource_name, '/')) == NULL) {
776
/* The exception list keeps track of those filename components that
777
* are not associated with extensions indicating metadata.
778
* The base name is always the first exception (i.e., "txt.html" has
779
* a basename of "txt" even though it might look like an extension).
781
ext = ap_getword(r->pool, &fn, '.');
782
*((const char **)apr_array_push(exception_list)) = ext;
784
/* Parse filename extensions which can be in any order
786
while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) {
787
const extension_info *exinfo = NULL;
790
if (*ext == '\0') { /* ignore empty extensions "bad..html" */
798
if (conf->extension_mappings != NULL) {
799
exinfo = (extension_info*)apr_hash_get(conf->extension_mappings,
800
ext, APR_HASH_KEY_STRING);
803
if (exinfo == NULL || !exinfo->forced_type) {
804
if ((type = apr_hash_get(mime_type_extensions, ext,
805
APR_HASH_KEY_STRING)) != NULL) {
806
ap_set_content_type(r, (char*) type);
811
if (exinfo != NULL) {
813
if (exinfo->forced_type) {
814
ap_set_content_type(r, exinfo->forced_type);
818
if (exinfo->charset_type) {
819
charset = exinfo->charset_type;
822
if (exinfo->language_type) {
823
if (!r->content_languages) {
824
r->content_languages = apr_array_make(r->pool, 2,
827
*((const char **)apr_array_push(r->content_languages))
828
= exinfo->language_type;
831
if (exinfo->encoding_type) {
832
if (!r->content_encoding) {
833
r->content_encoding = exinfo->encoding_type;
836
/* XXX should eliminate duplicate entities
838
* ah no. Order is important and double encoding is neither
839
* forbidden nor impossible. -- nd
841
r->content_encoding = apr_pstrcat(r->pool,
844
exinfo->encoding_type,
849
/* The following extensions are not 'Found'. That is, they don't
850
* make any contribution to metadata negotation, so they must have
851
* been explicitly requested by name.
853
if (exinfo->handler && r->proxyreq == PROXYREQ_NONE) {
854
r->handler = exinfo->handler;
855
if (conf->multimatch & MULTIMATCH_HANDLERS) {
859
/* XXX Two significant problems; 1, we don't check to see if we are
860
* setting redundant filters. 2, we insert these in the types config
861
* hook, which may be too early (dunno.)
863
if (exinfo->input_filters && r->proxyreq == PROXYREQ_NONE) {
864
const char *filter, *filters = exinfo->input_filters;
866
&& (filter = ap_getword(r->pool, &filters, ';'))) {
867
ap_add_input_filter(filter, NULL, r, r->connection);
869
if (conf->multimatch & MULTIMATCH_FILTERS) {
873
if (exinfo->output_filters && r->proxyreq == PROXYREQ_NONE) {
874
const char *filter, *filters = exinfo->output_filters;
876
&& (filter = ap_getword(r->pool, &filters, ';'))) {
877
ap_add_output_filter(filter, NULL, r, r->connection);
879
if (conf->multimatch & MULTIMATCH_FILTERS) {
885
if (found || (conf->multimatch & MULTIMATCH_ANY)) {
889
*((const char **) apr_array_push(exception_list)) = ext;
894
* Need to set a notes entry on r for unrecognized elements.
895
* Somebody better claim them! If we did absolutely nothing,
896
* skip the notes to alert mod_negotiation we are clueless.
898
if (found_metadata) {
899
apr_table_setn(r->notes, "ap-mime-exceptions-list",
900
(void *)exception_list);
903
if (r->content_type) {
907
if ((ctp = analyze_ct(r, r->content_type))) {
908
param *pp = ctp->param;
909
char *base_content_type = apr_palloc(r->pool, ctp->type_len +
912
char *tmp = base_content_type;
913
memcpy(tmp, ctp->type, ctp->type_len);
914
tmp += ctp->type_len;
916
memcpy(tmp, ctp->subtype, ctp->subtype_len);
917
tmp += ctp->subtype_len;
919
ap_set_content_type(r, base_content_type);
921
if (charset && !strcmp(pp->attr, "charset")) {
923
ap_set_content_type(r,
933
ap_set_content_type(r,
942
if (charset && !override) {
943
ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type,
944
"; charset=", charset,
950
/* Set default language, if none was specified by the extensions
951
* and we have a DefaultLanguage setting in force
954
if (!r->content_languages && conf->default_language) {
957
if (!r->content_languages) {
958
r->content_languages = apr_array_make(r->pool, 2, sizeof(char *));
960
new = (const char **)apr_array_push(r->content_languages);
961
*new = conf->default_language;
964
if (!r->content_type) {
971
static void register_hooks(apr_pool_t *p)
973
ap_hook_post_config(mime_post_config,NULL,NULL,APR_HOOK_MIDDLE);
974
ap_hook_type_checker(find_ct,NULL,NULL,APR_HOOK_MIDDLE);
976
* this hook seems redundant ... is there any reason a type checker isn't
977
* allowed to do this already? I'd think that fixups in general would be
978
* the last opportunity to get the filters right.
979
* ap_hook_insert_filter(mime_insert_filters,NULL,NULL,APR_HOOK_MIDDLE);
983
module AP_MODULE_DECLARE_DATA mime_module = {
984
STANDARD20_MODULE_STUFF,
985
create_mime_dir_config, /* create per-directory config structure */
986
merge_mime_dir_configs, /* merge per-directory config structures */
987
NULL, /* create per-server config structure */
988
NULL, /* merge per-server config structures */
989
mime_cmds, /* command apr_table_t */
990
register_hooks /* register hooks */