diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/mime_sniffer.cc | 44 | ||||
-rw-r--r-- | net/base/mime_sniffer_unittest.cc | 64 |
2 files changed, 107 insertions, 1 deletions
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc index 0a8bc57..07feb33 100644 --- a/net/base/mime_sniffer.cc +++ b/net/base/mime_sniffer.cc @@ -256,7 +256,7 @@ static bool CheckForMagicNumbers(const char* content, size_t size, Histogram* counter, std::string* result) { for (size_t i = 0; i < magic_len; ++i) { if (MatchMagicNumber(content, size, &(magic[i]), result)) { - counter->Add(static_cast<int>(i)); + if (counter) counter->Add(static_cast<int>(i)); return true; } } @@ -438,6 +438,43 @@ static bool IsUnknownMimeType(const std::string& mime_type) { return false; } +// Sniff a crx (chrome extension) file. +static bool SniffCRX(const char* content, size_t content_size, const GURL& url, + const std::string& type_hint, std::string* result) { + static SnifferHistogram counter("mime_sniffer.kSniffCRX", 3); + + // Technically, the crx magic number is just Cr24, but the bytes after that + // are a version number which changes infrequently. Including it in the + // sniffing gives us less room for error. If the version number ever changes, + // we can just add an entry to this list. + // + // TODO(aa): If we ever have another magic number, we'll want to pass a + // histogram into CheckForMagicNumbers(), below, to see which one matched. + const struct MagicNumber kCRXMagicNumbers[] = { + MAGIC_NUMBER("application/x-chrome-extension", "Cr24\x02\x00\x00\x00") + }; + + // Only consider files that have the extension ".crx". + const char kCRXExtension[] = ".crx"; + const int kExtensionLength = arraysize(kCRXExtension) - 1; // ignore null + if (url.path().rfind(kCRXExtension, std::string::npos, kExtensionLength) == + url.path().size() - kExtensionLength) { + counter.Add(1); + } else { + return false; + } + + if (CheckForMagicNumbers(content, content_size, + kCRXMagicNumbers, arraysize(kCRXMagicNumbers), + NULL, result)) { + counter.Add(2); + } else { + return false; + } + + return true; +} + bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { static SnifferHistogram should_sniff_counter( "mime_sniffer.ShouldSniffMimeType2", 3); @@ -535,6 +572,11 @@ bool SniffMimeType(const char* content, size_t content_size, return content_size >= kMaxBytesToSniff; } + // CRX files (chrome extensions) have a special sniffing algorithm. It is + // tighter than the others because we don't have to match legacy behavior. + if (SniffCRX(content, content_size, url, type_hint, result)) + return true; + // Now we look in our large table of magic numbers to see if we can find // anything that matches the content. if (SniffForMagicNumbers(content, content_size, result)) diff --git a/net/base/mime_sniffer_unittest.cc b/net/base/mime_sniffer_unittest.cc index 96eb441..ed1634c 100644 --- a/net/base/mime_sniffer_unittest.cc +++ b/net/base/mime_sniffer_unittest.cc @@ -90,6 +90,70 @@ TEST(MimeSnifferTest, BasicSniffingTest) { TestArray(tests, arraysize(tests)); } +TEST(MimeSnifferTest, ChromeExtensionsTest) { + SnifferTest tests[] = { + // schemes + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.crx", + "", "application/x-chrome-extension" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "https://www.example.com/foo.crx", + "", "application/x-chrome-extension" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "ftp://www.example.com/foo.crx", + "", "application/x-chrome-extension" }, + + // some other mimetypes that should get converted + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.crx", + "text/plain", "application/x-chrome-extension" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.crx", + "application/octet-stream", "application/x-chrome-extension" }, + + // success edge cases + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.crx?query=string", + "", "application/x-chrome-extension" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo..crx", + "", "application/x-chrome-extension" }, + + // wrong file extension + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.bin", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.bin?monkey", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "invalid-url", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foocrx", + "", "application/octet-stream" }, + { "Cr24\x02\x00\x00\x00", sizeof("Cr24\x02\x00\x00\x00")-1, + "http://www.example.com/foo.crx.blech", + "", "application/octet-stream" }, + + // wrong magic + { "Cr24\x02\x00\x00\x01", sizeof("Cr24\x02\x00\x00\x01")-1, + "http://www.example.com/foo.crx?monkey", + "", "application/octet-stream" }, + }; + + TestArray(tests, arraysize(tests)); +} + TEST(MimeSnifferTest, MozillaCompatibleTest) { SnifferTest tests[] = { { " \n <hTmL>\n <hea", sizeof(" \n <hTmL>\n <hea")-1, |