ServiceWorker: Rename 'current' to 'controller'
[chromium-blink-merge.git] / net / base / mime_util.cc
blob9d15256172ff9fc99f2a5c9e27021cfd785a6263
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <algorithm>
6 #include <iterator>
7 #include <map>
8 #include <string>
10 #include "base/containers/hash_tables.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "net/base/mime_util.h"
18 #include "net/base/platform_mime_util.h"
19 #include "net/http/http_util.h"
21 #if defined(OS_ANDROID)
22 #include "base/android/build_info.h"
23 #endif
25 using std::string;
27 namespace {
29 struct MediaType {
30 const char name[12];
31 const char matcher[13];
34 static const MediaType kIanaMediaTypes[] = {
35 { "application", "application/" },
36 { "audio", "audio/" },
37 { "example", "example/" },
38 { "image", "image/" },
39 { "message", "message/" },
40 { "model", "model/" },
41 { "multipart", "multipart/" },
42 { "text", "text/" },
43 { "video", "video/" },
46 } // namespace
48 namespace net {
50 // Singleton utility class for mime types.
51 class MimeUtil : public PlatformMimeUtil {
52 public:
53 bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
54 std::string* mime_type) const;
56 bool GetMimeTypeFromFile(const base::FilePath& file_path,
57 std::string* mime_type) const;
59 bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
60 std::string* mime_type) const;
62 bool IsSupportedImageMimeType(const std::string& mime_type) const;
63 bool IsSupportedMediaMimeType(const std::string& mime_type) const;
64 bool IsSupportedNonImageMimeType(const std::string& mime_type) const;
65 bool IsUnsupportedTextMimeType(const std::string& mime_type) const;
66 bool IsSupportedJavascriptMimeType(const std::string& mime_type) const;
68 bool IsSupportedMimeType(const std::string& mime_type) const;
70 bool MatchesMimeType(const std::string &mime_type_pattern,
71 const std::string &mime_type) const;
73 bool ParseMimeTypeWithoutParameter(const std::string& type_string,
74 std::string* top_level_type,
75 std::string* subtype) const;
77 bool IsValidTopLevelMimeType(const std::string& type_string) const;
79 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
81 void ParseCodecString(const std::string& codecs,
82 std::vector<std::string>* codecs_out,
83 bool strip);
85 bool IsStrictMediaMimeType(const std::string& mime_type) const;
86 SupportsType IsSupportedStrictMediaMimeType(
87 const std::string& mime_type,
88 const std::vector<std::string>& codecs) const;
90 void RemoveProprietaryMediaTypesAndCodecsForTests();
92 private:
93 friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
95 typedef base::hash_set<std::string> MimeMappings;
96 typedef std::map<std::string, MimeMappings> StrictMappings;
98 typedef std::vector<std::string> MimeExpressionMappings;
99 typedef std::map<std::string, MimeExpressionMappings>
100 StrictExpressionMappings;
102 MimeUtil();
104 // Returns true if |codecs| is nonempty and all the items in it are present in
105 // |supported_codecs|.
106 static bool AreSupportedCodecs(const MimeMappings& supported_codecs,
107 const std::vector<std::string>& codecs);
108 // Returns true is |codecs| is nonempty and all the items in it match with the
109 // codecs expression in |supported_codecs|.
110 static bool AreSupportedCodecsWithProfile(
111 const MimeExpressionMappings& supported_codecs,
112 const std::vector<std::string>& codecs);
114 // For faster lookup, keep hash sets.
115 void InitializeMimeTypeMaps();
117 bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext,
118 bool include_platform_types,
119 std::string* mime_type) const;
121 MimeMappings image_map_;
122 MimeMappings media_map_;
123 MimeMappings non_image_map_;
124 MimeMappings unsupported_text_map_;
125 MimeMappings javascript_map_;
126 MimeMappings codecs_map_;
128 // A map of mime_types and hash map of the supported codecs for the mime_type.
129 StrictMappings strict_format_map_;
130 // A map of MP4 mime_types which expect codecs with profile parameter and
131 // vector of supported codecs expressions for the mime_type.
132 StrictExpressionMappings strict_mp4_format_map_;
133 }; // class MimeUtil
135 // This variable is Leaky because we need to access it from WorkerPool threads.
136 static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
137 LAZY_INSTANCE_INITIALIZER;
139 struct MimeInfo {
140 const char* mime_type;
141 const char* extensions; // comma separated list
144 static const MimeInfo primary_mappings[] = {
145 { "text/html", "html,htm,shtml,shtm" },
146 { "text/css", "css" },
147 { "text/xml", "xml" },
148 { "image/gif", "gif" },
149 { "image/jpeg", "jpeg,jpg" },
150 { "image/webp", "webp" },
151 { "image/png", "png" },
152 { "video/mp4", "mp4,m4v" },
153 { "audio/x-m4a", "m4a" },
154 { "audio/mp3", "mp3" },
155 { "video/ogg", "ogv,ogm" },
156 { "audio/ogg", "ogg,oga,opus" },
157 { "video/webm", "webm" },
158 { "audio/webm", "webm" },
159 { "audio/wav", "wav" },
160 { "application/xhtml+xml", "xhtml,xht,xhtm" },
161 { "application/x-chrome-extension", "crx" },
162 { "multipart/related", "mhtml,mht" }
165 static const MimeInfo secondary_mappings[] = {
166 { "application/octet-stream", "exe,com,bin" },
167 { "application/gzip", "gz" },
168 { "application/pdf", "pdf" },
169 { "application/postscript", "ps,eps,ai" },
170 { "application/javascript", "js" },
171 { "application/font-woff", "woff" },
172 { "image/bmp", "bmp" },
173 { "image/x-icon", "ico" },
174 { "image/vnd.microsoft.icon", "ico" },
175 { "image/jpeg", "jfif,pjpeg,pjp" },
176 { "image/tiff", "tiff,tif" },
177 { "image/x-xbitmap", "xbm" },
178 { "image/svg+xml", "svg,svgz" },
179 { "image/x-png", "png"},
180 { "message/rfc822", "eml" },
181 { "text/plain", "txt,text" },
182 { "text/html", "ehtml" },
183 { "application/rss+xml", "rss" },
184 { "application/rdf+xml", "rdf" },
185 { "text/xml", "xsl,xbl,xslt" },
186 { "application/vnd.mozilla.xul+xml", "xul" },
187 { "application/x-shockwave-flash", "swf,swl" },
188 { "application/pkcs7-mime", "p7m,p7c,p7z" },
189 { "application/pkcs7-signature", "p7s" }
192 static const char* FindMimeType(const MimeInfo* mappings,
193 size_t mappings_len,
194 const char* ext) {
195 size_t ext_len = strlen(ext);
197 for (size_t i = 0; i < mappings_len; ++i) {
198 const char* extensions = mappings[i].extensions;
199 for (;;) {
200 size_t end_pos = strcspn(extensions, ",");
201 if (end_pos == ext_len &&
202 base::strncasecmp(extensions, ext, ext_len) == 0)
203 return mappings[i].mime_type;
204 extensions += end_pos;
205 if (!*extensions)
206 break;
207 extensions += 1; // skip over comma
210 return NULL;
213 bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
214 string* result) const {
215 return GetMimeTypeFromExtensionHelper(ext, true, result);
218 bool MimeUtil::GetWellKnownMimeTypeFromExtension(
219 const base::FilePath::StringType& ext,
220 string* result) const {
221 return GetMimeTypeFromExtensionHelper(ext, false, result);
224 bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path,
225 string* result) const {
226 base::FilePath::StringType file_name_str = file_path.Extension();
227 if (file_name_str.empty())
228 return false;
229 return GetMimeTypeFromExtension(file_name_str.substr(1), result);
232 bool MimeUtil::GetMimeTypeFromExtensionHelper(
233 const base::FilePath::StringType& ext,
234 bool include_platform_types,
235 string* result) const {
236 // Avoids crash when unable to handle a long file path. See crbug.com/48733.
237 const unsigned kMaxFilePathSize = 65536;
238 if (ext.length() > kMaxFilePathSize)
239 return false;
241 // We implement the same algorithm as Mozilla for mapping a file extension to
242 // a mime type. That is, we first check a hard-coded list (that cannot be
243 // overridden), and then if not found there, we defer to the system registry.
244 // Finally, we scan a secondary hard-coded list to catch types that we can
245 // deduce but that we also want to allow the OS to override.
247 base::FilePath path_ext(ext);
248 const string ext_narrow_str = path_ext.AsUTF8Unsafe();
249 const char* mime_type = FindMimeType(primary_mappings,
250 arraysize(primary_mappings),
251 ext_narrow_str.c_str());
252 if (mime_type) {
253 *result = mime_type;
254 return true;
257 if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result))
258 return true;
260 mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
261 ext_narrow_str.c_str());
262 if (mime_type) {
263 *result = mime_type;
264 return true;
267 return false;
270 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
272 static const char* const supported_image_types[] = {
273 "image/jpeg",
274 "image/pjpeg",
275 "image/jpg",
276 "image/webp",
277 "image/png",
278 "image/gif",
279 "image/bmp",
280 "image/vnd.microsoft.icon", // ico
281 "image/x-icon", // ico
282 "image/x-xbitmap", // xbm
283 "image/x-png"
286 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
287 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
288 // This set of codecs is supported by all variations of Chromium.
289 static const char* const common_media_types[] = {
290 // Ogg.
291 "audio/ogg",
292 "application/ogg",
293 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
294 "video/ogg",
295 #endif
297 // WebM.
298 "video/webm",
299 "audio/webm",
301 // Wav.
302 "audio/wav",
303 "audio/x-wav",
305 #if defined(OS_ANDROID)
306 // HLS. Supported by Android ICS and above.
307 "application/vnd.apple.mpegurl",
308 "application/x-mpegurl",
309 #endif
312 // List of proprietary types only supported by Google Chrome.
313 static const char* const proprietary_media_types[] = {
314 // MPEG-4.
315 "video/mp4",
316 "video/x-m4v",
317 "audio/mp4",
318 "audio/x-m4a",
320 // MP3.
321 "audio/mp3",
322 "audio/x-mp3",
323 "audio/mpeg",
326 // List of supported codecs when passed in with <source type="...">.
327 // This set of codecs is supported by all variations of Chromium.
329 // Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support
330 // for more information.
332 // The codecs for WAV are integers as defined in Appendix A of RFC2361:
333 // http://tools.ietf.org/html/rfc2361
334 static const char* const common_media_codecs[] = {
335 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
336 "theora",
337 #endif
338 "opus",
339 "vorbis",
340 "vp8",
341 "vp9",
342 "1" // WAVE_FORMAT_PCM.
345 // List of proprietary codecs only supported by Google Chrome.
346 static const char* const proprietary_media_codecs[] = {
347 "avc1",
348 "avc3",
349 "mp4a"
352 // Note:
353 // - does not include javascript types list (see supported_javascript_types)
354 // - does not include types starting with "text/" (see
355 // IsSupportedNonImageMimeType())
356 static const char* const supported_non_image_types[] = {
357 "image/svg+xml", // SVG is text-based XML, even though it has an image/ type
358 "application/xml",
359 "application/atom+xml",
360 "application/rss+xml",
361 "application/xhtml+xml",
362 "application/json",
363 "multipart/related", // For MHTML support.
364 "multipart/x-mixed-replace"
365 // Note: ADDING a new type here will probably render it AS HTML. This can
366 // result in cross site scripting.
369 // Dictionary of cryptographic file mime types.
370 struct CertificateMimeTypeInfo {
371 const char* mime_type;
372 CertificateMimeType cert_type;
375 static const CertificateMimeTypeInfo supported_certificate_types[] = {
376 { "application/x-x509-user-cert",
377 CERTIFICATE_MIME_TYPE_X509_USER_CERT },
378 #if defined(OS_ANDROID)
379 { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT },
380 { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE },
381 #endif
384 // These types are excluded from the logic that allows all text/ types because
385 // while they are technically text, it's very unlikely that a user expects to
386 // see them rendered in text form.
387 static const char* const unsupported_text_types[] = {
388 "text/calendar",
389 "text/x-calendar",
390 "text/x-vcalendar",
391 "text/vcalendar",
392 "text/vcard",
393 "text/x-vcard",
394 "text/directory",
395 "text/ldif",
396 "text/qif",
397 "text/x-qif",
398 "text/x-csv",
399 "text/x-vcf",
400 "text/rtf",
401 "text/comma-separated-values",
402 "text/csv",
403 "text/tab-separated-values",
404 "text/tsv",
405 "text/ofx", // http://crbug.com/162238
406 "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450
409 // Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
410 // Mozilla 1.8 accepts application/javascript, application/ecmascript, and
411 // application/x-javascript, but WinIE 7 doesn't.
412 // WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
413 // text/livescript, but Mozilla 1.8 doesn't.
414 // Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
415 // Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
416 // whitespace-only string.
417 // We want to accept all the values that either of these browsers accept, but
418 // not other values.
419 static const char* const supported_javascript_types[] = {
420 "text/javascript",
421 "text/ecmascript",
422 "application/javascript",
423 "application/ecmascript",
424 "application/x-javascript",
425 "text/javascript1.1",
426 "text/javascript1.2",
427 "text/javascript1.3",
428 "text/jscript",
429 "text/livescript"
432 #if defined(OS_ANDROID)
433 static bool IsCodecSupportedOnAndroid(const std::string& codec) {
434 // Theora is not supported in Android
435 if (!codec.compare("theora"))
436 return false;
438 // VP9 is supported only in KitKat+ (API Level 19).
439 if ((!codec.compare("vp9") || !codec.compare("vp9.0")) &&
440 base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
441 return false;
444 // TODO(vigneshv): Change this similar to the VP9 check once Opus is
445 // supported on Android (http://crbug.com/318436).
446 if (!codec.compare("opus")) {
447 return false;
449 return true;
452 static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) {
453 // HLS codecs are supported in ICS and above (API level 14)
454 if ((!mimeType.compare("application/vnd.apple.mpegurl") ||
455 !mimeType.compare("application/x-mpegurl")) &&
456 base::android::BuildInfo::GetInstance()->sdk_int() < 14) {
457 return false;
459 return true;
461 #endif
463 struct MediaFormatStrict {
464 const char* mime_type;
465 const char* codecs_list;
468 static const MediaFormatStrict format_codec_mappings[] = {
469 { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" },
470 { "audio/webm", "opus,vorbis" },
471 { "audio/wav", "1" },
472 { "audio/x-wav", "1" },
473 { "video/ogg", "opus,theora,vorbis" },
474 { "audio/ogg", "opus,vorbis" },
475 { "application/ogg", "opus,theora,vorbis" },
476 { "audio/mpeg", "" },
477 { "audio/mp3", "" },
478 { "audio/x-mp3", "" }
481 // Following is the list of RFC 6381 compliant codecs:
482 // mp4a.6B - MPEG-1 audio
483 // mp4a.69 - MPEG-2 extension to MPEG-1
484 // mp4a.67 - MPEG-2 AAC
485 // mp4a.40.2 - MPEG-4 AAC
486 // mp4a.40.5 - MPEG-4 HE-AAC
488 // avc1.42E0xx - H.264 Baseline
489 // avc1.4D40xx - H.264 Main
490 // avc1.6400xx - H.264 High
492 // Additionally, several non-RFC compliant codecs are allowed, due to their
493 // existing use on web.
494 // mp4a.40
495 // avc1.xxxxxx
496 // avc3.xxxxxx
497 // mp4a.6x
498 static const char kProprietaryAudioCodecsExpression[] =
499 "mp4a.6?,mp4a.40,mp4a.40.?";
500 static const char kProprietaryCodecsExpression[] =
501 "avc1,avc3,avc1.??????,avc3.??????,mp4a.6?,mp4a.40,mp4a.40.?";
503 static const MediaFormatStrict format_mp4_codec_mappings[] = {
504 { "audio/mp4", kProprietaryAudioCodecsExpression },
505 { "audio/x-m4a", kProprietaryAudioCodecsExpression },
506 { "video/mp4", kProprietaryCodecsExpression },
507 { "video/x-m4v", kProprietaryCodecsExpression },
508 { "application/x-mpegurl", kProprietaryCodecsExpression },
509 { "application/vnd.apple.mpegurl", kProprietaryCodecsExpression }
512 MimeUtil::MimeUtil() {
513 InitializeMimeTypeMaps();
516 // static
517 bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs,
518 const std::vector<std::string>& codecs) {
519 if (supported_codecs.empty())
520 return codecs.empty();
522 for (size_t i = 0; i < codecs.size(); ++i) {
523 if (supported_codecs.find(codecs[i]) == supported_codecs.end())
524 return false;
526 return !codecs.empty();
529 // Checks all the codecs present in the |codecs| against the entries in
530 // |supported_codecs|. Returns true only if |codecs| is non-empty and all the
531 // codecs match |supported_codecs| expressions.
532 bool MimeUtil::AreSupportedCodecsWithProfile(
533 const MimeExpressionMappings& supported_codecs,
534 const std::vector<std::string>& codecs) {
535 DCHECK(!supported_codecs.empty());
536 for (size_t i = 0; i < codecs.size(); ++i) {
537 bool codec_matched = false;
538 for (size_t j = 0; j < supported_codecs.size(); ++j) {
539 if (!MatchPattern(base::StringPiece(codecs[i]),
540 base::StringPiece(supported_codecs[j]))) {
541 continue;
543 // If suffix exists, check whether it is hexadecimal.
544 for (size_t wildcard_pos = supported_codecs[j].find('?');
545 wildcard_pos != std::string::npos &&
546 wildcard_pos < supported_codecs[j].length();
547 wildcard_pos = supported_codecs[j].find('?', wildcard_pos + 1)) {
548 // Don't enforce case sensitivity, even though it's called for, as it
549 // would break some websites.
550 if (wildcard_pos >= codecs[i].length() ||
551 !IsHexDigit(codecs[i].at(wildcard_pos))) {
552 return false;
555 codec_matched = true;
556 break;
558 if (!codec_matched)
559 return false;
561 return !codecs.empty();
564 void MimeUtil::InitializeMimeTypeMaps() {
565 for (size_t i = 0; i < arraysize(supported_image_types); ++i)
566 image_map_.insert(supported_image_types[i]);
568 // Initialize the supported non-image types.
569 for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
570 non_image_map_.insert(supported_non_image_types[i]);
571 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i)
572 non_image_map_.insert(supported_certificate_types[i].mime_type);
573 for (size_t i = 0; i < arraysize(unsupported_text_types); ++i)
574 unsupported_text_map_.insert(unsupported_text_types[i]);
575 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
576 non_image_map_.insert(supported_javascript_types[i]);
577 for (size_t i = 0; i < arraysize(common_media_types); ++i) {
578 #if defined(OS_ANDROID)
579 if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
580 continue;
581 #endif
582 non_image_map_.insert(common_media_types[i]);
584 #if defined(USE_PROPRIETARY_CODECS)
585 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
586 non_image_map_.insert(proprietary_media_types[i]);
587 #endif
589 // Initialize the supported media types.
590 for (size_t i = 0; i < arraysize(common_media_types); ++i) {
591 #if defined(OS_ANDROID)
592 if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
593 continue;
594 #endif
595 media_map_.insert(common_media_types[i]);
597 #if defined(USE_PROPRIETARY_CODECS)
598 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
599 media_map_.insert(proprietary_media_types[i]);
600 #endif
602 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
603 javascript_map_.insert(supported_javascript_types[i]);
605 for (size_t i = 0; i < arraysize(common_media_codecs); ++i) {
606 #if defined(OS_ANDROID)
607 if (!IsCodecSupportedOnAndroid(common_media_codecs[i]))
608 continue;
609 #endif
610 codecs_map_.insert(common_media_codecs[i]);
612 #if defined(USE_PROPRIETARY_CODECS)
613 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
614 codecs_map_.insert(proprietary_media_codecs[i]);
615 #endif
617 // Initialize the strict supported media types.
618 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
619 std::vector<std::string> mime_type_codecs;
620 ParseCodecString(format_codec_mappings[i].codecs_list,
621 &mime_type_codecs,
622 false);
624 MimeMappings codecs;
625 for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
626 #if defined(OS_ANDROID)
627 if (!IsCodecSupportedOnAndroid(mime_type_codecs[j]))
628 continue;
629 #endif
630 codecs.insert(mime_type_codecs[j]);
632 strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
634 for (size_t i = 0; i < arraysize(format_mp4_codec_mappings); ++i) {
635 std::vector<std::string> mime_type_codecs;
636 ParseCodecString(
637 format_mp4_codec_mappings[i].codecs_list, &mime_type_codecs, false);
639 MimeExpressionMappings codecs;
640 for (size_t j = 0; j < mime_type_codecs.size(); ++j)
641 codecs.push_back(mime_type_codecs[j]);
642 strict_mp4_format_map_[format_mp4_codec_mappings[i].mime_type] = codecs;
646 bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
647 return image_map_.find(mime_type) != image_map_.end();
650 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
651 return media_map_.find(mime_type) != media_map_.end();
654 bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
655 return non_image_map_.find(mime_type) != non_image_map_.end() ||
656 (mime_type.compare(0, 5, "text/") == 0 &&
657 !IsUnsupportedTextMimeType(mime_type)) ||
658 (mime_type.compare(0, 12, "application/") == 0 &&
659 MatchesMimeType("application/*+json", mime_type));
662 bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
663 return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end();
666 bool MimeUtil::IsSupportedJavascriptMimeType(
667 const std::string& mime_type) const {
668 return javascript_map_.find(mime_type) != javascript_map_.end();
671 // Mirrors WebViewImpl::CanShowMIMEType()
672 bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
673 return (mime_type.compare(0, 6, "image/") == 0 &&
674 IsSupportedImageMimeType(mime_type)) ||
675 IsSupportedNonImageMimeType(mime_type);
678 // Tests for MIME parameter equality. Each parameter in the |mime_type_pattern|
679 // must be matched by a parameter in the |mime_type|. If there are no
680 // parameters in the pattern, the match is a success.
681 bool MatchesMimeTypeParameters(const std::string& mime_type_pattern,
682 const std::string& mime_type) {
683 const std::string::size_type semicolon = mime_type_pattern.find(';');
684 const std::string::size_type test_semicolon = mime_type.find(';');
685 if (semicolon != std::string::npos) {
686 if (test_semicolon == std::string::npos)
687 return false;
689 std::vector<std::string> pattern_parameters;
690 base::SplitString(mime_type_pattern.substr(semicolon + 1),
691 ';', &pattern_parameters);
693 std::vector<std::string> test_parameters;
694 base::SplitString(mime_type.substr(test_semicolon + 1),
695 ';', &test_parameters);
697 sort(pattern_parameters.begin(), pattern_parameters.end());
698 sort(test_parameters.begin(), test_parameters.end());
699 std::vector<std::string> difference =
700 base::STLSetDifference<std::vector<std::string> >(pattern_parameters,
701 test_parameters);
702 return difference.size() == 0;
704 return true;
707 // This comparison handles absolute maching and also basic
708 // wildcards. The plugin mime types could be:
709 // application/x-foo
710 // application/*
711 // application/*+xml
712 // *
713 // Also tests mime parameters -- all parameters in the pattern must be present
714 // in the tested type for a match to succeed.
715 bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern,
716 const std::string& mime_type) const {
717 // Verify caller is passing lowercase strings.
718 DCHECK_EQ(StringToLowerASCII(mime_type_pattern), mime_type_pattern);
719 DCHECK_EQ(StringToLowerASCII(mime_type), mime_type);
721 if (mime_type_pattern.empty())
722 return false;
724 std::string::size_type semicolon = mime_type_pattern.find(';');
725 const std::string base_pattern(mime_type_pattern.substr(0, semicolon));
726 semicolon = mime_type.find(';');
727 const std::string base_type(mime_type.substr(0, semicolon));
729 if (base_pattern == "*" || base_pattern == "*/*")
730 return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
732 const std::string::size_type star = base_pattern.find('*');
733 if (star == std::string::npos) {
734 if (base_pattern == base_type)
735 return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
736 else
737 return false;
740 // Test length to prevent overlap between |left| and |right|.
741 if (base_type.length() < base_pattern.length() - 1)
742 return false;
744 const std::string left(base_pattern.substr(0, star));
745 const std::string right(base_pattern.substr(star + 1));
747 if (base_type.find(left) != 0)
748 return false;
750 if (!right.empty() &&
751 base_type.rfind(right) != base_type.length() - right.length())
752 return false;
754 return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
757 // See http://www.iana.org/assignments/media-types/media-types.xhtml
758 static const char* legal_top_level_types[] = {
759 "application",
760 "audio",
761 "example",
762 "image",
763 "message",
764 "model",
765 "multipart",
766 "text",
767 "video",
770 bool MimeUtil::ParseMimeTypeWithoutParameter(
771 const std::string& type_string,
772 std::string* top_level_type,
773 std::string* subtype) const {
774 std::vector<std::string> components;
775 base::SplitString(type_string, '/', &components);
776 if (components.size() != 2 ||
777 !HttpUtil::IsToken(components[0]) ||
778 !HttpUtil::IsToken(components[1]))
779 return false;
781 if (top_level_type)
782 *top_level_type = components[0];
783 if (subtype)
784 *subtype = components[1];
785 return true;
788 bool MimeUtil::IsValidTopLevelMimeType(const std::string& type_string) const {
789 std::string lower_type = StringToLowerASCII(type_string);
790 for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) {
791 if (lower_type.compare(legal_top_level_types[i]) == 0)
792 return true;
795 return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false);
798 bool MimeUtil::AreSupportedMediaCodecs(
799 const std::vector<std::string>& codecs) const {
800 return AreSupportedCodecs(codecs_map_, codecs);
803 void MimeUtil::ParseCodecString(const std::string& codecs,
804 std::vector<std::string>* codecs_out,
805 bool strip) {
806 std::string no_quote_codecs;
807 base::TrimString(codecs, "\"", &no_quote_codecs);
808 base::SplitString(no_quote_codecs, ',', codecs_out);
810 if (!strip)
811 return;
813 // Strip everything past the first '.'
814 for (std::vector<std::string>::iterator it = codecs_out->begin();
815 it != codecs_out->end();
816 ++it) {
817 size_t found = it->find_first_of('.');
818 if (found != std::string::npos)
819 it->resize(found);
823 bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
824 if (strict_format_map_.find(mime_type) == strict_format_map_.end() &&
825 strict_mp4_format_map_.find(mime_type) == strict_mp4_format_map_.end())
826 return false;
827 return true;
830 SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
831 const std::string& mime_type,
832 const std::vector<std::string>& codecs) const {
833 StrictMappings::const_iterator it_strict_map =
834 strict_format_map_.find(mime_type);
835 if ((it_strict_map != strict_format_map_.end()) &&
836 AreSupportedCodecs(it_strict_map->second, codecs)) {
837 return IsSupported;
840 StrictExpressionMappings::const_iterator it_expression_map =
841 strict_mp4_format_map_.find(mime_type);
842 if ((it_expression_map != strict_mp4_format_map_.end()) &&
843 AreSupportedCodecsWithProfile(it_expression_map->second, codecs)) {
844 return MayBeSupported;
847 if (codecs.empty())
848 return MayBeSupported;
850 return IsNotSupported;
853 void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
854 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) {
855 non_image_map_.erase(proprietary_media_types[i]);
856 media_map_.erase(proprietary_media_types[i]);
858 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
859 codecs_map_.erase(proprietary_media_codecs[i]);
862 //----------------------------------------------------------------------------
863 // Wrappers for the singleton
864 //----------------------------------------------------------------------------
866 bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
867 std::string* mime_type) {
868 return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
871 bool GetMimeTypeFromFile(const base::FilePath& file_path,
872 std::string* mime_type) {
873 return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
876 bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
877 std::string* mime_type) {
878 return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type);
881 bool GetPreferredExtensionForMimeType(const std::string& mime_type,
882 base::FilePath::StringType* extension) {
883 return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
884 extension);
887 bool IsSupportedImageMimeType(const std::string& mime_type) {
888 return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
891 bool IsSupportedMediaMimeType(const std::string& mime_type) {
892 return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
895 bool IsSupportedNonImageMimeType(const std::string& mime_type) {
896 return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
899 bool IsUnsupportedTextMimeType(const std::string& mime_type) {
900 return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
903 bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
904 return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
907 bool IsSupportedMimeType(const std::string& mime_type) {
908 return g_mime_util.Get().IsSupportedMimeType(mime_type);
911 bool MatchesMimeType(const std::string& mime_type_pattern,
912 const std::string& mime_type) {
913 return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
916 bool ParseMimeTypeWithoutParameter(const std::string& type_string,
917 std::string* top_level_type,
918 std::string* subtype) {
919 return g_mime_util.Get().ParseMimeTypeWithoutParameter(
920 type_string, top_level_type, subtype);
923 bool IsValidTopLevelMimeType(const std::string& type_string) {
924 return g_mime_util.Get().IsValidTopLevelMimeType(type_string);
927 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
928 return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
931 bool IsStrictMediaMimeType(const std::string& mime_type) {
932 return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
935 SupportsType IsSupportedStrictMediaMimeType(
936 const std::string& mime_type,
937 const std::vector<std::string>& codecs) {
938 return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
941 void ParseCodecString(const std::string& codecs,
942 std::vector<std::string>* codecs_out,
943 const bool strip) {
944 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
947 namespace {
949 // From http://www.w3schools.com/media/media_mimeref.asp and
950 // http://plugindoc.mozdev.org/winmime.php
951 static const char* const kStandardImageTypes[] = {
952 "image/bmp",
953 "image/cis-cod",
954 "image/gif",
955 "image/ief",
956 "image/jpeg",
957 "image/webp",
958 "image/pict",
959 "image/pipeg",
960 "image/png",
961 "image/svg+xml",
962 "image/tiff",
963 "image/vnd.microsoft.icon",
964 "image/x-cmu-raster",
965 "image/x-cmx",
966 "image/x-icon",
967 "image/x-portable-anymap",
968 "image/x-portable-bitmap",
969 "image/x-portable-graymap",
970 "image/x-portable-pixmap",
971 "image/x-rgb",
972 "image/x-xbitmap",
973 "image/x-xpixmap",
974 "image/x-xwindowdump"
976 static const char* const kStandardAudioTypes[] = {
977 "audio/aac",
978 "audio/aiff",
979 "audio/amr",
980 "audio/basic",
981 "audio/midi",
982 "audio/mp3",
983 "audio/mp4",
984 "audio/mpeg",
985 "audio/mpeg3",
986 "audio/ogg",
987 "audio/vorbis",
988 "audio/wav",
989 "audio/webm",
990 "audio/x-m4a",
991 "audio/x-ms-wma",
992 "audio/vnd.rn-realaudio",
993 "audio/vnd.wave"
995 static const char* const kStandardVideoTypes[] = {
996 "video/avi",
997 "video/divx",
998 "video/flc",
999 "video/mp4",
1000 "video/mpeg",
1001 "video/ogg",
1002 "video/quicktime",
1003 "video/sd-video",
1004 "video/webm",
1005 "video/x-dv",
1006 "video/x-m4v",
1007 "video/x-mpeg",
1008 "video/x-ms-asf",
1009 "video/x-ms-wmv"
1012 struct StandardType {
1013 const char* leading_mime_type;
1014 const char* const* standard_types;
1015 size_t standard_types_len;
1017 static const StandardType kStandardTypes[] = {
1018 { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) },
1019 { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) },
1020 { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) },
1021 { NULL, NULL, 0 }
1024 void GetExtensionsFromHardCodedMappings(
1025 const MimeInfo* mappings,
1026 size_t mappings_len,
1027 const std::string& leading_mime_type,
1028 base::hash_set<base::FilePath::StringType>* extensions) {
1029 base::FilePath::StringType extension;
1030 for (size_t i = 0; i < mappings_len; ++i) {
1031 if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
1032 std::vector<string> this_extensions;
1033 base::SplitString(mappings[i].extensions, ',', &this_extensions);
1034 for (size_t j = 0; j < this_extensions.size(); ++j) {
1035 #if defined(OS_WIN)
1036 base::FilePath::StringType extension(
1037 base::UTF8ToWide(this_extensions[j]));
1038 #else
1039 base::FilePath::StringType extension(this_extensions[j]);
1040 #endif
1041 extensions->insert(extension);
1047 void GetExtensionsHelper(
1048 const char* const* standard_types,
1049 size_t standard_types_len,
1050 const std::string& leading_mime_type,
1051 base::hash_set<base::FilePath::StringType>* extensions) {
1052 for (size_t i = 0; i < standard_types_len; ++i) {
1053 g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i],
1054 extensions);
1057 // Also look up the extensions from hard-coded mappings in case that some
1058 // supported extensions are not registered in the system registry, like ogg.
1059 GetExtensionsFromHardCodedMappings(primary_mappings,
1060 arraysize(primary_mappings),
1061 leading_mime_type,
1062 extensions);
1064 GetExtensionsFromHardCodedMappings(secondary_mappings,
1065 arraysize(secondary_mappings),
1066 leading_mime_type,
1067 extensions);
1070 // Note that the elements in the source set will be appended to the target
1071 // vector.
1072 template<class T>
1073 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
1074 size_t old_target_size = target->size();
1075 target->resize(old_target_size + source->size());
1076 size_t i = 0;
1077 for (typename base::hash_set<T>::iterator iter = source->begin();
1078 iter != source->end(); ++iter, ++i)
1079 (*target)[old_target_size + i] = *iter;
1083 void GetExtensionsForMimeType(
1084 const std::string& unsafe_mime_type,
1085 std::vector<base::FilePath::StringType>* extensions) {
1086 if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*")
1087 return;
1089 const std::string mime_type = StringToLowerASCII(unsafe_mime_type);
1090 base::hash_set<base::FilePath::StringType> unique_extensions;
1092 if (EndsWith(mime_type, "/*", true)) {
1093 std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1);
1095 // Find the matching StandardType from within kStandardTypes, or fall
1096 // through to the last (default) StandardType.
1097 const StandardType* type = NULL;
1098 for (size_t i = 0; i < arraysize(kStandardTypes); ++i) {
1099 type = &(kStandardTypes[i]);
1100 if (type->leading_mime_type &&
1101 leading_mime_type == type->leading_mime_type)
1102 break;
1104 DCHECK(type);
1105 GetExtensionsHelper(type->standard_types,
1106 type->standard_types_len,
1107 leading_mime_type,
1108 &unique_extensions);
1109 } else {
1110 g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type,
1111 &unique_extensions);
1113 // Also look up the extensions from hard-coded mappings in case that some
1114 // supported extensions are not registered in the system registry, like ogg.
1115 GetExtensionsFromHardCodedMappings(primary_mappings,
1116 arraysize(primary_mappings),
1117 mime_type,
1118 &unique_extensions);
1120 GetExtensionsFromHardCodedMappings(secondary_mappings,
1121 arraysize(secondary_mappings),
1122 mime_type,
1123 &unique_extensions);
1126 HashSetToVector(&unique_extensions, extensions);
1129 void RemoveProprietaryMediaTypesAndCodecsForTests() {
1130 g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
1133 const std::string GetIANAMediaType(const std::string& mime_type) {
1134 for (size_t i = 0; i < arraysize(kIanaMediaTypes); ++i) {
1135 if (StartsWithASCII(mime_type, kIanaMediaTypes[i].matcher, true)) {
1136 return kIanaMediaTypes[i].name;
1139 return std::string();
1142 CertificateMimeType GetCertificateMimeTypeForMimeType(
1143 const std::string& mime_type) {
1144 // Don't create a map, there is only one entry in the table,
1145 // except on Android.
1146 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) {
1147 if (mime_type == net::supported_certificate_types[i].mime_type)
1148 return net::supported_certificate_types[i].cert_type;
1150 return CERTIFICATE_MIME_TYPE_UNKNOWN;
1153 bool IsSupportedCertificateMimeType(const std::string& mime_type) {
1154 CertificateMimeType file_type =
1155 GetCertificateMimeTypeForMimeType(mime_type);
1156 return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN;
1159 void AddMultipartValueForUpload(const std::string& value_name,
1160 const std::string& value,
1161 const std::string& mime_boundary,
1162 const std::string& content_type,
1163 std::string* post_data) {
1164 DCHECK(post_data);
1165 // First line is the boundary.
1166 post_data->append("--" + mime_boundary + "\r\n");
1167 // Next line is the Content-disposition.
1168 post_data->append("Content-Disposition: form-data; name=\"" +
1169 value_name + "\"\r\n");
1170 if (!content_type.empty()) {
1171 // If Content-type is specified, the next line is that.
1172 post_data->append("Content-Type: " + content_type + "\r\n");
1174 // Leave an empty line and append the value.
1175 post_data->append("\r\n" + value + "\r\n");
1178 void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary,
1179 std::string* post_data) {
1180 DCHECK(post_data);
1181 post_data->append("--" + mime_boundary + "--\r\n");
1184 } // namespace net