1 /* Functionality for handling mime types */
4 #define _GNU_SOURCE /* XXX: we _WANT_ strcasestr() ! */
15 #include "cache/cache.h"
16 #include "config/options.h"
17 #include "encoding/encoding.h"
18 #include "intl/gettext/libintl.h"
19 #include "main/module.h"
20 #include "mime/backend/common.h"
21 #include "mime/mime.h"
22 #include "protocol/header.h" /* For parse_header() */
23 #include "protocol/uri.h"
24 #include "util/conv.h"
25 #include "util/file.h"
26 #include "util/memory.h"
27 #include "util/string.h"
37 static struct option_info mime_options
[] = {
38 INIT_OPT_TREE("", N_("MIME"),
40 N_("MIME-related options (handlers of various MIME types).")),
42 INIT_OPT_STRING("mime", N_("Default MIME-type"),
43 "default_type", 0, DEFAULT_MIME_TYPE
,
44 N_("Document MIME-type to assume by default (when we are unable to\n"
45 "guess it properly from known information about the document).")),
50 #define get_opt_mime(which) mime_options[(which)].option
51 #define get_default_mime_type() get_opt_mime(MIME_DEFAULT_TYPE).value.string
53 /* Checks protocols headers for a suitable filename */
54 static unsigned char *
55 get_content_filename(struct uri
*uri
, struct cache_entry
*cached
)
57 unsigned char *filename
, *pos
;
59 if (!cached
) cached
= find_in_cache(uri
);
61 if (!cached
|| !cached
->head
)
64 pos
= parse_header(cached
->head
, "Content-Disposition", NULL
);
65 if (!pos
) return NULL
;
67 filename
= parse_header_param(pos
, "filename");
69 if (!filename
) return NULL
;
71 /* Remove start and ending quotes. */
72 if (filename
[0] == '"') {
73 int len
= strlen(filename
);
75 if (len
> 1 && filename
[len
- 1] == '"') {
76 filename
[len
- 1] = 0;
77 memmove(filename
, filename
+ 1, len
);
80 /* It was an empty quotation: "" */
87 /* We don't want to add any directories from the path so make sure we
88 * only add the filename. */
89 pos
= get_filename_position(filename
);
96 memmove(filename
, pos
, strlen(pos
) + 1);
101 /* Checks if application/x-<extension> has any handlers. */
102 static inline unsigned char *
103 check_extension_type(unsigned char *extension
)
105 /* Trim the extension so only last .<extension> is used. */
106 unsigned char *trimmed
= strrchr(extension
, '.');
107 struct mime_handler
*handler
;
108 unsigned char *content_type
;
113 content_type
= straconcat("application/x-", trimmed
+ 1, NULL
);
117 handler
= get_mime_type_handler(content_type
, 1);
123 mem_free(content_type
);
127 /* Check if part of the extension coresponds to a supported encoding and if it
128 * has any handlers. */
129 static inline unsigned char *
130 check_encoding_type(unsigned char *extension
)
132 enum stream_encoding encoding
= guess_encoding(extension
);
133 unsigned char **extension_list
;
134 unsigned char *last_extension
= strrchr(extension
, '.');
136 if (encoding
== ENCODING_NONE
|| !last_extension
)
139 for (extension_list
= listext_encoded(encoding
);
140 extension_list
&& *extension_list
;
142 unsigned char *content_type
;
144 if (strcmp(*extension_list
, last_extension
))
147 *last_extension
= '\0';
148 content_type
= get_content_type_backends(extension
);
149 *last_extension
= '.';
158 #define DEBUG_CONTENT_TYPE
161 #ifdef DEBUG_CONTENT_TYPE
162 #define debug_get_content_type_params(cached) \
163 DBG("get_content_type(head, url)\n=== head ===\n%s\n=== url ===\n%s\n", (cached)->head, struri((cached)->uri))
164 #define debug_ctype(ctype__) DBG("ctype= %s", (ctype__))
165 #define debug_extension(extension__) DBG("extension= %s", (extension__))
167 #define debug_get_content_type_params(cached)
168 #define debug_ctype(ctype__)
169 #define debug_extension(extension__)
173 get_extension_content_type(unsigned char *extension
)
175 unsigned char *ctype
;
177 assert(extension
&& *extension
);
179 ctype
= get_content_type_backends(extension
);
181 if (ctype
) return ctype
;
183 ctype
= check_encoding_type(extension
);
185 if (ctype
) return ctype
;
187 ctype
= check_extension_type(extension
);
193 get_cache_header_content_type(struct cache_entry
*cached
)
195 unsigned char *extension
, *ctype
;
197 ctype
= parse_header(cached
->head
, "Content-Type", NULL
);
199 unsigned char *end
= strchr(ctype
, ';');
202 if (end
) *end
= '\0';
204 ctypelen
= strlen(ctype
);
205 while (ctypelen
&& ctype
[--ctypelen
] <= ' ')
206 ctype
[ctypelen
] = '\0';
217 /* This searches cached->head for filename so put here */
218 extension
= get_content_filename(cached
->uri
, cached
);
219 debug_extension(extension
);
221 ctype
= get_extension_content_type(extension
);
232 get_fragment_content_type(struct cache_entry
*cached
)
234 struct fragment
*fragment
;
236 unsigned char *sample
;
237 unsigned char *ctype
= NULL
;
239 if (list_empty(cached
->frag
))
242 fragment
= cached
->frag
.next
;
243 if (fragment
->offset
)
246 length
= fragment
->length
> 1024 ? 1024 : fragment
->length
;
247 sample
= memacpy(fragment
->data
, length
);
251 if (strcasestr(sample
, "<html>"))
252 ctype
= stracpy("text/html");
260 get_content_type(struct cache_entry
*cached
)
262 unsigned char *extension
, *ctype
;
264 debug_get_content_type_params(cached
);
266 if (cached
->content_type
)
267 return cached
->content_type
;
269 /* If there's one in header, it's simple.. */
271 ctype
= get_cache_header_content_type(cached
);
272 if (ctype
&& *ctype
) {
273 cached
->content_type
= ctype
;
279 /* We can't use the extension string we are getting below, because we
280 * want to support also things like "ps.gz" - that'd never work, as we
281 * would always compare only to "gz". */
282 /* Guess type accordingly to the extension */
283 extension
= get_extension_from_uri(cached
->uri
);
284 debug_extension(extension
);
287 /* XXX: A little hack for making extension handling case
288 * insensitive. We could probably do it better by making
289 * guess_encoding() case independent the real problem however
290 * is with default (via option system) and mimetypes resolving
291 * doing that option and hash lookup will not be easy to
292 * convert. --jonas */
293 convert_to_lowercase(extension
, strlen(extension
));
295 ctype
= get_extension_content_type(extension
);
297 if (ctype
&& *ctype
) {
298 cached
->content_type
= ctype
;
304 ctype
= get_fragment_content_type(cached
);
305 if (ctype
&& *ctype
) {
306 cached
->content_type
= ctype
;
310 debug_ctype(get_default_mime_type());
312 /* Fallback.. use some hardwired default */
313 cached
->content_type
= stracpy(get_default_mime_type());
315 return cached
->content_type
;
318 struct mime_handler
*
319 get_mime_type_handler(unsigned char *content_type
, int xwin
)
321 return get_mime_handler_backends(content_type
, xwin
);
325 add_mime_filename_to_string(struct string
*string
, struct uri
*uri
)
327 unsigned char *filename
= get_content_filename(uri
, NULL
);
332 add_shell_safe_to_string(string
, filename
, strlen(filename
));
338 return add_uri_to_string(string
, uri
, URI_FILENAME
);
341 /* Backends dynamic area: */
343 #include "mime/backend/default.h"
344 #include "mime/backend/mailcap.h"
345 #include "mime/backend/mimetypes.h"
347 static struct module
*mime_submodules
[] = {
348 &default_mime_module
,
349 #ifdef CONFIG_MAILCAP
350 &mailcap_mime_module
,
352 #ifdef CONFIG_MIMETYPES
353 &mimetypes_mime_module
,
358 struct module mime_module
= struct_module(
359 /* name: */ N_("MIME"),
360 /* options: */ mime_options
,
362 /* submodules: */ mime_submodules
,