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