blob: 06f9b523783ee4f6e4bddb93eb4d8dc558b76e4d [file] [log] [blame]
// 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"
#include "net/base/mime_util.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/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