xref: /aosp_15_r20/external/cronet/net/base/mime_sniffer_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 The Chromium Authors
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 "net/base/mime_sniffer.h"
6 
7 #include "build/build_config.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "url/gurl.h"
10 #include "url/url_constants.h"
11 
12 namespace net {
13 namespace {
14 
15 using ::testing::Range;
16 using ::testing::Values;
17 using ::net::SniffMimeType;  // It is shadowed by SniffMimeType(), below.
18 
19 // Turn |str|, a constant string with one or more embedded NULs, along with
20 // a NUL terminator, into an std::string() containing just that data.
21 // Turn |str|, a string with one or more embedded NULs, into an std::string()
22 template <size_t N>
MakeConstantString(const char (& str)[N])23 std::string MakeConstantString(const char (&str)[N]) {
24   return std::string(str, N - 1);
25 }
26 
SniffMimeType(std::string_view content,const std::string & url,const std::string & mime_type_hint)27 static std::string SniffMimeType(std::string_view content,
28                                  const std::string& url,
29                                  const std::string& mime_type_hint) {
30   std::string mime_type;
31   SniffMimeType(content, GURL(url), mime_type_hint,
32                 ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
33   return mime_type;
34 }
35 
TEST(MimeSnifferTest,SniffableSchemes)36 TEST(MimeSnifferTest, SniffableSchemes) {
37   struct {
38     const char* scheme;
39     bool sniffable;
40   } kTestCases[] = {
41     {url::kAboutScheme, false},
42     {url::kBlobScheme, false},
43 #if BUILDFLAG(IS_ANDROID)
44     {url::kContentScheme, true},
45 #else
46     {url::kContentScheme, false},
47 #endif
48     {url::kContentIDScheme, false},
49     {url::kDataScheme, false},
50     {url::kFileScheme, true},
51     {url::kFileSystemScheme, true},
52     {url::kFtpScheme, false},
53     {url::kHttpScheme, true},
54     {url::kHttpsScheme, true},
55     {url::kJavaScriptScheme, false},
56     {url::kMailToScheme, false},
57     {url::kWsScheme, false},
58     {url::kWssScheme, false}
59   };
60 
61   for (const auto test_case : kTestCases) {
62     GURL url(std::string(test_case.scheme) + "://host/path/whatever");
63     EXPECT_EQ(test_case.sniffable, ShouldSniffMimeType(url, ""));
64   }
65 }
66 
TEST(MimeSnifferTest,BoundaryConditionsTest)67 TEST(MimeSnifferTest, BoundaryConditionsTest) {
68   std::string mime_type;
69   std::string type_hint;
70 
71   char buf[] = {
72     'd', '\x1f', '\xFF'
73   };
74 
75   GURL url;
76 
77   SniffMimeType(std::string_view(), url, type_hint,
78                 ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
79   EXPECT_EQ("text/plain", mime_type);
80   SniffMimeType(std::string_view(buf, 1), url, type_hint,
81                 ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
82   EXPECT_EQ("text/plain", mime_type);
83   SniffMimeType(std::string_view(buf, 2), url, type_hint,
84                 ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
85   EXPECT_EQ("application/octet-stream", mime_type);
86 }
87 
TEST(MimeSnifferTest,BasicSniffingTest)88 TEST(MimeSnifferTest, BasicSniffingTest) {
89   EXPECT_EQ("text/html",
90             SniffMimeType(MakeConstantString("<!DOCTYPE html PUBLIC"),
91                           "http://www.example.com/", ""));
92   EXPECT_EQ("application/octet-stream",
93             SniffMimeType(MakeConstantString("<HtMl><Body></body></htMl>"),
94                           "http://www.example.com/foo.gif",
95                           "application/octet-stream"));
96   EXPECT_EQ("image/gif",
97             SniffMimeType(MakeConstantString("GIF89a\x1F\x83\x94"),
98                           "http://www.example.com/foo", "text/plain"));
99   EXPECT_EQ("application/octet-stream",
100             SniffMimeType(MakeConstantString("Gif87a\x1F\x83\x94"),
101                           "http://www.example.com/foo?param=tt.gif", ""));
102   EXPECT_EQ("text/plain",
103             SniffMimeType(MakeConstantString("%!PS-Adobe-3.0"),
104                           "http://www.example.com/foo", "text/plain"));
105   EXPECT_EQ(
106       "application/octet-stream",
107       SniffMimeType(MakeConstantString("\x89"
108                                        "PNG\x0D\x0A\x1A\x0A"),
109                     "http://www.example.com/foo", "application/octet-stream"));
110   EXPECT_EQ("image/jpeg",
111             SniffMimeType(MakeConstantString("\xFF\xD8\xFF\x23\x49\xAF"),
112                           "http://www.example.com/foo", ""));
113 }
114 
TEST(MimeSnifferTest,ChromeExtensionsTest)115 TEST(MimeSnifferTest, ChromeExtensionsTest) {
116   // schemes
117   EXPECT_EQ("application/x-chrome-extension",
118             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
119                           "http://www.example.com/foo.crx", ""));
120   EXPECT_EQ("application/x-chrome-extension",
121             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
122                           "https://www.example.com/foo.crx", ""));
123   EXPECT_EQ("application/x-chrome-extension",
124             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
125                           "ftp://www.example.com/foo.crx", ""));
126 
127   // some other mimetypes that should get converted
128   EXPECT_EQ("application/x-chrome-extension",
129             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
130                           "http://www.example.com/foo.crx", "text/plain"));
131   EXPECT_EQ("application/x-chrome-extension",
132             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
133                           "http://www.example.com/foo.crx",
134                           "application/octet-stream"));
135 
136   // success edge cases
137   EXPECT_EQ("application/x-chrome-extension",
138             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
139                           "http://www.example.com/foo.crx?query=string", ""));
140   EXPECT_EQ("application/x-chrome-extension",
141             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
142                           "http://www.example.com/foo..crx", ""));
143   EXPECT_EQ("application/x-chrome-extension",
144             SniffMimeType(MakeConstantString("Cr24\x03\x00\x00\x00"),
145                           "http://www.example.com/foo..crx", ""));
146 
147   // wrong file extension
148   EXPECT_EQ("application/octet-stream",
149             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
150                           "http://www.example.com/foo.bin", ""));
151   EXPECT_EQ("application/octet-stream",
152             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
153                           "http://www.example.com/foo.bin?monkey", ""));
154   EXPECT_EQ("application/octet-stream",
155             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
156                           "invalid-url", ""));
157   EXPECT_EQ("application/octet-stream",
158             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
159                           "http://www.example.com", ""));
160   EXPECT_EQ("application/octet-stream",
161             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
162                           "http://www.example.com/", ""));
163   EXPECT_EQ("application/octet-stream",
164             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
165                           "http://www.example.com/foo", ""));
166   EXPECT_EQ("application/octet-stream",
167             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
168                           "http://www.example.com/foocrx", ""));
169   EXPECT_EQ("application/octet-stream",
170             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x00"),
171                           "http://www.example.com/foo.crx.blech", ""));
172 
173   // wrong magic
174   EXPECT_EQ("application/octet-stream",
175             SniffMimeType(MakeConstantString("Cr24\x02\x00\x00\x01"),
176                           "http://www.example.com/foo.crx?monkey", ""));
177   EXPECT_EQ("application/octet-stream",
178             SniffMimeType(MakeConstantString("PADDING_Cr24\x02\x00\x00\x00"),
179                           "http://www.example.com/foo.crx?monkey", ""));
180 }
181 
TEST(MimeSnifferTest,MozillaCompatibleTest)182 TEST(MimeSnifferTest, MozillaCompatibleTest) {
183   EXPECT_EQ("text/html", SniffMimeType(MakeConstantString(" \n <hTmL>\n <hea"),
184                                        "http://www.example.com/", ""));
185   EXPECT_EQ("text/plain",
186             SniffMimeType(MakeConstantString(" \n <hTmL>\n <hea"),
187                           "http://www.example.com/", "text/plain"));
188   EXPECT_EQ("image/bmp", SniffMimeType(MakeConstantString("BMjlakdsfk"),
189                                        "http://www.example.com/foo", ""));
190   EXPECT_EQ("application/octet-stream",
191             SniffMimeType(MakeConstantString("\x00\x00\x30\x00"),
192                           "http://www.example.com/favicon.ico", ""));
193   EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("#!/bin/sh\nls /\n"),
194                                         "http://www.example.com/foo", ""));
195   EXPECT_EQ("text/plain",
196             SniffMimeType(MakeConstantString("From: Fred\nTo: Bob\n\nHi\n.\n"),
197                           "http://www.example.com/foo", ""));
198   EXPECT_EQ("text/xml",
199             SniffMimeType(MakeConstantString(
200                               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"),
201                           "http://www.example.com/foo", ""));
202   EXPECT_EQ(
203       "application/octet-stream",
204       SniffMimeType(
205           MakeConstantString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"),
206           "http://www.example.com/foo", "application/octet-stream"));
207 }
208 
TEST(MimeSnifferTest,DontAllowPrivilegeEscalationTest)209 TEST(MimeSnifferTest, DontAllowPrivilegeEscalationTest) {
210   EXPECT_EQ(
211       "image/gif",
212       SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
213                                        "<script>alert('haxorzed');\n</script>"
214                                        "</body></html>\n"),
215                     "http://www.example.com/foo", ""));
216   EXPECT_EQ(
217       "image/gif",
218       SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
219                                        "<script>alert('haxorzed');\n</script>"
220                                        "</body></html>\n"),
221                     "http://www.example.com/foo?q=ttt.html", ""));
222   EXPECT_EQ(
223       "image/gif",
224       SniffMimeType(MakeConstantString("GIF87a\n<html>\n<body>"
225                                        "<script>alert('haxorzed');\n</script>"
226                                        "</body></html>\n"),
227                     "http://www.example.com/foo#ttt.html", ""));
228   EXPECT_EQ(
229       "text/plain",
230       SniffMimeType(MakeConstantString("a\n<html>\n<body>"
231                                        "<script>alert('haxorzed');\n</script>"
232                                        "</body></html>\n"),
233                     "http://www.example.com/foo", ""));
234   EXPECT_EQ(
235       "text/plain",
236       SniffMimeType(MakeConstantString("a\n<html>\n<body>"
237                                        "<script>alert('haxorzed');\n</script>"
238                                        "</body></html>\n"),
239                     "http://www.example.com/foo?q=ttt.html", ""));
240   EXPECT_EQ(
241       "text/plain",
242       SniffMimeType(MakeConstantString("a\n<html>\n<body>"
243                                        "<script>alert('haxorzed');\n</script>"
244                                        "</body></html>\n"),
245                     "http://www.example.com/foo#ttt.html", ""));
246   EXPECT_EQ(
247       "text/plain",
248       SniffMimeType(MakeConstantString("a\n<html>\n<body>"
249                                        "<script>alert('haxorzed');\n</script>"
250                                        "</body></html>\n"),
251                     "http://www.example.com/foo.html", ""));
252 }
253 
TEST(MimeSnifferTest,SniffFilesAsHtml)254 TEST(MimeSnifferTest, SniffFilesAsHtml) {
255   const std::string kContent = "<html><body>text</body></html>";
256   const GURL kUrl("file:///C/test.unusualextension");
257 
258   std::string mime_type;
259   SniffMimeType(kContent, kUrl, "" /* type_hint */,
260                 ForceSniffFileUrlsForHtml::kDisabled, &mime_type);
261   EXPECT_EQ("text/plain", mime_type);
262 
263   SniffMimeType(kContent, kUrl, "" /* type_hint */,
264                 ForceSniffFileUrlsForHtml::kEnabled, &mime_type);
265   EXPECT_EQ("text/html", mime_type);
266 }
267 
TEST(MimeSnifferTest,UnicodeTest)268 TEST(MimeSnifferTest, UnicodeTest) {
269   EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("\xEF\xBB\xBF"
270                                                            "Hi there"),
271                                         "http://www.example.com/foo", ""));
272   EXPECT_EQ(
273       "text/plain",
274       SniffMimeType(MakeConstantString("\xEF\xBB\xBF\xED\x7A\xAD\x7A\x0D\x79"),
275                     "http://www.example.com/foo", ""));
276   EXPECT_EQ(
277       "text/plain",
278       SniffMimeType(MakeConstantString(
279                         "\xFE\xFF\xD0\xA5\xD0\xBE\xD0\xBB\xD1\x83\xD0\xB9"),
280                     "http://www.example.com/foo", ""));
281   EXPECT_EQ("text/plain",
282             SniffMimeType(
283                 MakeConstantString(
284                     "\xFE\xFF\x00\x41\x00\x20\xD8\x00\xDC\x00\xD8\x00\xDC\x01"),
285                 "http://www.example.com/foo", ""));
286 }
287 
TEST(MimeSnifferTest,FlashTest)288 TEST(MimeSnifferTest, FlashTest) {
289   EXPECT_EQ("application/octet-stream",
290             SniffMimeType(MakeConstantString("CWSdd\x00\xB3"),
291                           "http://www.example.com/foo", ""));
292   EXPECT_EQ("application/octet-stream",
293             SniffMimeType(MakeConstantString("FLVjdkl*(#)0sdj\x00"),
294                           "http://www.example.com/foo?q=ttt.swf", ""));
295   EXPECT_EQ("application/octet-stream",
296             SniffMimeType(MakeConstantString("FWS3$9\r\b\x00"),
297                           "http://www.example.com/foo#ttt.swf", ""));
298   EXPECT_EQ("text/plain", SniffMimeType(MakeConstantString("FLVjdkl*(#)0sdj"),
299                                         "http://www.example.com/foo.swf", ""));
300   EXPECT_EQ("application/octet-stream",
301             SniffMimeType(MakeConstantString("FLVjdkl*(#)0s\x01dj"),
302                           "http://www.example.com/foo/bar.swf", ""));
303   EXPECT_EQ("application/octet-stream",
304             SniffMimeType(MakeConstantString("FWS3$9\r\b\x1A"),
305                           "http://www.example.com/foo.swf?clickTAG=http://"
306                           "www.adnetwork.com/bar",
307                           ""));
308   EXPECT_EQ("application/octet-stream",
309             SniffMimeType(MakeConstantString("FWS3$9\r\x1C\b"),
310                           "http://www.example.com/foo.swf?clickTAG=http://"
311                           "www.adnetwork.com/bar",
312                           "text/plain"));
313 }
314 
TEST(MimeSnifferTest,XMLTest)315 TEST(MimeSnifferTest, XMLTest) {
316   // An easy feed to identify.
317   EXPECT_EQ("application/atom+xml",
318             SniffMimeType("<?xml?><feed", "", "text/xml"));
319   // Don't sniff out of plain text.
320   EXPECT_EQ("text/plain", SniffMimeType("<?xml?><feed", "", "text/plain"));
321   // Simple RSS.
322   EXPECT_EQ("application/rss+xml",
323             SniffMimeType("<?xml version='1.0'?>\r\n<rss", "", "text/xml"));
324 
325   // The top of CNN's RSS feed, which we'd like to recognize as RSS.
326   static const char kCNNRSS[] =
327       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
328       "<?xml-stylesheet href=\"http://rss.cnn.com/~d/styles/rss2full.xsl\" "
329       "type=\"text/xsl\" media=\"screen\"?>"
330       "<?xml-stylesheet href=\"http://rss.cnn.com/~d/styles/itemcontent.css\" "
331       "type=\"text/css\" media=\"screen\"?>"
332       "<rss xmlns:feedburner=\"http://rssnamespace.org/feedburner/ext/1.0\" "
333       "version=\"2.0\">";
334   // CNN's RSS
335   EXPECT_EQ("application/rss+xml", SniffMimeType(kCNNRSS, "", "text/xml"));
336   EXPECT_EQ("text/plain", SniffMimeType(kCNNRSS, "", "text/plain"));
337 
338   // Don't sniff random XML as something different.
339   EXPECT_EQ("text/xml", SniffMimeType("<?xml?><notafeed", "", "text/xml"));
340   // Don't sniff random plain-text as something different.
341   EXPECT_EQ("text/plain", SniffMimeType("<?xml?><notafeed", "", "text/plain"));
342 
343   // We never upgrade to application/xhtml+xml.
344   EXPECT_EQ("text/xml",
345             SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
346                           "text/xml"));
347   EXPECT_EQ("application/xml",
348             SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
349                           "application/xml"));
350   EXPECT_EQ("text/plain",
351             SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
352                           "text/plain"));
353   EXPECT_EQ("application/rss+xml",
354             SniffMimeType("<html xmlns=\"http://www.w3.org/1999/xhtml\">", "",
355                           "application/rss+xml"));
356   EXPECT_EQ("text/xml", SniffMimeType("<html><head>", "", "text/xml"));
357   EXPECT_EQ("text/xml",
358             SniffMimeType("<foo><rss "
359                           "xmlns:feedburner=\"http://rssnamespace.org/"
360                           "feedburner/ext/1.0\" version=\"2.0\">",
361                           "", "text/xml"));
362 }
363 
364 // Test content which is >= 1024 bytes, and includes no open angle bracket.
365 // http://code.google.com/p/chromium/issues/detail?id=3521
TEST(MimeSnifferTest,XMLTestLargeNoAngledBracket)366 TEST(MimeSnifferTest, XMLTestLargeNoAngledBracket) {
367   // Make a large input, with 1024 bytes of "x".
368   std::string content;
369   content.resize(1024);
370   std::fill(content.begin(), content.end(), 'x');
371 
372   // content.size() >= 1024 so the sniff is unambiguous.
373   std::string mime_type;
374   EXPECT_TRUE(SniffMimeType(content, GURL(), "text/xml",
375                             ForceSniffFileUrlsForHtml::kDisabled, &mime_type));
376   EXPECT_EQ("text/xml", mime_type);
377 }
378 
379 // Test content which is >= 1024 bytes, and includes a binary looking byte.
380 // http://code.google.com/p/chromium/issues/detail?id=15314
TEST(MimeSnifferTest,LooksBinary)381 TEST(MimeSnifferTest, LooksBinary) {
382   // Make a large input, with 1024 bytes of "x" and 1 byte of 0x01.
383   std::string content;
384   content.resize(1024);
385   std::fill(content.begin(), content.end(), 'x');
386   content[1000] = 0x01;
387 
388   // content.size() >= 1024 so the sniff is unambiguous.
389   std::string mime_type;
390   EXPECT_TRUE(SniffMimeType(content, GURL(), "text/plain",
391                             ForceSniffFileUrlsForHtml::kDisabled, &mime_type));
392   EXPECT_EQ("application/octet-stream", mime_type);
393 }
394 
TEST(MimeSnifferTest,OfficeTest)395 TEST(MimeSnifferTest, OfficeTest) {
396     // Check for URLs incorrectly reported as Microsoft Office files.
397     EXPECT_EQ(
398         "application/octet-stream",
399         SniffMimeType(MakeConstantString("Hi there"),
400                       "http://www.example.com/foo.doc", "application/msword"));
401     EXPECT_EQ("application/octet-stream",
402               SniffMimeType(MakeConstantString("Hi there"),
403                             "http://www.example.com/foo.xls",
404                             "application/vnd.ms-excel"));
405     EXPECT_EQ("application/octet-stream",
406               SniffMimeType(MakeConstantString("Hi there"),
407                             "http://www.example.com/foo.ppt",
408                             "application/vnd.ms-powerpoint"));
409     // Check for Microsoft Office files incorrectly reported as text.
410     EXPECT_EQ(
411         "application/msword",
412         SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
413                                          "Hi there"),
414                       "http://www.example.com/foo.doc", "text/plain"));
415     EXPECT_EQ(
416         "application/vnd.openxmlformats-officedocument."
417         "wordprocessingml.document",
418         SniffMimeType(MakeConstantString(
419 
420                           "PK\x03\x04"
421                           "Hi there"),
422                       "http://www.example.com/foo.doc", "text/plain"));
423     EXPECT_EQ(
424         "application/vnd.ms-excel",
425         SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
426                                          "Hi there"),
427                       "http://www.example.com/foo.xls", "text/plain"));
428     EXPECT_EQ(
429         "application/vnd.openxmlformats-officedocument."
430         "spreadsheetml.sheet",
431         SniffMimeType(MakeConstantString("PK\x03\x04"
432                                          "Hi there"),
433                       "http://www.example.com/foo.xls", "text/plain"));
434     EXPECT_EQ(
435         "application/vnd.ms-powerpoint",
436         SniffMimeType(MakeConstantString("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
437                                          "Hi there"),
438                       "http://www.example.com/foo.ppt", "text/plain"));
439     EXPECT_EQ(
440         "application/vnd.openxmlformats-officedocument."
441         "presentationml.presentation",
442         SniffMimeType(MakeConstantString("PK\x03\x04"
443                                          "Hi there"),
444                       "http://www.example.com/foo.ppt", "text/plain"));
445 }
446 
TEST(MimeSnifferTest,AudioVideoTest)447 TEST(MimeSnifferTest, AudioVideoTest) {
448   std::string mime_type;
449   const char kOggTestData[] = "OggS\x00";
450   EXPECT_TRUE(SniffMimeTypeFromLocalData(
451       std::string_view(kOggTestData, sizeof(kOggTestData) - 1), &mime_type));
452   EXPECT_EQ("audio/ogg", mime_type);
453   mime_type.clear();
454   // Check ogg header requires the terminal '\0' to be sniffed.
455   EXPECT_FALSE(SniffMimeTypeFromLocalData(
456       std::string_view(kOggTestData, sizeof(kOggTestData) - 2), &mime_type));
457   EXPECT_EQ("", mime_type);
458   mime_type.clear();
459 
460   const char kFlacTestData[] =
461       "fLaC\x00\x00\x00\x22\x12\x00\x12\x00\x00\x00\x00\x00";
462   EXPECT_TRUE(SniffMimeTypeFromLocalData(
463       std::string_view(kFlacTestData, sizeof(kFlacTestData) - 1), &mime_type));
464   EXPECT_EQ("audio/x-flac", mime_type);
465   mime_type.clear();
466 
467   const char kWMATestData[] =
468       "\x30\x26\xb2\x75\x8e\x66\xcf\x11\xa6\xd9\x00\xaa\x00\x62\xce\x6c";
469   EXPECT_TRUE(SniffMimeTypeFromLocalData(
470       std::string_view(kWMATestData, sizeof(kWMATestData) - 1), &mime_type));
471   EXPECT_EQ("video/x-ms-asf", mime_type);
472   mime_type.clear();
473 
474   // mp4a, m4b, m4p, and alac extension files which share the same container
475   // format.
476   const char kMP4TestData[] =
477       "\x00\x00\x00\x20\x66\x74\x79\x70\x4d\x34\x41\x20\x00\x00\x00\x00";
478   EXPECT_TRUE(SniffMimeTypeFromLocalData(
479       std::string_view(kMP4TestData, sizeof(kMP4TestData) - 1), &mime_type));
480   EXPECT_EQ("video/mp4", mime_type);
481   mime_type.clear();
482 
483   const char kAACTestData[] =
484       "\xff\xf1\x50\x80\x02\x20\xb0\x23\x0a\x83\x20\x7d\x61\x90\x3e\xb1";
485   EXPECT_TRUE(SniffMimeTypeFromLocalData(
486       std::string_view(kAACTestData, sizeof(kAACTestData) - 1), &mime_type));
487   EXPECT_EQ("audio/mpeg", mime_type);
488   mime_type.clear();
489 
490   const char kAMRTestData[] =
491       "\x23\x21\x41\x4d\x52\x0a\x3c\x53\x0a\x7c\xe8\xb8\x41\xa5\x80\xca";
492   EXPECT_TRUE(SniffMimeTypeFromLocalData(
493       std::string_view(kAMRTestData, sizeof(kAMRTestData) - 1), &mime_type));
494   EXPECT_EQ("audio/amr", mime_type);
495   mime_type.clear();
496 }
497 
TEST(MimeSnifferTest,ImageTest)498 TEST(MimeSnifferTest, ImageTest) {
499   std::string mime_type;
500   const char kWebPSimpleFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8 ";
501   EXPECT_TRUE(SniffMimeTypeFromLocalData(
502       std::string_view(kWebPSimpleFormat, sizeof(kWebPSimpleFormat) - 1),
503       &mime_type));
504   EXPECT_EQ("image/webp", mime_type);
505   mime_type.clear();
506 
507   const char kWebPLosslessFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8L";
508   EXPECT_TRUE(SniffMimeTypeFromLocalData(
509       std::string_view(kWebPLosslessFormat, sizeof(kWebPLosslessFormat) - 1),
510       &mime_type));
511   EXPECT_EQ("image/webp", mime_type);
512   mime_type.clear();
513 
514   const char kWebPExtendedFormat[] = "RIFF\xee\x81\x00\x00WEBPVP8X";
515   EXPECT_TRUE(SniffMimeTypeFromLocalData(
516       std::string_view(kWebPExtendedFormat, sizeof(kWebPExtendedFormat) - 1),
517       &mime_type));
518   EXPECT_EQ("image/webp", mime_type);
519   mime_type.clear();
520 }
521 
522 // The tests need char parameters, but the ranges to test include 0xFF, and some
523 // platforms have signed chars and are noisy about it. Using an int parameter
524 // and casting it to char inside the test case solves both these problems.
525 class MimeSnifferBinaryTest : public ::testing::TestWithParam<int> {};
526 
527 // From https://mimesniff.spec.whatwg.org/#binary-data-byte :
528 // A binary data byte is a byte in the range 0x00 to 0x08 (NUL to BS), the byte
529 // 0x0B (VT), a byte in the range 0x0E to 0x1A (SO to SUB), or a byte in the
530 // range 0x1C to 0x1F (FS to US).
TEST_P(MimeSnifferBinaryTest,IsBinaryControlCode)531 TEST_P(MimeSnifferBinaryTest, IsBinaryControlCode) {
532   std::string param(1, static_cast<char>(GetParam()));
533   EXPECT_TRUE(LooksLikeBinary(param));
534 }
535 
536 // ::testing::Range(a, b) tests an open-ended range, ie. "b" is not included.
537 INSTANTIATE_TEST_SUITE_P(MimeSnifferBinaryTestRange1,
538                          MimeSnifferBinaryTest,
539                          Range(0x00, 0x09));
540 
541 INSTANTIATE_TEST_SUITE_P(MimeSnifferBinaryTestByte0x0B,
542                          MimeSnifferBinaryTest,
543                          Values(0x0B));
544 
545 INSTANTIATE_TEST_SUITE_P(MimeSnifferBinaryTestRange2,
546                          MimeSnifferBinaryTest,
547                          Range(0x0E, 0x1B));
548 
549 INSTANTIATE_TEST_SUITE_P(MimeSnifferBinaryTestRange3,
550                          MimeSnifferBinaryTest,
551                          Range(0x1C, 0x20));
552 
553 class MimeSnifferPlainTextTest : public ::testing::TestWithParam<int> {};
554 
TEST_P(MimeSnifferPlainTextTest,NotBinaryControlCode)555 TEST_P(MimeSnifferPlainTextTest, NotBinaryControlCode) {
556   std::string param(1, static_cast<char>(GetParam()));
557   EXPECT_FALSE(LooksLikeBinary(param));
558 }
559 
560 INSTANTIATE_TEST_SUITE_P(MimeSnifferPlainTextTestPlainTextControlCodes,
561                          MimeSnifferPlainTextTest,
562                          Values(0x09, 0x0A, 0x0C, 0x0D, 0x1B));
563 
564 INSTANTIATE_TEST_SUITE_P(MimeSnifferPlainTextTestNotControlCodeRange,
565                          MimeSnifferPlainTextTest,
566                          Range(0x20, 0x100));
567 
568 class MimeSnifferControlCodesEdgeCaseTest
569     : public ::testing::TestWithParam<const char*> {};
570 
TEST_P(MimeSnifferControlCodesEdgeCaseTest,EdgeCase)571 TEST_P(MimeSnifferControlCodesEdgeCaseTest, EdgeCase) {
572   EXPECT_TRUE(LooksLikeBinary(GetParam()));
573 }
574 
575 INSTANTIATE_TEST_SUITE_P(MimeSnifferControlCodesEdgeCaseTest,
576                          MimeSnifferControlCodesEdgeCaseTest,
577                          Values("\x01__",  // first byte is binary
578                                 "__\x03",  // last byte is binary
579                                 "_\x02_"   // a byte in the middle is binary
580                                 ));
581 
582 }  // namespace
583 }  // namespace net
584