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