mime_util.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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_util.h"
17#include "base/strings/string_split.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 base::FilePath::StringType& ext,
49                                std::string* mime_type) const;
50
51  bool GetMimeTypeFromFile(const base::FilePath& file_path,
52                           std::string* mime_type) const;
53
54  bool GetWellKnownMimeTypeFromExtension(const base::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 IsSupportedMimeType(const std::string& mime_type) const;
64
65  bool MatchesMimeType(const std::string &mime_type_pattern,
66                       const std::string &mime_type) const;
67
68  bool IsMimeType(const std::string& type_string) const;
69
70  bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
71
72  void ParseCodecString(const std::string& codecs,
73                        std::vector<std::string>* codecs_out,
74                        bool strip);
75
76  bool IsStrictMediaMimeType(const std::string& mime_type) const;
77  bool IsSupportedStrictMediaMimeType(
78      const std::string& mime_type,
79      const std::vector<std::string>& codecs) const;
80
81 private:
82  friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
83
84  typedef base::hash_set<std::string> MimeMappings;
85  typedef std::map<std::string, MimeMappings> StrictMappings;
86
87  MimeUtil();
88
89  // Returns true if |codecs| is nonempty and all the items in it are present in
90  // |supported_codecs|.
91  static bool AreSupportedCodecs(const MimeMappings& supported_codecs,
92                                 const std::vector<std::string>& codecs);
93
94  // For faster lookup, keep hash sets.
95  void InitializeMimeTypeMaps();
96
97  bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext,
98                                      bool include_platform_types,
99                                      std::string* mime_type) const;
100
101  MimeMappings image_map_;
102  MimeMappings media_map_;
103  MimeMappings non_image_map_;
104  MimeMappings unsupported_text_map_;
105  MimeMappings javascript_map_;
106  MimeMappings codecs_map_;
107
108  StrictMappings strict_format_map_;
109};  // class MimeUtil
110
111// This variable is Leaky because we need to access it from WorkerPool threads.
112static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
113    LAZY_INSTANCE_INITIALIZER;
114
115struct MimeInfo {
116  const char* mime_type;
117  const char* extensions;  // comma separated list
118};
119
120static const MimeInfo primary_mappings[] = {
121  { "text/html", "html,htm" },
122  { "text/css", "css" },
123  { "text/xml", "xml" },
124  { "image/gif", "gif" },
125  { "image/jpeg", "jpeg,jpg" },
126  { "image/webp", "webp" },
127  { "image/png", "png" },
128  { "video/mp4", "mp4,m4v" },
129  { "audio/x-m4a", "m4a" },
130  { "audio/mp3", "mp3" },
131  { "video/ogg", "ogv,ogm" },
132  { "audio/ogg", "ogg,oga,opus" },
133  { "video/webm", "webm" },
134  { "audio/webm", "webm" },
135  { "audio/wav", "wav" },
136  { "application/xhtml+xml", "xhtml,xht" },
137  { "application/x-chrome-extension", "crx" },
138  { "multipart/related", "mhtml,mht" }
139};
140
141static const MimeInfo secondary_mappings[] = {
142  { "application/octet-stream", "exe,com,bin" },
143  { "application/gzip", "gz" },
144  { "application/pdf", "pdf" },
145  { "application/postscript", "ps,eps,ai" },
146  { "application/javascript", "js" },
147  { "application/font-woff", "woff" },
148  { "image/bmp", "bmp" },
149  { "image/x-icon", "ico" },
150  { "image/vnd.microsoft.icon", "ico" },
151  { "image/jpeg", "jfif,pjpeg,pjp" },
152  { "image/tiff", "tiff,tif" },
153  { "image/x-xbitmap", "xbm" },
154  { "image/svg+xml", "svg,svgz" },
155  { "message/rfc822", "eml" },
156  { "text/plain", "txt,text" },
157  { "text/html", "shtml,ehtml" },
158  { "application/rss+xml", "rss" },
159  { "application/rdf+xml", "rdf" },
160  { "text/xml", "xsl,xbl" },
161  { "application/vnd.mozilla.xul+xml", "xul" },
162  { "application/x-shockwave-flash", "swf,swl" },
163  { "application/pkcs7-mime", "p7m,p7c,p7z" },
164  { "application/pkcs7-signature", "p7s" }
165};
166
167static const char* FindMimeType(const MimeInfo* mappings,
168                                size_t mappings_len,
169                                const char* ext) {
170  size_t ext_len = strlen(ext);
171
172  for (size_t i = 0; i < mappings_len; ++i) {
173    const char* extensions = mappings[i].extensions;
174    for (;;) {
175      size_t end_pos = strcspn(extensions, ",");
176      if (end_pos == ext_len &&
177          base::strncasecmp(extensions, ext, ext_len) == 0)
178        return mappings[i].mime_type;
179      extensions += end_pos;
180      if (!*extensions)
181        break;
182      extensions += 1;  // skip over comma
183    }
184  }
185  return NULL;
186}
187
188bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
189                                        string* result) const {
190  return GetMimeTypeFromExtensionHelper(ext, true, result);
191}
192
193bool MimeUtil::GetWellKnownMimeTypeFromExtension(
194    const base::FilePath::StringType& ext,
195    string* result) const {
196  return GetMimeTypeFromExtensionHelper(ext, false, result);
197}
198
199bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path,
200                                   string* result) const {
201  base::FilePath::StringType file_name_str = file_path.Extension();
202  if (file_name_str.empty())
203    return false;
204  return GetMimeTypeFromExtension(file_name_str.substr(1), result);
205}
206
207bool MimeUtil::GetMimeTypeFromExtensionHelper(
208    const base::FilePath::StringType& ext,
209    bool include_platform_types,
210    string* result) const {
211  // Avoids crash when unable to handle a long file path. See crbug.com/48733.
212  const unsigned kMaxFilePathSize = 65536;
213  if (ext.length() > kMaxFilePathSize)
214    return false;
215
216  // We implement the same algorithm as Mozilla for mapping a file extension to
217  // a mime type.  That is, we first check a hard-coded list (that cannot be
218  // overridden), and then if not found there, we defer to the system registry.
219  // Finally, we scan a secondary hard-coded list to catch types that we can
220  // deduce but that we also want to allow the OS to override.
221
222#if defined(OS_WIN)
223  string ext_narrow_str = WideToUTF8(ext);
224#elif defined(OS_POSIX)
225  const string& ext_narrow_str = ext;
226#endif
227  const char* mime_type;
228
229  mime_type = FindMimeType(primary_mappings, arraysize(primary_mappings),
230                           ext_narrow_str.c_str());
231  if (mime_type) {
232    *result = mime_type;
233    return true;
234  }
235
236  if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result))
237    return true;
238
239  mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
240                           ext_narrow_str.c_str());
241  if (mime_type) {
242    *result = mime_type;
243    return true;
244  }
245
246  return false;
247}
248
249// From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
250
251static const char* const supported_image_types[] = {
252  "image/jpeg",
253  "image/pjpeg",
254  "image/jpg",
255  "image/webp",
256  "image/png",
257  "image/gif",
258  "image/bmp",
259  "image/vnd.microsoft.icon",    // ico
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  "multipart/related",  // For MHTML support.
343  "multipart/x-mixed-replace"
344  // Note: ADDING a new type here will probably render it AS HTML. This can
345  // result in cross site scripting.
346};
347
348// Dictionary of cryptographic file mime types.
349struct CertificateMimeTypeInfo {
350  const char* mime_type;
351  CertificateMimeType cert_type;
352};
353
354static const CertificateMimeTypeInfo supported_certificate_types[] = {
355  { "application/x-x509-user-cert",
356      CERTIFICATE_MIME_TYPE_X509_USER_CERT },
357#if defined(OS_ANDROID)
358  { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT },
359  { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE },
360#endif
361};
362
363// These types are excluded from the logic that allows all text/ types because
364// while they are technically text, it's very unlikely that a user expects to
365// see them rendered in text form.
366static const char* const unsupported_text_types[] = {
367  "text/calendar",
368  "text/x-calendar",
369  "text/x-vcalendar",
370  "text/vcalendar",
371  "text/vcard",
372  "text/x-vcard",
373  "text/directory",
374  "text/ldif",
375  "text/qif",
376  "text/x-qif",
377  "text/x-csv",
378  "text/x-vcf",
379  "text/rtf",
380  "text/comma-separated-values",
381  "text/csv",
382  "text/tab-separated-values",
383  "text/tsv",
384  "text/ofx",                           // http://crbug.com/162238
385  "text/vnd.sun.j2me.app-descriptor"    // http://crbug.com/176450
386};
387
388//  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
389//  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
390// application/x-javascript, but WinIE 7 doesn't.
391//  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
392// text/livescript, but Mozilla 1.8 doesn't.
393//  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
394//  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
395// whitespace-only string.
396//  We want to accept all the values that either of these browsers accept, but
397// not other values.
398static const char* const supported_javascript_types[] = {
399  "text/javascript",
400  "text/ecmascript",
401  "application/javascript",
402  "application/ecmascript",
403  "application/x-javascript",
404  "text/javascript1.1",
405  "text/javascript1.2",
406  "text/javascript1.3",
407  "text/jscript",
408  "text/livescript"
409};
410
411struct MediaFormatStrict {
412  const char* mime_type;
413  const char* codecs_list;
414};
415
416static const MediaFormatStrict format_codec_mappings[] = {
417  { "video/webm", "vorbis,vp8,vp8.0" },
418  { "audio/webm", "vorbis" },
419  { "audio/wav", "1" }
420};
421
422MimeUtil::MimeUtil() {
423  InitializeMimeTypeMaps();
424}
425
426// static
427bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs,
428                                  const std::vector<std::string>& codecs) {
429  for (size_t i = 0; i < codecs.size(); ++i) {
430    if (supported_codecs.find(codecs[i]) == supported_codecs.end())
431      return false;
432  }
433  return !codecs.empty();
434}
435
436void MimeUtil::InitializeMimeTypeMaps() {
437  for (size_t i = 0; i < arraysize(supported_image_types); ++i)
438    image_map_.insert(supported_image_types[i]);
439
440  // Initialize the supported non-image types.
441  for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
442    non_image_map_.insert(supported_non_image_types[i]);
443  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i)
444    non_image_map_.insert(supported_certificate_types[i].mime_type);
445  for (size_t i = 0; i < arraysize(unsupported_text_types); ++i)
446    unsupported_text_map_.insert(unsupported_text_types[i]);
447  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
448    non_image_map_.insert(supported_javascript_types[i]);
449  for (size_t i = 0; i < arraysize(common_media_types); ++i)
450    non_image_map_.insert(common_media_types[i]);
451#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
452  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
453    non_image_map_.insert(proprietary_media_types[i]);
454#endif
455
456  // Initialize the supported media types.
457  for (size_t i = 0; i < arraysize(common_media_types); ++i)
458    media_map_.insert(common_media_types[i]);
459#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
460  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
461    media_map_.insert(proprietary_media_types[i]);
462#endif
463
464  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
465    javascript_map_.insert(supported_javascript_types[i]);
466
467  for (size_t i = 0; i < arraysize(common_media_codecs); ++i)
468    codecs_map_.insert(common_media_codecs[i]);
469#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
470  for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
471    codecs_map_.insert(proprietary_media_codecs[i]);
472#endif
473
474  // Initialize the strict supported media types.
475  for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
476    std::vector<std::string> mime_type_codecs;
477    ParseCodecString(format_codec_mappings[i].codecs_list,
478                     &mime_type_codecs,
479                     false);
480
481    MimeMappings codecs;
482    for (size_t j = 0; j < mime_type_codecs.size(); ++j)
483      codecs.insert(mime_type_codecs[j]);
484    strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
485  }
486}
487
488bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
489  return image_map_.find(mime_type) != image_map_.end();
490}
491
492bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
493  return media_map_.find(mime_type) != media_map_.end();
494}
495
496bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
497  return non_image_map_.find(mime_type) != non_image_map_.end() ||
498      (mime_type.compare(0, 5, "text/") == 0 &&
499       !IsUnsupportedTextMimeType(mime_type));
500}
501
502bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
503  return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end();
504}
505
506bool MimeUtil::IsSupportedJavascriptMimeType(
507    const std::string& mime_type) const {
508  return javascript_map_.find(mime_type) != javascript_map_.end();
509}
510
511// Mirrors WebViewImpl::CanShowMIMEType()
512bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
513  return (mime_type.compare(0, 6, "image/") == 0 &&
514          IsSupportedImageMimeType(mime_type)) ||
515         IsSupportedNonImageMimeType(mime_type);
516}
517
518// Tests for MIME parameter equality. Each parameter in the |mime_type_pattern|
519// must be matched by a parameter in the |mime_type|. If there are no
520// parameters in the pattern, the match is a success.
521bool MatchesMimeTypeParameters(const std::string& mime_type_pattern,
522                               const std::string& mime_type) {
523  const std::string::size_type semicolon = mime_type_pattern.find(';');
524  const std::string::size_type test_semicolon = mime_type.find(';');
525  if (semicolon != std::string::npos) {
526    if (test_semicolon == std::string::npos)
527      return false;
528
529    std::vector<std::string> pattern_parameters;
530    base::SplitString(mime_type_pattern.substr(semicolon + 1),
531                      ';', &pattern_parameters);
532
533    std::vector<std::string> test_parameters;
534    base::SplitString(mime_type.substr(test_semicolon + 1),
535                      ';', &test_parameters);
536
537    sort(pattern_parameters.begin(), pattern_parameters.end());
538    sort(test_parameters.begin(), test_parameters.end());
539    std::vector<std::string> difference;
540    std::set_difference(pattern_parameters.begin(), pattern_parameters.end(),
541                        test_parameters.begin(), test_parameters.end(),
542                        std::inserter(difference, difference.begin()));
543
544    return difference.size() == 0;
545  }
546  return true;
547}
548
549// This comparison handles absolute maching and also basic
550// wildcards.  The plugin mime types could be:
551//      application/x-foo
552//      application/*
553//      application/*+xml
554//      *
555// Also tests mime parameters -- all parameters in the pattern must be present
556// in the tested type for a match to succeed.
557bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern,
558                               const std::string& mime_type) const {
559  // Verify caller is passing lowercase strings.
560  DCHECK_EQ(StringToLowerASCII(mime_type_pattern), mime_type_pattern);
561  DCHECK_EQ(StringToLowerASCII(mime_type), mime_type);
562
563  if (mime_type_pattern.empty())
564    return false;
565
566  std::string::size_type semicolon = mime_type_pattern.find(';');
567  const std::string base_pattern(mime_type_pattern.substr(0, semicolon));
568  semicolon = mime_type.find(';');
569  const std::string base_type(mime_type.substr(0, semicolon));
570
571  if (base_pattern == "*" || base_pattern == "*/*")
572    return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
573
574  const std::string::size_type star = base_pattern.find('*');
575  if (star == std::string::npos) {
576    if (base_pattern == base_type)
577      return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
578    else
579      return false;
580  }
581
582  // Test length to prevent overlap between |left| and |right|.
583  if (base_type.length() < base_pattern.length() - 1)
584    return false;
585
586  const std::string left(base_pattern.substr(0, star));
587  const std::string right(base_pattern.substr(star + 1));
588
589  if (base_type.find(left) != 0)
590    return false;
591
592  if (!right.empty() &&
593      base_type.rfind(right) != base_type.length() - right.length())
594    return false;
595
596  return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
597}
598
599// See http://www.iana.org/assignments/media-types/index.html
600static const char* legal_top_level_types[] = {
601  "application/",
602  "audio/",
603  "example/",
604  "image/",
605  "message/",
606  "model/",
607  "multipart/",
608  "text/",
609  "video/",
610};
611
612bool MimeUtil::IsMimeType(const std::string& type_string) const {
613  // MIME types are always ASCII and case-insensitive (at least, the top-level
614  // and secondary types we care about).
615  if (!IsStringASCII(type_string))
616    return false;
617
618  if (type_string == "*/*" || type_string == "*")
619    return true;
620
621  for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) {
622    if (StartsWithASCII(type_string, legal_top_level_types[i], false) &&
623        type_string.length() > strlen(legal_top_level_types[i])) {
624      return true;
625    }
626  }
627
628  // If there's a "/" separator character, and the token before it is
629  // "x-" + (ascii characters), it is also a MIME type.
630  size_t slash = type_string.find('/');
631  if (slash < 3 ||
632      slash == std::string::npos || slash == type_string.length() - 1) {
633    return false;
634  }
635
636  if (StartsWithASCII(type_string, "x-", false))
637    return true;
638
639  return false;
640}
641
642bool MimeUtil::AreSupportedMediaCodecs(
643    const std::vector<std::string>& codecs) const {
644  return AreSupportedCodecs(codecs_map_, codecs);
645}
646
647void MimeUtil::ParseCodecString(const std::string& codecs,
648                                std::vector<std::string>* codecs_out,
649                                bool strip) {
650  std::string no_quote_codecs;
651  TrimString(codecs, "\"", &no_quote_codecs);
652  base::SplitString(no_quote_codecs, ',', codecs_out);
653
654  if (!strip)
655    return;
656
657  // Strip everything past the first '.'
658  for (std::vector<std::string>::iterator it = codecs_out->begin();
659       it != codecs_out->end();
660       ++it) {
661    size_t found = it->find_first_of('.');
662    if (found != std::string::npos)
663      it->resize(found);
664  }
665}
666
667bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
668  if (strict_format_map_.find(mime_type) == strict_format_map_.end())
669    return false;
670  return true;
671}
672
673bool MimeUtil::IsSupportedStrictMediaMimeType(
674    const std::string& mime_type,
675    const std::vector<std::string>& codecs) const {
676  StrictMappings::const_iterator it = strict_format_map_.find(mime_type);
677  return (it != strict_format_map_.end()) &&
678      AreSupportedCodecs(it->second, codecs);
679}
680
681//----------------------------------------------------------------------------
682// Wrappers for the singleton
683//----------------------------------------------------------------------------
684
685bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
686                              std::string* mime_type) {
687  return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
688}
689
690bool GetMimeTypeFromFile(const base::FilePath& file_path,
691                         std::string* mime_type) {
692  return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
693}
694
695bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
696                                       std::string* mime_type) {
697  return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type);
698}
699
700bool GetPreferredExtensionForMimeType(const std::string& mime_type,
701                                      base::FilePath::StringType* extension) {
702  return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
703                                                            extension);
704}
705
706bool IsSupportedImageMimeType(const std::string& mime_type) {
707  return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
708}
709
710bool IsSupportedMediaMimeType(const std::string& mime_type) {
711  return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
712}
713
714bool IsSupportedNonImageMimeType(const std::string& mime_type) {
715  return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
716}
717
718bool IsUnsupportedTextMimeType(const std::string& mime_type) {
719  return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
720}
721
722bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
723  return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
724}
725
726bool IsSupportedMimeType(const std::string& mime_type) {
727  return g_mime_util.Get().IsSupportedMimeType(mime_type);
728}
729
730bool MatchesMimeType(const std::string& mime_type_pattern,
731                     const std::string& mime_type) {
732  return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
733}
734
735bool IsMimeType(const std::string& type_string) {
736  return g_mime_util.Get().IsMimeType(type_string);
737}
738
739bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
740  return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
741}
742
743bool IsStrictMediaMimeType(const std::string& mime_type) {
744  return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
745}
746
747bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
748                                    const std::vector<std::string>& codecs) {
749  return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
750}
751
752void ParseCodecString(const std::string& codecs,
753                      std::vector<std::string>* codecs_out,
754                      const bool strip) {
755  g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
756}
757
758namespace {
759
760// From http://www.w3schools.com/media/media_mimeref.asp and
761// http://plugindoc.mozdev.org/winmime.php
762static const char* const kStandardImageTypes[] = {
763  "image/bmp",
764  "image/cis-cod",
765  "image/gif",
766  "image/ief",
767  "image/jpeg",
768  "image/webp",
769  "image/pict",
770  "image/pipeg",
771  "image/png",
772  "image/svg+xml",
773  "image/tiff",
774  "image/vnd.microsoft.icon",
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<base::FilePath::StringType>* extensions) {
840  base::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        base::FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
849#else
850        base::FilePath::StringType extension(this_extensions[j]);
851#endif
852        extensions->insert(extension);
853      }
854    }
855  }
856}
857
858void GetExtensionsHelper(
859    const char* const* standard_types,
860    size_t standard_types_len,
861    const std::string& leading_mime_type,
862    base::hash_set<base::FilePath::StringType>* extensions) {
863  for (size_t i = 0; i < standard_types_len; ++i) {
864    g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i],
865                                                       extensions);
866  }
867
868  // Also look up the extensions from hard-coded mappings in case that some
869  // supported extensions are not registered in the system registry, like ogg.
870  GetExtensionsFromHardCodedMappings(primary_mappings,
871                                     arraysize(primary_mappings),
872                                     leading_mime_type,
873                                     extensions);
874
875  GetExtensionsFromHardCodedMappings(secondary_mappings,
876                                     arraysize(secondary_mappings),
877                                     leading_mime_type,
878                                     extensions);
879}
880
881// Note that the elements in the source set will be appended to the target
882// vector.
883template<class T>
884void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
885  size_t old_target_size = target->size();
886  target->resize(old_target_size + source->size());
887  size_t i = 0;
888  for (typename base::hash_set<T>::iterator iter = source->begin();
889       iter != source->end(); ++iter, ++i)
890    (*target)[old_target_size + i] = *iter;
891}
892}
893
894void GetExtensionsForMimeType(
895    const std::string& unsafe_mime_type,
896    std::vector<base::FilePath::StringType>* extensions) {
897  if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*")
898    return;
899
900  const std::string mime_type = StringToLowerASCII(unsafe_mime_type);
901  base::hash_set<base::FilePath::StringType> unique_extensions;
902
903  if (EndsWith(mime_type, "/*", true)) {
904    std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1);
905
906    // Find the matching StandardType from within kStandardTypes, or fall
907    // through to the last (default) StandardType.
908    const StandardType* type = NULL;
909    for (size_t i = 0; i < arraysize(kStandardTypes); ++i) {
910      type = &(kStandardTypes[i]);
911      if (type->leading_mime_type &&
912          leading_mime_type == type->leading_mime_type)
913        break;
914    }
915    DCHECK(type);
916    GetExtensionsHelper(type->standard_types,
917                        type->standard_types_len,
918                        leading_mime_type,
919                        &unique_extensions);
920  } else {
921    g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type,
922                                                       &unique_extensions);
923
924    // Also look up the extensions from hard-coded mappings in case that some
925    // supported extensions are not registered in the system registry, like ogg.
926    GetExtensionsFromHardCodedMappings(primary_mappings,
927                                       arraysize(primary_mappings),
928                                       mime_type,
929                                       &unique_extensions);
930
931    GetExtensionsFromHardCodedMappings(secondary_mappings,
932                                       arraysize(secondary_mappings),
933                                       mime_type,
934                                       &unique_extensions);
935  }
936
937  HashSetToVector(&unique_extensions, extensions);
938}
939
940void GetMediaTypesBlacklistedForTests(std::vector<std::string>* types) {
941  types->clear();
942
943// Unless/until WebM files are added to the media layout tests, we need to avoid
944// blacklisting mp4 and H.264 when Theora is not supported (and proprietary
945// codecs are) so that the media tests can still run.
946#if defined(ENABLE_MEDIA_CODEC_THEORA) || !defined(USE_PROPRIETARY_CODECS)
947  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
948    types->push_back(proprietary_media_types[i]);
949#endif
950}
951
952void GetMediaCodecsBlacklistedForTests(std::vector<std::string>* codecs) {
953  codecs->clear();
954
955// Unless/until WebM files are added to the media layout tests, we need to avoid
956// blacklisting mp4 and H.264 when Theora is not supported (and proprietary
957// codecs are) so that the media tests can still run.
958#if defined(ENABLE_MEDIA_CODEC_THEORA) || !defined(USE_PROPRIETARY_CODECS)
959  for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
960    codecs->push_back(proprietary_media_codecs[i]);
961#endif
962}
963
964const std::string GetIANAMediaType(const std::string& mime_type) {
965  for (size_t i = 0; i < arraysize(kIanaMediaTypes); ++i) {
966    if (StartsWithASCII(mime_type, kIanaMediaTypes[i].matcher, true)) {
967      return kIanaMediaTypes[i].name;
968    }
969  }
970  return std::string();
971}
972
973CertificateMimeType GetCertificateMimeTypeForMimeType(
974    const std::string& mime_type) {
975  // Don't create a map, there is only one entry in the table,
976  // except on Android.
977  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) {
978    if (mime_type == net::supported_certificate_types[i].mime_type)
979      return net::supported_certificate_types[i].cert_type;
980  }
981  return CERTIFICATE_MIME_TYPE_UNKNOWN;
982}
983
984bool IsSupportedCertificateMimeType(const std::string& mime_type) {
985  CertificateMimeType file_type =
986      GetCertificateMimeTypeForMimeType(mime_type);
987  return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN;
988}
989
990}  // namespace net
991