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