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