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/stl_util.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/string_split.h"
16#include "base/strings/string_util.h"
17#include "base/strings/utf_string_conversions.h"
18#include "net/base/mime_util.h"
19#include "net/base/platform_mime_util.h"
20#include "net/http/http_util.h"
21
22#if defined(OS_ANDROID)
23#include "base/android/build_info.h"
24#endif
25
26using std::string;
27
28namespace {
29
30struct MediaType {
31  const char name[12];
32  const char matcher[13];
33};
34
35static const MediaType kIanaMediaTypes[] = {
36  { "application", "application/" },
37  { "audio", "audio/" },
38  { "example", "example/" },
39  { "image", "image/" },
40  { "message", "message/" },
41  { "model", "model/" },
42  { "multipart", "multipart/" },
43  { "text", "text/" },
44  { "video", "video/" },
45};
46
47}  // namespace
48
49namespace net {
50
51// Singleton utility class for mime types.
52class MimeUtil : public PlatformMimeUtil {
53 public:
54  enum Codec {
55    INVALID_CODEC,
56    PCM,
57    MP3,
58    MPEG2_AAC_LC,
59    MPEG2_AAC_MAIN,
60    MPEG2_AAC_SSR,
61    MPEG4_AAC_LC,
62    MPEG4_AAC_SBRv1,
63    VORBIS,
64    OPUS,
65    H264_BASELINE,
66    H264_MAIN,
67    H264_HIGH,
68    VP8,
69    VP9,
70    THEORA
71  };
72
73  bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
74                                std::string* mime_type) const;
75
76  bool GetMimeTypeFromFile(const base::FilePath& file_path,
77                           std::string* mime_type) const;
78
79  bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
80                                         std::string* mime_type) const;
81
82  bool IsSupportedImageMimeType(const std::string& mime_type) const;
83  bool IsSupportedMediaMimeType(const std::string& mime_type) const;
84  bool IsSupportedNonImageMimeType(const std::string& mime_type) const;
85  bool IsUnsupportedTextMimeType(const std::string& mime_type) const;
86  bool IsSupportedJavascriptMimeType(const std::string& mime_type) const;
87
88  bool IsSupportedMimeType(const std::string& mime_type) const;
89
90  bool MatchesMimeType(const std::string &mime_type_pattern,
91                       const std::string &mime_type) const;
92
93  bool ParseMimeTypeWithoutParameter(const std::string& type_string,
94                                     std::string* top_level_type,
95                                     std::string* subtype) const;
96
97  bool IsValidTopLevelMimeType(const std::string& type_string) const;
98
99  bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
100
101  void ParseCodecString(const std::string& codecs,
102                        std::vector<std::string>* codecs_out,
103                        bool strip);
104
105  bool IsStrictMediaMimeType(const std::string& mime_type) const;
106  SupportsType IsSupportedStrictMediaMimeType(
107      const std::string& mime_type,
108      const std::vector<std::string>& codecs) const;
109
110  void RemoveProprietaryMediaTypesAndCodecsForTests();
111
112 private:
113  friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
114
115  typedef base::hash_set<std::string> MimeMappings;
116
117  typedef base::hash_set<int> CodecSet;
118  typedef std::map<std::string, CodecSet> StrictMappings;
119  struct CodecEntry {
120    CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {}
121    CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {}
122    Codec codec;
123    bool is_ambiguous;
124  };
125  typedef std::map<std::string, CodecEntry> StringToCodecMappings;
126
127  MimeUtil();
128
129  // Returns IsSupported if all codec IDs in |codecs| are unambiguous
130  // and are supported by the platform. MayBeSupported is returned if
131  // at least one codec ID in |codecs| is ambiguous but all the codecs
132  // are supported by the platform. IsNotSupported is returned if at
133  // least one codec ID  is not supported by the platform.
134  SupportsType AreSupportedCodecs(
135      const CodecSet& supported_codecs,
136      const std::vector<std::string>& codecs) const;
137
138  // For faster lookup, keep hash sets.
139  void InitializeMimeTypeMaps();
140
141  bool GetMimeTypeFromExtensionHelper(const base::FilePath::StringType& ext,
142                                      bool include_platform_types,
143                                      std::string* mime_type) const;
144
145  // Converts a codec ID into an Codec enum value and indicates
146  // whether the conversion was ambiguous.
147  // Returns true if this method was able to map |codec_id| to a specific
148  // Codec enum value. |codec| and |is_ambiguous| are only valid if true
149  // is returned. Otherwise their value is undefined after the call.
150  // |is_ambiguous| is true if |codec_id| did not have enough information to
151  // unambiguously determine the proper Codec enum value. If |is_ambiguous|
152  // is true |codec| contains the best guess for the intended Codec enum value.
153  bool StringToCodec(const std::string& codec_id,
154                     Codec* codec,
155                     bool* is_ambiguous) const;
156
157  // Returns true if |codec| is supported by the platform.
158  // Note: This method will return false if the platform supports proprietary
159  // codecs but |allow_proprietary_codecs_| is set to false.
160  bool IsCodecSupported(Codec codec) const;
161
162  // Returns true if |codec| refers to a proprietary codec.
163  bool IsCodecProprietary(Codec codec) const;
164
165  // Returns true and sets |*default_codec| if |mime_type| has a
166  // default codec associated with it.
167  // Returns false otherwise and the value of |*default_codec| is undefined.
168  bool GetDefaultCodec(const std::string& mime_type,
169                       Codec* default_codec) const;
170
171  // Returns true if |mime_type| has a default codec associated with it
172  // and IsCodecSupported() returns true for that particular codec.
173  bool IsDefaultCodecSupported(const std::string& mime_type) const;
174
175  MimeMappings image_map_;
176  MimeMappings media_map_;
177  MimeMappings non_image_map_;
178  MimeMappings unsupported_text_map_;
179  MimeMappings javascript_map_;
180
181  // A map of mime_types and hash map of the supported codecs for the mime_type.
182  StrictMappings strict_format_map_;
183
184  // Keeps track of whether proprietary codec support should be
185  // advertised to callers.
186  bool allow_proprietary_codecs_;
187
188  // Lookup table for string compare based string -> Codec mappings.
189  StringToCodecMappings string_to_codec_map_;
190};  // class MimeUtil
191
192// This variable is Leaky because we need to access it from WorkerPool threads.
193static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
194    LAZY_INSTANCE_INITIALIZER;
195
196struct MimeInfo {
197  const char* mime_type;
198  const char* extensions;  // comma separated list
199};
200
201static const MimeInfo primary_mappings[] = {
202  { "text/html", "html,htm,shtml,shtm" },
203  { "text/css", "css" },
204  { "text/xml", "xml" },
205  { "image/gif", "gif" },
206  { "image/jpeg", "jpeg,jpg" },
207  { "image/webp", "webp" },
208  { "image/png", "png" },
209  { "video/mp4", "mp4,m4v" },
210  { "audio/x-m4a", "m4a" },
211  { "audio/mp3", "mp3" },
212  { "video/ogg", "ogv,ogm" },
213  { "audio/ogg", "ogg,oga,opus" },
214  { "video/webm", "webm" },
215  { "audio/webm", "webm" },
216  { "audio/wav", "wav" },
217  { "application/xhtml+xml", "xhtml,xht,xhtm" },
218  { "application/x-chrome-extension", "crx" },
219  { "multipart/related", "mhtml,mht" }
220};
221
222static const MimeInfo secondary_mappings[] = {
223  { "application/octet-stream", "exe,com,bin" },
224  { "application/gzip", "gz" },
225  { "application/pdf", "pdf" },
226  { "application/postscript", "ps,eps,ai" },
227  { "application/javascript", "js" },
228  { "application/font-woff", "woff" },
229  { "image/bmp", "bmp" },
230  { "image/x-icon", "ico" },
231  { "image/vnd.microsoft.icon", "ico" },
232  { "image/jpeg", "jfif,pjpeg,pjp" },
233  { "image/tiff", "tiff,tif" },
234  { "image/x-xbitmap", "xbm" },
235  { "image/svg+xml", "svg,svgz" },
236  { "image/x-png", "png"},
237  { "message/rfc822", "eml" },
238  { "text/plain", "txt,text" },
239  { "text/html", "ehtml" },
240  { "application/rss+xml", "rss" },
241  { "application/rdf+xml", "rdf" },
242  { "text/xml", "xsl,xbl,xslt" },
243  { "application/vnd.mozilla.xul+xml", "xul" },
244  { "application/x-shockwave-flash", "swf,swl" },
245  { "application/pkcs7-mime", "p7m,p7c,p7z" },
246  { "application/pkcs7-signature", "p7s" },
247  { "application/x-mpegurl", "m3u8" },
248};
249
250static const char* FindMimeType(const MimeInfo* mappings,
251                                size_t mappings_len,
252                                const char* ext) {
253  size_t ext_len = strlen(ext);
254
255  for (size_t i = 0; i < mappings_len; ++i) {
256    const char* extensions = mappings[i].extensions;
257    for (;;) {
258      size_t end_pos = strcspn(extensions, ",");
259      if (end_pos == ext_len &&
260          base::strncasecmp(extensions, ext, ext_len) == 0)
261        return mappings[i].mime_type;
262      extensions += end_pos;
263      if (!*extensions)
264        break;
265      extensions += 1;  // skip over comma
266    }
267  }
268  return NULL;
269}
270
271bool MimeUtil::GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
272                                        string* result) const {
273  return GetMimeTypeFromExtensionHelper(ext, true, result);
274}
275
276bool MimeUtil::GetWellKnownMimeTypeFromExtension(
277    const base::FilePath::StringType& ext,
278    string* result) const {
279  return GetMimeTypeFromExtensionHelper(ext, false, result);
280}
281
282bool MimeUtil::GetMimeTypeFromFile(const base::FilePath& file_path,
283                                   string* result) const {
284  base::FilePath::StringType file_name_str = file_path.Extension();
285  if (file_name_str.empty())
286    return false;
287  return GetMimeTypeFromExtension(file_name_str.substr(1), result);
288}
289
290bool MimeUtil::GetMimeTypeFromExtensionHelper(
291    const base::FilePath::StringType& ext,
292    bool include_platform_types,
293    string* result) const {
294  // Avoids crash when unable to handle a long file path. See crbug.com/48733.
295  const unsigned kMaxFilePathSize = 65536;
296  if (ext.length() > kMaxFilePathSize)
297    return false;
298
299  // We implement the same algorithm as Mozilla for mapping a file extension to
300  // a mime type.  That is, we first check a hard-coded list (that cannot be
301  // overridden), and then if not found there, we defer to the system registry.
302  // Finally, we scan a secondary hard-coded list to catch types that we can
303  // deduce but that we also want to allow the OS to override.
304
305  base::FilePath path_ext(ext);
306  const string ext_narrow_str = path_ext.AsUTF8Unsafe();
307  const char* mime_type = FindMimeType(primary_mappings,
308                                       arraysize(primary_mappings),
309                                       ext_narrow_str.c_str());
310  if (mime_type) {
311    *result = mime_type;
312    return true;
313  }
314
315  if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result))
316    return true;
317
318  mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
319                           ext_narrow_str.c_str());
320  if (mime_type) {
321    *result = mime_type;
322    return true;
323  }
324
325  return false;
326}
327
328// From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
329
330static const char* const supported_image_types[] = {
331  "image/jpeg",
332  "image/pjpeg",
333  "image/jpg",
334  "image/webp",
335  "image/png",
336  "image/gif",
337  "image/bmp",
338  "image/vnd.microsoft.icon",    // ico
339  "image/x-icon",    // ico
340  "image/x-xbitmap",  // xbm
341  "image/x-png"
342};
343
344// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
345// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
346// This set of codecs is supported by all variations of Chromium.
347static const char* const common_media_types[] = {
348  // Ogg.
349  "audio/ogg",
350  "application/ogg",
351#if !defined(OS_ANDROID)  // Android doesn't support Ogg Theora.
352  "video/ogg",
353#endif
354
355  // WebM.
356  "video/webm",
357  "audio/webm",
358
359  // Wav.
360  "audio/wav",
361  "audio/x-wav",
362
363#if defined(OS_ANDROID)
364  // HLS. Supported by Android ICS and above.
365  "application/vnd.apple.mpegurl",
366  "application/x-mpegurl",
367#endif
368};
369
370// List of proprietary types only supported by Google Chrome.
371static const char* const proprietary_media_types[] = {
372  // MPEG-4.
373  "video/mp4",
374  "video/x-m4v",
375  "audio/mp4",
376  "audio/x-m4a",
377
378  // MP3.
379  "audio/mp3",
380  "audio/x-mp3",
381  "audio/mpeg",
382
383#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
384  // MPEG-2 TS.
385  "video/mp2t",
386#endif
387};
388
389// Note:
390// - does not include javascript types list (see supported_javascript_types)
391// - does not include types starting with "text/" (see
392//   IsSupportedNonImageMimeType())
393static const char* const supported_non_image_types[] = {
394  "image/svg+xml",  // SVG is text-based XML, even though it has an image/ type
395  "application/xml",
396  "application/atom+xml",
397  "application/rss+xml",
398  "application/xhtml+xml",
399  "application/json",
400  "multipart/related",  // For MHTML support.
401  "multipart/x-mixed-replace"
402  // Note: ADDING a new type here will probably render it AS HTML. This can
403  // result in cross site scripting.
404};
405
406// Dictionary of cryptographic file mime types.
407struct CertificateMimeTypeInfo {
408  const char* mime_type;
409  CertificateMimeType cert_type;
410};
411
412static const CertificateMimeTypeInfo supported_certificate_types[] = {
413  { "application/x-x509-user-cert",
414      CERTIFICATE_MIME_TYPE_X509_USER_CERT },
415#if defined(OS_ANDROID)
416  { "application/x-x509-ca-cert", CERTIFICATE_MIME_TYPE_X509_CA_CERT },
417  { "application/x-pkcs12", CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE },
418#endif
419};
420
421// These types are excluded from the logic that allows all text/ types because
422// while they are technically text, it's very unlikely that a user expects to
423// see them rendered in text form.
424static const char* const unsupported_text_types[] = {
425  "text/calendar",
426  "text/x-calendar",
427  "text/x-vcalendar",
428  "text/vcalendar",
429  "text/vcard",
430  "text/x-vcard",
431  "text/directory",
432  "text/ldif",
433  "text/qif",
434  "text/x-qif",
435  "text/x-csv",
436  "text/x-vcf",
437  "text/rtf",
438  "text/comma-separated-values",
439  "text/csv",
440  "text/tab-separated-values",
441  "text/tsv",
442  "text/ofx",                           // http://crbug.com/162238
443  "text/vnd.sun.j2me.app-descriptor"    // http://crbug.com/176450
444};
445
446//  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
447//  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
448// application/x-javascript, but WinIE 7 doesn't.
449//  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
450// text/livescript, but Mozilla 1.8 doesn't.
451//  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
452//  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
453// whitespace-only string.
454//  We want to accept all the values that either of these browsers accept, but
455// not other values.
456static const char* const supported_javascript_types[] = {
457  "text/javascript",
458  "text/ecmascript",
459  "application/javascript",
460  "application/ecmascript",
461  "application/x-javascript",
462  "text/javascript1.1",
463  "text/javascript1.2",
464  "text/javascript1.3",
465  "text/jscript",
466  "text/livescript"
467};
468
469#if defined(OS_ANDROID)
470static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
471  switch (codec) {
472    case MimeUtil::INVALID_CODEC:
473      return false;
474
475    case MimeUtil::PCM:
476    case MimeUtil::MP3:
477    case MimeUtil::MPEG4_AAC_LC:
478    case MimeUtil::MPEG4_AAC_SBRv1:
479    case MimeUtil::H264_BASELINE:
480    case MimeUtil::H264_MAIN:
481    case MimeUtil::H264_HIGH:
482    case MimeUtil::VP8:
483    case MimeUtil::VORBIS:
484      return true;
485
486    case MimeUtil::MPEG2_AAC_LC:
487    case MimeUtil::MPEG2_AAC_MAIN:
488    case MimeUtil::MPEG2_AAC_SSR:
489      // MPEG-2 variants of AAC are not supported on Android.
490      return false;
491
492    case MimeUtil::VP9:
493      // VP9 is supported only in KitKat+ (API Level 19).
494      return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
495
496    case MimeUtil::OPUS:
497      // TODO(vigneshv): Change this similar to the VP9 check once Opus is
498      // supported on Android (http://crbug.com/318436).
499      return false;
500
501    case MimeUtil::THEORA:
502      return false;
503  }
504
505  return false;
506}
507
508static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) {
509  // HLS codecs are supported in ICS and above (API level 14)
510  if ((!mimeType.compare("application/vnd.apple.mpegurl") ||
511      !mimeType.compare("application/x-mpegurl")) &&
512      base::android::BuildInfo::GetInstance()->sdk_int() < 14) {
513    return false;
514  }
515  return true;
516}
517#endif
518
519struct MediaFormatStrict {
520  const char* mime_type;
521  const char* codecs_list;
522};
523
524// Following is the list of RFC 6381 compliant codecs:
525//   mp4a.66     - MPEG-2 AAC MAIN
526//   mp4a.67     - MPEG-2 AAC LC
527//   mp4a.68     - MPEG-2 AAC SSR
528//   mp4a.69     - MPEG-2 extension to MPEG-1
529//   mp4a.6B     - MPEG-1 audio
530//   mp4a.40.2   - MPEG-4 AAC LC
531//   mp4a.40.5   - MPEG-4 AAC SBRv1
532//
533//   avc1.42E0xx - H.264 Baseline
534//   avc1.4D40xx - H.264 Main
535//   avc1.6400xx - H.264 High
536static const char kMP4AudioCodecsExpression[] =
537    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5";
538static const char kMP4VideoCodecsExpression[] =
539    "avc1.42E00A,avc1.4D400A,avc1.64000A," \
540    "mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.5";
541
542static const MediaFormatStrict format_codec_mappings[] = {
543  { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" },
544  { "audio/webm", "opus,vorbis" },
545  { "audio/wav", "1" },
546  { "audio/x-wav", "1" },
547  { "video/ogg", "opus,theora,vorbis" },
548  { "audio/ogg", "opus,vorbis" },
549  { "application/ogg", "opus,theora,vorbis" },
550  { "audio/mpeg", "mp3" },
551  { "audio/mp3", "" },
552  { "audio/x-mp3", "" },
553  { "audio/mp4", kMP4AudioCodecsExpression },
554  { "audio/x-m4a", kMP4AudioCodecsExpression },
555  { "video/mp4", kMP4VideoCodecsExpression },
556  { "video/x-m4v", kMP4VideoCodecsExpression },
557  { "application/x-mpegurl", kMP4VideoCodecsExpression },
558  { "application/vnd.apple.mpegurl", kMP4VideoCodecsExpression }
559};
560
561struct CodecIDMappings {
562  const char* const codec_id;
563  MimeUtil::Codec codec;
564};
565
566// List of codec IDs that provide enough information to determine the
567// codec and profile being requested.
568//
569// The "mp4a" strings come from RFC 6381.
570static const CodecIDMappings kUnambiguousCodecIDs[] = {
571  { "1", MimeUtil::PCM }, // We only allow this for WAV so it isn't ambiguous.
572  { "mp3", MimeUtil::MP3 },
573  { "mp4a.66", MimeUtil::MPEG2_AAC_MAIN },
574  { "mp4a.67", MimeUtil::MPEG2_AAC_LC },
575  { "mp4a.68", MimeUtil::MPEG2_AAC_SSR },
576  { "mp4a.69", MimeUtil::MP3 },
577  { "mp4a.6B", MimeUtil::MP3 },
578  { "mp4a.40.2", MimeUtil::MPEG4_AAC_LC },
579  { "mp4a.40.5", MimeUtil::MPEG4_AAC_SBRv1 },
580  { "vorbis", MimeUtil::VORBIS },
581  { "opus", MimeUtil::OPUS },
582  { "vp8", MimeUtil::VP8 },
583  { "vp8.0", MimeUtil::VP8 },
584  { "vp9", MimeUtil::VP9 },
585  { "vp9.0", MimeUtil::VP9 },
586  { "theora", MimeUtil::THEORA }
587};
588
589// List of codec IDs that are ambiguous and don't provide
590// enough information to determine the codec and profile.
591// The codec in these entries indicate the codec and profile
592// we assume the user is trying to indicate.
593static const CodecIDMappings kAmbiguousCodecIDs[] = {
594  { "mp4a.40", MimeUtil::MPEG4_AAC_LC },
595  { "avc1", MimeUtil::H264_BASELINE },
596  { "avc3", MimeUtil::H264_BASELINE },
597};
598
599MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) {
600  InitializeMimeTypeMaps();
601}
602
603SupportsType MimeUtil::AreSupportedCodecs(
604    const CodecSet& supported_codecs,
605    const std::vector<std::string>& codecs) const {
606  DCHECK(!supported_codecs.empty());
607  DCHECK(!codecs.empty());
608
609  SupportsType result = IsSupported;
610  for (size_t i = 0; i < codecs.size(); ++i) {
611    bool is_ambiguous = true;
612    Codec codec = INVALID_CODEC;
613    if (!StringToCodec(codecs[i], &codec, &is_ambiguous))
614      return IsNotSupported;
615
616    if (!IsCodecSupported(codec) ||
617        supported_codecs.find(codec) == supported_codecs.end()) {
618      return IsNotSupported;
619    }
620
621    if (is_ambiguous)
622      result = MayBeSupported;
623  }
624
625  return result;
626}
627
628void MimeUtil::InitializeMimeTypeMaps() {
629  for (size_t i = 0; i < arraysize(supported_image_types); ++i)
630    image_map_.insert(supported_image_types[i]);
631
632  // Initialize the supported non-image types.
633  for (size_t i = 0; i < arraysize(supported_non_image_types); ++i)
634    non_image_map_.insert(supported_non_image_types[i]);
635  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i)
636    non_image_map_.insert(supported_certificate_types[i].mime_type);
637  for (size_t i = 0; i < arraysize(unsupported_text_types); ++i)
638    unsupported_text_map_.insert(unsupported_text_types[i]);
639  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
640    non_image_map_.insert(supported_javascript_types[i]);
641  for (size_t i = 0; i < arraysize(common_media_types); ++i) {
642#if defined(OS_ANDROID)
643    if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
644      continue;
645#endif
646    non_image_map_.insert(common_media_types[i]);
647  }
648#if defined(USE_PROPRIETARY_CODECS)
649  allow_proprietary_codecs_ = true;
650
651  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
652    non_image_map_.insert(proprietary_media_types[i]);
653#endif
654
655  // Initialize the supported media types.
656  for (size_t i = 0; i < arraysize(common_media_types); ++i) {
657#if defined(OS_ANDROID)
658    if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
659      continue;
660#endif
661    media_map_.insert(common_media_types[i]);
662  }
663#if defined(USE_PROPRIETARY_CODECS)
664  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
665    media_map_.insert(proprietary_media_types[i]);
666#endif
667
668  for (size_t i = 0; i < arraysize(supported_javascript_types); ++i)
669    javascript_map_.insert(supported_javascript_types[i]);
670
671  for (size_t i = 0; i < arraysize(kUnambiguousCodecIDs); ++i) {
672    string_to_codec_map_[kUnambiguousCodecIDs[i].codec_id] =
673        CodecEntry(kUnambiguousCodecIDs[i].codec, false);
674  }
675
676  for (size_t i = 0; i < arraysize(kAmbiguousCodecIDs); ++i) {
677    string_to_codec_map_[kAmbiguousCodecIDs[i].codec_id] =
678        CodecEntry(kAmbiguousCodecIDs[i].codec, true);
679  }
680
681  // Initialize the strict supported media types.
682  for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
683    std::vector<std::string> mime_type_codecs;
684    ParseCodecString(format_codec_mappings[i].codecs_list,
685                     &mime_type_codecs,
686                     false);
687
688    CodecSet codecs;
689    for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
690      Codec codec = INVALID_CODEC;
691      bool is_ambiguous = true;
692      CHECK(StringToCodec(mime_type_codecs[j], &codec, &is_ambiguous));
693      DCHECK(!is_ambiguous);
694      codecs.insert(codec);
695    }
696
697    strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
698  }
699}
700
701bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
702  return image_map_.find(mime_type) != image_map_.end();
703}
704
705bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
706  return media_map_.find(mime_type) != media_map_.end();
707}
708
709bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
710  return non_image_map_.find(mime_type) != non_image_map_.end() ||
711      (mime_type.compare(0, 5, "text/") == 0 &&
712       !IsUnsupportedTextMimeType(mime_type)) ||
713      (mime_type.compare(0, 12, "application/") == 0 &&
714       MatchesMimeType("application/*+json", mime_type));
715}
716
717bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
718  return unsupported_text_map_.find(mime_type) != unsupported_text_map_.end();
719}
720
721bool MimeUtil::IsSupportedJavascriptMimeType(
722    const std::string& mime_type) const {
723  return javascript_map_.find(mime_type) != javascript_map_.end();
724}
725
726// Mirrors WebViewImpl::CanShowMIMEType()
727bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
728  return (mime_type.compare(0, 6, "image/") == 0 &&
729          IsSupportedImageMimeType(mime_type)) ||
730         IsSupportedNonImageMimeType(mime_type);
731}
732
733// Tests for MIME parameter equality. Each parameter in the |mime_type_pattern|
734// must be matched by a parameter in the |mime_type|. If there are no
735// parameters in the pattern, the match is a success.
736bool MatchesMimeTypeParameters(const std::string& mime_type_pattern,
737                               const std::string& mime_type) {
738  const std::string::size_type semicolon = mime_type_pattern.find(';');
739  const std::string::size_type test_semicolon = mime_type.find(';');
740  if (semicolon != std::string::npos) {
741    if (test_semicolon == std::string::npos)
742      return false;
743
744    std::vector<std::string> pattern_parameters;
745    base::SplitString(mime_type_pattern.substr(semicolon + 1),
746                      ';', &pattern_parameters);
747
748    std::vector<std::string> test_parameters;
749    base::SplitString(mime_type.substr(test_semicolon + 1),
750                      ';', &test_parameters);
751
752    sort(pattern_parameters.begin(), pattern_parameters.end());
753    sort(test_parameters.begin(), test_parameters.end());
754    std::vector<std::string> difference =
755      base::STLSetDifference<std::vector<std::string> >(pattern_parameters,
756                                                        test_parameters);
757    return difference.size() == 0;
758  }
759  return true;
760}
761
762// This comparison handles absolute maching and also basic
763// wildcards.  The plugin mime types could be:
764//      application/x-foo
765//      application/*
766//      application/*+xml
767//      *
768// Also tests mime parameters -- all parameters in the pattern must be present
769// in the tested type for a match to succeed.
770bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern,
771                               const std::string& mime_type) const {
772  // Verify caller is passing lowercase strings.
773  DCHECK_EQ(base::StringToLowerASCII(mime_type_pattern), mime_type_pattern);
774  DCHECK_EQ(base::StringToLowerASCII(mime_type), mime_type);
775
776  if (mime_type_pattern.empty())
777    return false;
778
779  std::string::size_type semicolon = mime_type_pattern.find(';');
780  const std::string base_pattern(mime_type_pattern.substr(0, semicolon));
781  semicolon = mime_type.find(';');
782  const std::string base_type(mime_type.substr(0, semicolon));
783
784  if (base_pattern == "*" || base_pattern == "*/*")
785    return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
786
787  const std::string::size_type star = base_pattern.find('*');
788  if (star == std::string::npos) {
789    if (base_pattern == base_type)
790      return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
791    else
792      return false;
793  }
794
795  // Test length to prevent overlap between |left| and |right|.
796  if (base_type.length() < base_pattern.length() - 1)
797    return false;
798
799  const std::string left(base_pattern.substr(0, star));
800  const std::string right(base_pattern.substr(star + 1));
801
802  if (base_type.find(left) != 0)
803    return false;
804
805  if (!right.empty() &&
806      base_type.rfind(right) != base_type.length() - right.length())
807    return false;
808
809  return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
810}
811
812// See http://www.iana.org/assignments/media-types/media-types.xhtml
813static const char* legal_top_level_types[] = {
814  "application",
815  "audio",
816  "example",
817  "image",
818  "message",
819  "model",
820  "multipart",
821  "text",
822  "video",
823};
824
825bool MimeUtil::ParseMimeTypeWithoutParameter(
826    const std::string& type_string,
827    std::string* top_level_type,
828    std::string* subtype) const {
829  std::vector<std::string> components;
830  base::SplitString(type_string, '/', &components);
831  if (components.size() != 2 ||
832      !HttpUtil::IsToken(components[0]) ||
833      !HttpUtil::IsToken(components[1]))
834    return false;
835
836  if (top_level_type)
837    *top_level_type = components[0];
838  if (subtype)
839    *subtype = components[1];
840  return true;
841}
842
843bool MimeUtil::IsValidTopLevelMimeType(const std::string& type_string) const {
844  std::string lower_type = base::StringToLowerASCII(type_string);
845  for (size_t i = 0; i < arraysize(legal_top_level_types); ++i) {
846    if (lower_type.compare(legal_top_level_types[i]) == 0)
847      return true;
848  }
849
850  return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false);
851}
852
853bool MimeUtil::AreSupportedMediaCodecs(
854    const std::vector<std::string>& codecs) const {
855  for (size_t i = 0; i < codecs.size(); ++i) {
856    Codec codec = INVALID_CODEC;
857    bool is_ambiguous = true;
858    if (!StringToCodec(codecs[i], &codec, &is_ambiguous) ||
859        !IsCodecSupported(codec)) {
860      return false;
861    }
862  }
863  return true;
864}
865
866void MimeUtil::ParseCodecString(const std::string& codecs,
867                                std::vector<std::string>* codecs_out,
868                                bool strip) {
869  std::string no_quote_codecs;
870  base::TrimString(codecs, "\"", &no_quote_codecs);
871  base::SplitString(no_quote_codecs, ',', codecs_out);
872
873  if (!strip)
874    return;
875
876  // Strip everything past the first '.'
877  for (std::vector<std::string>::iterator it = codecs_out->begin();
878       it != codecs_out->end();
879       ++it) {
880    size_t found = it->find_first_of('.');
881    if (found != std::string::npos)
882      it->resize(found);
883  }
884}
885
886bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
887  return strict_format_map_.find(mime_type) != strict_format_map_.end();
888}
889
890SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
891    const std::string& mime_type,
892    const std::vector<std::string>& codecs) const {
893  StrictMappings::const_iterator it_strict_map =
894      strict_format_map_.find(mime_type);
895  if (it_strict_map == strict_format_map_.end())
896    return codecs.empty() ? MayBeSupported : IsNotSupported;
897
898  if (it_strict_map->second.empty()) {
899    // We get here if the mimetype does not expect a codecs parameter.
900    return (codecs.empty() && IsDefaultCodecSupported(mime_type)) ?
901        IsSupported : IsNotSupported;
902  }
903
904  if (codecs.empty()) {
905    // We get here if the mimetype expects to get a codecs parameter,
906    // but didn't get one. If |mime_type| does not have a default codec
907    // the best we can do is say "maybe" because we don't have enough
908    // information.
909    Codec default_codec = INVALID_CODEC;
910    if (!GetDefaultCodec(mime_type, &default_codec))
911      return MayBeSupported;
912
913    return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported;
914  }
915
916  return AreSupportedCodecs(it_strict_map->second, codecs);
917}
918
919void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
920  for (size_t i = 0; i < arraysize(proprietary_media_types); ++i) {
921    non_image_map_.erase(proprietary_media_types[i]);
922    media_map_.erase(proprietary_media_types[i]);
923  }
924  allow_proprietary_codecs_ = false;
925}
926
927// Returns true iff |profile_str| conforms to hex string "42y0", where y is one
928// of [8..F]. Requiring constraint_set0_flag be set and profile_idc be 0x42 is
929// taken from ISO-14496-10 7.3.2.1, 7.4.2.1, and Annex A.2.1.
930//
931// |profile_str| is the first four characters of the H.264 suffix string
932// (ignoring the last 2 characters of the full 6 character suffix that are
933// level_idc). From ISO-14496-10 7.3.2.1, it consists of:
934// 8 bits: profile_idc: required to be 0x42 here.
935// 1 bit: constraint_set0_flag : required to be true here.
936// 1 bit: constraint_set1_flag : ignored here.
937// 1 bit: constraint_set2_flag : ignored here.
938// 1 bit: constraint_set3_flag : ignored here.
939// 4 bits: reserved : required to be 0 here.
940//
941// The spec indicates other ways, not implemented here, that a |profile_str|
942// can indicate a baseline conforming decoder is sufficient for decode in Annex
943// A.2.1: "[profile_idc not necessarily 0x42] with constraint_set0_flag set and
944// in which level_idc and constraint_set3_flag represent a level less than or
945// equal to the specified level."
946static bool IsValidH264BaselineProfile(const std::string& profile_str) {
947  uint32 constraint_set_bits;
948  if (profile_str.size() != 4 ||
949      profile_str[0] != '4' ||
950      profile_str[1] != '2' ||
951      profile_str[3] != '0' ||
952      !base::HexStringToUInt(base::StringPiece(profile_str.c_str() + 2, 1),
953                             &constraint_set_bits)) {
954    return false;
955  }
956
957  return constraint_set_bits >= 8;
958}
959
960static bool IsValidH264Level(const std::string& level_str) {
961  uint32 level;
962  if (level_str.size() != 2 || !base::HexStringToUInt(level_str, &level))
963    return false;
964
965  // Valid levels taken from Table A-1 in ISO-14496-10.
966  // Essentially |level_str| is toHex(10 * level).
967  return ((level >= 10 && level <= 13) ||
968          (level >= 20 && level <= 22) ||
969          (level >= 30 && level <= 32) ||
970          (level >= 40 && level <= 42) ||
971          (level >= 50 && level <= 51));
972}
973
974// Handle parsing H.264 codec IDs as outlined in RFC 6381 and ISO-14496-10.
975//   avc1.42y0xx, y >= 8 - H.264 Baseline
976//   avc1.4D40xx         - H.264 Main
977//   avc1.6400xx         - H.264 High
978//
979//   avc1.xxxxxx & avc3.xxxxxx are considered ambiguous forms that are trying to
980//   signal H.264 Baseline. For example, the idc_level, profile_idc and
981//   constraint_set3_flag pieces may explicitly require decoder to conform to
982//   baseline profile at the specified level (see Annex A and constraint_set0 in
983//   ISO-14496-10).
984static bool ParseH264CodecID(const std::string& codec_id,
985                             MimeUtil::Codec* codec,
986                             bool* is_ambiguous) {
987  // Make sure we have avc1.xxxxxx or avc3.xxxxxx
988  if (codec_id.size() != 11 ||
989      (!StartsWithASCII(codec_id, "avc1.", true) &&
990       !StartsWithASCII(codec_id, "avc3.", true))) {
991    return false;
992  }
993
994  std::string profile = StringToUpperASCII(codec_id.substr(5, 4));
995  if (IsValidH264BaselineProfile(profile)) {
996    *codec = MimeUtil::H264_BASELINE;
997  } else if (profile == "4D40") {
998    *codec = MimeUtil::H264_MAIN;
999  } else if (profile == "6400") {
1000    *codec = MimeUtil::H264_HIGH;
1001  } else {
1002    *codec = MimeUtil::H264_BASELINE;
1003    *is_ambiguous = true;
1004    return true;
1005  }
1006
1007  *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9)));
1008  return true;
1009}
1010
1011bool MimeUtil::StringToCodec(const std::string& codec_id,
1012                             Codec* codec,
1013                             bool* is_ambiguous) const {
1014  StringToCodecMappings::const_iterator itr =
1015      string_to_codec_map_.find(codec_id);
1016  if (itr != string_to_codec_map_.end()) {
1017    *codec = itr->second.codec;
1018    *is_ambiguous = itr->second.is_ambiguous;
1019    return true;
1020  }
1021
1022  // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
1023  // an H.264 codec ID because currently those are the only ones that can't be
1024  // stored in the |string_to_codec_map_| and require parsing.
1025  return ParseH264CodecID(codec_id, codec, is_ambiguous);
1026}
1027
1028bool MimeUtil::IsCodecSupported(Codec codec) const {
1029  DCHECK_NE(codec, INVALID_CODEC);
1030
1031#if defined(OS_ANDROID)
1032  if (!IsCodecSupportedOnAndroid(codec))
1033    return false;
1034#endif
1035
1036  return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
1037}
1038
1039bool MimeUtil::IsCodecProprietary(Codec codec) const {
1040  switch (codec) {
1041    case INVALID_CODEC:
1042    case MP3:
1043    case MPEG2_AAC_LC:
1044    case MPEG2_AAC_MAIN:
1045    case MPEG2_AAC_SSR:
1046    case MPEG4_AAC_LC:
1047    case MPEG4_AAC_SBRv1:
1048    case H264_BASELINE:
1049    case H264_MAIN:
1050    case H264_HIGH:
1051      return true;
1052
1053    case PCM:
1054    case VORBIS:
1055    case OPUS:
1056    case VP8:
1057    case VP9:
1058    case THEORA:
1059      return false;
1060  }
1061
1062  return true;
1063}
1064
1065bool MimeUtil::GetDefaultCodec(const std::string& mime_type,
1066                               Codec* default_codec) const {
1067  if (mime_type == "audio/mpeg" ||
1068      mime_type == "audio/mp3" ||
1069      mime_type == "audio/x-mp3") {
1070    *default_codec = MimeUtil::MP3;
1071    return true;
1072  }
1073
1074  return false;
1075}
1076
1077
1078bool MimeUtil::IsDefaultCodecSupported(const std::string& mime_type) const {
1079  Codec default_codec = Codec::INVALID_CODEC;
1080  if (!GetDefaultCodec(mime_type, &default_codec))
1081    return false;
1082  return IsCodecSupported(default_codec);
1083}
1084
1085//----------------------------------------------------------------------------
1086// Wrappers for the singleton
1087//----------------------------------------------------------------------------
1088
1089bool GetMimeTypeFromExtension(const base::FilePath::StringType& ext,
1090                              std::string* mime_type) {
1091  return g_mime_util.Get().GetMimeTypeFromExtension(ext, mime_type);
1092}
1093
1094bool GetMimeTypeFromFile(const base::FilePath& file_path,
1095                         std::string* mime_type) {
1096  return g_mime_util.Get().GetMimeTypeFromFile(file_path, mime_type);
1097}
1098
1099bool GetWellKnownMimeTypeFromExtension(const base::FilePath::StringType& ext,
1100                                       std::string* mime_type) {
1101  return g_mime_util.Get().GetWellKnownMimeTypeFromExtension(ext, mime_type);
1102}
1103
1104bool GetPreferredExtensionForMimeType(const std::string& mime_type,
1105                                      base::FilePath::StringType* extension) {
1106  return g_mime_util.Get().GetPreferredExtensionForMimeType(mime_type,
1107                                                            extension);
1108}
1109
1110bool IsSupportedImageMimeType(const std::string& mime_type) {
1111  return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
1112}
1113
1114bool IsSupportedMediaMimeType(const std::string& mime_type) {
1115  return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
1116}
1117
1118bool IsSupportedNonImageMimeType(const std::string& mime_type) {
1119  return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
1120}
1121
1122bool IsUnsupportedTextMimeType(const std::string& mime_type) {
1123  return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
1124}
1125
1126bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
1127  return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
1128}
1129
1130bool IsSupportedMimeType(const std::string& mime_type) {
1131  return g_mime_util.Get().IsSupportedMimeType(mime_type);
1132}
1133
1134bool MatchesMimeType(const std::string& mime_type_pattern,
1135                     const std::string& mime_type) {
1136  return g_mime_util.Get().MatchesMimeType(mime_type_pattern, mime_type);
1137}
1138
1139bool ParseMimeTypeWithoutParameter(const std::string& type_string,
1140                                   std::string* top_level_type,
1141                                   std::string* subtype) {
1142  return g_mime_util.Get().ParseMimeTypeWithoutParameter(
1143      type_string, top_level_type, subtype);
1144}
1145
1146bool IsValidTopLevelMimeType(const std::string& type_string) {
1147  return g_mime_util.Get().IsValidTopLevelMimeType(type_string);
1148}
1149
1150bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
1151  return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
1152}
1153
1154bool IsStrictMediaMimeType(const std::string& mime_type) {
1155  return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
1156}
1157
1158SupportsType IsSupportedStrictMediaMimeType(
1159    const std::string& mime_type,
1160    const std::vector<std::string>& codecs) {
1161  return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
1162}
1163
1164void ParseCodecString(const std::string& codecs,
1165                      std::vector<std::string>* codecs_out,
1166                      const bool strip) {
1167  g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
1168}
1169
1170namespace {
1171
1172// From http://www.w3schools.com/media/media_mimeref.asp and
1173// http://plugindoc.mozdev.org/winmime.php
1174static const char* const kStandardImageTypes[] = {
1175  "image/bmp",
1176  "image/cis-cod",
1177  "image/gif",
1178  "image/ief",
1179  "image/jpeg",
1180  "image/webp",
1181  "image/pict",
1182  "image/pipeg",
1183  "image/png",
1184  "image/svg+xml",
1185  "image/tiff",
1186  "image/vnd.microsoft.icon",
1187  "image/x-cmu-raster",
1188  "image/x-cmx",
1189  "image/x-icon",
1190  "image/x-portable-anymap",
1191  "image/x-portable-bitmap",
1192  "image/x-portable-graymap",
1193  "image/x-portable-pixmap",
1194  "image/x-rgb",
1195  "image/x-xbitmap",
1196  "image/x-xpixmap",
1197  "image/x-xwindowdump"
1198};
1199static const char* const kStandardAudioTypes[] = {
1200  "audio/aac",
1201  "audio/aiff",
1202  "audio/amr",
1203  "audio/basic",
1204  "audio/midi",
1205  "audio/mp3",
1206  "audio/mp4",
1207  "audio/mpeg",
1208  "audio/mpeg3",
1209  "audio/ogg",
1210  "audio/vorbis",
1211  "audio/wav",
1212  "audio/webm",
1213  "audio/x-m4a",
1214  "audio/x-ms-wma",
1215  "audio/vnd.rn-realaudio",
1216  "audio/vnd.wave"
1217};
1218static const char* const kStandardVideoTypes[] = {
1219  "video/avi",
1220  "video/divx",
1221  "video/flc",
1222  "video/mp4",
1223  "video/mpeg",
1224  "video/ogg",
1225  "video/quicktime",
1226  "video/sd-video",
1227  "video/webm",
1228  "video/x-dv",
1229  "video/x-m4v",
1230  "video/x-mpeg",
1231  "video/x-ms-asf",
1232  "video/x-ms-wmv"
1233};
1234
1235struct StandardType {
1236  const char* leading_mime_type;
1237  const char* const* standard_types;
1238  size_t standard_types_len;
1239};
1240static const StandardType kStandardTypes[] = {
1241  { "image/", kStandardImageTypes, arraysize(kStandardImageTypes) },
1242  { "audio/", kStandardAudioTypes, arraysize(kStandardAudioTypes) },
1243  { "video/", kStandardVideoTypes, arraysize(kStandardVideoTypes) },
1244  { NULL, NULL, 0 }
1245};
1246
1247void GetExtensionsFromHardCodedMappings(
1248    const MimeInfo* mappings,
1249    size_t mappings_len,
1250    const std::string& leading_mime_type,
1251    base::hash_set<base::FilePath::StringType>* extensions) {
1252  base::FilePath::StringType extension;
1253  for (size_t i = 0; i < mappings_len; ++i) {
1254    if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
1255      std::vector<string> this_extensions;
1256      base::SplitString(mappings[i].extensions, ',', &this_extensions);
1257      for (size_t j = 0; j < this_extensions.size(); ++j) {
1258#if defined(OS_WIN)
1259        base::FilePath::StringType extension(
1260            base::UTF8ToWide(this_extensions[j]));
1261#else
1262        base::FilePath::StringType extension(this_extensions[j]);
1263#endif
1264        extensions->insert(extension);
1265      }
1266    }
1267  }
1268}
1269
1270void GetExtensionsHelper(
1271    const char* const* standard_types,
1272    size_t standard_types_len,
1273    const std::string& leading_mime_type,
1274    base::hash_set<base::FilePath::StringType>* extensions) {
1275  for (size_t i = 0; i < standard_types_len; ++i) {
1276    g_mime_util.Get().GetPlatformExtensionsForMimeType(standard_types[i],
1277                                                       extensions);
1278  }
1279
1280  // Also look up the extensions from hard-coded mappings in case that some
1281  // supported extensions are not registered in the system registry, like ogg.
1282  GetExtensionsFromHardCodedMappings(primary_mappings,
1283                                     arraysize(primary_mappings),
1284                                     leading_mime_type,
1285                                     extensions);
1286
1287  GetExtensionsFromHardCodedMappings(secondary_mappings,
1288                                     arraysize(secondary_mappings),
1289                                     leading_mime_type,
1290                                     extensions);
1291}
1292
1293// Note that the elements in the source set will be appended to the target
1294// vector.
1295template<class T>
1296void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
1297  size_t old_target_size = target->size();
1298  target->resize(old_target_size + source->size());
1299  size_t i = 0;
1300  for (typename base::hash_set<T>::iterator iter = source->begin();
1301       iter != source->end(); ++iter, ++i)
1302    (*target)[old_target_size + i] = *iter;
1303}
1304}
1305
1306void GetExtensionsForMimeType(
1307    const std::string& unsafe_mime_type,
1308    std::vector<base::FilePath::StringType>* extensions) {
1309  if (unsafe_mime_type == "*/*" || unsafe_mime_type == "*")
1310    return;
1311
1312  const std::string mime_type = base::StringToLowerASCII(unsafe_mime_type);
1313  base::hash_set<base::FilePath::StringType> unique_extensions;
1314
1315  if (EndsWith(mime_type, "/*", true)) {
1316    std::string leading_mime_type = mime_type.substr(0, mime_type.length() - 1);
1317
1318    // Find the matching StandardType from within kStandardTypes, or fall
1319    // through to the last (default) StandardType.
1320    const StandardType* type = NULL;
1321    for (size_t i = 0; i < arraysize(kStandardTypes); ++i) {
1322      type = &(kStandardTypes[i]);
1323      if (type->leading_mime_type &&
1324          leading_mime_type == type->leading_mime_type)
1325        break;
1326    }
1327    DCHECK(type);
1328    GetExtensionsHelper(type->standard_types,
1329                        type->standard_types_len,
1330                        leading_mime_type,
1331                        &unique_extensions);
1332  } else {
1333    g_mime_util.Get().GetPlatformExtensionsForMimeType(mime_type,
1334                                                       &unique_extensions);
1335
1336    // Also look up the extensions from hard-coded mappings in case that some
1337    // supported extensions are not registered in the system registry, like ogg.
1338    GetExtensionsFromHardCodedMappings(primary_mappings,
1339                                       arraysize(primary_mappings),
1340                                       mime_type,
1341                                       &unique_extensions);
1342
1343    GetExtensionsFromHardCodedMappings(secondary_mappings,
1344                                       arraysize(secondary_mappings),
1345                                       mime_type,
1346                                       &unique_extensions);
1347  }
1348
1349  HashSetToVector(&unique_extensions, extensions);
1350}
1351
1352void RemoveProprietaryMediaTypesAndCodecsForTests() {
1353  g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
1354}
1355
1356const std::string GetIANAMediaType(const std::string& mime_type) {
1357  for (size_t i = 0; i < arraysize(kIanaMediaTypes); ++i) {
1358    if (StartsWithASCII(mime_type, kIanaMediaTypes[i].matcher, true)) {
1359      return kIanaMediaTypes[i].name;
1360    }
1361  }
1362  return std::string();
1363}
1364
1365CertificateMimeType GetCertificateMimeTypeForMimeType(
1366    const std::string& mime_type) {
1367  // Don't create a map, there is only one entry in the table,
1368  // except on Android.
1369  for (size_t i = 0; i < arraysize(supported_certificate_types); ++i) {
1370    if (mime_type == net::supported_certificate_types[i].mime_type)
1371      return net::supported_certificate_types[i].cert_type;
1372  }
1373  return CERTIFICATE_MIME_TYPE_UNKNOWN;
1374}
1375
1376bool IsSupportedCertificateMimeType(const std::string& mime_type) {
1377  CertificateMimeType file_type =
1378      GetCertificateMimeTypeForMimeType(mime_type);
1379  return file_type != CERTIFICATE_MIME_TYPE_UNKNOWN;
1380}
1381
1382void AddMultipartValueForUpload(const std::string& value_name,
1383                                const std::string& value,
1384                                const std::string& mime_boundary,
1385                                const std::string& content_type,
1386                                std::string* post_data) {
1387  DCHECK(post_data);
1388  // First line is the boundary.
1389  post_data->append("--" + mime_boundary + "\r\n");
1390  // Next line is the Content-disposition.
1391  post_data->append("Content-Disposition: form-data; name=\"" +
1392                    value_name + "\"\r\n");
1393  if (!content_type.empty()) {
1394    // If Content-type is specified, the next line is that.
1395    post_data->append("Content-Type: " + content_type + "\r\n");
1396  }
1397  // Leave an empty line and append the value.
1398  post_data->append("\r\n" + value + "\r\n");
1399}
1400
1401void AddMultipartFinalDelimiterForUpload(const std::string& mime_boundary,
1402                                         std::string* post_data) {
1403  DCHECK(post_data);
1404  post_data->append("--" + mime_boundary + "--\r\n");
1405}
1406
1407}  // namespace net
1408