Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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 <map>
      6 #include <string>
      7 
      8 #include "net/base/mime_util.h"
      9 #include "net/base/platform_mime_util.h"
     10 
     11 #include "base/hash_tables.h"
     12 #include "base/lazy_instance.h"
     13 #include "base/logging.h"
     14 #include "base/string_split.h"
     15 #include "base/string_util.h"
     16 #include "base/utf_string_conversions.h"
     17 
     18 using std::string;
     19 
     20 namespace net {
     21 
     22 // Singleton utility class for mime types.
     23 class MimeUtil : public PlatformMimeUtil {
     24  public:
     25   bool GetMimeTypeFromExtension(const FilePath::StringType& ext,
     26                                 std::string* mime_type) const;
     27 
     28   bool GetMimeTypeFromFile(const FilePath& file_path,
     29                            std::string* mime_type) const;
     30 
     31   bool IsSupportedImageMimeType(const char* mime_type) const;
     32   bool IsSupportedMediaMimeType(const char* mime_type) const;
     33   bool IsSupportedNonImageMimeType(const char* mime_type) const;
     34   bool IsSupportedJavascriptMimeType(const char* mime_type) const;
     35 
     36   bool IsViewSourceMimeType(const char* mime_type) const;
     37 
     38   bool IsSupportedMimeType(const std::string& mime_type) const;
     39 
     40   bool MatchesMimeType(const std::string &mime_type_pattern,
     41                        const std::string &mime_type) const;
     42 
     43   bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
     44 
     45   void ParseCodecString(const std::string& codecs,
     46                         std::vector<std::string>* codecs_out,
     47                         bool strip);
     48 
     49   bool IsStrictMediaMimeType(const std::string& mime_type) const;
     50   bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
     51       const std::vector<std::string>& codecs) const;
     52 
     53  private:
     54   friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
     55   MimeUtil() {
     56     InitializeMimeTypeMaps();
     57   }
     58 
     59   // For faster lookup, keep hash sets.
     60   void InitializeMimeTypeMaps();
     61 
     62   typedef base::hash_set<std::string> MimeMappings;
     63   MimeMappings image_map_;
     64   MimeMappings media_map_;
     65   MimeMappings non_image_map_;
     66   MimeMappings javascript_map_;
     67   MimeMappings view_source_map_;
     68   MimeMappings codecs_map_;
     69 
     70   typedef std::map<std::string, base::hash_set<std::string> > StrictMappings;
     71   StrictMappings strict_format_map_;
     72 };  // class MimeUtil
     73 
     74 static base::LazyInstance<MimeUtil> g_mime_util(base::LINKER_INITIALIZED);
     75 
     76 struct MimeInfo {
     77   const char* mime_type;
     78   const char* extensions;  // comma separated list
     79 };
     80 
     81 static const MimeInfo primary_mappings[] = {
     82   { "text/html", "html,htm" },
     83   { "text/css", "css" },
     84   { "text/xml", "xml" },
     85   { "image/gif", "gif" },
     86   { "image/jpeg", "jpeg,jpg" },
     87   { "image/webp", "webp" },
     88   { "image/png", "png" },
     89   { "video/mp4", "mp4,m4v" },
     90   { "audio/x-m4a", "m4a" },
     91   { "audio/mp3", "mp3" },
     92   { "video/ogg", "ogv,ogm" },
     93   { "audio/ogg", "ogg,oga" },
     94   { "video/webm", "webm" },
     95   { "audio/webm", "webm" },
     96   { "audio/wav", "wav" },
     97   { "application/xhtml+xml", "xhtml,xht" },
     98   { "application/x-chrome-extension", "crx" }
     99 };
    100 
    101 static const MimeInfo secondary_mappings[] = {
    102   { "application/octet-stream", "exe,com,bin" },
    103   { "application/gzip", "gz" },
    104   { "application/pdf", "pdf" },
    105   { "application/postscript", "ps,eps,ai" },
    106   { "application/x-javascript", "js" },
    107   { "image/bmp", "bmp" },
    108   { "image/x-icon", "ico" },
    109   { "image/jpeg", "jfif,pjpeg,pjp" },
    110   { "image/tiff", "tiff,tif" },
    111   { "image/x-xbitmap", "xbm" },
    112   { "image/svg+xml", "svg,svgz" },
    113   { "message/rfc822", "eml" },
    114   { "text/plain", "txt,text" },
    115   { "text/html", "shtml,ehtml" },
    116   { "application/rss+xml", "rss" },
    117   { "application/rdf+xml", "rdf" },
    118   { "text/xml", "xsl,xbl" },
    119   { "application/vnd.mozilla.xul+xml", "xul" },
    120   { "application/x-shockwave-flash", "swf,swl" }
    121 };
    122 
    123 static const char* FindMimeType(const MimeInfo* mappings,
    124                                 size_t mappings_len,
    125                                 const char* ext) {
    126   size_t ext_len = strlen(ext);
    127 
    128   for (size_t i = 0; i < mappings_len; ++i) {
    129     const char* extensions = mappings[i].extensions;
    130     for (;;) {
    131       size_t end_pos = strcspn(extensions, ",");
    132       if (end_pos == ext_len &&
    133           base::strncasecmp(extensions, ext, ext_len) == 0)
    134         return mappings[i].mime_type;
    135       extensions += end_pos;
    136       if (!*extensions)
    137         break;
    138       extensions += 1;  // skip over comma
    139     }
    140   }
    141   return NULL;
    142 }
    143 
    144 bool MimeUtil::GetMimeTypeFromExtension(const FilePath::StringType& ext,
    145                                         string* result) const {
    146   // Avoids crash when unable to handle a long file path. See crbug.com/48733.
    147   const unsigned kMaxFilePathSize = 65536;
    148   if (ext.length() > kMaxFilePathSize)
    149     return false;
    150 
    151   // We implement the same algorithm as Mozilla for mapping a file extension to
    152   // a mime type.  That is, we first check a hard-coded list (that cannot be
    153   // overridden), and then if not found there, we defer to the system registry.
    154   // Finally, we scan a secondary hard-coded list to catch types that we can
    155   // deduce but that we also want to allow the OS to override.
    156 
    157 #if defined(OS_WIN)
    158   string ext_narrow_str = WideToUTF8(ext);
    159 #elif defined(OS_POSIX)
    160   const string& ext_narrow_str = ext;
    161 #endif
    162   const char* mime_type;
    163 
    164   mime_type = FindMimeType(primary_mappings, arraysize(primary_mappings),
    165                            ext_narrow_str.c_str());
    166   if (mime_type) {
    167     *result = mime_type;
    168     return true;
    169   }
    170 
    171   if (GetPlatformMimeTypeFromExtension(ext, result))
    172     return true;
    173 
    174   mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
    175                            ext_narrow_str.c_str());
    176   if (mime_type) {
    177     *result = mime_type;
    178     return true;
    179   }
    180 
    181   return false;
    182 }
    183 
    184 bool MimeUtil::GetMimeTypeFromFile(const FilePath& file_path,
    185                                    string* result) const {
    186   FilePath::StringType file_name_str = file_path.Extension();
    187   if (file_name_str.empty())
    188     return false;
    189   return GetMimeTypeFromExtension(file_name_str.substr(1), result);
    190 }
    191 
    192 // From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
    193 
    194 static const char* const supported_image_types[] = {
    195   "image/jpeg",
    196   "image/pjpeg",
    197   "image/jpg",
    198   "image/webp",
    199   "image/png",
    200   "image/gif",
    201   "image/bmp",
    202   "image/x-icon",    // ico
    203   "image/x-xbitmap"  // xbm
    204 };
    205 
    206 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
    207 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
    208 static const char* const supported_media_types[] = {
    209   // Ogg.
    210   "video/ogg",
    211   "audio/ogg",
    212   "application/ogg",
    213   "video/webm",
    214   "audio/webm",
    215   "audio/wav",
    216   "audio/x-wav",
    217 
    218 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
    219   // MPEG-4.
    220   "video/mp4",
    221   "video/x-m4v",
    222   "audio/mp4",
    223   "audio/x-m4a",
    224 
    225   // MP3.
    226   "audio/mp3",
    227   "audio/x-mp3",
    228   "audio/mpeg",
    229 #endif
    230 };
    231 
    232 // List of supported codecs when passed in with <source type="...">.
    233 //
    234 // Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support
    235 // for more information.
    236 static const char* const supported_media_codecs[] = {
    237 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
    238   "avc1",
    239   "mp4a",
    240 #endif
    241   "theora",
    242   "vorbis",
    243   "vp8",
    244   "1"  // PCM for WAV.
    245 };
    246 
    247 // Note: does not include javascript types list (see supported_javascript_types)
    248 static const char* const supported_non_image_types[] = {
    249   "text/cache-manifest",
    250   "text/html",
    251   "text/xml",
    252   "text/xsl",
    253   "text/plain",
    254   // Many users complained about css files served for
    255   // download instead of displaying in the browser:
    256   // http://code.google.com/p/chromium/issues/detail?id=7192
    257   // So, by including "text/css" into this list we choose Firefox
    258   // behavior - css files will be displayed:
    259   "text/css",
    260   "text/vnd.chromium.ftp-dir",
    261   "text/",
    262   "image/svg+xml",  // SVG is text-based XML, even though it has an image/ type
    263   "application/xml",
    264   "application/xhtml+xml",
    265   "application/rss+xml",
    266   "application/atom+xml",
    267   "application/json",
    268   "application/x-x509-user-cert",
    269   "multipart/x-mixed-replace"
    270   // Note: ADDING a new type here will probably render it AS HTML. This can
    271   // result in cross site scripting.
    272 };
    273 COMPILE_ASSERT(arraysize(supported_non_image_types) == 16,
    274                supported_non_images_types_must_equal_16);
    275 
    276 //  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
    277 //  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
    278 // application/x-javascript, but WinIE 7 doesn't.
    279 //  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
    280 // text/livescript, but Mozilla 1.8 doesn't.
    281 //  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
    282 //  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
    283 // whitespace-only string.
    284 //  We want to accept all the values that either of these browsers accept, but
    285 // not other values.
    286 static const char* const supported_javascript_types[] = {
    287   "text/javascript",
    288   "text/ecmascript",
    289   "application/javascript",
    290   "application/ecmascript",
    291   "application/x-javascript",
    292   "text/javascript1.1",
    293   "text/javascript1.2",
    294   "text/javascript1.3",
    295   "text/jscript",
    296   "text/livescript"
    297 };
    298 
    299 static const char* const view_source_types[] = {
    300   "text/xml",
    301   "text/xsl",
    302   "application/xml",
    303   "application/rss+xml",
    304   "application/atom+xml",
    305   "image/svg+xml"
    306 };
    307 
    308 struct MediaFormatStrict {
    309   const char* mime_type;
    310   const char* codecs_list;
    311 };
    312 
    313 static const MediaFormatStrict format_codec_mappings[] = {
    314   { "video/webm", "vorbis,vp8,vp8.0" },
    315   { "audio/webm", "vorbis" },
    316   { "audio/wav", "1" }
    317 };
    318 
    319 void MimeUtil::InitializeMimeTypeMaps() {
    320   for (size_t i = 0; i < arraysize(supported_image_types); ++i)
    321     image_map_.insert(supported_image_types[i]);
    322 
    323   // Initialize the supported non-image types.
    324   for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
    325     non_image_map_.insert(supported_non_image_types[i]);
    326   for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
    327     non_image_map_.insert(supported_javascript_types[i]);
    328   for (size_t i = 0; i < arraysize(supported_media_types); ++i)
    329     non_image_map_.insert(supported_media_types[i]);
    330 
    331   // Initialize the supported media types.
    332   for (size_t i = 0; i < arraysize(supported_media_types); ++i)
    333     media_map_.insert(supported_media_types[i]);
    334 
    335   for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
    336     javascript_map_.insert(supported_javascript_types[i]);
    337 
    338   for (size_t i = 0; i < arraysize(view_source_types); ++i)
    339     view_source_map_.insert(view_source_types[i]);
    340 
    341   for (size_t i = 0; i < arraysize(supported_media_codecs); ++i)
    342     codecs_map_.insert(supported_media_codecs[i]);
    343 
    344   // Initialize the strict supported media types.
    345   for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
    346     std::vector<std::string> mime_type_codecs;
    347     ParseCodecString(format_codec_mappings[i].codecs_list,
    348                      &mime_type_codecs,
    349                      false);
    350 
    351     MimeMappings codecs;
    352     for (size_t j = 0; j < mime_type_codecs.size(); ++j)
    353       codecs.insert(mime_type_codecs[j]);
    354     strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
    355   }
    356 }
    357 
    358 bool MimeUtil::IsSupportedImageMimeType(const char* mime_type) const {
    359   return image_map_.find(mime_type) != image_map_.end();
    360 }
    361 
    362 bool MimeUtil::IsSupportedMediaMimeType(const char* mime_type) const {
    363   return media_map_.find(mime_type) != media_map_.end();
    364 }
    365 
    366 bool MimeUtil::IsSupportedNonImageMimeType(const char* mime_type) const {
    367   return non_image_map_.find(mime_type) != non_image_map_.end();
    368 }
    369 
    370 bool MimeUtil::IsSupportedJavascriptMimeType(const char* mime_type) const {
    371   return javascript_map_.find(mime_type) != javascript_map_.end();
    372 }
    373 
    374 bool MimeUtil::IsViewSourceMimeType(const char* mime_type) const {
    375   return view_source_map_.find(mime_type) != view_source_map_.end();
    376 }
    377 
    378 // Mirrors WebViewImpl::CanShowMIMEType()
    379 bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
    380   return (mime_type.compare(0, 6, "image/") == 0 &&
    381           IsSupportedImageMimeType(mime_type.c_str())) ||
    382          IsSupportedNonImageMimeType(mime_type.c_str());
    383 }
    384 
    385 bool MimeUtil::MatchesMimeType(const std::string &mime_type_pattern,
    386                                const std::string &mime_type) const {
    387   // verify caller is passing lowercase
    388   DCHECK_EQ(StringToLowerASCII(mime_type_pattern), mime_type_pattern);
    389   DCHECK_EQ(StringToLowerASCII(mime_type), mime_type);
    390 
    391   // This comparison handles absolute maching and also basic
    392   // wildcards.  The plugin mime types could be:
    393   //      application/x-foo
    394   //      application/*
    395   //      application/*+xml
    396   //      *
    397   if (mime_type_pattern.empty())
    398     return false;
    399 
    400   const std::string::size_type star = mime_type_pattern.find('*');
    401 
    402   if (star == std::string::npos)
    403     return mime_type_pattern == mime_type;
    404 
    405   // Test length to prevent overlap between |left| and |right|.
    406   if (mime_type.length() < mime_type_pattern.length() - 1)
    407     return false;
    408 
    409   const std::string left(mime_type_pattern.substr(0, star));
    410   const std::string right(mime_type_pattern.substr(star + 1));
    411 
    412   if (mime_type.find(left) != 0)
    413     return false;
    414 
    415   if (!right.empty() &&
    416       mime_type.rfind(right) != mime_type.length() - right.length())
    417     return false;
    418 
    419   return true;
    420 }
    421 
    422 bool MimeUtil::AreSupportedMediaCodecs(
    423     const std::vector<std::string>& codecs) const {
    424   for (size_t i = 0; i < codecs.size(); ++i) {
    425     if (codecs_map_.find(codecs[i]) == codecs_map_.end()) {
    426       return false;
    427     }
    428   }
    429   return true;
    430 }
    431 
    432 void MimeUtil::ParseCodecString(const std::string& codecs,
    433                                 std::vector<std::string>* codecs_out,
    434                                 bool strip) {
    435   std::string no_quote_codecs;
    436   TrimString(codecs, "\"", &no_quote_codecs);
    437   base::SplitString(no_quote_codecs, ',', codecs_out);
    438 
    439   if (!strip)
    440     return;
    441 
    442   // Strip everything past the first '.'
    443   for (std::vector<std::string>::iterator it = codecs_out->begin();
    444        it != codecs_out->end();
    445        ++it) {
    446     size_t found = it->find_first_of('.');
    447     if (found != std::string::npos)
    448       it->resize(found);
    449   }
    450 }
    451 
    452 bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
    453   if (strict_format_map_.find(mime_type) == strict_format_map_.end())
    454     return false;
    455   return true;
    456 }
    457 
    458 bool MimeUtil::IsSupportedStrictMediaMimeType(const std::string& mime_type,
    459     const std::vector<std::string>& codecs) const {
    460   StrictMappings::const_iterator it = strict_format_map_.find(mime_type);
    461 
    462   if (it == strict_format_map_.end())
    463     return false;
    464 
    465   const MimeMappings strict_codecs_map = it->second;
    466   for (size_t i = 0; i < codecs.size(); ++i) {
    467     if (strict_codecs_map.find(codecs[i]) == strict_codecs_map.end()) {
    468       return false;
    469     }
    470   }
    471   return true;
    472 }
    473 
    474 //----------------------------------------------------------------------------
    475 // Wrappers for the singleton
    476 //----------------------------------------------------------------------------
    477 
    478 bool GetMimeTypeFromExtension(const FilePath::StringType& ext,
    479                               std::string* mime_type) {
    480   return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
    481 }
    482 
    483 bool GetMimeTypeFromFile(const FilePath& file_path, std::string* mime_type) {
    484   return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
    485 }
    486 
    487 bool GetPreferredExtensionForMimeType(const std::string& mime_type,
    488                                       FilePath::StringType* extension) {
    489   return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
    490                                                             extension);
    491 }
    492 
    493 bool IsSupportedImageMimeType(const char* mime_type) {
    494   return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
    495 }
    496 
    497 bool IsSupportedMediaMimeType(const char* mime_type) {
    498   return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
    499 }
    500 
    501 bool IsSupportedNonImageMimeType(const char* mime_type) {
    502   return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
    503 }
    504 
    505 bool IsSupportedJavascriptMimeType(const char* mime_type) {
    506   return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
    507 }
    508 
    509 bool IsViewSourceMimeType(const char* mime_type) {
    510   return g_mime_util.Get().IsViewSourceMimeType(mime_type);
    511 }
    512 
    513 bool IsSupportedMimeType(const std::string& mime_type) {
    514   return g_mime_util.Get().IsSupportedMimeType(mime_type);
    515 }
    516 
    517 bool MatchesMimeType(const std::string &mime_type_pattern,
    518                      const std::string &mime_type) {
    519   return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
    520 }
    521 
    522 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
    523   return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
    524 }
    525 
    526 bool IsStrictMediaMimeType(const std::string& mime_type) {
    527   return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
    528 }
    529 
    530 bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
    531                                     const std::vector<std::string>& codecs) {
    532   return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
    533 }
    534 
    535 void ParseCodecString(const std::string& codecs,
    536                       std::vector<std::string>* codecs_out,
    537                       const bool strip) {
    538   g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
    539 }
    540 
    541 namespace {
    542 
    543 // From http://www.w3schools.com/media/media_mimeref.asp and
    544 // http://plugindoc.mozdev.org/winmime.php
    545 static const char* kStandardImageTypes[] = {
    546   "image/bmp",
    547   "image/cis-cod",
    548   "image/gif",
    549   "image/ief",
    550   "image/jpeg",
    551   "image/webp",
    552   "image/pict",
    553   "image/pipeg",
    554   "image/png",
    555   "image/svg+xml",
    556   "image/tiff",
    557   "image/x-cmu-raster",
    558   "image/x-cmx",
    559   "image/x-icon",
    560   "image/x-portable-anymap",
    561   "image/x-portable-bitmap",
    562   "image/x-portable-graymap",
    563   "image/x-portable-pixmap",
    564   "image/x-rgb",
    565   "image/x-xbitmap",
    566   "image/x-xpixmap",
    567   "image/x-xwindowdump"
    568 };
    569 static const char* kStandardAudioTypes[] = {
    570   "audio/aac",
    571   "audio/aiff",
    572   "audio/amr",
    573   "audio/basic",
    574   "audio/midi",
    575   "audio/mp3",
    576   "audio/mp4",
    577   "audio/mpeg",
    578   "audio/mpeg3",
    579   "audio/ogg",
    580   "audio/vorbis",
    581   "audio/wav",
    582   "audio/webm",
    583   "audio/x-m4a",
    584   "audio/x-ms-wma",
    585   "audio/vnd.rn-realaudio",
    586   "audio/vnd.wave"
    587 };
    588 static const char* kStandardVideoTypes[] = {
    589   "video/avi",
    590   "video/divx",
    591   "video/flc",
    592   "video/mp4",
    593   "video/mpeg",
    594   "video/ogg",
    595   "video/quicktime",
    596   "video/sd-video",
    597   "video/webm",
    598   "video/x-dv",
    599   "video/x-m4v",
    600   "video/x-mpeg",
    601   "video/x-ms-asf",
    602   "video/x-ms-wmv"
    603 };
    604 
    605 void GetExtensionsFromHardCodedMappings(
    606     const MimeInfo* mappings,
    607     size_t mappings_len,
    608     const std::string& leading_mime_type,
    609     base::hash_set<FilePath::StringType>* extensions) {
    610   FilePath::StringType extension;
    611   for (size_t i = 0; i < mappings_len; ++i) {
    612     if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
    613       std::vector<string> this_extensions;
    614       base::SplitStringUsingSubstr(mappings[i].extensions,
    615                                    ",",
    616                                    &this_extensions);
    617       for (size_t j = 0; j < this_extensions.size(); ++j) {
    618 #if defined(OS_WIN)
    619         FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
    620 #else
    621         FilePath::StringType extension(this_extensions[j]);
    622 #endif
    623         extensions->insert(extension);
    624       }
    625     }
    626   }
    627 }
    628 
    629 void GetExtensionsHelper(
    630     const char** standard_types,
    631     size_t standard_types_len,
    632     const std::string& leading_mime_type,
    633     base::hash_set<FilePath::StringType>* extensions) {
    634   FilePath::StringType extension;
    635   for (size_t i = 0; i < standard_types_len; ++i) {
    636     if (GetPreferredExtensionForMimeType(standard_types[i], &extension))
    637       extensions->insert(extension);
    638   }
    639 
    640   // Also look up the extensions from hard-coded mappings in case that some
    641   // supported extensions are not registered in the system registry, like ogg.
    642   GetExtensionsFromHardCodedMappings(primary_mappings,
    643                                      arraysize(primary_mappings),
    644                                      leading_mime_type,
    645                                      extensions);
    646 
    647   GetExtensionsFromHardCodedMappings(secondary_mappings,
    648                                      arraysize(secondary_mappings),
    649                                      leading_mime_type,
    650                                      extensions);
    651 }
    652 
    653 // Note that the elements in the source set will be appended to the target
    654 // vector.
    655 template<class T>
    656 void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
    657   size_t old_target_size = target->size();
    658   target->resize(old_target_size + source->size());
    659   size_t i = 0;
    660   for (typename base::hash_set<T>::iterator iter = source->begin();
    661        iter != source->end(); ++iter, ++i) {
    662     target->at(old_target_size + i) = *iter;
    663   }
    664 }
    665 }
    666 
    667 void GetImageExtensions(std::vector<FilePath::StringType>* extensions) {
    668   base::hash_set<FilePath::StringType> unique_extensions;
    669   GetExtensionsHelper(kStandardImageTypes,
    670                       arraysize(kStandardImageTypes),
    671                       "image/",
    672                       &unique_extensions);
    673   HashSetToVector(&unique_extensions, extensions);
    674 }
    675 
    676 void GetAudioExtensions(std::vector<FilePath::StringType>* extensions) {
    677   base::hash_set<FilePath::StringType> unique_extensions;
    678   GetExtensionsHelper(kStandardAudioTypes,
    679                       arraysize(kStandardAudioTypes),
    680                       "audio/",
    681                       &unique_extensions);
    682   HashSetToVector(&unique_extensions, extensions);
    683 }
    684 
    685 void GetVideoExtensions(std::vector<FilePath::StringType>* extensions) {
    686   base::hash_set<FilePath::StringType> unique_extensions;
    687   GetExtensionsHelper(kStandardVideoTypes,
    688                       arraysize(kStandardVideoTypes),
    689                       "video/",
    690                       &unique_extensions);
    691   HashSetToVector(&unique_extensions, extensions);
    692 }
    693 
    694 void GetExtensionsForMimeType(const std::string& mime_type,
    695                               std::vector<FilePath::StringType>* extensions) {
    696   base::hash_set<FilePath::StringType> unique_extensions;
    697   FilePath::StringType extension;
    698   if (GetPreferredExtensionForMimeType(mime_type, &extension))
    699     unique_extensions.insert(extension);
    700 
    701   // Also look up the extensions from hard-coded mappings in case that some
    702   // supported extensions are not registered in the system registry, like ogg.
    703   GetExtensionsFromHardCodedMappings(primary_mappings,
    704                                      arraysize(primary_mappings),
    705                                      mime_type,
    706                                      &unique_extensions);
    707 
    708   GetExtensionsFromHardCodedMappings(secondary_mappings,
    709                                      arraysize(secondary_mappings),
    710                                      mime_type,
    711                                      &unique_extensions);
    712 
    713   HashSetToVector(&unique_extensions, extensions);
    714 }
    715 
    716 }  // namespace net
    717