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.
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"
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/" },
43 { "video", "video/" },
50 // Singleton utility class for mime types.
51 class MimeUtil
: public PlatformMimeUtil
{
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
,
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();
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
;
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_
;
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
;
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
,
195 size_t ext_len
= strlen(ext
);
197 for (size_t i
= 0; i
< mappings_len
; ++i
) {
198 const char* extensions
= mappings
[i
].extensions
;
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
;
207 extensions
+= 1; // skip over comma
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())
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
)
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());
257 if (include_platform_types
&& GetPlatformMimeTypeFromExtension(ext
, result
))
260 mime_type
= FindMimeType(secondary_mappings
, arraysize(secondary_mappings
),
261 ext_narrow_str
.c_str());
270 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
272 static const char* const supported_image_types
[] = {
280 "image/vnd.microsoft.icon", // ico
281 "image/x-icon", // ico
282 "image/x-xbitmap", // xbm
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
[] = {
293 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
305 #if defined(OS_ANDROID)
306 // HLS. Supported by Android ICS and above.
307 "application/vnd.apple.mpegurl",
308 "application/x-mpegurl",
312 // List of proprietary types only supported by Google Chrome.
313 static const char* const proprietary_media_types
[] = {
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.
342 "1" // WAVE_FORMAT_PCM.
345 // List of proprietary codecs only supported by Google Chrome.
346 static const char* const proprietary_media_codecs
[] = {
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
359 "application/atom+xml",
360 "application/rss+xml",
361 "application/xhtml+xml",
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
},
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
[] = {
401 "text/comma-separated-values",
403 "text/tab-separated-values",
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
419 static const char* const supported_javascript_types
[] = {
422 "application/javascript",
423 "application/ecmascript",
424 "application/x-javascript",
425 "text/javascript1.1",
426 "text/javascript1.2",
427 "text/javascript1.3",
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"))
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) {
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")) {
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) {
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", "" },
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.
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();
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())
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
]))) {
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
))) {
555 codec_matched
= true;
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
]))
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
]);
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
]))
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
]);
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
]))
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
]);
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
,
625 for (size_t j
= 0; j
< mime_type_codecs
.size(); ++j
) {
626 #if defined(OS_ANDROID)
627 if (!IsCodecSupportedOnAndroid(mime_type_codecs
[j
]))
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
;
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
)
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
,
702 return difference
.size() == 0;
707 // This comparison handles absolute maching and also basic
708 // wildcards. The plugin mime types could be:
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())
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
);
740 // Test length to prevent overlap between |left| and |right|.
741 if (base_type
.length() < base_pattern
.length() - 1)
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)
750 if (!right
.empty() &&
751 base_type
.rfind(right
) != base_type
.length() - right
.length())
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
[] = {
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]))
782 *top_level_type
= components
[0];
784 *subtype
= components
[1];
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)
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
,
806 std::string no_quote_codecs
;
807 base::TrimString(codecs
, "\"", &no_quote_codecs
);
808 base::SplitString(no_quote_codecs
, ',', codecs_out
);
813 // Strip everything past the first '.'
814 for (std::vector
<std::string
>::iterator it
= codecs_out
->begin();
815 it
!= codecs_out
->end();
817 size_t found
= it
->find_first_of('.');
818 if (found
!= std::string::npos
)
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())
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
)) {
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
;
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
,
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
,
944 g_mime_util
.Get().ParseCodecString(codecs
, codecs_out
, strip
);
949 // From http://www.w3schools.com/media/media_mimeref.asp and
950 // http://plugindoc.mozdev.org/winmime.php
951 static const char* const kStandardImageTypes
[] = {
963 "image/vnd.microsoft.icon",
964 "image/x-cmu-raster",
967 "image/x-portable-anymap",
968 "image/x-portable-bitmap",
969 "image/x-portable-graymap",
970 "image/x-portable-pixmap",
974 "image/x-xwindowdump"
976 static const char* const kStandardAudioTypes
[] = {
992 "audio/vnd.rn-realaudio",
995 static const char* const kStandardVideoTypes
[] = {
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
) },
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
) {
1036 base::FilePath::StringType
extension(
1037 base::UTF8ToWide(this_extensions
[j
]));
1039 base::FilePath::StringType
extension(this_extensions
[j
]);
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
],
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
),
1064 GetExtensionsFromHardCodedMappings(secondary_mappings
,
1065 arraysize(secondary_mappings
),
1070 // Note that the elements in the source set will be appended to the target
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());
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
== "*")
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
)
1105 GetExtensionsHelper(type
->standard_types
,
1106 type
->standard_types_len
,
1108 &unique_extensions
);
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
),
1118 &unique_extensions
);
1120 GetExtensionsFromHardCodedMappings(secondary_mappings
,
1121 arraysize(secondary_mappings
),
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
) {
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
) {
1181 post_data
->append("--" + mime_boundary
+ "--\r\n");