OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <algorithm> | |
6 #include <iterator> | |
7 #include <map> | |
8 #include <string> | |
9 | |
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_number_conversions.h" | |
15 #include "base/strings/string_split.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/utf_string_conversions.h" | |
18 #include "net/base/mime_util.h" | |
19 #include "net/base/platform_mime_util.h" | |
20 #include "net/http/http_util.h" | |
21 | |
22 #if defined(OS_ANDROID) | |
23 #include "base/android/build_info.h" | |
24 #endif | |
25 | |
26 using std::string; | |
27 | |
28 namespace net { | |
29 | |
30 // Singleton utility class for mime types. | |
31 class MimeUtil : public PlatformMimeUtil { | |
32 public: | |
33 enum Codec { | |
34 INVALID_CODEC, | |
35 PCM, | |
36 MP3, | |
37 MPEG2_AAC_LC, | |
38 MPEG2_AAC_MAIN, | |
39 MPEG2_AAC_SSR, | |
40 MPEG4_AAC_LC, | |
41 MPEG4_AAC_SBR_v1, | |
42 MPEG4_AAC_SBR_PS_v2, | |
43 VORBIS, | |
44 OPUS, | |
45 H264_BASELINE, | |
46 H264_MAIN, | |
47 H264_HIGH, | |
48 VP8, | |
49 VP9, | |
50 THEORA | |
51 }; | |
52 | |
53 bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, | |
54 std::string* mime_type) const; | |
55 | |
56 bool GetMimeTypeFromFile(const base::FilePath& file_path, | |
57 std::string* mime_type) const; | |
58 | |
59 bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, | |
60 std::string* mime_type) const; | |
61 | |
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; | |
67 | |
68 bool IsSupportedMimeType(const std::string& mime_type) const; | |
69 | |
70 bool MatchesMimeType(const std::string &mime_type_pattern, | |
71 const std::string &mime_type) const; | |
72 | |
73 bool ParseMimeTypeWithoutParameter(const std::string& type_string, | |
74 std::string* top_level_type, | |
75 std::string* subtype) const; | |
76 | |
77 bool IsValidTopLevelMimeType(const std::string& type_string) const; | |
78 | |
79 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; | |
80 | |
81 void ParseCodecString(const std::string& codecs, | |
82 std::vector<std::string>* codecs_out, | |
83 bool strip); | |
84 | |
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; | |
89 | |
90 void RemoveProprietaryMediaTypesAndCodecsForTests(); | |
91 | |
92 private: | |
93 friend struct base::DefaultLazyInstanceTraits<MimeUtil>; | |
94 | |
95 typedef base::hash_set<std::string> MimeMappings; | |
96 | |
97 typedef base::hash_set<int> CodecSet; | |
98 typedef std::map<std::string, CodecSet> StrictMappings; | |
99 struct CodecEntry { | |
100 CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {} | |
101 CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {} | |
102 Codec codec; | |
103 bool is_ambiguous; | |
104 }; | |
105 typedef std::map<std::string, CodecEntry> StringToCodecMappings; | |
106 | |
107 MimeUtil(); | |
108 | |
109 // Returns IsSupported if all codec IDs in |codecs| are unambiguous | |
110 // and are supported by the platform. MayBeSupported is returned if | |
111 // at least one codec ID in |codecs| is ambiguous but all the codecs | |
112 // are supported by the platform. IsNotSupported is returned if at | |
113 // least one codec ID is not supported by the platform. | |
114 SupportsType AreSupportedCodecs( | |
115 const CodecSet& supported_codecs, | |
116 const std::vector<std::string>& codecs) const; | |
117 | |
118 // For faster lookup, keep hash sets. | |
119 void InitializeMimeTypeMaps(); | |
120 | |
121 bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, | |
122 bool include_platform_types, | |
123 std::string* mime_type) const; | |
124 | |
125 // Converts a codec ID into an Codec enum value and indicates | |
126 // whether the conversion was ambiguous. | |
127 // Returns true if this method was able to map |codec_id| to a specific | |
128 // Codec enum value. |codec| and |is_ambiguous| are only valid if true | |
129 // is returned. Otherwise their value is undefined after the call. | |
130 // |is_ambiguous| is true if |codec_id| did not have enough information to | |
131 // unambiguously determine the proper Codec enum value. If |is_ambiguous| | |
132 // is true |codec| contains the best guess for the intended Codec enum value. | |
133 bool StringToCodec(const std::string& codec_id, | |
134 Codec* codec, | |
135 bool* is_ambiguous) const; | |
136 | |
137 // Returns true if |codec| is supported by the platform. | |
138 // Note: This method will return false if the platform supports proprietary | |
139 // codecs but |allow_proprietary_codecs_| is set to false. | |
140 bool IsCodecSupported(Codec codec) const; | |
141 | |
142 // Returns true if |codec| refers to a proprietary codec. | |
143 bool IsCodecProprietary(Codec codec) const; | |
144 | |
145 // Returns true and sets |*default_codec| if |mime_type| has a default codec | |
146 // associated with it. Returns false otherwise and the value of | |
147 // |*default_codec| is undefined. | |
148 bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, | |
149 Codec* default_codec) const; | |
150 | |
151 // Returns true if |mime_type_lower_case| has a default codec associated with | |
152 // it and IsCodecSupported() returns true for that particular codec. | |
153 bool IsDefaultCodecSupportedLowerCase( | |
154 const std::string& mime_type_lower_case) const; | |
155 | |
156 MimeMappings image_map_; | |
157 MimeMappings media_map_; | |
158 MimeMappings non_image_map_; | |
159 MimeMappings unsupported_text_map_; | |
160 MimeMappings javascript_map_; | |
161 | |
162 // A map of mime_types and hash map of the supported codecs for the mime_type. | |
163 StrictMappings strict_format_map_; | |
164 | |
165 // Keeps track of whether proprietary codec support should be | |
166 // advertised to callers. | |
167 bool allow_proprietary_codecs_; | |
168 | |
169 // Lookup table for string compare based string -> Codec mappings. | |
170 StringToCodecMappings string_to_codec_map_; | |
171 }; // class MimeUtil | |
172 | |
173 // This variable is Leaky because we need to access it from WorkerPool threads. | |
174 static base::LazyInstance<MimeUtil>::Leaky g_mime_util = | |
175 LAZY_INSTANCE_INITIALIZER; | |
176 | |
177 struct MimeInfo { | |
178 const char* const mime_type; | |
179 const char* const extensions; // comma separated list | |
180 }; | |
181 | |
182 static const MimeInfo primary_mappings[] = { | |
183 { "text/html", "html,htm,shtml,shtm" }, | |
184 { "text/css", "css" }, | |
185 { "text/xml", "xml" }, | |
186 { "image/gif", "gif" }, | |
187 { "image/jpeg", "jpeg,jpg" }, | |
188 { "image/webp", "webp" }, | |
189 { "image/png", "png" }, | |
190 { "video/mp4", "mp4,m4v" }, | |
191 { "audio/x-m4a", "m4a" }, | |
192 { "audio/mp3", "mp3" }, | |
193 { "video/ogg", "ogv,ogm" }, | |
194 { "audio/ogg", "ogg,oga,opus" }, | |
195 { "video/webm", "webm" }, | |
196 { "audio/webm", "webm" }, | |
197 { "audio/wav", "wav" }, | |
198 { "application/xhtml+xml", "xhtml,xht,xhtm" }, | |
199 { "application/x-chrome-extension", "crx" }, | |
200 { "multipart/related", "mhtml,mht" } | |
201 }; | |
202 | |
203 static const MimeInfo secondary_mappings[] = { | |
204 { "application/octet-stream", "exe,com,bin" }, | |
205 { "application/gzip", "gz" }, | |
206 { "application/pdf", "pdf" }, | |
207 { "application/postscript", "ps,eps,ai" }, | |
208 { "application/javascript", "js" }, | |
209 { "application/font-woff", "woff" }, | |
210 { "image/bmp", "bmp" }, | |
211 { "image/x-icon", "ico" }, | |
212 { "image/vnd.microsoft.icon", "ico" }, | |
213 { "image/jpeg", "jfif,pjpeg,pjp" }, | |
214 { "image/tiff", "tiff,tif" }, | |
215 { "image/x-xbitmap", "xbm" }, | |
216 { "image/svg+xml", "svg,svgz" }, | |
217 { "image/x-png", "png"}, | |
218 { "message/rfc822", "eml" }, | |
219 { "text/plain", "txt,text" }, | |
220 { "text/html", "ehtml" }, | |
221 { "application/rss+xml", "rss" }, | |
222 { "application/rdf+xml", "rdf" }, | |
223 { "text/xml", "xsl,xbl,xslt" }, | |
224 { "application/vnd.mozilla.xul+xml", "xul" }, | |
225 { "application/x-shockwave-flash", "swf,swl" }, | |
226 { "application/pkcs7-mime", "p7m,p7c,p7z" }, | |
227 { "application/pkcs7-signature", "p7s" }, | |
228 { "application/x-mpegurl", "m3u8" }, | |
229 }; | |
230 | |
231 static const char* FindMimeType(const MimeInfo* mappings, | |
232 size_t mappings_len, | |
233 const char* ext) { | |
234 size_t ext_len = strlen(ext); | |
235 | |
236 for (size_t i = 0; i < mappings_len; ++i) { | |
237 const char* extensions = mappings[i].extensions; | |
238 for (;;) { | |
239 size_t end_pos = strcspn(extensions, ","); | |
240 if (end_pos == ext_len && | |
241 base::strncasecmp(extensions, ext, ext_len) == 0) | |
242 return mappings[i].mime_type; | |
243 extensions += end_pos; | |
244 if (!*extensions) | |
245 break; | |
246 extensions += 1; // skip over comma | |
247 } | |
248 } | |
249 return NULL; | |
250 } | |
251 | |
252 bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext, | |
253 string* result) const { | |
254 return GetMimeTypeFromExtensionHelper(ext, true, result); | |
255 } | |
256 | |
257 bool MimeUtil::GetWellKnownMimeTypeFromExtension( | |
258 const base::FilePath::StringType& ext, | |
259 string* result) const { | |
260 return GetMimeTypeFromExtensionHelper(ext, false, result); | |
261 } | |
262 | |
263 bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path, | |
264 string* result) const { | |
265 base::FilePath::StringType file_name_str = file_path.Extension(); | |
266 if (file_name_str.empty()) | |
267 return false; | |
268 return GetMimeTypeFromExtension(file_name_str.substr(1), result); | |
269 } | |
270 | |
271 bool MimeUtil::GetMimeTypeFromExtensionHelper( | |
272 const base::FilePath::StringType& ext, | |
273 bool include_platform_types, | |
274 string* result) const { | |
275 // Avoids crash when unable to handle a long file path. See crbug.com/48733. | |
276 const unsigned kMaxFilePathSize = 65536; | |
277 if (ext.length() > kMaxFilePathSize) | |
278 return false; | |
279 | |
280 // We implement the same algorithm as Mozilla for mapping a file extension to | |
281 // a mime type. That is, we first check a hard-coded list (that cannot be | |
282 // overridden), and then if not found there, we defer to the system registry. | |
283 // Finally, we scan a secondary hard-coded list to catch types that we can | |
284 // deduce but that we also want to allow the OS to override. | |
285 | |
286 base::FilePath path_ext(ext); | |
287 const string ext_narrow_str = path_ext.AsUTF8Unsafe(); | |
288 const char* mime_type = FindMimeType(primary_mappings, | |
289 arraysize(primary_mappings), | |
290 ext_narrow_str.c_str()); | |
291 if (mime_type) { | |
292 *result = mime_type; | |
293 return true; | |
294 } | |
295 | |
296 if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) | |
297 return true; | |
298 | |
299 mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings), | |
300 ext_narrow_str.c_str()); | |
301 if (mime_type) { | |
302 *result = mime_type; | |
303 return true; | |
304 } | |
305 | |
306 return false; | |
307 } | |
308 | |
309 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp: | |
310 | |
311 static const char* const supported_image_types[] = { | |
312 "image/jpeg", | |
313 "image/pjpeg", | |
314 "image/jpg", | |
315 "image/webp", | |
316 "image/png", | |
317 "image/gif", | |
318 "image/bmp", | |
319 "image/vnd.microsoft.icon", // ico | |
320 "image/x-icon", // ico | |
321 "image/x-xbitmap", // xbm | |
322 "image/x-png" | |
323 }; | |
324 | |
325 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type | |
326 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php | |
327 // This set of codecs is supported by all variations of Chromium. | |
328 static const char* const common_media_types[] = { | |
329 // Ogg. | |
330 "audio/ogg", | |
331 "application/ogg", | |
332 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. | |
333 "video/ogg", | |
334 #endif | |
335 | |
336 // WebM. | |
337 "video/webm", | |
338 "audio/webm", | |
339 | |
340 // Wav. | |
341 "audio/wav", | |
342 "audio/x-wav", | |
343 | |
344 #if defined(OS_ANDROID) | |
345 // HLS. Supported by Android ICS and above. | |
346 "application/vnd.apple.mpegurl", | |
347 "application/x-mpegurl", | |
348 #endif | |
349 }; | |
350 | |
351 // List of proprietary types only supported by Google Chrome. | |
352 static const char* const proprietary_media_types[] = { | |
353 // MPEG-4. | |
354 "video/mp4", | |
355 "video/x-m4v", | |
356 "audio/mp4", | |
357 "audio/x-m4a", | |
358 | |
359 // MP3. | |
360 "audio/mp3", | |
361 "audio/x-mp3", | |
362 "audio/mpeg", | |
363 "audio/aac", | |
364 | |
365 #if defined(ENABLE_MPEG2TS_STREAM_PARSER) | |
366 // MPEG-2 TS. | |
367 "video/mp2t", | |
368 #endif | |
369 }; | |
370 | |
371 // Note: | |
372 // - does not include javascript types list (see supported_javascript_types) | |
373 // - does not include types starting with "text/" (see | |
374 // IsSupportedNonImageMimeType()) | |
375 static const char* const supported_non_image_types[] = { | |
376 "image/svg+xml", // SVG is text-based XML, even though it has an image/ type | |
377 "application/xml", | |
378 "application/atom+xml", | |
379 "application/rss+xml", | |
380 "application/xhtml+xml", | |
381 "application/json", | |
382 "multipart/related", // For MHTML support. | |
383 "multipart/x-mixed-replace" | |
384 // Note: ADDING a new type here will probably render it AS HTML. This can | |
385 // result in cross site scripting. | |
386 }; | |
387 | |
388 // Dictionary of cryptographic file mime types. | |
389 struct CertificateMimeTypeInfo { | |
390 const char* const mime_type; | |
391 CertificateMimeType cert_type; | |
392 }; | |
393 | |
394 static const CertificateMimeTypeInfo supported_certificate_types[] = { | |
395 { "application/x-x509-user-cert", | |
396 CERTIFICATE_MIME_TYPE_X509_USER_CERT }, | |
397 #if defined(OS_ANDROID) | |
398 { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT }, | |
399 { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE }, | |
400 #endif | |
401 }; | |
402 | |
403 // These types are excluded from the logic that allows all text/ types because | |
404 // while they are technically text, it's very unlikely that a user expects to | |
405 // see them rendered in text form. | |
406 static const char* const unsupported_text_types[] = { | |
407 "text/calendar", | |
408 "text/x-calendar", | |
409 "text/x-vcalendar", | |
410 "text/vcalendar", | |
411 "text/vcard", | |
412 "text/x-vcard", | |
413 "text/directory", | |
414 "text/ldif", | |
415 "text/qif", | |
416 "text/x-qif", | |
417 "text/x-csv", | |
418 "text/x-vcf", | |
419 "text/rtf", | |
420 "text/comma-separated-values", | |
421 "text/csv", | |
422 "text/tab-separated-values", | |
423 "text/tsv", | |
424 "text/ofx", // http://crbug.com/162238 | |
425 "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450 | |
426 }; | |
427 | |
428 // Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript. | |
429 // Mozilla 1.8 accepts application/javascript, application/ecmascript, and | |
430 // application/x-javascript, but WinIE 7 doesn't. | |
431 // WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and | |
432 // text/livescript, but Mozilla 1.8 doesn't. | |
433 // Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't. | |
434 // Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a | |
435 // whitespace-only string. | |
436 // We want to accept all the values that either of these browsers accept, but | |
437 // not other values. | |
438 static const char* const supported_javascript_types[] = { | |
439 "text/javascript", | |
440 "text/ecmascript", | |
441 "application/javascript", | |
442 "application/ecmascript", | |
443 "application/x-javascript", | |
444 "text/javascript1.1", | |
445 "text/javascript1.2", | |
446 "text/javascript1.3", | |
447 "text/jscript", | |
448 "text/livescript" | |
449 }; | |
450 | |
451 #if defined(OS_ANDROID) | |
452 static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { | |
453 switch (codec) { | |
454 case MimeUtil::INVALID_CODEC: | |
455 return false; | |
456 | |
457 case MimeUtil::PCM: | |
458 case MimeUtil::MP3: | |
459 case MimeUtil::MPEG4_AAC_LC: | |
460 case MimeUtil::MPEG4_AAC_SBR_v1: | |
461 case MimeUtil::MPEG4_AAC_SBR_PS_v2: | |
462 case MimeUtil::H264_BASELINE: | |
463 case MimeUtil::H264_MAIN: | |
464 case MimeUtil::H264_HIGH: | |
465 case MimeUtil::VP8: | |
466 case MimeUtil::VORBIS: | |
467 return true; | |
468 | |
469 case MimeUtil::MPEG2_AAC_LC: | |
470 case MimeUtil::MPEG2_AAC_MAIN: | |
471 case MimeUtil::MPEG2_AAC_SSR: | |
472 // MPEG-2 variants of AAC are not supported on Android. | |
473 return false; | |
474 | |
475 case MimeUtil::VP9: | |
476 // VP9 is supported only in KitKat+ (API Level 19). | |
477 return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; | |
478 | |
479 case MimeUtil::OPUS: | |
480 // Opus is supported only in Lollipop+ (API Level 21). | |
481 return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; | |
482 | |
483 case MimeUtil::THEORA: | |
484 return false; | |
485 } | |
486 | |
487 return false; | |
488 } | |
489 | |
490 static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) { | |
491 // HLS codecs are supported in ICS and above (API level 14) | |
492 if ((!mimeType.compare("application/vnd.apple.mpegurl") || | |
493 !mimeType.compare("application/x-mpegurl")) && | |
494 base::android::BuildInfo::GetInstance()->sdk_int() < 14) { | |
495 return false; | |
496 } | |
497 return true; | |
498 } | |
499 #endif | |
500 | |
501 struct MediaFormatStrict { | |
502 const char* const mime_type; | |
503 const char* const codecs_list; | |
504 }; | |
505 | |
506 // Following is the list of RFC 6381 compliant codecs: | |
507 // mp4a.66 - MPEG-2 AAC MAIN | |
508 // mp4a.67 - MPEG-2 AAC LC | |
509 // mp4a.68 - MPEG-2 AAC SSR | |
510 // mp4a.69 - MPEG-2 extension to MPEG-1 | |
511 // mp4a.6B - MPEG-1 audio | |
512 // mp4a.40.2 - MPEG-4 AAC LC | |
513 // mp4a.40.02 - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility) | |
514 // mp4a.40.5 - MPEG-4 HE-AAC v1 (AAC LC + SBR) | |
515 // mp4a.40.05 - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for | |
516 // compatibility) | |
517 // mp4a.40.29 - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS) | |
518 // | |
519 // avc1.42E0xx - H.264 Baseline | |
520 // avc1.4D40xx - H.264 Main | |
521 // avc1.6400xx - H.264 High | |
522 static const char kMP4AudioCodecsExpression[] = | |
523 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," | |
524 "mp4a.40.05,mp4a.40.29"; | |
525 static const char kMP4VideoCodecsExpression[] = | |
526 "avc1.42E00A,avc1.4D400A,avc1.64000A," | |
527 "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5," | |
528 "mp4a.40.05,mp4a.40.29"; | |
529 | |
530 static const MediaFormatStrict format_codec_mappings[] = { | |
531 {"video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0"}, | |
532 {"audio/webm", "opus,vorbis"}, | |
533 {"audio/wav", "1"}, | |
534 {"audio/x-wav", "1"}, | |
535 // Android does not support Opus in Ogg container. | |
536 #if defined(OS_ANDROID) | |
537 {"video/ogg", "theora,vorbis"}, | |
538 {"audio/ogg", "vorbis"}, | |
539 {"application/ogg", "theora,vorbis"}, | |
540 #else | |
541 {"video/ogg", "opus,theora,vorbis"}, | |
542 {"audio/ogg", "opus,vorbis"}, | |
543 {"application/ogg", "opus,theora,vorbis"}, | |
544 #endif | |
545 {"audio/mpeg", "mp3"}, | |
546 {"audio/mp3", ""}, | |
547 {"audio/x-mp3", ""}, | |
548 {"audio/mp4", kMP4AudioCodecsExpression}, | |
549 {"audio/x-m4a", kMP4AudioCodecsExpression}, | |
550 {"video/mp4", kMP4VideoCodecsExpression}, | |
551 {"video/x-m4v", kMP4VideoCodecsExpression}, | |
552 {"application/x-mpegurl", kMP4VideoCodecsExpression}, | |
553 {"application/vnd.apple.mpegurl", kMP4VideoCodecsExpression}}; | |
554 | |
555 struct CodecIDMappings { | |
556 const char* const codec_id; | |
557 MimeUtil::Codec codec; | |
558 }; | |
559 | |
560 // List of codec IDs that provide enough information to determine the | |
561 // codec and profile being requested. | |
562 // | |
563 // The "mp4a" strings come from RFC 6381. | |
564 static const CodecIDMappings kUnambiguousCodecIDs[] = { | |
565 {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. | |
566 {"mp3", MimeUtil::MP3}, | |
567 {"mp4a.66", MimeUtil::MPEG2_AAC_MAIN}, | |
568 {"mp4a.67", MimeUtil::MPEG2_AAC_LC}, | |
569 {"mp4a.68", MimeUtil::MPEG2_AAC_SSR}, | |
570 {"mp4a.69", MimeUtil::MP3}, | |
571 {"mp4a.6B", MimeUtil::MP3}, | |
572 {"mp4a.40.2", MimeUtil::MPEG4_AAC_LC}, | |
573 {"mp4a.40.02", MimeUtil::MPEG4_AAC_LC}, | |
574 {"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1}, | |
575 {"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1}, | |
576 {"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2}, | |
577 {"vorbis", MimeUtil::VORBIS}, | |
578 {"opus", MimeUtil::OPUS}, | |
579 {"vp8", MimeUtil::VP8}, | |
580 {"vp8.0", MimeUtil::VP8}, | |
581 {"vp9", MimeUtil::VP9}, | |
582 {"vp9.0", MimeUtil::VP9}, | |
583 {"theora", MimeUtil::THEORA}}; | |
584 | |
585 // List of codec IDs that are ambiguous and don't provide | |
586 // enough information to determine the codec and profile. | |
587 // The codec in these entries indicate the codec and profile | |
588 // we assume the user is trying to indicate. | |
589 static const CodecIDMappings kAmbiguousCodecIDs[] = { | |
590 { "mp4a.40", MimeUtil::MPEG4_AAC_LC }, | |
591 { "avc1", MimeUtil::H264_BASELINE }, | |
592 { "avc3", MimeUtil::H264_BASELINE }, | |
593 }; | |
594 | |
595 MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { | |
596 InitializeMimeTypeMaps(); | |
597 } | |
598 | |
599 SupportsType MimeUtil::AreSupportedCodecs( | |
600 const CodecSet& supported_codecs, | |
601 const std::vector<std::string>& codecs) const { | |
602 DCHECK(!supported_codecs.empty()); | |
603 DCHECK(!codecs.empty()); | |
604 | |
605 SupportsType result = IsSupported; | |
606 for (size_t i = 0; i < codecs.size(); ++i) { | |
607 bool is_ambiguous = true; | |
608 Codec codec = INVALID_CODEC; | |
609 if (!StringToCodec(codecs[i], &codec, &is_ambiguous)) | |
610 return IsNotSupported; | |
611 | |
612 if (!IsCodecSupported(codec) || | |
613 supported_codecs.find(codec) == supported_codecs.end()) { | |
614 return IsNotSupported; | |
615 } | |
616 | |
617 if (is_ambiguous) | |
618 result = MayBeSupported; | |
619 } | |
620 | |
621 return result; | |
622 } | |
623 | |
624 void MimeUtil::InitializeMimeTypeMaps() { | |
625 for (size_t i = 0; i < arraysize(supported_image_types); ++i) | |
626 image_map_.insert(supported_image_types[i]); | |
627 | |
628 // Initialize the supported non-image types. | |
629 for (size_t i = 0; i < arraysize(supported_non_image_types); ++i) | |
630 non_image_map_.insert(supported_non_image_types[i]); | |
631 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) | |
632 non_image_map_.insert(supported_certificate_types[i].mime_type); | |
633 for (size_t i = 0; i < arraysize(unsupported_text_types); ++i) | |
634 unsupported_text_map_.insert(unsupported_text_types[i]); | |
635 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) | |
636 non_image_map_.insert(supported_javascript_types[i]); | |
637 for (size_t i = 0; i < arraysize(common_media_types); ++i) { | |
638 #if defined(OS_ANDROID) | |
639 if (!IsMimeTypeSupportedOnAndroid(common_media_types[i])) | |
640 continue; | |
641 #endif | |
642 non_image_map_.insert(common_media_types[i]); | |
643 } | |
644 #if defined(USE_PROPRIETARY_CODECS) | |
645 allow_proprietary_codecs_ = true; | |
646 | |
647 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) | |
648 non_image_map_.insert(proprietary_media_types[i]); | |
649 #endif | |
650 | |
651 // Initialize the supported media types. | |
652 for (size_t i = 0; i < arraysize(common_media_types); ++i) { | |
653 #if defined(OS_ANDROID) | |
654 if (!IsMimeTypeSupportedOnAndroid(common_media_types[i])) | |
655 continue; | |
656 #endif | |
657 media_map_.insert(common_media_types[i]); | |
658 } | |
659 #if defined(USE_PROPRIETARY_CODECS) | |
660 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) | |
661 media_map_.insert(proprietary_media_types[i]); | |
662 #endif | |
663 | |
664 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) | |
665 javascript_map_.insert(supported_javascript_types[i]); | |
666 | |
667 for (size_t i = 0; i < arraysize(kUnambiguousCodecIDs); ++i) { | |
668 string_to_codec_map_[kUnambiguousCodecIDs[i].codec_id] = | |
669 CodecEntry(kUnambiguousCodecIDs[i].codec, false); | |
670 } | |
671 | |
672 for (size_t i = 0; i < arraysize(kAmbiguousCodecIDs); ++i) { | |
673 string_to_codec_map_[kAmbiguousCodecIDs[i].codec_id] = | |
674 CodecEntry(kAmbiguousCodecIDs[i].codec, true); | |
675 } | |
676 | |
677 // Initialize the strict supported media types. | |
678 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { | |
679 std::vector<std::string> mime_type_codecs; | |
680 ParseCodecString(format_codec_mappings[i].codecs_list, | |
681 &mime_type_codecs, | |
682 false); | |
683 | |
684 CodecSet codecs; | |
685 for (size_t j = 0; j < mime_type_codecs.size(); ++j) { | |
686 Codec codec = INVALID_CODEC; | |
687 bool is_ambiguous = true; | |
688 CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); | |
689 DCHECK(!is_ambiguous); | |
690 codecs.insert(codec); | |
691 } | |
692 | |
693 strict_format_map_[format_codec_mappings[i].mime_type] = codecs; | |
694 } | |
695 } | |
696 | |
697 bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const { | |
698 return image_map_.find(base::StringToLowerASCII(mime_type)) != | |
699 image_map_.end(); | |
700 } | |
701 | |
702 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { | |
703 return media_map_.find(base::StringToLowerASCII(mime_type)) != | |
704 media_map_.end(); | |
705 } | |
706 | |
707 bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { | |
708 return non_image_map_.find(base::StringToLowerASCII(mime_type)) != | |
709 non_image_map_.end() || | |
710 (StartsWithASCII(mime_type, "text/", false /* case insensitive */) && | |
711 !IsUnsupportedTextMimeType(mime_type)) || | |
712 (StartsWithASCII(mime_type, "application/", false) && | |
713 MatchesMimeType("application/*+json", mime_type)); | |
714 } | |
715 | |
716 bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const { | |
717 return unsupported_text_map_.find(base::StringToLowerASCII(mime_type)) != | |
718 unsupported_text_map_.end(); | |
719 } | |
720 | |
721 bool MimeUtil::IsSupportedJavascriptMimeType( | |
722 const std::string& mime_type) const { | |
723 return javascript_map_.find(mime_type) != javascript_map_.end(); | |
724 } | |
725 | |
726 // Mirrors WebViewImpl::CanShowMIMEType() | |
727 bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const { | |
728 return (StartsWithASCII(mime_type, "image/", false) && | |
729 IsSupportedImageMimeType(mime_type)) || | |
730 IsSupportedNonImageMimeType(mime_type); | |
731 } | |
732 | |
733 // Tests for MIME parameter equality. Each parameter in the |mime_type_pattern| | |
734 // must be matched by a parameter in the |mime_type|. If there are no | |
735 // parameters in the pattern, the match is a success. | |
736 // | |
737 // According rfc2045 keys of parameters are case-insensitive, while values may | |
738 // or may not be case-sensitive, but they are usually case-sensitive. So, this | |
739 // function matches values in *case-sensitive* manner, however note that this | |
740 // may produce some false negatives. | |
741 bool MatchesMimeTypeParameters(const std::string& mime_type_pattern, | |
742 const std::string& mime_type) { | |
743 typedef std::map<std::string, std::string> StringPairMap; | |
744 | |
745 const std::string::size_type semicolon = mime_type_pattern.find(';'); | |
746 const std::string::size_type test_semicolon = mime_type.find(';'); | |
747 if (semicolon != std::string::npos) { | |
748 if (test_semicolon == std::string::npos) | |
749 return false; | |
750 | |
751 base::StringPairs pattern_parameters; | |
752 base::SplitStringIntoKeyValuePairs(mime_type_pattern.substr(semicolon + 1), | |
753 '=', ';', &pattern_parameters); | |
754 base::StringPairs test_parameters; | |
755 base::SplitStringIntoKeyValuePairs(mime_type.substr(test_semicolon + 1), | |
756 '=', ';', &test_parameters); | |
757 | |
758 // Put the parameters to maps with the keys converted to lower case. | |
759 StringPairMap pattern_parameter_map; | |
760 for (const auto& pair : pattern_parameters) { | |
761 pattern_parameter_map[base::StringToLowerASCII(pair.first)] = pair.second; | |
762 } | |
763 | |
764 StringPairMap test_parameter_map; | |
765 for (const auto& pair : test_parameters) { | |
766 test_parameter_map[base::StringToLowerASCII(pair.first)] = pair.second; | |
767 } | |
768 | |
769 if (pattern_parameter_map.size() > test_parameter_map.size()) | |
770 return false; | |
771 | |
772 for (const auto& parameter_pair : pattern_parameter_map) { | |
773 const auto& test_parameter_pair_it = | |
774 test_parameter_map.find(parameter_pair.first); | |
775 if (test_parameter_pair_it == test_parameter_map.end()) | |
776 return false; | |
777 if (parameter_pair.second != test_parameter_pair_it->second) | |
778 return false; | |
779 } | |
780 } | |
781 | |
782 return true; | |
783 } | |
784 | |
785 // This comparison handles absolute maching and also basic | |
786 // wildcards. The plugin mime types could be: | |
787 // application/x-foo | |
788 // application/* | |
789 // application/*+xml | |
790 // * | |
791 // Also tests mime parameters -- all parameters in the pattern must be present | |
792 // in the tested type for a match to succeed. | |
793 bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern, | |
794 const std::string& mime_type) const { | |
795 if (mime_type_pattern.empty()) | |
796 return false; | |
797 | |
798 std::string::size_type semicolon = mime_type_pattern.find(';'); | |
799 const std::string base_pattern(mime_type_pattern.substr(0, semicolon)); | |
800 semicolon = mime_type.find(';'); | |
801 const std::string base_type(mime_type.substr(0, semicolon)); | |
802 | |
803 if (base_pattern == "*" || base_pattern == "*/*") | |
804 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); | |
805 | |
806 const std::string::size_type star = base_pattern.find('*'); | |
807 if (star == std::string::npos) { | |
808 if (base_pattern.size() == base_type.size() && | |
809 base::strncasecmp(base_pattern.c_str(), base_type.c_str(), | |
810 base_pattern.size()) == 0) { | |
811 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); | |
812 } else { | |
813 return false; | |
814 } | |
815 } | |
816 | |
817 // Test length to prevent overlap between |left| and |right|. | |
818 if (base_type.length() < base_pattern.length() - 1) | |
819 return false; | |
820 | |
821 const std::string left(base_pattern.substr(0, star)); | |
822 const std::string right(base_pattern.substr(star + 1)); | |
823 | |
824 if (!StartsWithASCII(base_type, left, false)) | |
825 return false; | |
826 | |
827 if (!right.empty() && !EndsWith(base_type, right, false)) | |
828 return false; | |
829 | |
830 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); | |
831 } | |
832 | |
833 // See http://www.iana.org/assignments/media-types/media-types.xhtml | |
834 static const char* const legal_top_level_types[] = { | |
835 "application", | |
836 "audio", | |
837 "example", | |
838 "image", | |
839 "message", | |
840 "model", | |
841 "multipart", | |
842 "text", | |
843 "video", | |
844 }; | |
845 | |
846 bool MimeUtil::ParseMimeTypeWithoutParameter( | |
847 const std::string& type_string, | |
848 std::string* top_level_type, | |
849 std::string* subtype) const { | |
850 std::vector<std::string> components; | |
851 base::SplitString(type_string, '/', &components); | |
852 if (components.size() != 2 || | |
853 !HttpUtil::IsToken(components[0]) || | |
854 !HttpUtil::IsToken(components[1])) | |
855 return false; | |
856 | |
857 if (top_level_type) | |
858 *top_level_type = components[0]; | |
859 if (subtype) | |
860 *subtype = components[1]; | |
861 return true; | |
862 } | |
863 | |
864 bool MimeUtil::IsValidTopLevelMimeType(const std::string& type_string) const { | |
865 std::string lower_type = base::StringToLowerASCII(type_string); | |
866 for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) { | |
867 if (lower_type.compare(legal_top_level_types[i]) == 0) | |
868 return true; | |
869 } | |
870 | |
871 return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false); | |
872 } | |
873 | |
874 bool MimeUtil::AreSupportedMediaCodecs( | |
875 const std::vector<std::string>& codecs) const { | |
876 for (size_t i = 0; i < codecs.size(); ++i) { | |
877 Codec codec = INVALID_CODEC; | |
878 bool is_ambiguous = true; | |
879 if (!StringToCodec(codecs[i], &codec, &is_ambiguous) || | |
880 !IsCodecSupported(codec)) { | |
881 return false; | |
882 } | |
883 } | |
884 return true; | |
885 } | |
886 | |
887 void MimeUtil::ParseCodecString(const std::string& codecs, | |
888 std::vector<std::string>* codecs_out, | |
889 bool strip) { | |
890 std::string no_quote_codecs; | |
891 base::TrimString(codecs, "\"", &no_quote_codecs); | |
892 base::SplitString(no_quote_codecs, ',', codecs_out); | |
893 | |
894 if (!strip) | |
895 return; | |
896 | |
897 // Strip everything past the first '.' | |
898 for (std::vector<std::string>::iterator it = codecs_out->begin(); | |
899 it != codecs_out->end(); | |
900 ++it) { | |
901 size_t found = it->find_first_of('.'); | |
902 if (found != std::string::npos) | |
903 it->resize(found); | |
904 } | |
905 } | |
906 | |
907 bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const { | |
908 return strict_format_map_.find(base::StringToLowerASCII(mime_type)) != | |
909 strict_format_map_.end(); | |
910 } | |
911 | |
912 SupportsType MimeUtil::IsSupportedStrictMediaMimeType( | |
913 const std::string& mime_type, | |
914 const std::vector<std::string>& codecs) const { | |
915 const std::string mime_type_lower_case = base::StringToLowerASCII(mime_type); | |
916 StrictMappings::const_iterator it_strict_map = | |
917 strict_format_map_.find(mime_type_lower_case); | |
918 if (it_strict_map == strict_format_map_.end()) | |
919 return codecs.empty() ? MayBeSupported : IsNotSupported; | |
920 | |
921 if (it_strict_map->second.empty()) { | |
922 // We get here if the mimetype does not expect a codecs parameter. | |
923 return (codecs.empty() && | |
924 IsDefaultCodecSupportedLowerCase(mime_type_lower_case)) | |
925 ? IsSupported | |
926 : IsNotSupported; | |
927 } | |
928 | |
929 if (codecs.empty()) { | |
930 // We get here if the mimetype expects to get a codecs parameter, | |
931 // but didn't get one. If |mime_type_lower_case| does not have a default | |
932 // codec the best we can do is say "maybe" because we don't have enough | |
933 // information. | |
934 Codec default_codec = INVALID_CODEC; | |
935 if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) | |
936 return MayBeSupported; | |
937 | |
938 return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported; | |
939 } | |
940 | |
941 return AreSupportedCodecs(it_strict_map->second, codecs); | |
942 } | |
943 | |
944 void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() { | |
945 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) { | |
946 non_image_map_.erase(proprietary_media_types[i]); | |
947 media_map_.erase(proprietary_media_types[i]); | |
948 } | |
949 allow_proprietary_codecs_ = false; | |
950 } | |
951 | |
952 // Returns true iff |profile_str| conforms to hex string "42y0", where y is one | |
953 // of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is | |
954 // taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1. | |
955 // | |
956 // |profile_str| is the first four characters of the H.264 suffix string | |
957 // (ignoring the last 2 characters of the full 6 character suffix that are | |
958 // level_idc). From ISO-14496-10 7.3.2.1, it consists of: | |
959 // 8 bits: profile_idc: required to be 0x42 here. | |
960 // 1 bit: constraint_set0_flag : required to be true here. | |
961 // 1 bit: constraint_set1_flag : ignored here. | |
962 // 1 bit: constraint_set2_flag : ignored here. | |
963 // 1 bit: constraint_set3_flag : ignored here. | |
964 // 4 bits: reserved : required to be 0 here. | |
965 // | |
966 // The spec indicates other ways, not implemented here, that a |profile_str| | |
967 // can indicate a baseline conforming decoder is sufficient for decode in Annex | |
968 // A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and | |
969 // in which level_idc and constraint_set3_flag represent a level less than or | |
970 // equal to the specified level." | |
971 static bool IsValidH264BaselineProfile(const std::string& profile_str) { | |
972 uint32 constraint_set_bits; | |
973 if (profile_str.size() != 4 || | |
974 profile_str[0] != '4' || | |
975 profile_str[1] != '2' || | |
976 profile_str[3] != '0' || | |
977 !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), | |
978 &constraint_set_bits)) { | |
979 return false; | |
980 } | |
981 | |
982 return constraint_set_bits >= 8; | |
983 } | |
984 | |
985 static bool IsValidH264Level(const std::string& level_str) { | |
986 uint32 level; | |
987 if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) | |
988 return false; | |
989 | |
990 // Valid levels taken from Table A-1 in ISO-14496-10. | |
991 // Essentially |level_str| is toHex(10 * level). | |
992 return ((level >= 10 && level <= 13) || | |
993 (level >= 20 && level <= 22) || | |
994 (level >= 30 && level <= 32) || | |
995 (level >= 40 && level <= 42) || | |
996 (level >= 50 && level <= 51)); | |
997 } | |
998 | |
999 // Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. | |
1000 // avc1.42y0xx, y >= 8 - H.264 Baseline | |
1001 // avc1.4D40xx - H.264 Main | |
1002 // avc1.6400xx - H.264 High | |
1003 // | |
1004 // avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to | |
1005 // signal H.264 Baseline. For example, the idc_level, profile_idc and | |
1006 // constraint_set3_flag pieces may explicitly require decoder to conform to | |
1007 // baseline profile at the specified level (see Annex A and constraint_set0 in | |
1008 // ISO-14496-10). | |
1009 static bool ParseH264CodecID(const std::string& codec_id, | |
1010 MimeUtil::Codec* codec, | |
1011 bool* is_ambiguous) { | |
1012 // Make sure we have avc1.xxxxxx or avc3.xxxxxx | |
1013 if (codec_id.size() != 11 || | |
1014 (!StartsWithASCII(codec_id, "avc1.", true) && | |
1015 !StartsWithASCII(codec_id, "avc3.", true))) { | |
1016 return false; | |
1017 } | |
1018 | |
1019 std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); | |
1020 if (IsValidH264BaselineProfile(profile)) { | |
1021 *codec = MimeUtil::H264_BASELINE; | |
1022 } else if (profile == "4D40") { | |
1023 *codec = MimeUtil::H264_MAIN; | |
1024 } else if (profile == "6400") { | |
1025 *codec = MimeUtil::H264_HIGH; | |
1026 } else { | |
1027 *codec = MimeUtil::H264_BASELINE; | |
1028 *is_ambiguous = true; | |
1029 return true; | |
1030 } | |
1031 | |
1032 *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9))); | |
1033 return true; | |
1034 } | |
1035 | |
1036 bool MimeUtil::StringToCodec(const std::string& codec_id, | |
1037 Codec* codec, | |
1038 bool* is_ambiguous) const { | |
1039 StringToCodecMappings::const_iterator itr = | |
1040 string_to_codec_map_.find(codec_id); | |
1041 if (itr != string_to_codec_map_.end()) { | |
1042 *codec = itr->second.codec; | |
1043 *is_ambiguous = itr->second.is_ambiguous; | |
1044 return true; | |
1045 } | |
1046 | |
1047 // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is | |
1048 // an H.264 codec ID because currently those are the only ones that can't be | |
1049 // stored in the |string_to_codec_map_| and require parsing. | |
1050 return ParseH264CodecID(codec_id, codec, is_ambiguous); | |
1051 } | |
1052 | |
1053 bool MimeUtil::IsCodecSupported(Codec codec) const { | |
1054 DCHECK_NE(codec, INVALID_CODEC); | |
1055 | |
1056 #if defined(OS_ANDROID) | |
1057 if (!IsCodecSupportedOnAndroid(codec)) | |
1058 return false; | |
1059 #endif | |
1060 | |
1061 return allow_proprietary_codecs_ || !IsCodecProprietary(codec); | |
1062 } | |
1063 | |
1064 bool MimeUtil::IsCodecProprietary(Codec codec) const { | |
1065 switch (codec) { | |
1066 case INVALID_CODEC: | |
1067 case MP3: | |
1068 case MPEG2_AAC_LC: | |
1069 case MPEG2_AAC_MAIN: | |
1070 case MPEG2_AAC_SSR: | |
1071 case MPEG4_AAC_LC: | |
1072 case MPEG4_AAC_SBR_v1: | |
1073 case MPEG4_AAC_SBR_PS_v2: | |
1074 case H264_BASELINE: | |
1075 case H264_MAIN: | |
1076 case H264_HIGH: | |
1077 return true; | |
1078 | |
1079 case PCM: | |
1080 case VORBIS: | |
1081 case OPUS: | |
1082 case VP8: | |
1083 case VP9: | |
1084 case THEORA: | |
1085 return false; | |
1086 } | |
1087 | |
1088 return true; | |
1089 } | |
1090 | |
1091 bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, | |
1092 Codec* default_codec) const { | |
1093 if (mime_type_lower_case == "audio/mpeg" || | |
1094 mime_type_lower_case == "audio/mp3" || | |
1095 mime_type_lower_case == "audio/x-mp3") { | |
1096 *default_codec = MimeUtil::MP3; | |
1097 return true; | |
1098 } | |
1099 | |
1100 return false; | |
1101 } | |
1102 | |
1103 bool MimeUtil::IsDefaultCodecSupportedLowerCase( | |
1104 const std::string& mime_type_lower_case) const { | |
1105 Codec default_codec = Codec::INVALID_CODEC; | |
1106 if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec)) | |
1107 return false; | |
1108 return IsCodecSupported(default_codec); | |
1109 } | |
1110 | |
1111 //---------------------------------------------------------------------------- | |
1112 // Wrappers for the singleton | |
1113 //---------------------------------------------------------------------------- | |
1114 | |
1115 bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, | |
1116 std::string* mime_type) { | |
1117 return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type); | |
1118 } | |
1119 | |
1120 bool GetMimeTypeFromFile(const base::FilePath& file_path, | |
1121 std::string* mime_type) { | |
1122 return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type); | |
1123 } | |
1124 | |
1125 bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, | |
1126 std::string* mime_type) { | |
1127 return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type); | |
1128 } | |
1129 | |
1130 bool GetPreferredExtensionForMimeType(const std::string& mime_type, | |
1131 base::FilePath::StringType* extension) { | |
1132 return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type, | |
1133 extension); | |
1134 } | |
1135 | |
1136 bool IsSupportedImageMimeType(const std::string& mime_type) { | |
1137 return g_mime_util.Get().IsSupportedImageMimeType(mime_type); | |
1138 } | |
1139 | |
1140 bool IsSupportedMediaMimeType(const std::string& mime_type) { | |
1141 return g_mime_util.Get().IsSupportedMediaMimeType(mime_type); | |
1142 } | |
1143 | |
1144 bool IsSupportedNonImageMimeType(const std::string& mime_type) { | |
1145 return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type); | |
1146 } | |
1147 | |
1148 bool IsUnsupportedTextMimeType(const std::string& mime_type) { | |
1149 return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type); | |
1150 } | |
1151 | |
1152 bool IsSupportedJavascriptMimeType(const std::string& mime_type) { | |
1153 return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type); | |
1154 } | |
1155 | |
1156 bool IsSupportedMimeType(const std::string& mime_type) { | |
1157 return g_mime_util.Get().IsSupportedMimeType(mime_type); | |
1158 } | |
1159 | |
1160 bool MatchesMimeType(const std::string& mime_type_pattern, | |
1161 const std::string& mime_type) { | |
1162 return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type); | |
1163 } | |
1164 | |
1165 bool ParseMimeTypeWithoutParameter(const std::string& type_string, | |
1166 std::string* top_level_type, | |
1167 std::string* subtype) { | |
1168 return g_mime_util.Get().ParseMimeTypeWithoutParameter( | |
1169 type_string, top_level_type, subtype); | |
1170 } | |
1171 | |
1172 bool IsValidTopLevelMimeType(const std::string& type_string) { | |
1173 return g_mime_util.Get().IsValidTopLevelMimeType(type_string); | |
1174 } | |
1175 | |
1176 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) { | |
1177 return g_mime_util.Get().AreSupportedMediaCodecs(codecs); | |
1178 } | |
1179 | |
1180 bool IsStrictMediaMimeType(const std::string& mime_type) { | |
1181 return g_mime_util.Get().IsStrictMediaMimeType(mime_type); | |
1182 } | |
1183 | |
1184 SupportsType IsSupportedStrictMediaMimeType( | |
1185 const std::string& mime_type, | |
1186 const std::vector<std::string>& codecs) { | |
1187 return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs); | |
1188 } | |
1189 | |
1190 void ParseCodecString(const std::string& codecs, | |
1191 std::vector<std::string>* codecs_out, | |
1192 const bool strip) { | |
1193 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); | |
1194 } | |
1195 | |
1196 namespace { | |
1197 | |
1198 // From http://www.w3schools.com/media/media_mimeref.asp and | |
1199 // http://plugindoc.mozdev.org/winmime.php | |
1200 static const char* const kStandardImageTypes[] = { | |
1201 "image/bmp", | |
1202 "image/cis-cod", | |
1203 "image/gif", | |
1204 "image/ief", | |
1205 "image/jpeg", | |
1206 "image/webp", | |
1207 "image/pict", | |
1208 "image/pipeg", | |
1209 "image/png", | |
1210 "image/svg+xml", | |
1211 "image/tiff", | |
1212 "image/vnd.microsoft.icon", | |
1213 "image/x-cmu-raster", | |
1214 "image/x-cmx", | |
1215 "image/x-icon", | |
1216 "image/x-portable-anymap", | |
1217 "image/x-portable-bitmap", | |
1218 "image/x-portable-graymap", | |
1219 "image/x-portable-pixmap", | |
1220 "image/x-rgb", | |
1221 "image/x-xbitmap", | |
1222 "image/x-xpixmap", | |
1223 "image/x-xwindowdump" | |
1224 }; | |
1225 static const char* const kStandardAudioTypes[] = { | |
1226 "audio/aac", | |
1227 "audio/aiff", | |
1228 "audio/amr", | |
1229 "audio/basic", | |
1230 "audio/midi", | |
1231 "audio/mp3", | |
1232 "audio/mp4", | |
1233 "audio/mpeg", | |
1234 "audio/mpeg3", | |
1235 "audio/ogg", | |
1236 "audio/vorbis", | |
1237 "audio/wav", | |
1238 "audio/webm", | |
1239 "audio/x-m4a", | |
1240 "audio/x-ms-wma", | |
1241 "audio/vnd.rn-realaudio", | |
1242 "audio/vnd.wave" | |
1243 }; | |
1244 static const char* const kStandardVideoTypes[] = { | |
1245 "video/avi", | |
1246 "video/divx", | |
1247 "video/flc", | |
1248 "video/mp4", | |
1249 "video/mpeg", | |
1250 "video/ogg", | |
1251 "video/quicktime", | |
1252 "video/sd-video", | |
1253 "video/webm", | |
1254 "video/x-dv", | |
1255 "video/x-m4v", | |
1256 "video/x-mpeg", | |
1257 "video/x-ms-asf", | |
1258 "video/x-ms-wmv" | |
1259 }; | |
1260 | |
1261 struct StandardType { | |
1262 const char* const leading_mime_type; | |
1263 const char* const* standard_types; | |
1264 size_t standard_types_len; | |
1265 }; | |
1266 static const StandardType kStandardTypes[] = { | |
1267 { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) }, | |
1268 { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) }, | |
1269 { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) }, | |
1270 { NULL, NULL, 0 } | |
1271 }; | |
1272 | |
1273 void GetExtensionsFromHardCodedMappings( | |
1274 const MimeInfo* mappings, | |
1275 size_t mappings_len, | |
1276 const std::string& leading_mime_type, | |
1277 base::hash_set<base::FilePath::StringType>* extensions) { | |
1278 base::FilePath::StringType extension; | |
1279 for (size_t i = 0; i < mappings_len; ++i) { | |
1280 if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) { | |
1281 std::vector<string> this_extensions; | |
1282 base::SplitString(mappings[i].extensions, ',', &this_extensions); | |
1283 for (size_t j = 0; j < this_extensions.size(); ++j) { | |
1284 #if defined(OS_WIN) | |
1285 base::FilePath::StringType extension( | |
1286 base::UTF8ToWide(this_extensions[j])); | |
1287 #else | |
1288 base::FilePath::StringType extension(this_extensions[j]); | |
1289 #endif | |
1290 extensions->insert(extension); | |
1291 } | |
1292 } | |
1293 } | |
1294 } | |
1295 | |
1296 void GetExtensionsHelper( | |
1297 const char* const* standard_types, | |
1298 size_t standard_types_len, | |
1299 const std::string& leading_mime_type, | |
1300 base::hash_set<base::FilePath::StringType>* extensions) { | |
1301 for (size_t i = 0; i < standard_types_len; ++i) { | |
1302 g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i], | |
1303 extensions); | |
1304 } | |
1305 | |
1306 // Also look up the extensions from hard-coded mappings in case that some | |
1307 // supported extensions are not registered in the system registry, like ogg. | |
1308 GetExtensionsFromHardCodedMappings(primary_mappings, | |
1309 arraysize(primary_mappings), | |
1310 leading_mime_type, | |
1311 extensions); | |
1312 | |
1313 GetExtensionsFromHardCodedMappings(secondary_mappings, | |
1314 arraysize(secondary_mappings), | |
1315 leading_mime_type, | |
1316 extensions); | |
1317 } | |
1318 | |
1319 // Note that the elements in the source set will be appended to the target | |
1320 // vector. | |
1321 template<class T> | |
1322 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { | |
1323 size_t old_target_size = target->size(); | |
1324 target->resize(old_target_size + source->size()); | |
1325 size_t i = 0; | |
1326 for (typename base::hash_set<T>::iterator iter = source->begin(); | |
1327 iter != source->end(); ++iter, ++i) | |
1328 (*target)[old_target_size + i] = *iter; | |
1329 } | |
1330 | |
1331 } // namespace | |
1332 | |
1333 void GetExtensionsForMimeType( | |
1334 const std::string& unsafe_mime_type, | |
1335 std::vector<base::FilePath::StringType>* extensions) { | |
1336 if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*") | |
1337 return; | |
1338 | |
1339 const std::string mime_type = base::StringToLowerASCII(unsafe_mime_type); | |
1340 base::hash_set<base::FilePath::StringType> unique_extensions; | |
1341 | |
1342 if (EndsWith(mime_type, "/*", false)) { | |
1343 std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1); | |
1344 | |
1345 // Find the matching StandardType from within kStandardTypes, or fall | |
1346 // through to the last (default) StandardType. | |
1347 const StandardType* type = NULL; | |
1348 for (size_t i = 0; i < arraysize(kStandardTypes); ++i) { | |
1349 type = &(kStandardTypes[i]); | |
1350 if (type->leading_mime_type && | |
1351 leading_mime_type == type->leading_mime_type) | |
1352 break; | |
1353 } | |
1354 DCHECK(type); | |
1355 GetExtensionsHelper(type->standard_types, | |
1356 type->standard_types_len, | |
1357 leading_mime_type, | |
1358 &unique_extensions); | |
1359 } else { | |
1360 g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type, | |
1361 &unique_extensions); | |
1362 | |
1363 // Also look up the extensions from hard-coded mappings in case that some | |
1364 // supported extensions are not registered in the system registry, like ogg. | |
1365 GetExtensionsFromHardCodedMappings(primary_mappings, | |
1366 arraysize(primary_mappings), | |
1367 mime_type, | |
1368 &unique_extensions); | |
1369 | |
1370 GetExtensionsFromHardCodedMappings(secondary_mappings, | |
1371 arraysize(secondary_mappings), | |
1372 mime_type, | |
1373 &unique_extensions); | |
1374 } | |
1375 | |
1376 HashSetToVector(&unique_extensions, extensions); | |
1377 } | |
1378 | |
1379 void RemoveProprietaryMediaTypesAndCodecsForTests() { | |
1380 g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests(); | |
1381 } | |
1382 | |
1383 CertificateMimeType GetCertificateMimeTypeForMimeType( | |
1384 const std::string& mime_type) { | |
1385 // Don't create a map, there is only one entry in the table, | |
1386 // except on Android. | |
1387 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { | |
1388 if (base::strcasecmp(mime_type.c_str(), | |
1389 net::supported_certificate_types[i].mime_type) == 0) { | |
1390 return net::supported_certificate_types[i].cert_type; | |
1391 } | |
1392 } | |
1393 return CERTIFICATE_MIME_TYPE_UNKNOWN; | |
1394 } | |
1395 | |
1396 bool IsSupportedCertificateMimeType(const std::string& mime_type) { | |
1397 CertificateMimeType file_type = | |
1398 GetCertificateMimeTypeForMimeType(mime_type); | |
1399 return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; | |
1400 } | |
1401 | |
1402 void AddMultipartValueForUpload(const std::string& value_name, | |
1403 const std::string& value, | |
1404 const std::string& mime_boundary, | |
1405 const std::string& content_type, | |
1406 std::string* post_data) { | |
1407 DCHECK(post_data); | |
1408 // First line is the boundary. | |
1409 post_data->append("--" + mime_boundary + "\r\n"); | |
1410 // Next line is the Content-disposition. | |
1411 post_data->append("Content-Disposition: form-data; name=\"" + | |
1412 value_name + "\"\r\n"); | |
1413 if (!content_type.empty()) { | |
1414 // If Content-type is specified, the next line is that. | |
1415 post_data->append("Content-Type: " + content_type + "\r\n"); | |
1416 } | |
1417 // Leave an empty line and append the value. | |
1418 post_data->append("\r\n" + value + "\r\n"); | |
1419 } | |
1420 | |
1421 void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary, | |
1422 std::string* post_data) { | |
1423 DCHECK(post_data); | |
1424 post_data->append("--" + mime_boundary + "--\r\n"); | |
1425 } | |
1426 | |
1427 } // namespace net | |
OLD | NEW |