15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Detecting mime types is a tricky business because we need to balance 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compatibility concerns with security issues. Here is a survey of how other 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// browsers behave and then a description of how we intend to behave. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML payload, no Content-Type header: 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as HTML 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Render as HTML 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Render as HTML 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as HTML 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Here the choice seems clear: 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Render as HTML 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML payload, Content-Type: "text/plain": 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as HTML 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Render as text 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Render as text (Note: Safari will Render as HTML if the URL 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// has an HTML extension) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as text 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Here we choose to follow the majority (and break some compatibility with IE). 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Many folks dislike IE's behavior here. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Render as text 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We generalize this as follows. If the Content-Type header is text/plain 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we won't detect dangerous mime types (those that can execute script). 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML payload, Content-Type: "application/octet-stream": 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as HTML 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Download as application/octet-stream 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Render as HTML 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as HTML 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We follow Firefox. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Download as application/octet-stream 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// One factor in this decision is that IIS 4 and 5 will send 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// application/octet-stream for .xhtml files (because they don't recognize 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the extension). We did some experiments and it looks like this doesn't occur 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// very often on the web. We choose the more secure option. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GIF payload, no Content-Type header: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as GIF 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Render as GIF 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL has an GIF extension) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as GIF 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The choice is clear. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Render as GIF 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Once we decide to render HTML without a Content-Type header, there isn't much 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reason not to render GIFs. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GIF payload, Content-Type: "text/plain": 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as GIF 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Download as application/octet-stream (Note: Firefox will 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Download as GIF if the URL has an GIF extension) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL has an GIF extension) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as GIF 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Displaying as text/plain makes little sense as the content will look like 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// gibberish. Here, we could change our minds and download. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Render as GIF 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GIF payload, Content-Type: "application/octet-stream": 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as GIF 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Download as application/octet-stream (Note: Firefox will 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Download as GIF if the URL has an GIF extension) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL has an GIF extension) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as GIF 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We used to render as GIF here, but the problem is that some sites want to 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// trigger downloads by sending application/octet-stream (even though they 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// should be sending Content-Disposition: attachment). Although it is safe 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to render as GIF from a security perspective, we actually get better 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compatibility if we don't sniff from application/octet stream at all. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// => Chrome: Download as application/octet-stream 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// XHTML payload, Content-Type: "text/xml": 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * IE 7: Render as XML 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Firefox 2: Render as HTML 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Safari 3: Render as HTML 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Opera 9: Render as HTML 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The layout tests rely on us rendering this as HTML. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// But we're conservative in XHTML detection, as this runs afoul of the 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "don't detect dangerous mime types" rule. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that our definition of HTML payload is much stricter than IE's 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// definition and roughly the same as Firefox's definition. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_sniffer.h" 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 1025e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_util.h" 1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of content bytes we need to use all our magic numbers. Feel free 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to increase this number if you add a longer magic number. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kBytesRequiredForMagic = 42; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct MagicNumber { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* mime_type; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* magic; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t magic_len; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_string; 117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const char* mask; // if set, must have same length as |magic| 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAGIC_NUMBER(mime_type, magic) \ 121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) { (mime_type), (magic), sizeof(magic)-1, false, NULL }, 122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)template <int MagicSize, int MaskSize> 124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class VerifySizes { 125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) COMPILE_ASSERT(MagicSize == MaskSize, sizes_must_be_equal); 126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) public: 127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) enum { SIZES = MagicSize }; 128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}; 129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#define verified_sizeof(magic, mask) \ 131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)VerifySizes<sizeof(magic), sizeof(mask)>::SIZES 132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#define MAGIC_MASK(mime_type, magic, mask) \ 134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) { (mime_type), (magic), verified_sizeof(magic, mask)-1, false, (mask) }, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Magic strings are case insensitive and must not include '\0' characters 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAGIC_STRING(mime_type, magic) \ 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) { (mime_type), (magic), sizeof(magic)-1, true, NULL }, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const MagicNumber kMagicNumbers[] = { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Source: HTML 5 specification 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/pdf", "%PDF-") 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/postscript", "%!PS-Adobe-") 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/gif", "GIF87a") 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/gif", "GIF89a") 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/png", "\x89" "PNG\x0D\x0A\x1A\x0A") 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/jpeg", "\xFF\xD8\xFF") 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/bmp", "BM") 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Source: Mozilla 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "#!") // Script 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "%!") // Script, similar to PS 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "From") 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", ">From") 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Chrome specific 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/x-gzip", "\x1F\x8B\x08") 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("audio/x-pn-realaudio", "\x2E\x52\x4D\x46") 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("video/x-ms-asf", 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C") 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/tiff", "I I") 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/tiff", "II*") 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/tiff", "MM\x00*") 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("audio/mpeg", "ID3") 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("image/webp", "RIFF....WEBPVP8 ") 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("video/webm", "\x1A\x45\xDF\xA3") 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(abarth): we don't handle partial byte matches yet 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("video/mpeg", "\x00\x00\x01\xB") 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("audio/mpeg", "\xFF\xE") 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("audio/mpeg", "\xFF\xF") 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/zip", "PK\x03\x04") 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/x-rar-compressed", "Rar!\x1A\x07\x00") 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/x-msmetafile", "\xD7\xCD\xC6\x9A") 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/octet-stream", "MZ") // EXE 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sniffing for Flash: 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("application/x-shockwave-flash", "CWS") 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("application/x-shockwave-flash", "FLV") 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAGIC_NUMBER("application/x-shockwave-flash", "FWS") 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Including these magic number for Flash is a trade off. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pros: 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Flash is an important and popular file format 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cons: 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * These patterns are fairly weak 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * If we mistakenly decide something is Flash, we will execute it 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the origin of an unsuspecting site. This could be a security 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // vulnerability if the site allows users to upload content. 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On balance, we do not include these patterns. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 193b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// The number of content bytes we need to use all our Microsoft Office magic 194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// numbers. 195b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const size_t kBytesRequiredForOfficeMagic = 8; 196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const MagicNumber kOfficeMagicNumbers[] = { 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) MAGIC_NUMBER("CFB", "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1") 199b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) MAGIC_NUMBER("OOXML", "PK\x03\x04") 200b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)enum OfficeDocType { 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DOC_TYPE_WORD, 204b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DOC_TYPE_EXCEL, 205b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DOC_TYPE_POWERPOINT, 206b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) DOC_TYPE_NONE 207b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 208b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 209b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)struct OfficeExtensionType { 210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OfficeDocType doc_type; 211b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const char* extension; 212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t extension_len; 213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 214b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 215b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#define OFFICE_EXTENSION(type, extension) \ 216b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) { (type), (extension), sizeof(extension) - 1 }, 217b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static const OfficeExtensionType kOfficeExtensionTypes[] = { 219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_WORD, ".doc") 220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_EXCEL, ".xls") 221b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_POWERPOINT, ".ppt") 222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_WORD, ".docx") 223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_EXCEL, ".xlsx") 224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OFFICE_EXTENSION(DOC_TYPE_POWERPOINT, ".pptx") 225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}; 226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 227a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const MagicNumber kExtraMagicNumbers[] = { 228a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("image/x-xbitmap", "#define") 229a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("image/x-icon", "\x00\x00\x01\x00") 230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("image/svg+xml", "<?xml_version=") 231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("audio/wav", "RIFF....WAVEfmt ") 232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("video/avi", "RIFF....AVI LIST") 233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("audio/ogg", "OggS") 234a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_MASK("video/mpeg", "\x00\x00\x01\xB0", "\xFF\xFF\xFF\xF0") 235a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_MASK("audio/mpeg", "\xFF\xE0", "\xFF\xE0") 236a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("video/3gpp", "....ftyp3g") 237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("video/3gpp", "....ftypavcl") 238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("video/mp4", "....ftyp") 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MAGIC_NUMBER("video/quicktime", "....moov") 240a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("application/x-shockwave-flash", "CWS") 241a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("application/x-shockwave-flash", "FWS") 242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) MAGIC_NUMBER("video/x-flv", "FLV") 2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MAGIC_NUMBER("audio/x-flac", "fLaC") 24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // RAW image types. 24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-canon-cr2", "II\x2a\x00\x10\x00\x00\x00CR") 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-canon-crw", "II\x1a\x00\x00\x00HEAPCCDR") 24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-minolta-mrw", "\x00MRM") 24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-olympus-orf", "MMOR") // big-endian 25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-olympus-orf", "IIRO") // little-endian 25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-olympus-orf", "IIRS") // little-endian 25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-fuji-raf", "FUJIFILMCCD-RAW ") 25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-panasonic-raw", 25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "IIU\x00\x08\x00\x00\x00") // Panasonic .raw 25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-panasonic-raw", 25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "IIU\x00\x18\x00\x00\x00") // Panasonic .rw2 25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-phaseone-raw", "MMMMRaw") 25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) MAGIC_NUMBER("image/x-x3f", "FOVb") 259a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}; 260a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Our HTML sniffer differs slightly from Mozilla. For example, Mozilla will 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// decide that a document that begins "<!DOCTYPE SOAP-ENV:Envelope PUBLIC " is 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTML, but we will not. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAGIC_HTML_TAG(tag) \ 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_STRING("text/html", "<" tag) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const MagicNumber kSniffableTags[] = { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // XML processing directive. Although this is not an HTML mime type, we sniff 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for this in the HTML phase because text/xml is just as powerful as HTML and 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we want to leverage our white space skipping technology. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/xml", "<?xml") // Mozilla 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DOCTYPEs 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("!DOCTYPE html") // HTML5 spec 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sniffable tags, ordered by how often they occur in sniffable documents. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("script") // HTML5 spec, Mozilla 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("html") // HTML5 spec, Mozilla 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("!--") 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("head") // HTML5 spec, Mozilla 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("iframe") // Mozilla 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("h1") // Mozilla 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("div") // Mozilla 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("font") // Mozilla 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("table") // Mozilla 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("a") // Mozilla 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("style") // Mozilla 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("title") // Mozilla 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("b") // Mozilla 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("body") // Mozilla 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("br") 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_HTML_TAG("p") // Mozilla 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static base::HistogramBase* UMASnifferHistogramGet(const char* name, 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int array_size) { 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::HistogramBase* counter = 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::LinearHistogram::FactoryGet(name, 1, array_size - 1, array_size, 29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::HistogramBase::kUmaTargetedHistogramFlag); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return counter; 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Compare content header to a magic number where magic_entry can contain '.' 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for single character of anything, allowing some bytes to be skipped. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool MagicCmp(const char* magic_entry, const char* content, size_t len) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (len) { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((*magic_entry != '.') && (*magic_entry != *content)) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++magic_entry; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++content; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --len; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Like MagicCmp() except that it ANDs each byte with a mask before 316a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// the comparison, because there are some bits we don't care about. 317a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static bool MagicMaskCmp(const char* magic_entry, 318a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const char* content, 319a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t len, 320a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const char* mask) { 321a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) while (len) { 322a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if ((*magic_entry != '.') && (*magic_entry != (*mask & *content))) 323a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 324a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ++magic_entry; 325a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ++content; 326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ++mask; 327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) --len; 328a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 329a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return true; 330a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 331a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 332a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static bool MatchMagicNumber(const char* content, 333a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t size, 33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const MagicNumber& magic_entry, 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const size_t len = magic_entry.magic_len; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keep kBytesRequiredForMagic honest. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(len, kBytesRequiredForMagic); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To compare with magic strings, we need to compute strlen(content), but 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // content might not actually have a null terminator. In that case, we 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pretend the length is content_size. 34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const char* end = static_cast<const char*>(memchr(content, '\0', size)); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t content_strlen = 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (end != NULL) ? static_cast<size_t>(end - content) : size; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool match = false; 34990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (magic_entry.is_string) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_strlen >= len) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // String comparisons are case-insensitive 35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match = (base::strncasecmp(magic_entry.magic, content, len) == 0); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 355a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (size >= len) { 35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!magic_entry.mask) { 35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match = MagicCmp(magic_entry.magic, content, len); 358a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 35990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) match = MagicMaskCmp(magic_entry.magic, content, len, magic_entry.mask); 360a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 361a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (match) { 36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) result->assign(magic_entry.mime_type); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool CheckForMagicNumbers(const char* content, size_t size, 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MagicNumber* magic, size_t magic_len, 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::HistogramBase* counter, 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < magic_len; ++i) { 37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (MatchMagicNumber(content, size, magic[i], result)) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (counter) counter->Add(static_cast<int>(i)); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Truncates |size| to |max_size| and returns true if |size| is at least 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |max_size|. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool TruncateSize(const size_t max_size, size_t* size) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Keep kMaxBytesToSniff honest. 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(static_cast<int>(max_size), kMaxBytesToSniff); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*size >= max_size) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = max_size; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true and sets result if the content appears to be HTML. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clears have_enough_content if more data could possibly change the result. 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SniffForHTML(const char* content, 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* have_enough_content, 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For HTML, we are willing to consider up to 512 bytes. This may be overly 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // conservative as IE only considers 256. 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *have_enough_content &= TruncateSize(512, &size); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We adopt a strategy similar to that used by Mozilla to sniff HTML tags, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but with some modifications to better match the HTML5 spec. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const end = content + size; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* pos; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (pos = content; pos < end; ++pos) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsAsciiWhitespace(*pos)) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 41690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kSniffableTags2", 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kSniffableTags)); 41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |pos| now points to first non-whitespace character (or at end). 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CheckForMagicNumbers(pos, end - pos, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kSniffableTags, arraysize(kSniffableTags), 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter, result); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true and sets result if the content matches any of kMagicNumbers. 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clears have_enough_content if more data could possibly change the result. 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SniffForMagicNumbers(const char* content, 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* have_enough_content, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *have_enough_content &= TruncateSize(kBytesRequiredForMagic, &size); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check our big table of Magic Numbers 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 43690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kMagicNumbers2", 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kMagicNumbers)); 43990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CheckForMagicNumbers(content, size, 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMagicNumbers, arraysize(kMagicNumbers), 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter, result); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Returns true and sets result if the content matches any of 446b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// kOfficeMagicNumbers, and the URL has the proper extension. 447b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Clears |have_enough_content| if more data could possibly change the result. 448b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)static bool SniffForOfficeDocs(const char* content, 449b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) size_t size, 450b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const GURL& url, 451b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) bool* have_enough_content, 452b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) std::string* result) { 453b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *have_enough_content &= TruncateSize(kBytesRequiredForOfficeMagic, &size); 454b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 455b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Check our table of magic numbers for Office file types. 456b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) std::string office_version; 457b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!CheckForMagicNumbers(content, size, 458b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) kOfficeMagicNumbers, arraysize(kOfficeMagicNumbers), 459b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) NULL, &office_version)) 460b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 461b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 462b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) OfficeDocType type = DOC_TYPE_NONE; 463b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) for (size_t i = 0; i < arraysize(kOfficeExtensionTypes); ++i) { 464b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) std::string url_path = url.path(); 465b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 466b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (url_path.length() < kOfficeExtensionTypes[i].extension_len) 467b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) continue; 468b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 469b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const char* extension = 47090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) &url_path[url_path.length() - kOfficeExtensionTypes[i].extension_len]; 471b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 472b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (0 == base::strncasecmp(extension, kOfficeExtensionTypes[i].extension, 473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) kOfficeExtensionTypes[i].extension_len)) { 474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) type = kOfficeExtensionTypes[i].doc_type; 475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) break; 476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 477b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 478b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (type == DOC_TYPE_NONE) 480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 481b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (office_version == "CFB") { 483b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) switch (type) { 484b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_WORD: 485b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/msword"; 486b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 487b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_EXCEL: 488b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/vnd.ms-excel"; 489b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 490b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_POWERPOINT: 491b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/vnd.ms-powerpoint"; 492b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 493b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_NONE: 494b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) NOTREACHED(); 495b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 496b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 497b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } else if (office_version == "OOXML") { 498b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) switch (type) { 499b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_WORD: 500b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/vnd.openxmlformats-officedocument." 501b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) "wordprocessingml.document"; 502b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 503b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_EXCEL: 504b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/vnd.openxmlformats-officedocument." 505b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) "spreadsheetml.sheet"; 506b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 507b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_POWERPOINT: 508b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *result = "application/vnd.openxmlformats-officedocument." 509b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) "presentationml.presentation"; 510b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; 511b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case DOC_TYPE_NONE: 512b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) NOTREACHED(); 513b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 514b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 515b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 516b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 517b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) NOTREACHED(); 518b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 519b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 520b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)static bool IsOfficeType(const std::string& type_hint) { 52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return (type_hint == "application/msword" || 52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-excel" || 52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-powerpoint" || 52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.openxmlformats-officedocument." 52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "wordprocessingml.document" || 52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.openxmlformats-officedocument." 52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "spreadsheetml.sheet" || 52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.openxmlformats-officedocument." 53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "presentationml.presentation" || 53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-excel.sheet.macroenabled.12" || 53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-word.document.macroenabled.12" || 53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-powerpoint.presentation." 53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "macroenabled.12" || 53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/mspowerpoint" || 53690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/msexcel" || 53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-word" || 53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.ms-word.document.12" || 53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) type_hint == "application/vnd.msword"); 54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 54190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 54290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// This function checks for files that have a Microsoft Office MIME type 54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// set, but are not actually Office files. 54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// If this is not actually an Office file, |*result| is set to 546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// "application/octet-stream", otherwise it is not modified. 54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Returns false if additional data is required to determine the file type, or 54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// true if there is enough data to make a decision. 55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)static bool SniffForInvalidOfficeDocs(const char* content, 55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t size, 55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const GURL& url, 55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string* result) { 55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!TruncateSize(kBytesRequiredForOfficeMagic, &size)) 55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Check our table of magic numbers for Office file types. If it does not 55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // match one, the MIME type was invalid. Set it instead to a safe value. 55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string office_version; 56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!CheckForMagicNumbers(content, size, 56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) kOfficeMagicNumbers, arraysize(kOfficeMagicNumbers), 56290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) NULL, &office_version)) { 563868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *result = "application/octet-stream"; 56490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 56590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // We have enough information to determine if this was a Microsoft Office 56790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // document or not, so sniffing is completed. 56890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 56990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 57090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Byte order marks 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const MagicNumber kMagicXML[] = { 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to be very conservative in interpreting text/xml content as 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // XHTML -- we just want to sniff enough to make unit tests pass. 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // So we match explicitly on this, and don't match other ways of writing 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it in semantically-equivalent ways. 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_STRING("application/xhtml+xml", 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<html xmlns=\"http://www.w3.org/1999/xhtml\"") 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_STRING("application/atom+xml", "<feed") 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_STRING("application/rss+xml", "<rss") // UTF-8 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true and sets result if the content appears to contain XHTML or a 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// feed. 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clears have_enough_content if more data could possibly change the result. 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(evanm): this is similar but more conservative than what Safari does, 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// while HTML5 has a different recommendation -- what should we do? 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(evanm): this is incorrect for documents whose encoding isn't a superset 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of ASCII -- do we care? 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SniffXML(const char* content, 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* have_enough_content, 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We allow at most 300 bytes of content before we expect the opening tag. 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *have_enough_content &= TruncateSize(300, &size); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* pos = content; 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const end = content + size; 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This loop iterates through tag-looking offsets in the file. 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to skip XML processing instructions (of the form "<?xml ...") 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and stop at the first "plain" tag, then make a decision on the mime-type 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // based on the name (or possibly attributes) of that tag. 6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 60590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kMagicXML2", 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kMagicXML)); 60890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int kMaxTagIterations = 5; 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kMaxTagIterations && pos < end; ++i) { 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos = reinterpret_cast<const char*>(memchr(pos, '<', end - pos)); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pos) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 61590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (base::strncasecmp(pos, "<?xml", sizeof("<?xml") - 1) == 0) { 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip XML declarations. 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++pos; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (base::strncasecmp(pos, "<!DOCTYPE", 62090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) sizeof("<!DOCTYPE") - 1) == 0) { 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip DOCTYPE declarations. 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++pos; 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CheckForMagicNumbers(pos, end - pos, 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kMagicXML, arraysize(kMagicXML), 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter, result)) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(evanm): handle RSS 1.0, which is an RDF format and more difficult 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to identify. 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we get here, we've hit an initial tag that hasn't matched one of the 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // above tests. Abort. 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We iterated too far without finding a start tag. 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have more content to look at, we aren't going to change our mind by 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // seeing more bytes from the network. 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pos < end; 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Byte order marks 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const MagicNumber kByteOrderMark[] = { 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "\xFE\xFF") // UTF-16BE 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "\xFF\xFE") // UTF-16LE 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("text/plain", "\xEF\xBB\xBF") // UTF-8 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Whether a given byte looks like it might be part of binary content. 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Source: HTML5 spec 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char kByteLooksBinary[] = { 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, // 0x00 - 0x0F 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1F 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20 - 0x2F 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30 - 0x3F 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0x4F 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0x5F 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60 - 0x6F 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0x7F 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0x8F 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9F 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0 - 0xAF 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xB0 - 0xBF 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0 - 0xCF 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xD0 - 0xDF 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0 - 0xEF 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xF0 - 0xFF 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true and sets result to "application/octet-stream" if the content 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// appears to be binary data. Otherwise, returns false and sets "text/plain". 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clears have_enough_content if more data could possibly change the result. 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SniffBinary(const char* content, 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* have_enough_content, 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no concensus about exactly how to sniff for binary content. 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * IE 7: Don't sniff for binary looking bytes, but trust the file extension. 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Firefox 3.5: Sniff first 4096 bytes for a binary looking byte. 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Here, we side with FF, but with a smaller buffer. This size was chosen 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because it is small enough to comfortably fit into a single packet (after 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allowing for headers) and yet large enough to account for binary formats 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that have a significant amount of ASCII at the beginning (crbug.com/15314). 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool is_truncated = TruncateSize(kMaxBytesToSniff, &size); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First, we look for a BOM. 6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 69190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kByteOrderMark2", 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kByteOrderMark)); 69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unused; 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CheckForMagicNumbers(content, size, 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kByteOrderMark, arraysize(kByteOrderMark), 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter, &unused)) { 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is BOM, we think the buffer is not binary. 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->assign("text/plain"); 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Next we look to see if any of the bytes "look binary." 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < size; ++i) { 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we a see a binary-looking byte, we think the content is binary. 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kByteLooksBinary[static_cast<unsigned char>(content[i])]) { 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->assign("application/octet-stream"); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No evidence either way. Default to non-binary and, if truncated, clear 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have_enough_content because there could be a binary looking byte in the 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // truncated data. 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *have_enough_content &= is_truncated; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->assign("text/plain"); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsUnknownMimeType(const std::string& mime_type) { 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(tc): Maybe reuse some code in net/http/http_response_headers.* here. 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we do, please be careful not to alter the semantics at all. 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char* kUnknownMimeTypes[] = { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty mime types are as unknown as they get. 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "", 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The unknown/unknown type is popular and uninformative 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "unknown/unknown", 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The second most popular unknown mime type is application/unknown 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "application/unknown", 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Firefox rejects a mime type if it is exactly */* 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "*/*", 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 73590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kUnknownMimeTypes2", 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kUnknownMimeTypes) + 1); 73890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kUnknownMimeTypes); ++i) { 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mime_type == kUnknownMimeTypes[i]) { 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(i); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mime_type.find('/') == std::string::npos) { 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Firefox rejects a mime type if it does not contain a slash 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(arraysize(kUnknownMimeTypes)); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 753b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// Returns true and sets result if the content appears to be a crx (Chrome 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extension) file. 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Clears have_enough_content if more data could possibly change the result. 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool SniffCRX(const char* content, 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t size, 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& type_hint, 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* have_enough_content, 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!counter) 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kSniffCRX", 3); 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Technically, the crx magic number is just Cr24, but the bytes after that 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are a version number which changes infrequently. Including it in the 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sniffing gives us less room for error. If the version number ever changes, 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we can just add an entry to this list. 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(aa): If we ever have another magic number, we'll want to pass a 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // histogram into CheckForMagicNumbers(), below, to see which one matched. 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct MagicNumber kCRXMagicNumbers[] = { 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGIC_NUMBER("application/x-chrome-extension", "Cr24\x02\x00\x00\x00") 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only consider files that have the extension ".crx". 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kCRXExtension[] = ".crx"; 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore null by subtracting 1. 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kExtensionLength = arraysize(kCRXExtension) - 1; 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.path().rfind(kCRXExtension, std::string::npos, kExtensionLength) == 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url.path().size() - kExtensionLength) { 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(1); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *have_enough_content &= TruncateSize(kBytesRequiredForMagic, &size); 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CheckForMagicNumbers(content, size, 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCRXMagicNumbers, arraysize(kCRXMagicNumbers), 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, result)) { 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(2); 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { 8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* should_sniff_counter(NULL); 80290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!should_sniff_counter) { 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_sniff_counter = 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMASnifferHistogramGet("mime_sniffer.ShouldSniffMimeType2", 3); 80590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool sniffable_scheme = url.is_empty() || 8073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) url.SchemeIsHTTPOrHTTPS() || 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url.SchemeIs("ftp") || 809ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#if defined(OS_ANDROID) 810ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch url.SchemeIs("content") || 811ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#endif 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url.SchemeIsFile() || 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url.SchemeIsFileSystem(); 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!sniffable_scheme) { 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_sniff_counter->Add(1); 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char* kSniffableTypes[] = { 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Many web servers are misconfigured to send text/plain for many 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // different types of content. 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "text/plain", 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We want to sniff application/octet-stream for 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // application/x-chrome-extension, but nothing else. 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "application/octet-stream", 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // XHTML and Atom/RSS feeds are often served as plain xml instead of 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // their more specific mime types. 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "text/xml", 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "application/xml", 83090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Check for false Microsoft Office MIME types. 83190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/msword", 83290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-excel", 83390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-powerpoint", 83490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 83590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 83690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.openxmlformats-officedocument.presentationml.presentation", 83790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-excel.sheet.macroenabled.12", 83890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-word.document.macroenabled.12", 83990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-powerpoint.presentation.macroenabled.12", 84090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/mspowerpoint", 84190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/msexcel", 84290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-word", 84390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.ms-word.document.12", 84490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) "application/vnd.msword", 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::HistogramBase* counter(NULL); 84790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!counter) { 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter = UMASnifferHistogramGet("mime_sniffer.kSniffableTypes2", 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) arraysize(kSniffableTypes) + 1); 85090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kSniffableTypes); ++i) { 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mime_type == kSniffableTypes[i]) { 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(i); 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_sniff_counter->Add(2); 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnknownMimeType(mime_type)) { 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The web server didn't specify a content type or specified a mime 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type that we ignore. 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) counter->Add(arraysize(kSniffableTypes)); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_sniff_counter->Add(2); 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_sniff_counter->Add(1); 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 869a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool SniffMimeType(const char* content, 870a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t content_size, 871a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const GURL& url, 872a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const std::string& type_hint, 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(content_size, 1000000U); // sanity check 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(content); 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // By default, we assume we have enough content. 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Each sniff routine may unset this if it wasn't provided enough content. 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool have_enough_content = true; 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // By default, we'll return the type hint. 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Each sniff routine may modify this if it has a better guess.. 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->assign(type_hint); 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 88690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // If the file has a Microsoft Office MIME type, we should only check that it 88790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // is a valid Office file. Because this is the only reason we sniff files 88890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // with a Microsoft Office MIME type, we can return early. 88990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (IsOfficeType(type_hint)) 89090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return SniffForInvalidOfficeDocs(content, content_size, url, result); 89190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cache information about the type_hint 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool hint_is_unknown_mime_type = IsUnknownMimeType(type_hint); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First check for HTML 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hint_is_unknown_mime_type) { 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're only willing to sniff HTML if the server has not supplied a mime 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // type, or if the type it did supply indicates that it doesn't know what 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the type should be. 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SniffForHTML(content, content_size, &have_enough_content, result)) 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // We succeeded in sniffing HTML. No more content needed. 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're only willing to sniff for binary in 3 cases: 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. The server has not supplied a mime type. 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. The type it did supply indicates that it doesn't know what the type 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should be. 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. The type is "text/plain" which is the default on some web servers and 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // could be indicative of a mis-configuration that we shield the user from. 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool hint_is_text_plain = (type_hint == "text/plain"); 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hint_is_unknown_mime_type || hint_is_text_plain) { 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SniffBinary(content, content_size, &have_enough_content, result)) { 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the server said the content was text/plain and it doesn't appear 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be binary, then we trust it. 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hint_is_text_plain) { 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return have_enough_content; 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have plain XML, sniff XML subtypes. 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_hint == "text/xml" || type_hint == "application/xml") { 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're not interested in sniffing these types for images and the like. 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Instead, we're looking explicitly for a feed. If we don't find one 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we're done and return early. 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SniffXML(content, content_size, &have_enough_content, result)) 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return have_enough_content; 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 931b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // CRX files (Chrome extensions) have a special sniffing algorithm. It is 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // tighter than the others because we don't have to match legacy behavior. 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SniffCRX(content, content_size, url, type_hint, 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &have_enough_content, result)) 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 937b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Check the file extension and magic numbers to see if this is an Office 938b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // document. This needs to be checked before the general magic numbers 939b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // because zip files and Office documents (OOXML) have the same magic number. 940b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (SniffForOfficeDocs(content, content_size, url, 941b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) &have_enough_content, result)) 942b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return true; // We've matched a magic number. No more content needed. 943b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're not interested in sniffing for magic numbers when the type_hint 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is application/octet-stream. Time to bail out. 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_hint == "application/octet-stream") 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return have_enough_content; 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now we look in our large table of magic numbers to see if we can find 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // anything that matches the content. 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SniffForMagicNumbers(content, content_size, 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &have_enough_content, result)) 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // We've matched a magic number. No more content needed. 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return have_enough_content; 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 958a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool SniffMimeTypeFromLocalData(const char* content, 959a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t size, 960a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::string* result) { 961a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // First check the extra table. 962a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (CheckForMagicNumbers(content, size, kExtraMagicNumbers, 963a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) arraysize(kExtraMagicNumbers), NULL, result)) 964a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return true; 965a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Finally check the original table. 966a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return CheckForMagicNumbers(content, size, kMagicNumbers, 967a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) arraysize(kMagicNumbers), NULL, result); 968a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 969a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 971