mime_util.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/x-javascript", "js" },
147  { "application/x-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};
385
386//  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
387//  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
388// application/x-javascript, but WinIE 7 doesn't.
389//  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
390// text/livescript, but Mozilla 1.8 doesn't.
391//  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
392//  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
393// whitespace-only string.
394//  We want to accept all the values that either of these browsers accept, but
395// not other values.
396static const char* const supported_javascript_types[] = {
397  "text/javascript",
398  "text/ecmascript",
399  "application/javascript",
400  "application/ecmascript",
401  "application/x-javascript",
402  "text/javascript1.1",
403  "text/javascript1.2",
404  "text/javascript1.3",
405  "text/jscript",
406  "text/livescript"
407};
408
409struct MediaFormatStrict {
410  const char* mime_type;
411  const char* codecs_list;
412};
413
414static const MediaFormatStrict format_codec_mappings[] = {
415  { "video/webm", "vorbis,vp8,vp8.0" },
416  { "audio/webm", "vorbis" },
417  { "audio/wav", "1" }
418};
419
420MimeUtil::MimeUtil() {
421  InitializeMimeTypeMaps();
422}
423
424// static
425bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs,
426                                  const std::vector<std::string>& codecs) {
427  for (size_t i = 0; i < codecs.size(); ++i) {
428    if (supported_codecs.find(codecs[i]) == supported_codecs.end())
429      return false;
430  }
431  return !codecs.empty();
432}
433
434void MimeUtil::InitializeMimeTypeMaps() {
435  for (size_t i = 0; i < arraysize(supported_image_types); ++i)
436    image_map_.insert(supported_image_types[i]);
437
438  // Initialize the supported non-image types.
439  for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
440    non_image_map_.insert(supported_non_image_types[i]);
441  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i)
442    non_image_map_.insert(supported_certificate_types[i].mime_type);
443  for (size_t i = 0; i < arraysize(unsupported_text_types); ++i)
444    unsupported_text_map_.insert(unsupported_text_types[i]);
445  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
446    non_image_map_.insert(supported_javascript_types[i]);
447  for (size_t i = 0; i < arraysize(common_media_types); ++i)
448    non_image_map_.insert(common_media_types[i]);
449#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
450  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
451    non_image_map_.insert(proprietary_media_types[i]);
452#endif
453
454  // Initialize the supported media types.
455  for (size_t i = 0; i < arraysize(common_media_types); ++i)
456    media_map_.insert(common_media_types[i]);
457#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
458  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
459    media_map_.insert(proprietary_media_types[i]);
460#endif
461
462  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
463    javascript_map_.insert(supported_javascript_types[i]);
464
465  for (size_t i = 0; i < arraysize(common_media_codecs); ++i)
466    codecs_map_.insert(common_media_codecs[i]);
467#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
468  for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
469    codecs_map_.insert(proprietary_media_codecs[i]);
470#endif
471
472  // Initialize the strict supported media types.
473  for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
474    std::vector<std::string> mime_type_codecs;
475    ParseCodecString(format_codec_mappings[i].codecs_list,
476                     &mime_type_codecs,
477                     false);
478
479    MimeMappings codecs;
480    for (size_t j = 0; j < mime_type_codecs.size(); ++j)
481      codecs.insert(mime_type_codecs[j]);
482    strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
483  }
484}
485
486bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
487  return image_map_.find(mime_type) != image_map_.end();
488}
489
490bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
491  return media_map_.find(mime_type) != media_map_.end();
492}
493
494bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
495  return non_image_map_.find(mime_type) != non_image_map_.end() ||
496      (mime_type.compare(0, 5, "text/") == 0 &&
497       !IsUnsupportedTextMimeType(mime_type));
498}
499
500bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
501  return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end();
502}
503
504bool MimeUtil::IsSupportedJavascriptMimeType(
505    const std::string& mime_type) const {
506  return javascript_map_.find(mime_type) != javascript_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 base::FilePath::StringType& ext,
684                              std::string* mime_type) {
685  return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
686}
687
688bool GetMimeTypeFromFile(const base::FilePath& file_path,
689                         std::string* mime_type) {
690  return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
691}
692
693bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
694                                       std::string* mime_type) {
695  return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type);
696}
697
698bool GetPreferredExtensionForMimeType(const std::string& mime_type,
699                                      base::FilePath::StringType* extension) {
700  return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
701                                                            extension);
702}
703
704bool IsSupportedImageMimeType(const std::string& mime_type) {
705  return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
706}
707
708bool IsSupportedMediaMimeType(const std::string& mime_type) {
709  return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
710}
711
712bool IsSupportedNonImageMimeType(const std::string& mime_type) {
713  return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
714}
715
716bool IsUnsupportedTextMimeType(const std::string& mime_type) {
717  return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
718}
719
720bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
721  return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
722}
723
724bool IsSupportedMimeType(const std::string& mime_type) {
725  return g_mime_util.Get().IsSupportedMimeType(mime_type);
726}
727
728bool MatchesMimeType(const std::string& mime_type_pattern,
729                     const std::string& mime_type) {
730  return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
731}
732
733bool IsMimeType(const std::string& type_string) {
734  return g_mime_util.Get().IsMimeType(type_string);
735}
736
737bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
738  return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
739}
740
741bool IsStrictMediaMimeType(const std::string& mime_type) {
742  return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
743}
744
745bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
746                                    const std::vector<std::string>& codecs) {
747  return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
748}
749
750void ParseCodecString(const std::string& codecs,
751                      std::vector<std::string>* codecs_out,
752                      const bool strip) {
753  g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
754}
755
756namespace {
757
758// From http://www.w3schools.com/media/media_mimeref.asp and
759// http://plugindoc.mozdev.org/winmime.php
760static const char* const kStandardImageTypes[] = {
761  "image/bmp",
762  "image/cis-cod",
763  "image/gif",
764  "image/ief",
765  "image/jpeg",
766  "image/webp",
767  "image/pict",
768  "image/pipeg",
769  "image/png",
770  "image/svg+xml",
771  "image/tiff",
772  "image/vnd.microsoft.icon",
773  "image/x-cmu-raster",
774  "image/x-cmx",
775  "image/x-icon",
776  "image/x-portable-anymap",
777  "image/x-portable-bitmap",
778  "image/x-portable-graymap",
779  "image/x-portable-pixmap",
780  "image/x-rgb",
781  "image/x-xbitmap",
782  "image/x-xpixmap",
783  "image/x-xwindowdump"
784};
785static const char* const kStandardAudioTypes[] = {
786  "audio/aac",
787  "audio/aiff",
788  "audio/amr",
789  "audio/basic",
790  "audio/midi",
791  "audio/mp3",
792  "audio/mp4",
793  "audio/mpeg",
794  "audio/mpeg3",
795  "audio/ogg",
796  "audio/vorbis",
797  "audio/wav",
798  "audio/webm",
799  "audio/x-m4a",
800  "audio/x-ms-wma",
801  "audio/vnd.rn-realaudio",
802  "audio/vnd.wave"
803};
804static const char* const kStandardVideoTypes[] = {
805  "video/avi",
806  "video/divx",
807  "video/flc",
808  "video/mp4",
809  "video/mpeg",
810  "video/ogg",
811  "video/quicktime",
812  "video/sd-video",
813  "video/webm",
814  "video/x-dv",
815  "video/x-m4v",
816  "video/x-mpeg",
817  "video/x-ms-asf",
818  "video/x-ms-wmv"
819};
820
821struct StandardType {
822  const char* leading_mime_type;
823  const char* const* standard_types;
824  size_t standard_types_len;
825};
826static const StandardType kStandardTypes[] = {
827  { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) },
828  { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) },
829  { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) },
830  { NULL, NULL, 0 }
831};
832
833void GetExtensionsFromHardCodedMappings(
834    const MimeInfo* mappings,
835    size_t mappings_len,
836    const std::string& leading_mime_type,
837    base::hash_set<base::FilePath::StringType>* extensions) {
838  base::FilePath::StringType extension;
839  for (size_t i = 0; i < mappings_len; ++i) {
840    if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
841      std::vector<string> this_extensions;
842      base::SplitStringUsingSubstr(mappings[i].extensions, ",",
843                                   &this_extensions);
844      for (size_t j = 0; j < this_extensions.size(); ++j) {
845#if defined(OS_WIN)
846        base::FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
847#else
848        base::FilePath::StringType extension(this_extensions[j]);
849#endif
850        extensions->insert(extension);
851      }
852    }
853  }
854}
855
856void GetExtensionsHelper(
857    const char* const* standard_types,
858    size_t standard_types_len,
859    const std::string& leading_mime_type,
860    base::hash_set<base::FilePath::StringType>* extensions) {
861  for (size_t i = 0; i < standard_types_len; ++i) {
862    g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i],
863                                                       extensions);
864  }
865
866  // Also look up the extensions from hard-coded mappings in case that some
867  // supported extensions are not registered in the system registry, like ogg.
868  GetExtensionsFromHardCodedMappings(primary_mappings,
869                                     arraysize(primary_mappings),
870                                     leading_mime_type,
871                                     extensions);
872
873  GetExtensionsFromHardCodedMappings(secondary_mappings,
874                                     arraysize(secondary_mappings),
875                                     leading_mime_type,
876                                     extensions);
877}
878
879// Note that the elements in the source set will be appended to the target
880// vector.
881template<class T>
882void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
883  size_t old_target_size = target->size();
884  target->resize(old_target_size + source->size());
885  size_t i = 0;
886  for (typename base::hash_set<T>::iterator iter = source->begin();
887       iter != source->end(); ++iter, ++i)
888    (*target)[old_target_size + i] = *iter;
889}
890}
891
892void GetExtensionsForMimeType(
893    const std::string& unsafe_mime_type,
894    std::vector<base::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<base::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
971CertificateMimeType GetCertificateMimeTypeForMimeType(
972    const std::string& mime_type) {
973  // Don't create a map, there is only one entry in the table,
974  // except on Android.
975  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) {
976    if (mime_type == net::supported_certificate_types[i].mime_type)
977      return net::supported_certificate_types[i].cert_type;
978  }
979  return CERTIFICATE_MIME_TYPE_UNKNOWN;
980}
981
982bool IsSupportedCertificateMimeType(const std::string& mime_type) {
983  CertificateMimeType file_type =
984      GetCertificateMimeTypeForMimeType(mime_type);
985  return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN;
986}
987
988}  // namespace net
989