1/* 2 Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18*/ 19 20#include "config.h" 21#include "MIMESniffing.h" 22 23#include <cstring> 24#include <stdint.h> 25#include <wtf/StdLibExtras.h> 26 27using namespace std; 28 29// MIME type sniffing implementation based on http://tools.ietf.org/html/draft-abarth-mime-sniff-06 30 31namespace { 32 33static inline bool isTextInList(const char* text, size_t size, const char** data) 34{ 35 for (size_t i = 0; i < size; ++i) { 36 if (!strcmp(text, data[i])) 37 return true; 38 } 39 return false; 40 41} 42 43// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 44const char* textTypes[] = { 45 "text/plain", 46 "text/plain; charset=ISO-8859-1", 47 "text/plain; charset=iso-8859-1", 48 "text/plain; charset=UTF-8" 49}; 50const size_t textTypesSize = sizeof(textTypes) / sizeof(textTypes[0]); 51 52static inline bool isTextOrBinaryType(const char* type) 53{ 54 return isTextInList(type, textTypesSize, textTypes); 55} 56 57// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 58const char* unknownTypes[] = { 59 "", 60 "unknown/unknown", 61 "application/unknown", 62 "*/*" 63}; 64const size_t unknownTypesSize = sizeof(unknownTypes) / sizeof(unknownTypes[0]); 65 66static inline bool isUnknownType(const char* type) 67{ 68 if (isTextInList(type, unknownTypesSize, unknownTypes)) 69 return true; 70 if (!strchr(type, '/')) { 71 // Firefox/Chrome rejects a mime type if it does not contain a slash. 72 return true; 73 } 74 return false; 75} 76 77const char* xmlTypes[] = { 78 "text/xml", 79 "application/xml" 80}; 81const size_t xmlTypesSize = sizeof(xmlTypes) / sizeof(xmlTypes[0]); 82 83const char xmlSuffix[] = "+xml"; 84 85static inline bool isXMLType(const char* type) 86{ 87 const size_t xmlSuffixSize = sizeof(xmlSuffix) - 1; 88 size_t typeSize = strlen(type); 89 if (typeSize >= xmlSuffixSize && !memcmp(type + typeSize - xmlSuffixSize, xmlSuffix, xmlSuffixSize)) 90 return true; 91 92 return isTextInList(type, xmlTypesSize, xmlTypes); 93} 94 95// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 96const char binaryFlags[256] = { 97 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 98 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 113}; 114 115static inline bool isBinaryChar(unsigned char data) 116{ 117 return binaryFlags[data]; 118} 119 120static inline bool isBinaryData(const char* data, size_t size) 121{ 122 for (size_t i = 0; i < size; ++i) { 123 if (isBinaryChar(data[i])) 124 return true; 125 } 126 return false; 127} 128 129// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-11 130const char whiteSpaceChars[256] = { 131 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 147}; 148 149static inline bool isWhiteSpace(unsigned char data) 150{ 151 return whiteSpaceChars[data]; 152} 153 154static inline void skipWhiteSpace(const char* data, size_t& pos, size_t dataSize) 155{ 156 while (pos < dataSize && isWhiteSpace(data[pos])) 157 ++pos; 158} 159 160enum { 161 SkipWhiteSpace = 1, 162 TrailingSpaceOrBracket = 2 163}; 164 165struct MagicNumbers { 166 const char* pattern; 167 const char* mask; 168 const char* mimeType; 169 size_t size; 170 int flags; 171}; 172 173#define MAGIC_NUMBERS_MASKED(pattern, mask, mimeType, flags) {(pattern), (mask), (mimeType), sizeof(pattern) - 1, (flags)} 174#define MAGIC_NUMBERS_SIMPLE(pattern, mimeType) {(pattern), 0, (mimeType), sizeof(pattern) - 1, 0} 175 176// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-12 177const MagicNumbers securityConstrainedTypes[] = { 178 MAGIC_NUMBERS_MASKED("<!DOCTYPE HTML", "\xFF\xFF\xDF\xDF\xDF\xDF\xDF\xDF\xDF\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 179 MAGIC_NUMBERS_MASKED("<HTML", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 180 MAGIC_NUMBERS_MASKED("<HEAD", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 181 MAGIC_NUMBERS_MASKED("<SCRIPT", "\xFF\xDF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 182 MAGIC_NUMBERS_MASKED("<IFRAME", "\xFF\xDF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 183 MAGIC_NUMBERS_MASKED("<H1", "\xFF\xDF\xFF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 184 MAGIC_NUMBERS_MASKED("<DIV", "\xFF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 185 MAGIC_NUMBERS_MASKED("<FONT", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 186 MAGIC_NUMBERS_MASKED("<TABLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 187 MAGIC_NUMBERS_MASKED("<A", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 188 MAGIC_NUMBERS_MASKED("<STYLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 189 MAGIC_NUMBERS_MASKED("<TITLE", "\xFF\xDF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 190 MAGIC_NUMBERS_MASKED("<B", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 191 MAGIC_NUMBERS_MASKED("<BODY", "\xFF\xDF\xDF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 192 MAGIC_NUMBERS_MASKED("<BR", "\xFF\xDF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 193 MAGIC_NUMBERS_MASKED("<P", "\xFF\xDF", "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 194 MAGIC_NUMBERS_MASKED("<!--", 0, "text/html", SkipWhiteSpace | TrailingSpaceOrBracket), 195 MAGIC_NUMBERS_MASKED("<?xml", 0, "text/xml", SkipWhiteSpace), 196 MAGIC_NUMBERS_SIMPLE("%PDF-", "application/pdf") 197}; 198const size_t securityConstrainedTypesSize = sizeof(securityConstrainedTypes) / sizeof(securityConstrainedTypes[0]); 199 200// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 201const MagicNumbers bomTypes[] = { 202 MAGIC_NUMBERS_SIMPLE("\xFE\xFF", "text/plain"), // UTF-16BE BOM 203 MAGIC_NUMBERS_SIMPLE("\xFF\xFE", "text/plain"), // UTF-16LE BOM 204 MAGIC_NUMBERS_SIMPLE("\xEF\xBB\xBF", "text/plain") // UTF-8 BOM 205}; 206const size_t bomTypesSize = sizeof(bomTypes) / sizeof(bomTypes[0]); 207 208// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-13 209const MagicNumbers safeTypes[] = { 210 MAGIC_NUMBERS_SIMPLE("%!PS-Adobe-", "application/postscript"), 211 MAGIC_NUMBERS_SIMPLE("\x4F\x67\x67\x53\x00", "application/ogg"), // An Ogg Vorbis audio or video signature. 212 MAGIC_NUMBERS_MASKED("RIFF\x00\x00\x00\x00WAVE", "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF", "audio/x-wave", 0), // "RIFF" followed by four bytes, followed by "WAVE". 213 MAGIC_NUMBERS_SIMPLE("\x1A\x45\xDF\xA3", "video/webm"), // The WebM signature. 214 MAGIC_NUMBERS_SIMPLE("Rar!\x1A\x07\x00", "application/x-rar-compressed"), // A RAR archive. 215 MAGIC_NUMBERS_SIMPLE("\x50\x4B\x03\x04", "application/zip"), // A ZIP archive. 216 MAGIC_NUMBERS_SIMPLE("\x1F\x8B\x08", "application/x-gzip") // A GZIP archive. 217}; 218const size_t safeTypesSize = sizeof(safeTypes) / sizeof(safeTypes[0]); 219 220// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-16 221const MagicNumbers imageTypes[] = { 222 MAGIC_NUMBERS_MASKED("RIFF\x00\x00\x00\x00WEBPVP", "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF", "image/webp", 0), // "RIFF" followed by four bytes, followed by "WEBPVP". 223 MAGIC_NUMBERS_SIMPLE("GIF87a", "image/gif"), 224 MAGIC_NUMBERS_SIMPLE("GIF89a", "image/gif"), 225 MAGIC_NUMBERS_SIMPLE("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", "image/png"), 226 MAGIC_NUMBERS_SIMPLE("\xFF\xD8\xFF", "image/jpeg"), 227 MAGIC_NUMBERS_SIMPLE("BM", "image/bmp"), 228 MAGIC_NUMBERS_SIMPLE("\x00\x00\x01\x00", "image/vnd.microsoft.icon") // A Windows Icon signature. 229}; 230const size_t imageTypesSize = sizeof(imageTypes) / sizeof(imageTypes[0]); 231 232static inline size_t dataSizeNeededForImageSniffing() 233{ 234 size_t result = 0; 235 for (size_t i = 0; i < imageTypesSize; ++i) { 236 if (imageTypes[i].size > result) 237 result = imageTypes[i].size; 238 } 239 return result; 240} 241 242static inline bool maskedCompareSlowCase(const MagicNumbers& info, const char* data) 243{ 244 const char* pattern = reinterpret_cast<const char*>(info.pattern); 245 const char* mask = reinterpret_cast<const char*>(info.mask); 246 247 size_t count = info.size; 248 249 for (size_t i = 0; i < count; ++i) { 250 if ((*data++ & *mask++) != *pattern++) 251 return false; 252 } 253 return true; 254} 255 256static inline bool maskedCompare(const MagicNumbers& info, const char* data, size_t dataSize) 257{ 258 if (dataSize < info.size) 259 return false; 260 261 if (!isPointerTypeAlignmentOkay(static_cast<const uint32_t*>(static_cast<const void*>(data)))) 262 return maskedCompareSlowCase(info, data); 263 264 const uint32_t* pattern32 = reinterpret_cast_ptr<const uint32_t*>(info.pattern); 265 const uint32_t* mask32 = reinterpret_cast_ptr<const uint32_t*>(info.mask); 266 const uint32_t* data32 = reinterpret_cast_ptr<const uint32_t*>(data); 267 268 size_t count = info.size >> 2; 269 270 for (size_t i = 0; i < count; ++i) { 271 if ((*data32++ & *mask32++) != *pattern32++) 272 return false; 273 } 274 275 const char* p = reinterpret_cast<const char*>(pattern32); 276 const char* m = reinterpret_cast<const char*>(mask32); 277 const char* d = reinterpret_cast<const char*>(data32); 278 279 count = info.size & 3; 280 281 for (size_t i = 0; i < count; ++i) { 282 if ((*d++ & *m++) != *p++) 283 return false; 284 } 285 286 return true; 287} 288 289// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-11 290static inline bool checkSpaceOrBracket(const char* data) 291{ 292 return isWhiteSpace(*data) || *data == 0x3E; 293} 294 295static inline bool compare(const MagicNumbers& info, const char* data, size_t dataSize) 296{ 297 if (info.flags & SkipWhiteSpace) { 298 size_t pos = 0; 299 skipWhiteSpace(data, pos, dataSize); 300 data += pos; 301 dataSize -= pos; 302 } 303 304 bool result; 305 if (info.mask) 306 result = maskedCompare(info, data, info.size); 307 else 308 result = dataSize >= info.size && !memcmp(data, info.pattern, info.size); 309 310 return result && (!(info.flags & TrailingSpaceOrBracket) || checkSpaceOrBracket(data + info.size)); 311} 312 313static inline const char* findMIMEType(const char* data, size_t dataSize, const MagicNumbers* types, size_t typesCount) 314{ 315 for (size_t i = 0; i < typesCount; ++i) { 316 if (compare(types[i], data, dataSize)) 317 return types[i].mimeType; 318 } 319 return 0; 320} 321 322static inline const char* findSimpleMIMEType(const char* data, size_t dataSize, const MagicNumbers* types, size_t typesCount) 323{ 324 for (size_t i = 0; i < typesCount; ++i) { 325 ASSERT(!types[i].mask); 326 ASSERT(!types[i].flags); 327 328 if (dataSize >= types[i].size && !memcmp(data, types[i].pattern, types[i].size)) 329 return types[i].mimeType; 330 } 331 return 0; 332} 333 334bool isTypeInList(const char* type, const MagicNumbers* types, size_t typesCount) 335{ 336 for (size_t i = 0; i < typesCount; ++i) { 337 if (!strcmp(type, types[i].mimeType)) 338 return true; 339 } 340 return false; 341} 342 343// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-8 344static const char* internalTextOrBinaryTypeSniffingProcedure(const char* data, size_t dataSize) 345{ 346 const char* mimeType = 0; 347 348 mimeType = findSimpleMIMEType(data, dataSize, bomTypes, bomTypesSize); 349 if (mimeType) 350 return mimeType; 351 352 if (!isBinaryData(data, dataSize)) 353 return "text/plain"; 354 355 mimeType = findMIMEType(data, dataSize, safeTypes, safeTypesSize); 356 if (mimeType) 357 return mimeType; 358 359 mimeType = findMIMEType(data, dataSize, imageTypes, imageTypesSize); 360 if (mimeType) 361 return mimeType; 362 363 return "application/octet-stream"; 364} 365 366static const char* textOrBinaryTypeSniffingProcedure(const char* data, size_t dataSize) 367{ 368 const char* result = internalTextOrBinaryTypeSniffingProcedure(data, dataSize); 369 ASSERT(!isTypeInList(result, securityConstrainedTypes, securityConstrainedTypesSize)); 370 return result; 371} 372 373// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-10 374static const char* unknownTypeSniffingProcedure(const char* data, size_t dataSize) 375{ 376 const char* mimeType = 0; 377 378 mimeType = findMIMEType(data, dataSize, securityConstrainedTypes, securityConstrainedTypesSize); 379 if (mimeType) 380 return mimeType; 381 382 mimeType = findSimpleMIMEType(data, dataSize, bomTypes, bomTypesSize); 383 if (mimeType) 384 return mimeType; 385 386 mimeType = findMIMEType(data, dataSize, safeTypes, safeTypesSize); 387 if (mimeType) 388 return mimeType; 389 390 mimeType = findMIMEType(data, dataSize, imageTypes, imageTypesSize); 391 if (mimeType) 392 return mimeType; 393 394 if (!isBinaryData(data, dataSize)) 395 return "text/plain"; 396 397 return "application/octet-stream"; 398} 399 400// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-16 401static const char* imageTypeSniffingProcedure(const char* data, size_t dataSize) 402{ 403 return findMIMEType(data, dataSize, imageTypes, imageTypesSize); 404} 405 406static inline bool checkText(const char* data, size_t& pos, size_t dataSize, const char* text, size_t textSize) 407{ 408 if (dataSize - pos < textSize || memcmp(data + pos, text, textSize)) 409 return false; 410 411 pos += textSize; 412 return true; 413} 414 415const char rssUrl[] = "http://purl.org/rss/1.0"; 416const char rdfUrl[] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 417 418static inline const char* checkRDF(const char* data, size_t pos, size_t dataSize) 419{ 420 bool isRDF = false; 421 bool isRSS = false; 422 423 while (pos <= dataSize) { 424 if (checkText(data, pos, dataSize, rssUrl, sizeof(rssUrl) - 1)) { 425 isRSS = true; 426 continue; 427 } 428 429 if (checkText(data, pos, dataSize, rdfUrl, sizeof(rdfUrl) - 1)) { 430 isRDF = true; 431 continue; 432 } 433 434 ++pos; 435 436 if (isRSS && isRDF) 437 return "application/rdf+xml"; 438 } 439 440 return 0; 441} 442 443static inline bool skipTag(const char*& data, size_t& pos, size_t dataSize, const char* tag, size_t tagSize, const char* tagEnd, size_t tagEndSize) 444{ 445 if (!checkText(data, pos, dataSize, tag, tagSize)) 446 return false; 447 448 while (pos < dataSize && !checkText(data, pos, dataSize, tagEnd, tagEndSize)) 449 ++pos; 450 451 return true; 452} 453 454// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-17 455static const char* feedTypeSniffingProcedure(const char* data, size_t dataSize) 456{ 457 size_t pos = 0; 458 459 if (dataSize >= 3 && !memcmp(data, "\xEF\xBB\xBF", 3)) 460 pos += 3; 461 462 while (pos < dataSize) { 463 skipWhiteSpace(data, pos, dataSize); 464 465 if (!skipTag(data, pos, dataSize, "<!--", 4, "-->", 3) && !skipTag(data, pos, dataSize, "<!", 2, "!>", 2) && !skipTag(data, pos, dataSize, "<?", 2, "?>", 2)) 466 break; 467 } 468 469 if (checkText(data, pos, dataSize, "<rss", 4)) 470 return "application/rss+xml"; 471 472 if (checkText(data, pos, dataSize, "<feed", 5)) 473 return "application/atom+xml"; 474 475 if (checkText(data, pos, dataSize, "<rdf:RDF", 8)) 476 return checkRDF(data, pos, dataSize); 477 478 return 0; 479} 480 481} 482 483// http://tools.ietf.org/html/draft-abarth-mime-sniff-06#page-6 484MIMESniffer::MIMESniffer(const char* advertisedMIMEType, bool isSupportedImageType) 485 : m_dataSize(0) 486 , m_function(0) 487{ 488 if (!advertisedMIMEType) { 489 m_dataSize = 512; 490 m_function = &unknownTypeSniffingProcedure; 491 return; 492 } 493 494 if (isTextOrBinaryType(advertisedMIMEType)) { 495 m_dataSize = 512; 496 m_function = &textOrBinaryTypeSniffingProcedure; 497 return; 498 } 499 500 if (isUnknownType(advertisedMIMEType)) { 501 m_dataSize = 512; 502 m_function = &unknownTypeSniffingProcedure; 503 return; 504 } 505 506 if (isXMLType(advertisedMIMEType)) 507 return; 508 509 if (isSupportedImageType) { 510 static const size_t dataSize = dataSizeNeededForImageSniffing(); 511 m_dataSize = dataSize; 512 m_function = &imageTypeSniffingProcedure; 513 return; 514 } 515 516 if (!strcmp(advertisedMIMEType, "text/html")) { 517 m_dataSize = 512; 518 m_function = &feedTypeSniffingProcedure; 519 return; 520 } 521} 522