Commit 9dade7b1 authored by Matt Menke's avatar Matt Menke Committed by Commit Bot

Add MIME sniffer overloads that take base::StringPieces, plumbing

StringPieces all the way through the MIME sniffing code.

This CL only updates net/ consumers to use the overloads, which are all
test-only code. I'll update consumers and remove the old methods in
another CL.

Bug: 1123179
Change-Id: I04328913fa1c7bfd9049fa7aaae6a8a538cbe8e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2382896
Commit-Queue: Matt Menke <mmenke@chromium.org>
Reviewed-by: default avatarEric Roman <eroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#803339}
parent 4b059f06
This diff is collapsed.
......@@ -9,6 +9,7 @@
#include <string>
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
class GURL;
......@@ -35,13 +36,12 @@ enum class ForceSniffFileUrlsForHtml {
// |mime_type| is the current mime type, e.g. from the Content-Type header.
// Returns true if the mime type should be sniffed.
NET_EXPORT bool ShouldSniffMimeType(const GURL& url,
const std::string& mime_type);
base::StringPiece mime_type);
// Guess a mime type from the first few bytes of content an its URL. Always
// assigns |result| with its best guess of a mime type.
//
// |content| is the buffer containing the bytes to sniff.
// |content_size| is the number of bytes in the |content| buffer.
// |content| contains the bytes to sniff.
// |url| is the URL from which the content was obtained.
// |type_hint| is the current mime type, e.g. from the Content-Type header.
// |result| is the address at which to place the sniffed mime type.
......@@ -52,6 +52,16 @@ NET_EXPORT bool ShouldSniffMimeType(const GURL& url,
// Returns true if |content| had enough data to guess the mime type. Otherwise,
// |result| will be populated with a putative MIME type, but the method should
// be called again with more of the content.
NET_EXPORT bool SniffMimeType(
base::StringPiece content,
const GURL& url,
const std::string& type_hint,
ForceSniffFileUrlsForHtml force_sniff_file_url_for_html,
std::string* result);
// Older deprecated version of the above function.
//
// TODO(https://crbug.com/1123179): Update callers and remove this method.
NET_EXPORT bool SniffMimeType(
const char* content,
size_t content_size,
......@@ -68,20 +78,22 @@ NET_EXPORT bool SniffMimeType(
// The caller should understand the security ramifications of trusting
// uncontrolled data before accepting the results of this function.
//
// @param content A buffer containing the bytes to sniff.
// @param content_size The number of bytes in the |content| buffer.
// @param result Address at which to place the sniffed mime type.
// @return Returns true if a MIME type match was found.
// |content| contains the bytes to sniff.
// |result| is address at which to place the sniffed mime type.
// Returns true if a MIME type match was found.
NET_EXPORT bool SniffMimeTypeFromLocalData(base::StringPiece content,
std::string* result);
// Older deprecated version of the above function.
//
// TODO(https://crbug.com/1123179): Update callers and remove this method.
NET_EXPORT bool SniffMimeTypeFromLocalData(const char* content,
size_t content_size,
std::string* result);
// Returns true if |content| contains bytes that are control codes that do
// not usually appear in plain text.
// @param content A buffer contains bytes that may be binary.
// @param size The number of bytes in the |content| buffer.
// @return Returns true if |content| looks like binary.
NET_EXPORT_PRIVATE bool LooksLikeBinary(const char* content, size_t size);
NET_EXPORT_PRIVATE bool LooksLikeBinary(base::StringPiece content);
} // namespace net
......
......@@ -44,10 +44,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::string input = data_provider.ConsumeRemainingBytesAsString();
std::string result;
net::SniffMimeType(input.data(), input.length(), GURL(url_string),
mime_type_hint, force_sniff_file_urls_for_html, &result);
net::SniffMimeType(input, GURL(url_string), mime_type_hint,
force_sniff_file_urls_for_html, &result);
net::SniffMimeTypeFromLocalData(input.data(), input.length(), &result);
net::SniffMimeTypeFromLocalData(input, &result);
return 0;
}
......@@ -72,7 +72,7 @@ const char kRepresentativePlainText[] =
void RunLooksLikeBinary(const std::string& plaintext, size_t iterations) {
bool looks_like_binary = false;
for (size_t i = 0; i < iterations; ++i) {
if (LooksLikeBinary(plaintext.data(), plaintext.size()))
if (LooksLikeBinary(plaintext))
looks_like_binary = true;
}
CHECK(!looks_like_binary);
......
......@@ -24,11 +24,11 @@ std::string MakeConstantString(const char (&str)[N]) {
return std::string(str, N - 1);
}
static std::string SniffMimeType(const std::string& content,
static std::string SniffMimeType(base::StringPiece content,
const std::string& url,
const std::string& mime_type_hint) {
std::string mime_type;
SniffMimeType(content.data(), content.size(), GURL(url), mime_type_hint,
SniffMimeType(content, GURL(url), mime_type_hint,
ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
return mime_type;
}
......@@ -74,14 +74,14 @@ TEST(MimeSnifferTest, BoundaryConditionsTest) {
GURL url;
SniffMimeType(buf, 0, url, type_hint, ForceSniffFileUrlsForHtml::kDisabled,
&mime_type);
SniffMimeType(base::StringPiece(), url, type_hint,
ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
EXPECT_EQ("text/plain", mime_type);
SniffMimeType(buf, 1, url, type_hint, ForceSniffFileUrlsForHtml::kDisabled,
&mime_type);
SniffMimeType(base::StringPiece(buf, 1), url, type_hint,
ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
EXPECT_EQ("text/plain", mime_type);
SniffMimeType(buf, 2, url, type_hint, ForceSniffFileUrlsForHtml::kDisabled,
&mime_type);
SniffMimeType(base::StringPiece(buf, 2), url, type_hint,
ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
EXPECT_EQ("application/octet-stream", mime_type);
}
......@@ -256,11 +256,11 @@ TEST(MimeSnifferTest, SniffFilesAsHtml) {
const GURL kUrl("file:///C/test.unusualextension");
std::string mime_type;
SniffMimeType(kContent.c_str(), kContent.length(), kUrl, "" /* type_hint */,
SniffMimeType(kContent, kUrl, "" /* type_hint */,
ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
EXPECT_EQ("text/plain", mime_type);
SniffMimeType(kContent.c_str(), kContent.length(), kUrl, "" /* type_hint */,
SniffMimeType(kContent, kUrl, "" /* type_hint */,
ForceSniffFileUrlsForHtml::kEnabled, &mime_type);
EXPECT_EQ("text/html", mime_type);
}
......@@ -371,7 +371,7 @@ TEST(MimeSnifferTest, XMLTestLargeNoAngledBracket) {
// content.size() >= 1024 so the sniff is unambiguous.
std::string mime_type;
EXPECT_TRUE(SniffMimeType(content.data(), content.size(), GURL(), "text/xml",
EXPECT_TRUE(SniffMimeType(content, GURL(), "text/xml",
ForceSniffFileUrlsForHtml::kDisabled, &mime_type));
EXPECT_EQ("text/xml", mime_type);
}
......@@ -387,9 +387,8 @@ TEST(MimeSnifferTest, LooksBinary) {
// content.size() >= 1024 so the sniff is unambiguous.
std::string mime_type;
EXPECT_TRUE(SniffMimeType(content.data(), content.size(), GURL(),
"text/plain", ForceSniffFileUrlsForHtml::kDisabled,
&mime_type));
EXPECT_TRUE(SniffMimeType(content, GURL(), "text/plain",
ForceSniffFileUrlsForHtml::kDisabled, &mime_type));
EXPECT_EQ("application/octet-stream", mime_type);
}
......@@ -450,27 +449,27 @@ TEST(MimeSnifferTest, OfficeTest) {
TEST(MimeSnifferTest, AudioVideoTest) {
std::string mime_type;
const char kOggTestData[] = "OggS\x00";
EXPECT_TRUE(SniffMimeTypeFromLocalData(kOggTestData, sizeof(kOggTestData) - 1,
&mime_type));
EXPECT_TRUE(SniffMimeTypeFromLocalData(
base::StringPiece(kOggTestData, sizeof(kOggTestData) - 1), &mime_type));
EXPECT_EQ("audio/ogg", mime_type);
mime_type.clear();
// Check ogg header requires the terminal '\0' to be sniffed.
EXPECT_FALSE(SniffMimeTypeFromLocalData(
kOggTestData, sizeof(kOggTestData) - 2, &mime_type));
base::StringPiece(kOggTestData, sizeof(kOggTestData) - 2), &mime_type));
EXPECT_EQ("", mime_type);
mime_type.clear();
const char kFlacTestData[] =
"fLaC\x00\x00\x00\x22\x12\x00\x12\x00\x00\x00\x00\x00";
EXPECT_TRUE(SniffMimeTypeFromLocalData(
kFlacTestData, sizeof(kFlacTestData) - 1, &mime_type));
base::StringPiece(kFlacTestData, sizeof(kFlacTestData) - 1), &mime_type));
EXPECT_EQ("audio/x-flac", mime_type);
mime_type.clear();
const char kWMATestData[] =
"\x30\x26\xb2\x75\x8e\x66\xcf\x11\xa6\xd9\x00\xaa\x00\x62\xce\x6c";
EXPECT_TRUE(SniffMimeTypeFromLocalData(kWMATestData, sizeof(kWMATestData) - 1,
&mime_type));
EXPECT_TRUE(SniffMimeTypeFromLocalData(
base::StringPiece(kWMATestData, sizeof(kWMATestData) - 1), &mime_type));
EXPECT_EQ("video/x-ms-asf", mime_type);
mime_type.clear();
......@@ -478,22 +477,22 @@ TEST(MimeSnifferTest, AudioVideoTest) {
// format.
const char kMP4TestData[] =
"\x00\x00\x00\x20\x66\x74\x79\x70\x4d\x34\x41\x20\x00\x00\x00\x00";
EXPECT_TRUE(SniffMimeTypeFromLocalData(kMP4TestData, sizeof(kMP4TestData) - 1,
&mime_type));
EXPECT_TRUE(SniffMimeTypeFromLocalData(
base::StringPiece(kMP4TestData, sizeof(kMP4TestData) - 1), &mime_type));
EXPECT_EQ("video/mp4", mime_type);
mime_type.clear();
const char kAACTestData[] =
"\xff\xf1\x50\x80\x02\x20\xb0\x23\x0a\x83\x20\x7d\x61\x90\x3e\xb1";
EXPECT_TRUE(SniffMimeTypeFromLocalData(kAACTestData, sizeof(kAACTestData) - 1,
&mime_type));
EXPECT_TRUE(SniffMimeTypeFromLocalData(
base::StringPiece(kAACTestData, sizeof(kAACTestData) - 1), &mime_type));
EXPECT_EQ("audio/mpeg", mime_type);
mime_type.clear();
const char kAMRTestData[] =
"\x23\x21\x41\x4d\x52\x0a\x3c\x53\x0a\x7c\xe8\xb8\x41\xa5\x80\xca";
EXPECT_TRUE(SniffMimeTypeFromLocalData(kAMRTestData, sizeof(kAMRTestData) - 1,
&mime_type));
EXPECT_TRUE(SniffMimeTypeFromLocalData(
base::StringPiece(kAMRTestData, sizeof(kAMRTestData) - 1), &mime_type));
EXPECT_EQ("audio/amr", mime_type);
mime_type.clear();
}
......@@ -502,19 +501,22 @@ TEST(MimeSnifferTest, ImageTest) {
std::string mime_type;
const char kWebPSimpleFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8 ";
EXPECT_TRUE(SniffMimeTypeFromLocalData(
kWebPSimpleFormat, sizeof(kWebPSimpleFormat) - 1, &mime_type));
base::StringPiece(kWebPSimpleFormat, sizeof(kWebPSimpleFormat) - 1),
&mime_type));
EXPECT_EQ("image/webp", mime_type);
mime_type.clear();
const char kWebPLosslessFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8L";
EXPECT_TRUE(SniffMimeTypeFromLocalData(
kWebPLosslessFormat, sizeof(kWebPLosslessFormat) - 1, &mime_type));
base::StringPiece(kWebPLosslessFormat, sizeof(kWebPLosslessFormat) - 1),
&mime_type));
EXPECT_EQ("image/webp", mime_type);
mime_type.clear();
const char kWebPExtendedFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8X";
EXPECT_TRUE(SniffMimeTypeFromLocalData(
kWebPExtendedFormat, sizeof(kWebPExtendedFormat) - 1, &mime_type));
base::StringPiece(kWebPExtendedFormat, sizeof(kWebPExtendedFormat) - 1),
&mime_type));
EXPECT_EQ("image/webp", mime_type);
mime_type.clear();
}
......@@ -529,8 +531,8 @@ class MimeSnifferBinaryTest : public ::testing::TestWithParam<int> {};
// 0x0B (VT), a byte in the range 0x0E to 0x1A (SO to SUB), or a byte in the
// range 0x1C to 0x1F (FS to US).
TEST_P(MimeSnifferBinaryTest, IsBinaryControlCode) {
char param = static_cast<char>(GetParam());
EXPECT_TRUE(LooksLikeBinary(&param, 1));
std::string param(1, static_cast<char>(GetParam()));
EXPECT_TRUE(LooksLikeBinary(param));
}
// ::testing::Range(a, b) tests an open-ended range, ie. "b" is not included.
......@@ -553,8 +555,8 @@ INSTANTIATE_TEST_SUITE_P(MimeSnifferBinaryTestRange3,
class MimeSnifferPlainTextTest : public ::testing::TestWithParam<int> {};
TEST_P(MimeSnifferPlainTextTest, NotBinaryControlCode) {
char param = static_cast<char>(GetParam());
EXPECT_FALSE(LooksLikeBinary(&param, 1));
std::string param(1, static_cast<char>(GetParam()));
EXPECT_FALSE(LooksLikeBinary(param));
}
INSTANTIATE_TEST_SUITE_P(MimeSnifferPlainTextTestPlainTextControlCodes,
......@@ -569,8 +571,7 @@ class MimeSnifferControlCodesEdgeCaseTest
: public ::testing::TestWithParam<const char*> {};
TEST_P(MimeSnifferControlCodesEdgeCaseTest, EdgeCase) {
const char* param = GetParam();
EXPECT_TRUE(LooksLikeBinary(param, strlen(param)));
EXPECT_TRUE(LooksLikeBinary(GetParam()));
}
INSTANTIATE_TEST_SUITE_P(MimeSnifferControlCodesEdgeCaseTest,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment