Index: net/base/mime_sniffer.cc |
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc |
index d53b567ffec075a6f4b871ffafbe388f00fb2b63..68881f1d16c2c40a2a1e73bb026754892eff7187 100644 |
--- a/net/base/mime_sniffer.cc |
+++ b/net/base/mime_sniffer.cc |
@@ -116,9 +116,20 @@ struct MagicNumber { |
bool is_string; |
}; |
+struct MagicMaskNumber { |
vandebo (ex-Chrome)
2013/04/29 19:43:50
I think it's ok to modify MagicNumber. It's an im
Kevin Bailey
2013/04/30 20:57:56
Done.
|
+ const char* mime_type; |
+ const char* magic; |
+ size_t magic_len; |
+ bool is_string; |
+ const char* mask; // must have same length as |magic| |
+}; |
+ |
#define MAGIC_NUMBER(mime_type, magic) \ |
{ (mime_type), (magic), sizeof(magic)-1, false }, |
+#define MAGIC_MASK(mime_type, magic, mask) \ |
+ { (mime_type), (magic), sizeof(magic)-1, false, (mask) }, |
+ |
// Magic strings are case insensitive and must not include '\0' characters |
#define MAGIC_STRING(mime_type, magic) \ |
{ (mime_type), (magic), sizeof(magic)-1, true }, |
@@ -176,6 +187,25 @@ static const MagicNumber kMagicNumbers[] = { |
// On balance, we do not include these patterns. |
}; |
+static const MagicMaskNumber kMagicMaskNumbers[] = { |
vandebo (ex-Chrome)
2013/04/29 19:43:50
These aren't all mask'd magic numbers... maybe kEx
Kevin Bailey
2013/04/30 20:57:56
Done.
|
+ MAGIC_NUMBER("image/x-xbitmap", "#define") |
+ MAGIC_NUMBER("image/x-icon", "\x00\x00\x01\x00") |
+ MAGIC_NUMBER("image/svg+xml", "<?xml_version=") |
+ MAGIC_NUMBER("audio/wav", "RIFF....WAVEfmt ") |
+ MAGIC_NUMBER("video/avi", "RIFF....AVI LIST") |
+ MAGIC_NUMBER("video/x-ms-wmv", "RIFF....AVI LIST") |
+ MAGIC_NUMBER("audio/ogg", "OggS") |
+ MAGIC_MASK("video/mpeg", "\x00\x00\x01\xB0", "\xFF\xFF\xFF\xF0") |
+ MAGIC_MASK("audio/mpeg", "\xFF\xE0", "\xFF\xE0") |
+ MAGIC_NUMBER("video/3gpp", "....ftyp3g") |
+ MAGIC_NUMBER("video/3gpp", "....ftypavcl") |
+ MAGIC_NUMBER("video/mp4", "....ftyp") |
+ MAGIC_NUMBER("video/quicktime", "MOVI") |
+ MAGIC_NUMBER("application/x-shockwave-flash", "CWS") |
+ MAGIC_NUMBER("application/x-shockwave-flash", "FWS") |
+ MAGIC_NUMBER("video/x-flv", "FLV") |
+}; |
+ |
// Our HTML sniffer differs slightly from Mozilla. For example, Mozilla will |
// decide that a document that begins "<!DOCTYPE SOAP-ENV:Envelope PUBLIC " is |
// HTML, but we will not. |
@@ -264,6 +294,61 @@ static bool MatchMagicNumber(const char* content, size_t size, |
return false; |
} |
+// Like MagicCmp() except that it ANDs each byte with a mask before |
+// the comparison, because there are some bits we don't care about. |
+static bool MagicMaskCmp(const char* magic_entry, const char* mask, |
+ const char* content, size_t len) { |
+ while (len) { |
+ if ((*magic_entry != '.') && (*magic_entry != (*mask & *content))) |
+ return false; |
+ ++magic_entry; |
+ ++content; |
+ ++mask; |
+ --len; |
+ } |
+ return true; |
+} |
+ |
+static bool MatchMagicMaskNumber(const char* content, size_t size, |
+ const MagicMaskNumber* magic_entry, |
+ std::string* result) { |
+ const size_t len = magic_entry->magic_len; |
+ |
+ // Keep kBytesRequiredForMagic honest. |
+ DCHECK_LE(len, kBytesRequiredForMagic); |
+ |
+ // To compare with magic strings, we need to compute strlen(content), but |
+ // content might not actually have a null terminator. In that case, we |
+ // pretend the length is content_size. |
+ const char* end = |
+ static_cast<const char*>(memchr(content, '\0', size)); |
+ const size_t content_strlen = |
+ (end != NULL) ? static_cast<size_t>(end - content) : size; |
+ |
+ bool match = false; |
+ if (magic_entry->is_string) { |
+ if (content_strlen >= len) { |
+ // String comparisons are case-insensitive |
+ match = (base::strncasecmp(magic_entry->magic, content, len) == 0); |
+ } |
+ } else { |
+ if (size >= len) { |
+ if (magic_entry->mask) { |
+ match = MagicMaskCmp(magic_entry->magic, magic_entry->mask, content, |
+ len); |
+ } else { |
+ match = MagicCmp(magic_entry->magic, content, len); |
+ } |
+ } |
+ } |
+ |
+ if (match) { |
+ result->assign(magic_entry->mime_type); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
static bool CheckForMagicNumbers(const char* content, size_t size, |
const MagicNumber* magic, size_t magic_len, |
base::HistogramBase* counter, |
@@ -277,6 +362,30 @@ static bool CheckForMagicNumbers(const char* content, size_t size, |
return false; |
} |
+static bool CheckForMagicMaskNumbers(const char* content, size_t size, |
+ const MagicMaskNumber* magic, |
+ size_t magic_len, |
+ std::string* result) { |
+ for (size_t i = 0; i < magic_len; ++i) { |
+ if (MatchMagicMaskNumber(content, size, &(magic[i]), result)) |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool IdentifyExtraMimeType(const char* content, size_t size, |
+ std::string* result) { |
+ // First check the extra table. |
+ if (CheckForMagicMaskNumbers(content, size, kMagicMaskNumbers, |
+ sizeof(kMagicMaskNumbers) / |
+ sizeof(MagicMaskNumber), result)) |
+ return true; |
+ // Finally check the original table. |
+ return CheckForMagicNumbers(content, size, kMagicNumbers, |
+ sizeof(kMagicNumbers) / sizeof(MagicNumber), |
+ NULL, result); |
+} |
+ |
// Truncates |size| to |max_size| and returns true if |size| is at least |
// |max_size|. |
static bool TruncateSize(const size_t max_size, size_t* size) { |