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