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