mime_util.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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/strings/string_split.h" 14#include "base/strings/string_util.h" 15#include "base/strings/utf_string_conversions.h" 16#include "net/base/mime_util.h" 17#include "net/base/platform_mime_util.h" 18 19using std::string; 20 21namespace { 22 23struct MediaType { 24 const char name[12]; 25 const char matcher[13]; 26}; 27 28static const MediaType kIanaMediaTypes[] = { 29 { "application", "application/" }, 30 { "audio", "audio/" }, 31 { "example", "example/" }, 32 { "image", "image/" }, 33 { "message", "message/" }, 34 { "model", "model/" }, 35 { "multipart", "multipart/" }, 36 { "text", "text/" }, 37 { "video", "video/" }, 38}; 39 40} // namespace 41 42namespace net { 43 44// Singleton utility class for mime types. 45class MimeUtil : public PlatformMimeUtil { 46 public: 47 bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, 48 std::string* mime_type) const; 49 50 bool GetMimeTypeFromFile(const base::FilePath& file_path, 51 std::string* mime_type) const; 52 53 bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, 54 std::string* mime_type) const; 55 56 bool IsSupportedImageMimeType(const std::string& mime_type) const; 57 bool IsSupportedMediaMimeType(const std::string& mime_type) const; 58 bool IsSupportedNonImageMimeType(const std::string& mime_type) const; 59 bool IsUnsupportedTextMimeType(const std::string& mime_type) const; 60 bool IsSupportedJavascriptMimeType(const std::string& mime_type) const; 61 62 bool IsSupportedMimeType(const std::string& mime_type) const; 63 64 bool MatchesMimeType(const std::string &mime_type_pattern, 65 const std::string &mime_type) const; 66 67 bool IsMimeType(const std::string& type_string) const; 68 69 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; 70 71 void ParseCodecString(const std::string& codecs, 72 std::vector<std::string>* codecs_out, 73 bool strip); 74 75 bool IsStrictMediaMimeType(const std::string& mime_type) const; 76 bool IsSupportedStrictMediaMimeType( 77 const std::string& mime_type, 78 const std::vector<std::string>& codecs) const; 79 80 private: 81 friend struct base::DefaultLazyInstanceTraits<MimeUtil>; 82 83 typedef base::hash_set<std::string> MimeMappings; 84 typedef std::map<std::string, MimeMappings> StrictMappings; 85 86 MimeUtil(); 87 88 // Returns true if |codecs| is nonempty and all the items in it are present in 89 // |supported_codecs|. 90 static bool AreSupportedCodecs(const MimeMappings& supported_codecs, 91 const std::vector<std::string>& codecs); 92 93 // For faster lookup, keep hash sets. 94 void InitializeMimeTypeMaps(); 95 96 bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, 97 bool include_platform_types, 98 std::string* mime_type) const; 99 100 MimeMappings image_map_; 101 MimeMappings media_map_; 102 MimeMappings non_image_map_; 103 MimeMappings unsupported_text_map_; 104 MimeMappings javascript_map_; 105 MimeMappings codecs_map_; 106 107 StrictMappings strict_format_map_; 108}; // class MimeUtil 109 110// This variable is Leaky because we need to access it from WorkerPool threads. 111static base::LazyInstance<MimeUtil>::Leaky g_mime_util = 112 LAZY_INSTANCE_INITIALIZER; 113 114struct MimeInfo { 115 const char* mime_type; 116 const char* extensions; // comma separated list 117}; 118 119static const MimeInfo primary_mappings[] = { 120 { "text/html", "html,htm" }, 121 { "text/css", "css" }, 122 { "text/xml", "xml" }, 123 { "image/gif", "gif" }, 124 { "image/jpeg", "jpeg,jpg" }, 125 { "image/webp", "webp" }, 126 { "image/png", "png" }, 127 { "video/mp4", "mp4,m4v" }, 128 { "audio/x-m4a", "m4a" }, 129 { "audio/mp3", "mp3" }, 130 { "video/ogg", "ogv,ogm" }, 131 { "audio/ogg", "ogg,oga,opus" }, 132 { "video/webm", "webm" }, 133 { "audio/webm", "webm" }, 134 { "audio/wav", "wav" }, 135 { "application/xhtml+xml", "xhtml,xht" }, 136 { "application/x-chrome-extension", "crx" }, 137 { "multipart/related", "mhtml,mht" } 138}; 139 140static const MimeInfo secondary_mappings[] = { 141 { "application/octet-stream", "exe,com,bin" }, 142 { "application/gzip", "gz" }, 143 { "application/pdf", "pdf" }, 144 { "application/postscript", "ps,eps,ai" }, 145 { "application/javascript", "js" }, 146 { "application/font-woff", "woff" }, 147 { "image/bmp", "bmp" }, 148 { "image/x-icon", "ico" }, 149 { "image/vnd.microsoft.icon", "ico" }, 150 { "image/jpeg", "jfif,pjpeg,pjp" }, 151 { "image/tiff", "tiff,tif" }, 152 { "image/x-xbitmap", "xbm" }, 153 { "image/svg+xml", "svg,svgz" }, 154 { "message/rfc822", "eml" }, 155 { "text/plain", "txt,text" }, 156 { "text/html", "shtml,ehtml" }, 157 { "application/rss+xml", "rss" }, 158 { "application/rdf+xml", "rdf" }, 159 { "text/xml", "xsl,xbl" }, 160 { "application/vnd.mozilla.xul+xml", "xul" }, 161 { "application/x-shockwave-flash", "swf,swl" }, 162 { "application/pkcs7-mime", "p7m,p7c,p7z" }, 163 { "application/pkcs7-signature", "p7s" } 164}; 165 166static const char* FindMimeType(const MimeInfo* mappings, 167 size_t mappings_len, 168 const char* ext) { 169 size_t ext_len = strlen(ext); 170 171 for (size_t i = 0; i < mappings_len; ++i) { 172 const char* extensions = mappings[i].extensions; 173 for (;;) { 174 size_t end_pos = strcspn(extensions, ","); 175 if (end_pos == ext_len && 176 base::strncasecmp(extensions, ext, ext_len) == 0) 177 return mappings[i].mime_type; 178 extensions += end_pos; 179 if (!*extensions) 180 break; 181 extensions += 1; // skip over comma 182 } 183 } 184 return NULL; 185} 186 187bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext, 188 string* result) const { 189 return GetMimeTypeFromExtensionHelper(ext, true, result); 190} 191 192bool MimeUtil::GetWellKnownMimeTypeFromExtension( 193 const base::FilePath::StringType& ext, 194 string* result) const { 195 return GetMimeTypeFromExtensionHelper(ext, false, result); 196} 197 198bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path, 199 string* result) const { 200 base::FilePath::StringType file_name_str = file_path.Extension(); 201 if (file_name_str.empty()) 202 return false; 203 return GetMimeTypeFromExtension(file_name_str.substr(1), result); 204} 205 206bool MimeUtil::GetMimeTypeFromExtensionHelper( 207 const base::FilePath::StringType& ext, 208 bool include_platform_types, 209 string* result) const { 210 // Avoids crash when unable to handle a long file path. See crbug.com/48733. 211 const unsigned kMaxFilePathSize = 65536; 212 if (ext.length() > kMaxFilePathSize) 213 return false; 214 215 // We implement the same algorithm as Mozilla for mapping a file extension to 216 // a mime type. That is, we first check a hard-coded list (that cannot be 217 // overridden), and then if not found there, we defer to the system registry. 218 // Finally, we scan a secondary hard-coded list to catch types that we can 219 // deduce but that we also want to allow the OS to override. 220 221 base::FilePath path_ext(ext); 222 const string ext_narrow_str = path_ext.AsUTF8Unsafe(); 223 const char* mime_type; 224 225 mime_type = FindMimeType(primary_mappings, arraysize(primary_mappings), 226 ext_narrow_str.c_str()); 227 if (mime_type) { 228 *result = mime_type; 229 return true; 230 } 231 232 if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) 233 return true; 234 235 mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings), 236 ext_narrow_str.c_str()); 237 if (mime_type) { 238 *result = mime_type; 239 return true; 240 } 241 242 return false; 243} 244 245// From WebKit's WebCore/platform/MIMETypeRegistry.cpp: 246 247static const char* const supported_image_types[] = { 248 "image/jpeg", 249 "image/pjpeg", 250 "image/jpg", 251 "image/webp", 252 "image/png", 253 "image/gif", 254 "image/bmp", 255 "image/vnd.microsoft.icon", // ico 256 "image/x-icon", // ico 257 "image/x-xbitmap" // xbm 258}; 259 260// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type 261// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php 262// This set of codecs is supported by all variations of Chromium. 263static const char* const common_media_types[] = { 264 // Ogg. 265 "audio/ogg", 266 "application/ogg", 267#if defined(ENABLE_MEDIA_CODEC_THEORA) 268 "video/ogg", 269#endif 270 271 // WebM. 272 "video/webm", 273 "audio/webm", 274 275 // Wav. 276 "audio/wav", 277 "audio/x-wav", 278}; 279 280// List of proprietary types only supported by Google Chrome. 281static const char* const proprietary_media_types[] = { 282 // MPEG-4. 283 "video/mp4", 284 "video/x-m4v", 285 "audio/mp4", 286 "audio/x-m4a", 287 288 // MP3. 289 "audio/mp3", 290 "audio/x-mp3", 291 "audio/mpeg", 292}; 293 294// List of supported codecs when passed in with <source type="...">. 295// This set of codecs is supported by all variations of Chromium. 296// 297// Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support 298// for more information. 299// 300// The codecs for WAV are integers as defined in Appendix A of RFC2361: 301// http://tools.ietf.org/html/rfc2361 302static const char* const common_media_codecs[] = { 303#if defined(ENABLE_MEDIA_CODEC_THEORA) 304 "theora", 305#endif 306 "vorbis", 307 "vp8", 308 "vp9", 309 "1" // WAVE_FORMAT_PCM. 310}; 311 312// List of proprietary codecs only supported by Google Chrome. 313static const char* const proprietary_media_codecs[] = { 314 "avc1", 315 "mp4a" 316}; 317 318// Note: does not include javascript types list (see supported_javascript_types) 319static const char* const supported_non_image_types[] = { 320 "text/cache-manifest", 321 "text/html", 322 "text/xml", 323 "text/xsl", 324 "text/plain", 325 // Many users complained about css files served for 326 // download instead of displaying in the browser: 327 // http://code.google.com/p/chromium/issues/detail?id=7192 328 // So, by including "text/css" into this list we choose Firefox 329 // behavior - css files will be displayed: 330 "text/css", 331 "text/vnd.chromium.ftp-dir", 332 "text/", 333 "image/svg+xml", // SVG is text-based XML, even though it has an image/ type 334 "application/xml", 335 "application/atom+xml", 336 "application/rss+xml", 337 "application/xhtml+xml", 338 "application/json", 339 "multipart/related", // For MHTML support. 340 "multipart/x-mixed-replace" 341 // Note: ADDING a new type here will probably render it AS HTML. This can 342 // result in cross site scripting. 343}; 344 345// Dictionary of cryptographic file mime types. 346struct CertificateMimeTypeInfo { 347 const char* mime_type; 348 CertificateMimeType cert_type; 349}; 350 351static const CertificateMimeTypeInfo supported_certificate_types[] = { 352 { "application/x-x509-user-cert", 353 CERTIFICATE_MIME_TYPE_X509_USER_CERT }, 354#if defined(OS_ANDROID) 355 { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT }, 356 { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE }, 357#endif 358}; 359 360// These types are excluded from the logic that allows all text/ types because 361// while they are technically text, it's very unlikely that a user expects to 362// see them rendered in text form. 363static const char* const unsupported_text_types[] = { 364 "text/calendar", 365 "text/x-calendar", 366 "text/x-vcalendar", 367 "text/vcalendar", 368 "text/vcard", 369 "text/x-vcard", 370 "text/directory", 371 "text/ldif", 372 "text/qif", 373 "text/x-qif", 374 "text/x-csv", 375 "text/x-vcf", 376 "text/rtf", 377 "text/comma-separated-values", 378 "text/csv", 379 "text/tab-separated-values", 380 "text/tsv", 381 "text/ofx", // http://crbug.com/162238 382 "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450 383}; 384 385// Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript. 386// Mozilla 1.8 accepts application/javascript, application/ecmascript, and 387// application/x-javascript, but WinIE 7 doesn't. 388// WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and 389// text/livescript, but Mozilla 1.8 doesn't. 390// Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't. 391// Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a 392// whitespace-only string. 393// We want to accept all the values that either of these browsers accept, but 394// not other values. 395static const char* const supported_javascript_types[] = { 396 "text/javascript", 397 "text/ecmascript", 398 "application/javascript", 399 "application/ecmascript", 400 "application/x-javascript", 401 "text/javascript1.1", 402 "text/javascript1.2", 403 "text/javascript1.3", 404 "text/jscript", 405 "text/livescript" 406}; 407 408struct MediaFormatStrict { 409 const char* mime_type; 410 const char* codecs_list; 411}; 412 413static const MediaFormatStrict format_codec_mappings[] = { 414 { "video/webm", "vorbis,vp8,vp8.0,vp9,vp9.0" }, 415 { "audio/webm", "vorbis" }, 416 { "audio/wav", "1" } 417}; 418 419MimeUtil::MimeUtil() { 420 InitializeMimeTypeMaps(); 421} 422 423// static 424bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs, 425 const std::vector<std::string>& codecs) { 426 for (size_t i = 0; i < codecs.size(); ++i) { 427 if (supported_codecs.find(codecs[i]) == supported_codecs.end()) 428 return false; 429 } 430 return !codecs.empty(); 431} 432 433void MimeUtil::InitializeMimeTypeMaps() { 434 for (size_t i = 0; i < arraysize(supported_image_types); ++i) 435 image_map_.insert(supported_image_types[i]); 436 437 // Initialize the supported non-image types. 438 for (size_t i = 0; i < arraysize(supported_non_image_types); ++i) 439 non_image_map_.insert(supported_non_image_types[i]); 440 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) 441 non_image_map_.insert(supported_certificate_types[i].mime_type); 442 for (size_t i = 0; i < arraysize(unsupported_text_types); ++i) 443 unsupported_text_map_.insert(unsupported_text_types[i]); 444 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) 445 non_image_map_.insert(supported_javascript_types[i]); 446 for (size_t i = 0; i < arraysize(common_media_types); ++i) 447 non_image_map_.insert(common_media_types[i]); 448#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 449 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) 450 non_image_map_.insert(proprietary_media_types[i]); 451#endif 452 453 // Initialize the supported media types. 454 for (size_t i = 0; i < arraysize(common_media_types); ++i) 455 media_map_.insert(common_media_types[i]); 456#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 457 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) 458 media_map_.insert(proprietary_media_types[i]); 459#endif 460 461 for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) 462 javascript_map_.insert(supported_javascript_types[i]); 463 464 for (size_t i = 0; i < arraysize(common_media_codecs); ++i) 465 codecs_map_.insert(common_media_codecs[i]); 466#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS) 467 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i) 468 codecs_map_.insert(proprietary_media_codecs[i]); 469#endif 470 471 // Initialize the strict supported media types. 472 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { 473 std::vector<std::string> mime_type_codecs; 474 ParseCodecString(format_codec_mappings[i].codecs_list, 475 &mime_type_codecs, 476 false); 477 478 MimeMappings codecs; 479 for (size_t j = 0; j < mime_type_codecs.size(); ++j) 480 codecs.insert(mime_type_codecs[j]); 481 strict_format_map_[format_codec_mappings[i].mime_type] = codecs; 482 } 483} 484 485bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const { 486 return image_map_.find(mime_type) != image_map_.end(); 487} 488 489bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { 490 return media_map_.find(mime_type) != media_map_.end(); 491} 492 493bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { 494 return non_image_map_.find(mime_type) != non_image_map_.end() || 495 (mime_type.compare(0, 5, "text/") == 0 && 496 !IsUnsupportedTextMimeType(mime_type)); 497} 498 499bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const { 500 return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end(); 501} 502 503bool MimeUtil::IsSupportedJavascriptMimeType( 504 const std::string& mime_type) const { 505 return javascript_map_.find(mime_type) != javascript_map_.end(); 506} 507 508// Mirrors WebViewImpl::CanShowMIMEType() 509bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const { 510 return (mime_type.compare(0, 6, "image/") == 0 && 511 IsSupportedImageMimeType(mime_type)) || 512 IsSupportedNonImageMimeType(mime_type); 513} 514 515// Tests for MIME parameter equality. Each parameter in the |mime_type_pattern| 516// must be matched by a parameter in the |mime_type|. If there are no 517// parameters in the pattern, the match is a success. 518bool MatchesMimeTypeParameters(const std::string& mime_type_pattern, 519 const std::string& mime_type) { 520 const std::string::size_type semicolon = mime_type_pattern.find(';'); 521 const std::string::size_type test_semicolon = mime_type.find(';'); 522 if (semicolon != std::string::npos) { 523 if (test_semicolon == std::string::npos) 524 return false; 525 526 std::vector<std::string> pattern_parameters; 527 base::SplitString(mime_type_pattern.substr(semicolon + 1), 528 ';', &pattern_parameters); 529 530 std::vector<std::string> test_parameters; 531 base::SplitString(mime_type.substr(test_semicolon + 1), 532 ';', &test_parameters); 533 534 sort(pattern_parameters.begin(), pattern_parameters.end()); 535 sort(test_parameters.begin(), test_parameters.end()); 536 std::vector<std::string> difference; 537 std::set_difference(pattern_parameters.begin(), pattern_parameters.end(), 538 test_parameters.begin(), test_parameters.end(), 539 std::inserter(difference, difference.begin())); 540 541 return difference.size() == 0; 542 } 543 return true; 544} 545 546// This comparison handles absolute maching and also basic 547// wildcards. The plugin mime types could be: 548// application/x-foo 549// application/* 550// application/*+xml 551// * 552// Also tests mime parameters -- all parameters in the pattern must be present 553// in the tested type for a match to succeed. 554bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern, 555 const std::string& mime_type) const { 556 // Verify caller is passing lowercase strings. 557 DCHECK_EQ(StringToLowerASCII(mime_type_pattern), mime_type_pattern); 558 DCHECK_EQ(StringToLowerASCII(mime_type), mime_type); 559 560 if (mime_type_pattern.empty()) 561 return false; 562 563 std::string::size_type semicolon = mime_type_pattern.find(';'); 564 const std::string base_pattern(mime_type_pattern.substr(0, semicolon)); 565 semicolon = mime_type.find(';'); 566 const std::string base_type(mime_type.substr(0, semicolon)); 567 568 if (base_pattern == "*" || base_pattern == "*/*") 569 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); 570 571 const std::string::size_type star = base_pattern.find('*'); 572 if (star == std::string::npos) { 573 if (base_pattern == base_type) 574 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); 575 else 576 return false; 577 } 578 579 // Test length to prevent overlap between |left| and |right|. 580 if (base_type.length() < base_pattern.length() - 1) 581 return false; 582 583 const std::string left(base_pattern.substr(0, star)); 584 const std::string right(base_pattern.substr(star + 1)); 585 586 if (base_type.find(left) != 0) 587 return false; 588 589 if (!right.empty() && 590 base_type.rfind(right) != base_type.length() - right.length()) 591 return false; 592 593 return MatchesMimeTypeParameters(mime_type_pattern, mime_type); 594} 595 596// See http://www.iana.org/assignments/media-types/index.html 597static const char* legal_top_level_types[] = { 598 "application/", 599 "audio/", 600 "example/", 601 "image/", 602 "message/", 603 "model/", 604 "multipart/", 605 "text/", 606 "video/", 607}; 608 609bool MimeUtil::IsMimeType(const std::string& type_string) const { 610 // MIME types are always ASCII and case-insensitive (at least, the top-level 611 // and secondary types we care about). 612 if (!IsStringASCII(type_string)) 613 return false; 614 615 if (type_string == "*/*" || type_string == "*") 616 return true; 617 618 for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) { 619 if (StartsWithASCII(type_string, legal_top_level_types[i], false) && 620 type_string.length() > strlen(legal_top_level_types[i])) { 621 return true; 622 } 623 } 624 625 // If there's a "/" separator character, and the token before it is 626 // "x-" + (ascii characters), it is also a MIME type. 627 size_t slash = type_string.find('/'); 628 if (slash < 3 || 629 slash == std::string::npos || slash == type_string.length() - 1) { 630 return false; 631 } 632 633 if (StartsWithASCII(type_string, "x-", false)) 634 return true; 635 636 return false; 637} 638 639bool MimeUtil::AreSupportedMediaCodecs( 640 const std::vector<std::string>& codecs) const { 641 return AreSupportedCodecs(codecs_map_, codecs); 642} 643 644void MimeUtil::ParseCodecString(const std::string& codecs, 645 std::vector<std::string>* codecs_out, 646 bool strip) { 647 std::string no_quote_codecs; 648 TrimString(codecs, "\"", &no_quote_codecs); 649 base::SplitString(no_quote_codecs, ',', codecs_out); 650 651 if (!strip) 652 return; 653 654 // Strip everything past the first '.' 655 for (std::vector<std::string>::iterator it = codecs_out->begin(); 656 it != codecs_out->end(); 657 ++it) { 658 size_t found = it->find_first_of('.'); 659 if (found != std::string::npos) 660 it->resize(found); 661 } 662} 663 664bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const { 665 if (strict_format_map_.find(mime_type) == strict_format_map_.end()) 666 return false; 667 return true; 668} 669 670bool MimeUtil::IsSupportedStrictMediaMimeType( 671 const std::string& mime_type, 672 const std::vector<std::string>& codecs) const { 673 StrictMappings::const_iterator it = strict_format_map_.find(mime_type); 674 return (it != strict_format_map_.end()) && 675 AreSupportedCodecs(it->second, codecs); 676} 677 678//---------------------------------------------------------------------------- 679// Wrappers for the singleton 680//---------------------------------------------------------------------------- 681 682bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, 683 std::string* mime_type) { 684 return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type); 685} 686 687bool GetMimeTypeFromFile(const base::FilePath& file_path, 688 std::string* mime_type) { 689 return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type); 690} 691 692bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, 693 std::string* mime_type) { 694 return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type); 695} 696 697bool GetPreferredExtensionForMimeType(const std::string& mime_type, 698 base::FilePath::StringType* extension) { 699 return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type, 700 extension); 701} 702 703bool IsSupportedImageMimeType(const std::string& mime_type) { 704 return g_mime_util.Get().IsSupportedImageMimeType(mime_type); 705} 706 707bool IsSupportedMediaMimeType(const std::string& mime_type) { 708 return g_mime_util.Get().IsSupportedMediaMimeType(mime_type); 709} 710 711bool IsSupportedNonImageMimeType(const std::string& mime_type) { 712 return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type); 713} 714 715bool IsUnsupportedTextMimeType(const std::string& mime_type) { 716 return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type); 717} 718 719bool IsSupportedJavascriptMimeType(const std::string& mime_type) { 720 return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type); 721} 722 723bool IsSupportedMimeType(const std::string& mime_type) { 724 return g_mime_util.Get().IsSupportedMimeType(mime_type); 725} 726 727bool MatchesMimeType(const std::string& mime_type_pattern, 728 const std::string& mime_type) { 729 return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type); 730} 731 732bool IsMimeType(const std::string& type_string) { 733 return g_mime_util.Get().IsMimeType(type_string); 734} 735 736bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) { 737 return g_mime_util.Get().AreSupportedMediaCodecs(codecs); 738} 739 740bool IsStrictMediaMimeType(const std::string& mime_type) { 741 return g_mime_util.Get().IsStrictMediaMimeType(mime_type); 742} 743 744bool IsSupportedStrictMediaMimeType(const std::string& mime_type, 745 const std::vector<std::string>& codecs) { 746 return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs); 747} 748 749void ParseCodecString(const std::string& codecs, 750 std::vector<std::string>* codecs_out, 751 const bool strip) { 752 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); 753} 754 755namespace { 756 757// From http://www.w3schools.com/media/media_mimeref.asp and 758// http://plugindoc.mozdev.org/winmime.php 759static const char* const kStandardImageTypes[] = { 760 "image/bmp", 761 "image/cis-cod", 762 "image/gif", 763 "image/ief", 764 "image/jpeg", 765 "image/webp", 766 "image/pict", 767 "image/pipeg", 768 "image/png", 769 "image/svg+xml", 770 "image/tiff", 771 "image/vnd.microsoft.icon", 772 "image/x-cmu-raster", 773 "image/x-cmx", 774 "image/x-icon", 775 "image/x-portable-anymap", 776 "image/x-portable-bitmap", 777 "image/x-portable-graymap", 778 "image/x-portable-pixmap", 779 "image/x-rgb", 780 "image/x-xbitmap", 781 "image/x-xpixmap", 782 "image/x-xwindowdump" 783}; 784static const char* const kStandardAudioTypes[] = { 785 "audio/aac", 786 "audio/aiff", 787 "audio/amr", 788 "audio/basic", 789 "audio/midi", 790 "audio/mp3", 791 "audio/mp4", 792 "audio/mpeg", 793 "audio/mpeg3", 794 "audio/ogg", 795 "audio/vorbis", 796 "audio/wav", 797 "audio/webm", 798 "audio/x-m4a", 799 "audio/x-ms-wma", 800 "audio/vnd.rn-realaudio", 801 "audio/vnd.wave" 802}; 803static const char* const kStandardVideoTypes[] = { 804 "video/avi", 805 "video/divx", 806 "video/flc", 807 "video/mp4", 808 "video/mpeg", 809 "video/ogg", 810 "video/quicktime", 811 "video/sd-video", 812 "video/webm", 813 "video/x-dv", 814 "video/x-m4v", 815 "video/x-mpeg", 816 "video/x-ms-asf", 817 "video/x-ms-wmv" 818}; 819 820struct StandardType { 821 const char* leading_mime_type; 822 const char* const* standard_types; 823 size_t standard_types_len; 824}; 825static const StandardType kStandardTypes[] = { 826 { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) }, 827 { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) }, 828 { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) }, 829 { NULL, NULL, 0 } 830}; 831 832void GetExtensionsFromHardCodedMappings( 833 const MimeInfo* mappings, 834 size_t mappings_len, 835 const std::string& leading_mime_type, 836 base::hash_set<base::FilePath::StringType>* extensions) { 837 base::FilePath::StringType extension; 838 for (size_t i = 0; i < mappings_len; ++i) { 839 if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) { 840 std::vector<string> this_extensions; 841 base::SplitStringUsingSubstr(mappings[i].extensions, ",", 842 &this_extensions); 843 for (size_t j = 0; j < this_extensions.size(); ++j) { 844#if defined(OS_WIN) 845 base::FilePath::StringType extension(UTF8ToWide(this_extensions[j])); 846#else 847 base::FilePath::StringType extension(this_extensions[j]); 848#endif 849 extensions->insert(extension); 850 } 851 } 852 } 853} 854 855void GetExtensionsHelper( 856 const char* const* standard_types, 857 size_t standard_types_len, 858 const std::string& leading_mime_type, 859 base::hash_set<base::FilePath::StringType>* extensions) { 860 for (size_t i = 0; i < standard_types_len; ++i) { 861 g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i], 862 extensions); 863 } 864 865 // Also look up the extensions from hard-coded mappings in case that some 866 // supported extensions are not registered in the system registry, like ogg. 867 GetExtensionsFromHardCodedMappings(primary_mappings, 868 arraysize(primary_mappings), 869 leading_mime_type, 870 extensions); 871 872 GetExtensionsFromHardCodedMappings(secondary_mappings, 873 arraysize(secondary_mappings), 874 leading_mime_type, 875 extensions); 876} 877 878// Note that the elements in the source set will be appended to the target 879// vector. 880template<class T> 881void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { 882 size_t old_target_size = target->size(); 883 target->resize(old_target_size + source->size()); 884 size_t i = 0; 885 for (typename base::hash_set<T>::iterator iter = source->begin(); 886 iter != source->end(); ++iter, ++i) 887 (*target)[old_target_size + i] = *iter; 888} 889} 890 891void GetExtensionsForMimeType( 892 const std::string& unsafe_mime_type, 893 std::vector<base::FilePath::StringType>* extensions) { 894 if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*") 895 return; 896 897 const std::string mime_type = StringToLowerASCII(unsafe_mime_type); 898 base::hash_set<base::FilePath::StringType> unique_extensions; 899 900 if (EndsWith(mime_type, "/*", true)) { 901 std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1); 902 903 // Find the matching StandardType from within kStandardTypes, or fall 904 // through to the last (default) StandardType. 905 const StandardType* type = NULL; 906 for (size_t i = 0; i < arraysize(kStandardTypes); ++i) { 907 type = &(kStandardTypes[i]); 908 if (type->leading_mime_type && 909 leading_mime_type == type->leading_mime_type) 910 break; 911 } 912 DCHECK(type); 913 GetExtensionsHelper(type->standard_types, 914 type->standard_types_len, 915 leading_mime_type, 916 &unique_extensions); 917 } else { 918 g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type, 919 &unique_extensions); 920 921 // Also look up the extensions from hard-coded mappings in case that some 922 // supported extensions are not registered in the system registry, like ogg. 923 GetExtensionsFromHardCodedMappings(primary_mappings, 924 arraysize(primary_mappings), 925 mime_type, 926 &unique_extensions); 927 928 GetExtensionsFromHardCodedMappings(secondary_mappings, 929 arraysize(secondary_mappings), 930 mime_type, 931 &unique_extensions); 932 } 933 934 HashSetToVector(&unique_extensions, extensions); 935} 936 937void GetMediaTypesBlacklistedForTests(std::vector<std::string>* types) { 938 types->clear(); 939 940// Unless/until WebM files are added to the media layout tests, we need to avoid 941// blacklisting mp4 and H.264 when Theora is not supported (and proprietary 942// codecs are) so that the media tests can still run. 943#if defined(ENABLE_MEDIA_CODEC_THEORA) || !defined(USE_PROPRIETARY_CODECS) 944 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) 945 types->push_back(proprietary_media_types[i]); 946#endif 947} 948 949void GetMediaCodecsBlacklistedForTests(std::vector<std::string>* codecs) { 950 codecs->clear(); 951 952// Unless/until WebM files are added to the media layout tests, we need to avoid 953// blacklisting mp4 and H.264 when Theora is not supported (and proprietary 954// codecs are) so that the media tests can still run. 955#if defined(ENABLE_MEDIA_CODEC_THEORA) || !defined(USE_PROPRIETARY_CODECS) 956 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i) 957 codecs->push_back(proprietary_media_codecs[i]); 958#endif 959} 960 961const std::string GetIANAMediaType(const std::string& mime_type) { 962 for (size_t i = 0; i < arraysize(kIanaMediaTypes); ++i) { 963 if (StartsWithASCII(mime_type, kIanaMediaTypes[i].matcher, true)) { 964 return kIanaMediaTypes[i].name; 965 } 966 } 967 return std::string(); 968} 969 970CertificateMimeType GetCertificateMimeTypeForMimeType( 971 const std::string& mime_type) { 972 // Don't create a map, there is only one entry in the table, 973 // except on Android. 974 for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { 975 if (mime_type == net::supported_certificate_types[i].mime_type) 976 return net::supported_certificate_types[i].cert_type; 977 } 978 return CERTIFICATE_MIME_TYPE_UNKNOWN; 979} 980 981bool IsSupportedCertificateMimeType(const std::string& mime_type) { 982 CertificateMimeType file_type = 983 GetCertificateMimeTypeForMimeType(mime_type); 984 return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; 985} 986 987void AddMultipartValueForUpload(const std::string& value_name, 988 const std::string& value, 989 const std::string& mime_boundary, 990 const std::string& content_type, 991 std::string* post_data) { 992 DCHECK(post_data); 993 // First line is the boundary. 994 post_data->append("--" + mime_boundary + "\r\n"); 995 // Next line is the Content-disposition. 996 post_data->append("Content-Disposition: form-data; name=\"" + 997 value_name + "\"\r\n"); 998 if (!content_type.empty()) { 999 // If Content-type is specified, the next line is that. 1000 post_data->append("Content-Type: " + content_type + "\r\n"); 1001 } 1002 // Leave an empty line and append the value. 1003 post_data->append("\r\n" + value + "\r\n"); 1004} 1005 1006void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary, 1007 std::string* post_data) { 1008 DCHECK(post_data); 1009 post_data->append("--" + mime_boundary + "--\r\n"); 1010} 1011 1012} // namespace net 1013