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