| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <map> |
| #include <string> |
| |
| #include "base/containers/hash_tables.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "net/base/mime_util.h" |
| #include "net/base/platform_mime_util.h" |
| #include "net/http/http_util.h" |
| |
| #if defined(OS_ANDROID) |
| #include "base/android/build_info.h" |
| #endif |
| |
| using std::string; |
| |
| namespace { |
| |
| struct MediaType { |
| const char name[12]; |
| const char matcher[13]; |
| }; |
| |
| static const MediaType kIanaMediaTypes[] = { |
| { "application", "application/" }, |
| { "audio", "audio/" }, |
| { "example", "example/" }, |
| { "image", "image/" }, |
| { "message", "message/" }, |
| { "model", "model/" }, |
| { "multipart", "multipart/" }, |
| { "text", "text/" }, |
| { "video", "video/" }, |
| }; |
| |
| } // namespace |
| |
| namespace net { |
| |
| // Singleton utility class for mime types. |
| class MimeUtil : public PlatformMimeUtil { |
| public: |
| enum Codec { |
| INVALID_CODEC, |
| PCM, |
| MP3, |
| MPEG2_AAC_LC, |
| MPEG2_AAC_MAIN, |
| MPEG2_AAC_SSR, |
| MPEG4_AAC_LC, |
| MPEG4_AAC_SBRv1, |
| VORBIS, |
| OPUS, |
| H264_BASELINE, |
| H264_MAIN, |
| H264_HIGH, |
| VP8, |
| VP9, |
| THEORA |
| }; |
| |
| bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, |
| std::string* mime_type) const; |
| |
| bool GetMimeTypeFromFile(const base::FilePath& file_path, |
| std::string* mime_type) const; |
| |
| bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, |
| std::string* mime_type) const; |
| |
| bool IsSupportedImageMimeType(const std::string& mime_type) const; |
| bool IsSupportedMediaMimeType(const std::string& mime_type) const; |
| bool IsSupportedNonImageMimeType(const std::string& mime_type) const; |
| bool IsUnsupportedTextMimeType(const std::string& mime_type) const; |
| bool IsSupportedJavascriptMimeType(const std::string& mime_type) const; |
| |
| bool IsSupportedMimeType(const std::string& mime_type) const; |
| |
| bool MatchesMimeType(const std::string &mime_type_pattern, |
| const std::string &mime_type) const; |
| |
| bool ParseMimeTypeWithoutParameter(const std::string& type_string, |
| std::string* top_level_type, |
| std::string* subtype) const; |
| |
| bool IsValidTopLevelMimeType(const std::string& type_string) const; |
| |
| bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const; |
| |
| void ParseCodecString(const std::string& codecs, |
| std::vector<std::string>* codecs_out, |
| bool strip); |
| |
| bool IsStrictMediaMimeType(const std::string& mime_type) const; |
| SupportsType IsSupportedStrictMediaMimeType( |
| const std::string& mime_type, |
| const std::vector<std::string>& codecs) const; |
| |
| void RemoveProprietaryMediaTypesAndCodecsForTests(); |
| |
| private: |
| friend struct base::DefaultLazyInstanceTraits<MimeUtil>; |
| |
| typedef base::hash_set<std::string> MimeMappings; |
| |
| typedef base::hash_set<int> CodecSet; |
| typedef std::map<std::string, CodecSet> StrictMappings; |
| struct CodecEntry { |
| CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {} |
| CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {} |
| Codec codec; |
| bool is_ambiguous; |
| }; |
| typedef std::map<std::string, CodecEntry> StringToCodecMappings; |
| |
| MimeUtil(); |
| |
| // Returns IsSupported if all codec IDs in |codecs| are unambiguous |
| // and are supported by the platform. MayBeSupported is returned if |
| // at least one codec ID in |codecs| is ambiguous but all the codecs |
| // are supported by the platform. IsNotSupported is returned if at |
| // least one codec ID is not supported by the platform. |
| SupportsType AreSupportedCodecs( |
| const CodecSet& supported_codecs, |
| const std::vector<std::string>& codecs) const; |
| |
| // For faster lookup, keep hash sets. |
| void InitializeMimeTypeMaps(); |
| |
| bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext, |
| bool include_platform_types, |
| std::string* mime_type) const; |
| |
| // Converts a codec ID into an Codec enum value and indicates |
| // whether the conversion was ambiguous. |
| // Returns true if this method was able to map |codec_id| to a specific |
| // Codec enum value. |codec| and |is_ambiguous| are only valid if true |
| // is returned. Otherwise their value is undefined after the call. |
| // |is_ambiguous| is true if |codec_id| did not have enough information to |
| // unambiguously determine the proper Codec enum value. If |is_ambiguous| |
| // is true |codec| contains the best guess for the intended Codec enum value. |
| bool StringToCodec(const std::string& codec_id, |
| Codec* codec, |
| bool* is_ambiguous) const; |
| |
| // Returns true if |codec| is supported by the platform. |
| // Note: This method will return false if the platform supports proprietary |
| // codecs but |allow_proprietary_codecs_| is set to false. |
| bool IsCodecSupported(Codec codec) const; |
| |
| // Returns true if |codec| refers to a proprietary codec. |
| bool IsCodecProprietary(Codec codec) const; |
| |
| // Returns true and sets |*default_codec| if |mime_type| has a |
| // default codec associated with it. |
| // Returns false otherwise and the value of |*default_codec| is undefined. |
| bool GetDefaultCodec(const std::string& mime_type, |
| Codec* default_codec) const; |
| |
| // Returns true if |mime_type| has a default codec associated with it |
| // and IsCodecSupported() returns true for that particular codec. |
| bool IsDefaultCodecSupported(const std::string& mime_type) const; |
| |
| MimeMappings image_map_; |
| MimeMappings media_map_; |
| MimeMappings non_image_map_; |
| MimeMappings unsupported_text_map_; |
| MimeMappings javascript_map_; |
| |
| // A map of mime_types and hash map of the supported codecs for the mime_type. |
| StrictMappings strict_format_map_; |
| |
| // Keeps track of whether proprietary codec support should be |
| // advertised to callers. |
| bool allow_proprietary_codecs_; |
| |
| // Lookup table for string compare based string -> Codec mappings. |
| StringToCodecMappings string_to_codec_map_; |
| }; // class MimeUtil |
| |
| // This variable is Leaky because we need to access it from WorkerPool threads. |
| static base::LazyInstance<MimeUtil>::Leaky g_mime_util = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| struct MimeInfo { |
| const char* mime_type; |
| const char* extensions; // comma separated list |
| }; |
| |
| static const MimeInfo primary_mappings[] = { |
| { "text/html", "html,htm,shtml,shtm" }, |
| { "text/css", "css" }, |
| { "text/xml", "xml" }, |
| { "image/gif", "gif" }, |
| { "image/jpeg", "jpeg,jpg" }, |
| { "image/webp", "webp" }, |
| { "image/png", "png" }, |
| { "video/mp4", "mp4,m4v" }, |
| { "audio/x-m4a", "m4a" }, |
| { "audio/mp3", "mp3" }, |
| { "video/ogg", "ogv,ogm" }, |
| { "audio/ogg", "ogg,oga,opus" }, |
| { "video/webm", "webm" }, |
| { "audio/webm", "webm" }, |
| { "audio/wav", "wav" }, |
| { "application/xhtml+xml", "xhtml,xht,xhtm" }, |
| { "application/x-chrome-extension", "crx" }, |
| { "multipart/related", "mhtml,mht" } |
| }; |
| |
| static const MimeInfo secondary_mappings[] = { |
| { "application/octet-stream", "exe,com,bin" }, |
| { "application/gzip", "gz" }, |
| { "application/pdf", "pdf" }, |
| { "application/postscript", "ps,eps,ai" }, |
| { "application/javascript", "js" }, |
| { "application/font-woff", "woff" }, |
| { "image/bmp", "bmp" }, |
| { "image/x-icon", "ico" }, |
| { "image/vnd.microsoft.icon", "ico" }, |
| { "image/jpeg", "jfif,pjpeg,pjp" }, |
| { "image/tiff", "tiff,tif" }, |
| { "image/x-xbitmap", "xbm" }, |
| { "image/svg+xml", "svg,svgz" }, |
| { "image/x-png", "png"}, |
| { "message/rfc822", "eml" }, |
| { "text/plain", "txt,text" }, |
| { "text/html", "ehtml" }, |
| { "application/rss+xml", "rss" }, |
| { "application/rdf+xml", "rdf" }, |
| { "text/xml", "xsl,xbl,xslt" }, |
| { "application/vnd.mozilla.xul+xml", "xul" }, |
| { "application/x-shockwave-flash", "swf,swl" }, |
| { "application/pkcs7-mime", "p7m,p7c,p7z" }, |
| { "application/pkcs7-signature", "p7s" }, |
| { "application/x-mpegurl", "m3u8" }, |
| }; |
| |
| static const char* FindMimeType(const MimeInfo* mappings, |
| size_t mappings_len, |
| const char* ext) { |
| size_t ext_len = strlen(ext); |
| |
| for (size_t i = 0; i < mappings_len; ++i) { |
| const char* extensions = mappings[i].extensions; |
| for (;;) { |
| size_t end_pos = strcspn(extensions, ","); |
| if (end_pos == ext_len && |
| base::strncasecmp(extensions, ext, ext_len) == 0) |
| return mappings[i].mime_type; |
| extensions += end_pos; |
| if (!*extensions) |
| break; |
| extensions += 1; // skip over comma |
| } |
| } |
| return NULL; |
| } |
| |
| bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext, |
| string* result) const { |
| return GetMimeTypeFromExtensionHelper(ext, true, result); |
| } |
| |
| bool MimeUtil::GetWellKnownMimeTypeFromExtension( |
| const base::FilePath::StringType& ext, |
| string* result) const { |
| return GetMimeTypeFromExtensionHelper(ext, false, result); |
| } |
| |
| bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path, |
| string* result) const { |
| base::FilePath::StringType file_name_str = file_path.Extension(); |
| if (file_name_str.empty()) |
| return false; |
| return GetMimeTypeFromExtension(file_name_str.substr(1), result); |
| } |
| |
| bool MimeUtil::GetMimeTypeFromExtensionHelper( |
| const base::FilePath::StringType& ext, |
| bool include_platform_types, |
| string* result) const { |
| // Avoids crash when unable to handle a long file path. See crbug.com/48733. |
| const unsigned kMaxFilePathSize = 65536; |
| if (ext.length() > kMaxFilePathSize) |
| return false; |
| |
| // We implement the same algorithm as Mozilla for mapping a file extension to |
| // a mime type. That is, we first check a hard-coded list (that cannot be |
| // overridden), and then if not found there, we defer to the system registry. |
| // Finally, we scan a secondary hard-coded list to catch types that we can |
| // deduce but that we also want to allow the OS to override. |
| |
| base::FilePath path_ext(ext); |
| const string ext_narrow_str = path_ext.AsUTF8Unsafe(); |
| const char* mime_type = FindMimeType(primary_mappings, |
| arraysize(primary_mappings), |
| ext_narrow_str.c_str()); |
| if (mime_type) { |
| *result = mime_type; |
| return true; |
| } |
| |
| if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) |
| return true; |
| |
| mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings), |
| ext_narrow_str.c_str()); |
| if (mime_type) { |
| *result = mime_type; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // From WebKit's WebCore/platform/MIMETypeRegistry.cpp: |
| |
| static const char* const supported_image_types[] = { |
| "image/jpeg", |
| "image/pjpeg", |
| "image/jpg", |
| "image/webp", |
| "image/png", |
| "image/gif", |
| "image/bmp", |
| "image/vnd.microsoft.icon", // ico |
| "image/x-icon", // ico |
| "image/x-xbitmap", // xbm |
| "image/x-png" |
| }; |
| |
| // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type |
| // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php |
| // This set of codecs is supported by all variations of Chromium. |
| static const char* const common_media_types[] = { |
| // Ogg. |
| "audio/ogg", |
| "application/ogg", |
| #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora. |
| "video/ogg", |
| #endif |
| |
| // WebM. |
| "video/webm", |
| "audio/webm", |
| |
| // Wav. |
| "audio/wav", |
| "audio/x-wav", |
| |
| #if defined(OS_ANDROID) |
| // HLS. Supported by Android ICS and above. |
| "application/vnd.apple.mpegurl", |
| "application/x-mpegurl", |
| #endif |
| }; |
| |
| // List of proprietary types only supported by Google Chrome. |
| static const char* const proprietary_media_types[] = { |
| // MPEG-4. |
| "video/mp4", |
| "video/x-m4v", |
| "audio/mp4", |
| "audio/x-m4a", |
| |
| // MP3. |
| "audio/mp3", |
| "audio/x-mp3", |
| "audio/mpeg", |
| |
| #if defined(ENABLE_MPEG2TS_STREAM_PARSER) |
| // MPEG-2 TS. |
| "video/mp2t", |
| #endif |
| }; |
| |
| // Note: |
| // - does not include javascript types list (see supported_javascript_types) |
| // - does not include types starting with "text/" (see |
| // IsSupportedNonImageMimeType()) |
| static const char* const supported_non_image_types[] = { |
| "image/svg+xml", // SVG is text-based XML, even though it has an image/ type |
| "application/xml", |
| "application/atom+xml", |
| "application/rss+xml", |
| "application/xhtml+xml", |
| "application/json", |
| "multipart/related", // For MHTML support. |
| "multipart/x-mixed-replace" |
| // Note: ADDING a new type here will probably render it AS HTML. This can |
| // result in cross site scripting. |
| }; |
| |
| // Dictionary of cryptographic file mime types. |
| struct CertificateMimeTypeInfo { |
| const char* mime_type; |
| CertificateMimeType cert_type; |
| }; |
| |
| static const CertificateMimeTypeInfo supported_certificate_types[] = { |
| { "application/x-x509-user-cert", |
| CERTIFICATE_MIME_TYPE_X509_USER_CERT }, |
| #if defined(OS_ANDROID) |
| { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT }, |
| { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE }, |
| #endif |
| }; |
| |
| // These types are excluded from the logic that allows all text/ types because |
| // while they are technically text, it's very unlikely that a user expects to |
| // see them rendered in text form. |
| static const char* const unsupported_text_types[] = { |
| "text/calendar", |
| "text/x-calendar", |
| "text/x-vcalendar", |
| "text/vcalendar", |
| "text/vcard", |
| "text/x-vcard", |
| "text/directory", |
| "text/ldif", |
| "text/qif", |
| "text/x-qif", |
| "text/x-csv", |
| "text/x-vcf", |
| "text/rtf", |
| "text/comma-separated-values", |
| "text/csv", |
| "text/tab-separated-values", |
| "text/tsv", |
| "text/ofx", // http://crbug.com/162238 |
| "text/vnd.sun.j2me.app-descriptor" // http://crbug.com/176450 |
| }; |
| |
| // Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript. |
| // Mozilla 1.8 accepts application/javascript, application/ecmascript, and |
| // application/x-javascript, but WinIE 7 doesn't. |
| // WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and |
| // text/livescript, but Mozilla 1.8 doesn't. |
| // Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't. |
| // Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a |
| // whitespace-only string. |
| // We want to accept all the values that either of these browsers accept, but |
| // not other values. |
| static const char* const supported_javascript_types[] = { |
| "text/javascript", |
| "text/ecmascript", |
| "application/javascript", |
| "application/ecmascript", |
| "application/x-javascript", |
| "text/javascript1.1", |
| "text/javascript1.2", |
| "text/javascript1.3", |
| "text/jscript", |
| "text/livescript" |
| }; |
| |
| #if defined(OS_ANDROID) |
| static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) { |
| switch (codec) { |
| case MimeUtil::INVALID_CODEC: |
| return false; |
| |
| case MimeUtil::PCM: |
| case MimeUtil::MP3: |
| case MimeUtil::MPEG4_AAC_LC: |
| case MimeUtil::MPEG4_AAC_SBRv1: |
| case MimeUtil::H264_BASELINE: |
| case MimeUtil::H264_MAIN: |
| case MimeUtil::H264_HIGH: |
| case MimeUtil::VP8: |
| case MimeUtil::VORBIS: |
| return true; |
| |
| case MimeUtil::MPEG2_AAC_LC: |
| case MimeUtil::MPEG2_AAC_MAIN: |
| case MimeUtil::MPEG2_AAC_SSR: |
| // MPEG-2 variants of AAC are not supported on Android. |
| return false; |
| |
| case MimeUtil::VP9: |
| // VP9 is supported only in KitKat+ (API Level 19). |
| return base::android::BuildInfo::GetInstance()->sdk_int() >= 19; |
| |
| case MimeUtil::OPUS: |
| // TODO(vigneshv): Change this similar to the VP9 check once Opus is |
| // supported on Android (http://crbug.com/318436). |
| return false; |
| |
| case MimeUtil::THEORA: |
| return false; |
| } |
| |
| return false; |
| } |
| |
| static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) { |
| // HLS codecs are supported in ICS and above (API level 14) |
| if ((!mimeType.compare("application/vnd.apple.mpegurl") || |
| !mimeType.compare("application/x-mpegurl")) && |
| base::android::BuildInfo::GetInstance()->sdk_int() < 14) { |
| return false; |
| } |
| return true; |
| } |
| #endif |
| |
| struct MediaFormatStrict { |
| const char* mime_type; |
| const char* codecs_list; |
| }; |
| |
| // Following is the list of RFC 6381 compliant codecs: |
| // mp4a.66 - MPEG-2 AAC MAIN |
| // mp4a.67 - MPEG-2 AAC LC |
| // mp4a.68 - MPEG-2 AAC SSR |
| // mp4a.69 - MPEG-2 extension to MPEG-1 |
| // mp4a.6B - MPEG-1 audio |
| // mp4a.40.2 - MPEG-4 AAC LC |
| // mp4a.40.5 - MPEG-4 AAC SBRv1 |
| // |
| // avc1.42E0xx - H.264 Baseline |
| // avc1.4D40xx - H.264 Main |
| // avc1.6400xx - H.264 High |
| static const char kMP4AudioCodecsExpression[] = |
| "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; |
| static const char kMP4VideoCodecsExpression[] = |
| "avc1.42E00A,avc1.4D400A,avc1.64000A," \ |
| "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5"; |
| |
| static const MediaFormatStrict format_codec_mappings[] = { |
| { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" }, |
| { "audio/webm", "opus,vorbis" }, |
| { "audio/wav", "1" }, |
| { "audio/x-wav", "1" }, |
| { "video/ogg", "opus,theora,vorbis" }, |
| { "audio/ogg", "opus,vorbis" }, |
| { "application/ogg", "opus,theora,vorbis" }, |
| { "audio/mpeg", "mp3" }, |
| { "audio/mp3", "" }, |
| { "audio/x-mp3", "" }, |
| { "audio/mp4", kMP4AudioCodecsExpression }, |
| { "audio/x-m4a", kMP4AudioCodecsExpression }, |
| { "video/mp4", kMP4VideoCodecsExpression }, |
| { "video/x-m4v", kMP4VideoCodecsExpression }, |
| { "application/x-mpegurl", kMP4VideoCodecsExpression }, |
| { "application/vnd.apple.mpegurl", kMP4VideoCodecsExpression } |
| }; |
| |
| struct CodecIDMappings { |
| const char* const codec_id; |
| MimeUtil::Codec codec; |
| }; |
| |
| // List of codec IDs that provide enough information to determine the |
| // codec and profile being requested. |
| // |
| // The "mp4a" strings come from RFC 6381. |
| static const CodecIDMappings kUnambiguousCodecIDs[] = { |
| { "1", MimeUtil::PCM }, // We only allow this for WAV so it isn't ambiguous. |
| { "mp3", MimeUtil::MP3 }, |
| { "mp4a.66", MimeUtil::MPEG2_AAC_MAIN }, |
| { "mp4a.67", MimeUtil::MPEG2_AAC_LC }, |
| { "mp4a.68", MimeUtil::MPEG2_AAC_SSR }, |
| { "mp4a.69", MimeUtil::MP3 }, |
| { "mp4a.6B", MimeUtil::MP3 }, |
| { "mp4a.40.2", MimeUtil::MPEG4_AAC_LC }, |
| { "mp4a.40.5", MimeUtil::MPEG4_AAC_SBRv1 }, |
| { "vorbis", MimeUtil::VORBIS }, |
| { "opus", MimeUtil::OPUS }, |
| { "vp8", MimeUtil::VP8 }, |
| { "vp8.0", MimeUtil::VP8 }, |
| { "vp9", MimeUtil::VP9 }, |
| { "vp9.0", MimeUtil::VP9 }, |
| { "theora", MimeUtil::THEORA } |
| }; |
| |
| // List of codec IDs that are ambiguous and don't provide |
| // enough information to determine the codec and profile. |
| // The codec in these entries indicate the codec and profile |
| // we assume the user is trying to indicate. |
| static const CodecIDMappings kAmbiguousCodecIDs[] = { |
| { "mp4a.40", MimeUtil::MPEG4_AAC_LC }, |
| { "avc1", MimeUtil::H264_BASELINE }, |
| { "avc3", MimeUtil::H264_BASELINE }, |
| }; |
| |
| MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { |
| InitializeMimeTypeMaps(); |
| } |
| |
| SupportsType MimeUtil::AreSupportedCodecs( |
| const CodecSet& supported_codecs, |
| const std::vector<std::string>& codecs) const { |
| DCHECK(!supported_codecs.empty()); |
| DCHECK(!codecs.empty()); |
| |
| SupportsType result = IsSupported; |
| for (size_t i = 0; i < codecs.size(); ++i) { |
| bool is_ambiguous = true; |
| Codec codec = INVALID_CODEC; |
| if (!StringToCodec(codecs[i], &codec, &is_ambiguous)) |
| return IsNotSupported; |
| |
| if (!IsCodecSupported(codec) || |
| supported_codecs.find(codec) == supported_codecs.end()) { |
| return IsNotSupported; |
| } |
| |
| if (is_ambiguous) |
| result = MayBeSupported; |
| } |
| |
| return result; |
| } |
| |
| void MimeUtil::InitializeMimeTypeMaps() { |
| for (size_t i = 0; i < arraysize(supported_image_types); ++i) |
| image_map_.insert(supported_image_types[i]); |
| |
| // Initialize the supported non-image types. |
| for (size_t i = 0; i < arraysize(supported_non_image_types); ++i) |
| non_image_map_.insert(supported_non_image_types[i]); |
| for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) |
| non_image_map_.insert(supported_certificate_types[i].mime_type); |
| for (size_t i = 0; i < arraysize(unsupported_text_types); ++i) |
| unsupported_text_map_.insert(unsupported_text_types[i]); |
| for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) |
| non_image_map_.insert(supported_javascript_types[i]); |
| for (size_t i = 0; i < arraysize(common_media_types); ++i) { |
| #if defined(OS_ANDROID) |
| if (!IsMimeTypeSupportedOnAndroid(common_media_types[i])) |
| continue; |
| #endif |
| non_image_map_.insert(common_media_types[i]); |
| } |
| #if defined(USE_PROPRIETARY_CODECS) |
| allow_proprietary_codecs_ = true; |
| |
| for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) |
| non_image_map_.insert(proprietary_media_types[i]); |
| #endif |
| |
| // Initialize the supported media types. |
| for (size_t i = 0; i < arraysize(common_media_types); ++i) { |
| #if defined(OS_ANDROID) |
| if (!IsMimeTypeSupportedOnAndroid(common_media_types[i])) |
| continue; |
| #endif |
| media_map_.insert(common_media_types[i]); |
| } |
| #if defined(USE_PROPRIETARY_CODECS) |
| for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) |
| media_map_.insert(proprietary_media_types[i]); |
| #endif |
| |
| for (size_t i = 0; i < arraysize(supported_javascript_types); ++i) |
| javascript_map_.insert(supported_javascript_types[i]); |
| |
| for (size_t i = 0; i < arraysize(kUnambiguousCodecIDs); ++i) { |
| string_to_codec_map_[kUnambiguousCodecIDs[i].codec_id] = |
| CodecEntry(kUnambiguousCodecIDs[i].codec, false); |
| } |
| |
| for (size_t i = 0; i < arraysize(kAmbiguousCodecIDs); ++i) { |
| string_to_codec_map_[kAmbiguousCodecIDs[i].codec_id] = |
| CodecEntry(kAmbiguousCodecIDs[i].codec, true); |
| } |
| |
| // Initialize the strict supported media types. |
| for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) { |
| std::vector<std::string> mime_type_codecs; |
| ParseCodecString(format_codec_mappings[i].codecs_list, |
| &mime_type_codecs, |
| false); |
| |
| CodecSet codecs; |
| for (size_t j = 0; j < mime_type_codecs.size(); ++j) { |
| Codec codec = INVALID_CODEC; |
| bool is_ambiguous = true; |
| CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous)); |
| DCHECK(!is_ambiguous); |
| codecs.insert(codec); |
| } |
| |
| strict_format_map_[format_codec_mappings[i].mime_type] = codecs; |
| } |
| } |
| |
| bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const { |
| return image_map_.find(mime_type) != image_map_.end(); |
| } |
| |
| bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const { |
| return media_map_.find(mime_type) != media_map_.end(); |
| } |
| |
| bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const { |
| return non_image_map_.find(mime_type) != non_image_map_.end() || |
| (mime_type.compare(0, 5, "text/") == 0 && |
| !IsUnsupportedTextMimeType(mime_type)) || |
| (mime_type.compare(0, 12, "application/") == 0 && |
| MatchesMimeType("application/*+json", mime_type)); |
| } |
| |
| bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const { |
| return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end(); |
| } |
| |
| bool MimeUtil::IsSupportedJavascriptMimeType( |
| const std::string& mime_type) const { |
| return javascript_map_.find(mime_type) != javascript_map_.end(); |
| } |
| |
| // Mirrors WebViewImpl::CanShowMIMEType() |
| bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const { |
| return (mime_type.compare(0, 6, "image/") == 0 && |
| IsSupportedImageMimeType(mime_type)) || |
| IsSupportedNonImageMimeType(mime_type); |
| } |
| |
| // Tests for MIME parameter equality. Each parameter in the |mime_type_pattern| |
| // must be matched by a parameter in the |mime_type|. If there are no |
| // parameters in the pattern, the match is a success. |
| bool MatchesMimeTypeParameters(const std::string& mime_type_pattern, |
| const std::string& mime_type) { |
| const std::string::size_type semicolon = mime_type_pattern.find(';'); |
| const std::string::size_type test_semicolon = mime_type.find(';'); |
| if (semicolon != std::string::npos) { |
| if (test_semicolon == std::string::npos) |
| return false; |
| |
| std::vector<std::string> pattern_parameters; |
| base::SplitString(mime_type_pattern.substr(semicolon + 1), |
| ';', &pattern_parameters); |
| |
| std::vector<std::string> test_parameters; |
| base::SplitString(mime_type.substr(test_semicolon + 1), |
| ';', &test_parameters); |
| |
| sort(pattern_parameters.begin(), pattern_parameters.end()); |
| sort(test_parameters.begin(), test_parameters.end()); |
| std::vector<std::string> difference = |
| base::STLSetDifference<std::vector<std::string> >(pattern_parameters, |
| test_parameters); |
| return difference.size() == 0; |
| } |
| return true; |
| } |
| |
| // This comparison handles absolute maching and also basic |
| // wildcards. The plugin mime types could be: |
| // application/x-foo |
| // application/* |
| // application/*+xml |
| // * |
| // Also tests mime parameters -- all parameters in the pattern must be present |
| // in the tested type for a match to succeed. |
| bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern, |
| const std::string& mime_type) const { |
| // Verify caller is passing lowercase strings. |
| DCHECK_EQ(base::StringToLowerASCII(mime_type_pattern), mime_type_pattern); |
| DCHECK_EQ(base::StringToLowerASCII(mime_type), mime_type); |
| |
| if (mime_type_pattern.empty()) |
| return false; |
| |
| std::string::size_type semicolon = mime_type_pattern.find(';'); |
| const std::string base_pattern(mime_type_pattern.substr(0, semicolon)); |
| semicolon = mime_type.find(';'); |
| const std::string base_type(mime_type.substr(0, semicolon)); |
| |
| if (base_pattern == "*" || base_pattern == "*/*") |
| return MatchesMimeTypeParameters(mime_type_pattern, mime_type); |
| |
| const std::string::size_type star = base_pattern.find('*'); |
| if (star == std::string::npos) { |
| if (base_pattern == base_type) |
| return MatchesMimeTypeParameters(mime_type_pattern, mime_type); |
| else |
| return false; |
| } |
| |
| // Test length to prevent overlap between |left| and |right|. |
| if (base_type.length() < base_pattern.length() - 1) |
| return false; |
| |
| const std::string left(base_pattern.substr(0, star)); |
| const std::string right(base_pattern.substr(star + 1)); |
| |
| if (base_type.find(left) != 0) |
| return false; |
| |
| if (!right.empty() && |
| base_type.rfind(right) != base_type.length() - right.length()) |
| return false; |
| |
| return MatchesMimeTypeParameters(mime_type_pattern, mime_type); |
| } |
| |
| // See http://www.iana.org/assignments/media-types/media-types.xhtml |
| static const char* legal_top_level_types[] = { |
| "application", |
| "audio", |
| "example", |
| "image", |
| "message", |
| "model", |
| "multipart", |
| "text", |
| "video", |
| }; |
| |
| bool MimeUtil::ParseMimeTypeWithoutParameter( |
| const std::string& type_string, |
| std::string* top_level_type, |
| std::string* subtype) const { |
| std::vector<std::string> components; |
| base::SplitString(type_string, '/', &components); |
| if (components.size() != 2 || |
| !HttpUtil::IsToken(components[0]) || |
| !HttpUtil::IsToken(components[1])) |
| return false; |
| |
| if (top_level_type) |
| *top_level_type = components[0]; |
| if (subtype) |
| *subtype = components[1]; |
| return true; |
| } |
| |
| bool MimeUtil::IsValidTopLevelMimeType(const std::string& type_string) const { |
| std::string lower_type = base::StringToLowerASCII(type_string); |
| for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) { |
| if (lower_type.compare(legal_top_level_types[i]) == 0) |
| return true; |
| } |
| |
| return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false); |
| } |
| |
| bool MimeUtil::AreSupportedMediaCodecs( |
| const std::vector<std::string>& codecs) const { |
| for (size_t i = 0; i < codecs.size(); ++i) { |
| Codec codec = INVALID_CODEC; |
| bool is_ambiguous = true; |
| if (!StringToCodec(codecs[i], &codec, &is_ambiguous) || |
| !IsCodecSupported(codec)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void MimeUtil::ParseCodecString(const std::string& codecs, |
| std::vector<std::string>* codecs_out, |
| bool strip) { |
| std::string no_quote_codecs; |
| base::TrimString(codecs, "\"", &no_quote_codecs); |
| base::SplitString(no_quote_codecs, ',', codecs_out); |
| |
| if (!strip) |
| return; |
| |
| // Strip everything past the first '.' |
| for (std::vector<std::string>::iterator it = codecs_out->begin(); |
| it != codecs_out->end(); |
| ++it) { |
| size_t found = it->find_first_of('.'); |
| if (found != std::string::npos) |
| it->resize(found); |
| } |
| } |
| |
| bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const { |
| return strict_format_map_.find(mime_type) != strict_format_map_.end(); |
| } |
| |
| SupportsType MimeUtil::IsSupportedStrictMediaMimeType( |
| const std::string& mime_type, |
| const std::vector<std::string>& codecs) const { |
| StrictMappings::const_iterator it_strict_map = |
| strict_format_map_.find(mime_type); |
| if (it_strict_map == strict_format_map_.end()) |
| return codecs.empty() ? MayBeSupported : IsNotSupported; |
| |
| if (it_strict_map->second.empty()) { |
| // We get here if the mimetype does not expect a codecs parameter. |
| return (codecs.empty() && IsDefaultCodecSupported(mime_type)) ? |
| IsSupported : IsNotSupported; |
| } |
| |
| if (codecs.empty()) { |
| // We get here if the mimetype expects to get a codecs parameter, |
| // but didn't get one. If |mime_type| does not have a default codec |
| // the best we can do is say "maybe" because we don't have enough |
| // information. |
| Codec default_codec = INVALID_CODEC; |
| if (!GetDefaultCodec(mime_type, &default_codec)) |
| return MayBeSupported; |
| |
| return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported; |
| } |
| |
| return AreSupportedCodecs(it_strict_map->second, codecs); |
| } |
| |
| void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() { |
| for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) { |
| non_image_map_.erase(proprietary_media_types[i]); |
| media_map_.erase(proprietary_media_types[i]); |
| } |
| allow_proprietary_codecs_ = false; |
| } |
| |
| // Returns true iff |profile_str| conforms to hex string "42y0", where y is one |
| // of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is |
| // taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1. |
| // |
| // |profile_str| is the first four characters of the H.264 suffix string |
| // (ignoring the last 2 characters of the full 6 character suffix that are |
| // level_idc). From ISO-14496-10 7.3.2.1, it consists of: |
| // 8 bits: profile_idc: required to be 0x42 here. |
| // 1 bit: constraint_set0_flag : required to be true here. |
| // 1 bit: constraint_set1_flag : ignored here. |
| // 1 bit: constraint_set2_flag : ignored here. |
| // 1 bit: constraint_set3_flag : ignored here. |
| // 4 bits: reserved : required to be 0 here. |
| // |
| // The spec indicates other ways, not implemented here, that a |profile_str| |
| // can indicate a baseline conforming decoder is sufficient for decode in Annex |
| // A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and |
| // in which level_idc and constraint_set3_flag represent a level less than or |
| // equal to the specified level." |
| static bool IsValidH264BaselineProfile(const std::string& profile_str) { |
| uint32 constraint_set_bits; |
| if (profile_str.size() != 4 || |
| profile_str[0] != '4' || |
| profile_str[1] != '2' || |
| profile_str[3] != '0' || |
| !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1), |
| &constraint_set_bits)) { |
| return false; |
| } |
| |
| return constraint_set_bits >= 8; |
| } |
| |
| static bool IsValidH264Level(const std::string& level_str) { |
| uint32 level; |
| if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level)) |
| return false; |
| |
| // Valid levels taken from Table A-1 in ISO-14496-10. |
| // Essentially |level_str| is toHex(10 * level). |
| return ((level >= 10 && level <= 13) || |
| (level >= 20 && level <= 22) || |
| (level >= 30 && level <= 32) || |
| (level >= 40 && level <= 42) || |
| (level >= 50 && level <= 51)); |
| } |
| |
| // Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10. |
| // avc1.42y0xx, y >= 8 - H.264 Baseline |
| // avc1.4D40xx - H.264 Main |
| // avc1.6400xx - H.264 High |
| // |
| // avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to |
| // signal H.264 Baseline. For example, the idc_level, profile_idc and |
| // constraint_set3_flag pieces may explicitly require decoder to conform to |
| // baseline profile at the specified level (see Annex A and constraint_set0 in |
| // ISO-14496-10). |
| static bool ParseH264CodecID(const std::string& codec_id, |
| MimeUtil::Codec* codec, |
| bool* is_ambiguous) { |
| // Make sure we have avc1.xxxxxx or avc3.xxxxxx |
| if (codec_id.size() != 11 || |
| (!StartsWithASCII(codec_id, "avc1.", true) && |
| !StartsWithASCII(codec_id, "avc3.", true))) { |
| return false; |
| } |
| |
| std::string profile = StringToUpperASCII(codec_id.substr(5, 4)); |
| if (IsValidH264BaselineProfile(profile)) { |
| *codec = MimeUtil::H264_BASELINE; |
| } else if (profile == "4D40") { |
| *codec = MimeUtil::H264_MAIN; |
| } else if (profile == "6400") { |
| *codec = MimeUtil::H264_HIGH; |
| } else { |
| *codec = MimeUtil::H264_BASELINE; |
| *is_ambiguous = true; |
| return true; |
| } |
| |
| *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9))); |
| return true; |
| } |
| |
| bool MimeUtil::StringToCodec(const std::string& codec_id, |
| Codec* codec, |
| bool* is_ambiguous) const { |
| StringToCodecMappings::const_iterator itr = |
| string_to_codec_map_.find(codec_id); |
| if (itr != string_to_codec_map_.end()) { |
| *codec = itr->second.codec; |
| *is_ambiguous = itr->second.is_ambiguous; |
| return true; |
| } |
| |
| // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is |
| // an H.264 codec ID because currently those are the only ones that can't be |
| // stored in the |string_to_codec_map_| and require parsing. |
| return ParseH264CodecID(codec_id, codec, is_ambiguous); |
| } |
| |
| bool MimeUtil::IsCodecSupported(Codec codec) const { |
| DCHECK_NE(codec, INVALID_CODEC); |
| |
| #if defined(OS_ANDROID) |
| if (!IsCodecSupportedOnAndroid(codec)) |
| return false; |
| #endif |
| |
| return allow_proprietary_codecs_ || !IsCodecProprietary(codec); |
| } |
| |
| bool MimeUtil::IsCodecProprietary(Codec codec) const { |
| switch (codec) { |
| case INVALID_CODEC: |
| case MP3: |
| case MPEG2_AAC_LC: |
| case MPEG2_AAC_MAIN: |
| case MPEG2_AAC_SSR: |
| case MPEG4_AAC_LC: |
| case MPEG4_AAC_SBRv1: |
| case H264_BASELINE: |
| case H264_MAIN: |
| case H264_HIGH: |
| return true; |
| |
| case PCM: |
| case VORBIS: |
| case OPUS: |
| case VP8: |
| case VP9: |
| case THEORA: |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool MimeUtil::GetDefaultCodec(const std::string& mime_type, |
| Codec* default_codec) const { |
| if (mime_type == "audio/mpeg" || |
| mime_type == "audio/mp3" || |
| mime_type == "audio/x-mp3") { |
| *default_codec = MimeUtil::MP3; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| bool MimeUtil::IsDefaultCodecSupported(const std::string& mime_type) const { |
| Codec default_codec = Codec::INVALID_CODEC; |
| if (!GetDefaultCodec(mime_type, &default_codec)) |
| return false; |
| return IsCodecSupported(default_codec); |
| } |
| |
| //---------------------------------------------------------------------------- |
| // Wrappers for the singleton |
| //---------------------------------------------------------------------------- |
| |
| bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext, |
| std::string* mime_type) { |
| return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type); |
| } |
| |
| bool GetMimeTypeFromFile(const base::FilePath& file_path, |
| std::string* mime_type) { |
| return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type); |
| } |
| |
| bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext, |
| std::string* mime_type) { |
| return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type); |
| } |
| |
| bool GetPreferredExtensionForMimeType(const std::string& mime_type, |
| base::FilePath::StringType* extension) { |
| return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type, |
| extension); |
| } |
| |
| bool IsSupportedImageMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsSupportedImageMimeType(mime_type); |
| } |
| |
| bool IsSupportedMediaMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsSupportedMediaMimeType(mime_type); |
| } |
| |
| bool IsSupportedNonImageMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type); |
| } |
| |
| bool IsUnsupportedTextMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type); |
| } |
| |
| bool IsSupportedJavascriptMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type); |
| } |
| |
| bool IsSupportedMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsSupportedMimeType(mime_type); |
| } |
| |
| bool MatchesMimeType(const std::string& mime_type_pattern, |
| const std::string& mime_type) { |
| return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type); |
| } |
| |
| bool ParseMimeTypeWithoutParameter(const std::string& type_string, |
| std::string* top_level_type, |
| std::string* subtype) { |
| return g_mime_util.Get().ParseMimeTypeWithoutParameter( |
| type_string, top_level_type, subtype); |
| } |
| |
| bool IsValidTopLevelMimeType(const std::string& type_string) { |
| return g_mime_util.Get().IsValidTopLevelMimeType(type_string); |
| } |
| |
| bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) { |
| return g_mime_util.Get().AreSupportedMediaCodecs(codecs); |
| } |
| |
| bool IsStrictMediaMimeType(const std::string& mime_type) { |
| return g_mime_util.Get().IsStrictMediaMimeType(mime_type); |
| } |
| |
| SupportsType IsSupportedStrictMediaMimeType( |
| const std::string& mime_type, |
| const std::vector<std::string>& codecs) { |
| return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs); |
| } |
| |
| void ParseCodecString(const std::string& codecs, |
| std::vector<std::string>* codecs_out, |
| const bool strip) { |
| g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip); |
| } |
| |
| namespace { |
| |
| // From http://www.w3schools.com/media/media_mimeref.asp and |
| // http://plugindoc.mozdev.org/winmime.php |
| static const char* const kStandardImageTypes[] = { |
| "image/bmp", |
| "image/cis-cod", |
| "image/gif", |
| "image/ief", |
| "image/jpeg", |
| "image/webp", |
| "image/pict", |
| "image/pipeg", |
| "image/png", |
| "image/svg+xml", |
| "image/tiff", |
| "image/vnd.microsoft.icon", |
| "image/x-cmu-raster", |
| "image/x-cmx", |
| "image/x-icon", |
| "image/x-portable-anymap", |
| "image/x-portable-bitmap", |
| "image/x-portable-graymap", |
| "image/x-portable-pixmap", |
| "image/x-rgb", |
| "image/x-xbitmap", |
| "image/x-xpixmap", |
| "image/x-xwindowdump" |
| }; |
| static const char* const kStandardAudioTypes[] = { |
| "audio/aac", |
| "audio/aiff", |
| "audio/amr", |
| "audio/basic", |
| "audio/midi", |
| "audio/mp3", |
| "audio/mp4", |
| "audio/mpeg", |
| "audio/mpeg3", |
| "audio/ogg", |
| "audio/vorbis", |
| "audio/wav", |
| "audio/webm", |
| "audio/x-m4a", |
| "audio/x-ms-wma", |
| "audio/vnd.rn-realaudio", |
| "audio/vnd.wave" |
| }; |
| static const char* const kStandardVideoTypes[] = { |
| "video/avi", |
| "video/divx", |
| "video/flc", |
| "video/mp4", |
| "video/mpeg", |
| "video/ogg", |
| "video/quicktime", |
| "video/sd-video", |
| "video/webm", |
| "video/x-dv", |
| "video/x-m4v", |
| "video/x-mpeg", |
| "video/x-ms-asf", |
| "video/x-ms-wmv" |
| }; |
| |
| struct StandardType { |
| const char* leading_mime_type; |
| const char* const* standard_types; |
| size_t standard_types_len; |
| }; |
| static const StandardType kStandardTypes[] = { |
| { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) }, |
| { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) }, |
| { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) }, |
| { NULL, NULL, 0 } |
| }; |
| |
| void GetExtensionsFromHardCodedMappings( |
| const MimeInfo* mappings, |
| size_t mappings_len, |
| const std::string& leading_mime_type, |
| base::hash_set<base::FilePath::StringType>* extensions) { |
| base::FilePath::StringType extension; |
| for (size_t i = 0; i < mappings_len; ++i) { |
| if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) { |
| std::vector<string> this_extensions; |
| base::SplitString(mappings[i].extensions, ',', &this_extensions); |
| for (size_t j = 0; j < this_extensions.size(); ++j) { |
| #if defined(OS_WIN) |
| base::FilePath::StringType extension( |
| base::UTF8ToWide(this_extensions[j])); |
| #else |
| base::FilePath::StringType extension(this_extensions[j]); |
| #endif |
| extensions->insert(extension); |
| } |
| } |
| } |
| } |
| |
| void GetExtensionsHelper( |
| const char* const* standard_types, |
| size_t standard_types_len, |
| const std::string& leading_mime_type, |
| base::hash_set<base::FilePath::StringType>* extensions) { |
| for (size_t i = 0; i < standard_types_len; ++i) { |
| g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i], |
| extensions); |
| } |
| |
| // Also look up the extensions from hard-coded mappings in case that some |
| // supported extensions are not registered in the system registry, like ogg. |
| GetExtensionsFromHardCodedMappings(primary_mappings, |
| arraysize(primary_mappings), |
| leading_mime_type, |
| extensions); |
| |
| GetExtensionsFromHardCodedMappings(secondary_mappings, |
| arraysize(secondary_mappings), |
| leading_mime_type, |
| extensions); |
| } |
| |
| // Note that the elements in the source set will be appended to the target |
| // vector. |
| template<class T> |
| void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) { |
| size_t old_target_size = target->size(); |
| target->resize(old_target_size + source->size()); |
| size_t i = 0; |
| for (typename base::hash_set<T>::iterator iter = source->begin(); |
| iter != source->end(); ++iter, ++i) |
| (*target)[old_target_size + i] = *iter; |
| } |
| } |
| |
| void GetExtensionsForMimeType( |
| const std::string& unsafe_mime_type, |
| std::vector<base::FilePath::StringType>* extensions) { |
| if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*") |
| return; |
| |
| const std::string mime_type = base::StringToLowerASCII(unsafe_mime_type); |
| base::hash_set<base::FilePath::StringType> unique_extensions; |
| |
| if (EndsWith(mime_type, "/*", true)) { |
| std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1); |
| |
| // Find the matching StandardType from within kStandardTypes, or fall |
| // through to the last (default) StandardType. |
| const StandardType* type = NULL; |
| for (size_t i = 0; i < arraysize(kStandardTypes); ++i) { |
| type = &(kStandardTypes[i]); |
| if (type->leading_mime_type && |
| leading_mime_type == type->leading_mime_type) |
| break; |
| } |
| DCHECK(type); |
| GetExtensionsHelper(type->standard_types, |
| type->standard_types_len, |
| leading_mime_type, |
| &unique_extensions); |
| } else { |
| g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type, |
| &unique_extensions); |
| |
| // Also look up the extensions from hard-coded mappings in case that some |
| // supported extensions are not registered in the system registry, like ogg. |
| GetExtensionsFromHardCodedMappings(primary_mappings, |
| arraysize(primary_mappings), |
| mime_type, |
| &unique_extensions); |
| |
| GetExtensionsFromHardCodedMappings(secondary_mappings, |
| arraysize(secondary_mappings), |
| mime_type, |
| &unique_extensions); |
| } |
| |
| HashSetToVector(&unique_extensions, extensions); |
| } |
| |
| void RemoveProprietaryMediaTypesAndCodecsForTests() { |
| g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests(); |
| } |
| |
| const std::string GetIANAMediaType(const std::string& mime_type) { |
| for (size_t i = 0; i < arraysize(kIanaMediaTypes); ++i) { |
| if (StartsWithASCII(mime_type, kIanaMediaTypes[i].matcher, true)) { |
| return kIanaMediaTypes[i].name; |
| } |
| } |
| return std::string(); |
| } |
| |
| CertificateMimeType GetCertificateMimeTypeForMimeType( |
| const std::string& mime_type) { |
| // Don't create a map, there is only one entry in the table, |
| // except on Android. |
| for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) { |
| if (mime_type == net::supported_certificate_types[i].mime_type) |
| return net::supported_certificate_types[i].cert_type; |
| } |
| return CERTIFICATE_MIME_TYPE_UNKNOWN; |
| } |
| |
| bool IsSupportedCertificateMimeType(const std::string& mime_type) { |
| CertificateMimeType file_type = |
| GetCertificateMimeTypeForMimeType(mime_type); |
| return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN; |
| } |
| |
| void AddMultipartValueForUpload(const std::string& value_name, |
| const std::string& value, |
| const std::string& mime_boundary, |
| const std::string& content_type, |
| std::string* post_data) { |
| DCHECK(post_data); |
| // First line is the boundary. |
| post_data->append("--" + mime_boundary + "\r\n"); |
| // Next line is the Content-disposition. |
| post_data->append("Content-Disposition: form-data; name=\"" + |
| value_name + "\"\r\n"); |
| if (!content_type.empty()) { |
| // If Content-type is specified, the next line is that. |
| post_data->append("Content-Type: " + content_type + "\r\n"); |
| } |
| // Leave an empty line and append the value. |
| post_data->append("\r\n" + value + "\r\n"); |
| } |
| |
| void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary, |
| std::string* post_data) { |
| DCHECK(post_data); |
| post_data->append("--" + mime_boundary + "--\r\n"); |
| } |
| |
| } // namespace net |