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