text: // Copyright 2015 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "components/mime_util/mime_util.h"
  
  #include <stddef.h>
  
  #include "base/containers/hash_tables.h"
  #include "base/lazy_instance.h"
  #include "base/macros.h"
  #include "base/strings/string_util.h"
  #include "build/build_config.h"
  
  #if !defined(OS_IOS)
  // iOS doesn't use and must not depend on //media
  #include "media/base/mime_util.h"
  #endif
  
  namespace mime_util {
  
  namespace {
  
  // From WebKit's WebCore/platform/MIMETypeRegistry.cpp:
  
  const char* const kSupportedImageTypes[] = {"image/jpeg",
                                              "image/pjpeg",
                                              "image/jpg",
                                              "image/webp",
                                              "image/png",
                                              "image/gif",
                                              "image/bmp",
                                              "image/vnd.microsoft.icon",  // ico
                                              "image/x-icon",              // ico
                                              "image/x-xbitmap",           // xbm
                                              "image/x-png"};
  
  //  Mozilla 1.8 and WinIE 7 both accept text/javascript and text/ecmascript.
  //  Mozilla 1.8 accepts application/javascript, application/ecmascript, and
  // application/x-javascript, but WinIE 7 doesn't.
  //  WinIE 7 accepts text/javascript1.1 - text/javascript1.3, text/jscript, and
  // text/livescript, but Mozilla 1.8 doesn't.
  //  Mozilla 1.8 allows leading and trailing whitespace, but WinIE 7 doesn't.
  //  Mozilla 1.8 and WinIE 7 both accept the empty string, but neither accept a
  // whitespace-only string.
  //  We want to accept all the values that either of these browsers accept, but
  // not other values.
  const char* const kSupportedJavascriptTypes[] = {"text/javascript",
                                                   "text/ecmascript",
                                                   "application/javascript",
                                                   "application/ecmascript",
                                                   "application/x-javascript",
                                                   "text/javascript1.1",
                                                   "text/javascript1.2",
                                                   "text/javascript1.3",
                                                   "text/jscript",
                                                   "text/livescript"};
  
  // These types are excluded from the logic that allows all text/ types because
  // while they are technically text, it's very unlikely that a user expects to
  // see them rendered in text form.
  static const char* const kUnsupportedTextTypes[] = {
      "text/calendar",
      "text/x-calendar",
      "text/x-vcalendar",
      "text/vcalendar",
      "text/vcard",
      "text/x-vcard",
      "text/directory",
      "text/ldif",
      "text/qif",
      "text/x-qif",
      "text/x-csv",
      "text/x-vcf",
      "text/rtf",
      "text/x-suse-ymp",                  // Added by Vivaldi (VB-6861)
      "text/comma-separated-values",
      "text/csv",
      "text/tab-separated-values",
      "text/tsv",
      "text/ofx",                         // http://crbug.com/162238
      "text/vnd.sun.j2me.app-descriptor"  // http://crbug.com/176450
  };
  
  // Note:
  // - does not include javascript types list (see supported_javascript_types)
  // - does not include types starting with "text/" (see
  //   IsSupportedNonImageMimeType())
  static const char* const kSupportedNonImageTypes[] = {
      "image/svg+xml",  // SVG is text-based XML, even though it has an image/
                        // type
      "application/xml",
      "application/atom+xml",
      "application/rss+xml",
      "application/xhtml+xml",
      "application/json",
      "multipart/related",  // For MHTML support.
      "multipart/x-mixed-replace"
      // Note: ADDING a new type here will probably render it AS HTML. This can
      // result in cross site scripting.
  };
  
  // Singleton utility class for mime types
  class MimeUtil {
   public:
    bool IsSupportedImageMimeType(const std::string& mime_type) const;
    bool IsSupportedNonImageMimeType(const std::string& mime_type) const;
    bool IsUnsupportedTextMimeType(const std::string& mime_type) const;
    bool IsSupportedJavascriptMimeType(const std::string& mime_type) const;
  
    bool IsSupportedMimeType(const std::string& mime_type) const;
  
   private:
    friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
  
    using MimeTypes = base::hash_set<std::string>;
  
    MimeUtil();
  
    MimeTypes image_types_;
    MimeTypes non_image_types_;
    MimeTypes unsupported_text_types_;
    MimeTypes javascript_types_;
  
    DISALLOW_COPY_AND_ASSIGN(MimeUtil);
  };
  
  MimeUtil::MimeUtil() {
    for (size_t i = 0; i < arraysize(kSupportedNonImageTypes); ++i)
      non_image_types_.insert(kSupportedNonImageTypes[i]);
    for (size_t i = 0; i < arraysize(kSupportedImageTypes); ++i)
      image_types_.insert(kSupportedImageTypes[i]);
    for (size_t i = 0; i < arraysize(kUnsupportedTextTypes); ++i)
      unsupported_text_types_.insert(kUnsupportedTextTypes[i]);
    for (size_t i = 0; i < arraysize(kSupportedJavascriptTypes); ++i) {
      javascript_types_.insert(kSupportedJavascriptTypes[i]);
      non_image_types_.insert(kSupportedJavascriptTypes[i]);
    }
  }
  
  bool MimeUtil::IsSupportedImageMimeType(const std::string& mime_type) const {
    return image_types_.find(base::ToLowerASCII(mime_type)) != image_types_.end();
  }
  
  bool MimeUtil::IsSupportedNonImageMimeType(const std::string& mime_type) const {
    return non_image_types_.find(base::ToLowerASCII(mime_type)) !=
               non_image_types_.end() ||
  #if !defined(OS_IOS)
           media::IsSupportedMediaMimeType(mime_type) ||
  #endif
           (base::StartsWith(mime_type, "text/",
                             base::CompareCase::INSENSITIVE_ASCII) &&
            !IsUnsupportedTextMimeType(mime_type)) ||
           (base::StartsWith(mime_type, "application/",
                             base::CompareCase::INSENSITIVE_ASCII) &&
            net::MatchesMimeType("application/*+json", mime_type));
  }
  
  bool MimeUtil::IsUnsupportedTextMimeType(const std::string& mime_type) const {
    return unsupported_text_types_.find(base::ToLowerASCII(mime_type)) !=
           unsupported_text_types_.end();
  }
  
  bool MimeUtil::IsSupportedJavascriptMimeType(
      const std::string& mime_type) const {
    return javascript_types_.find(mime_type) != javascript_types_.end();
  }
  
  bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
    return (base::StartsWith(mime_type, "image/",
                             base::CompareCase::INSENSITIVE_ASCII) &&
            IsSupportedImageMimeType(mime_type)) ||
           IsSupportedNonImageMimeType(mime_type);
  }
  
  // This variable is Leaky because it is accessed from WorkerPool threads.
  static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
      LAZY_INSTANCE_INITIALIZER;
  
  }  // namespace
  
  bool IsSupportedImageMimeType(const std::string& mime_type) {
    return g_mime_util.Get().IsSupportedImageMimeType(mime_type);
  }
  
  bool IsSupportedNonImageMimeType(const std::string& mime_type) {
    return g_mime_util.Get().IsSupportedNonImageMimeType(mime_type);
  }
  
  bool IsUnsupportedTextMimeType(const std::string& mime_type) {
    return g_mime_util.Get().IsUnsupportedTextMimeType(mime_type);
  }
  
  bool IsSupportedJavascriptMimeType(const std::string& mime_type) {
    return g_mime_util.Get().IsSupportedJavascriptMimeType(mime_type);
  }
  
  bool IsSupportedMimeType(const std::string& mime_type) {
    return g_mime_util.Get().IsSupportedMimeType(mime_type);
  }
  
  }  // namespace mime_util
  