• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "config.h"
30#import "WebCoreURLResponse.h"
31
32#import "MIMETypeRegistry.h"
33#import "WebCoreSystemInterface.h"
34#import <wtf/Assertions.h>
35#import <wtf/RetainPtr.h>
36
37namespace WebCore {
38
39// <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream
40// When we sniff a resource as application/octet-stream but the http response headers had "text/plain",
41// we have a hard decision to make about which of the two generic MIME types to go with.
42// When the URL's extension is a known binary type, we'll go with application/octet-stream.
43// Otherwise, we'll trust the server.
44static CFSetRef createBinaryExtensionsSet()
45{
46    CFStringRef extensions[] = {
47        CFSTR("3g2"),
48        CFSTR("3gp"),
49        CFSTR("ai"),
50        CFSTR("aif"),
51        CFSTR("aifc"),
52        CFSTR("aiff"),
53        CFSTR("au"),
54        CFSTR("avi"),
55        CFSTR("bcpio"),
56        CFSTR("bin"),
57        CFSTR("bmp"),
58        CFSTR("boz"),
59        CFSTR("bpk"),
60        CFSTR("bz"),
61        CFSTR("bz2"),
62        CFSTR("chm"),
63        CFSTR("class"),
64        CFSTR("com"),
65        CFSTR("cpio"),
66        CFSTR("dcr"),
67        CFSTR("dir"),
68        CFSTR("dist"),
69        CFSTR("distz"),
70        CFSTR("dll"),
71        CFSTR("dmg"),
72        CFSTR("dms"),
73        CFSTR("doc"),
74        CFSTR("dot"),
75        CFSTR("dump"),
76        CFSTR("dv"),
77        CFSTR("dvi"),
78        CFSTR("dxr"),
79        CFSTR("elc"),
80        CFSTR("eot"),
81        CFSTR("eps"),
82        CFSTR("exe"),
83        CFSTR("fgd"),
84        CFSTR("gif"),
85        CFSTR("gtar"),
86        CFSTR("h261"),
87        CFSTR("h263"),
88        CFSTR("h264"),
89        CFSTR("ico"),
90        CFSTR("ims"),
91        CFSTR("indd"),
92        CFSTR("iso"),
93        CFSTR("jp2"),
94        CFSTR("jpe"),
95        CFSTR("jpeg"),
96        CFSTR("jpg"),
97        CFSTR("jpgm"),
98        CFSTR("jpgv"),
99        CFSTR("jpm"),
100        CFSTR("kar"),
101        CFSTR("kmz"),
102        CFSTR("lha"),
103        CFSTR("lrm"),
104        CFSTR("lzh"),
105        CFSTR("m1v"),
106        CFSTR("m2a"),
107        CFSTR("m2v"),
108        CFSTR("m3a"),
109        CFSTR("m3u"),
110        CFSTR("m4a"),
111        CFSTR("m4p"),
112        CFSTR("m4v"),
113        CFSTR("mdb"),
114        CFSTR("mid"),
115        CFSTR("midi"),
116        CFSTR("mj2"),
117        CFSTR("mjp2"),
118        CFSTR("mov"),
119        CFSTR("movie"),
120        CFSTR("mp2"),
121        CFSTR("mp2a"),
122        CFSTR("mp3"),
123        CFSTR("mp4"),
124        CFSTR("mp4a"),
125        CFSTR("mp4s"),
126        CFSTR("mp4v"),
127        CFSTR("mpe"),
128        CFSTR("mpeg"),
129        CFSTR("mpg"),
130        CFSTR("mpg4"),
131        CFSTR("mpga"),
132        CFSTR("mpp"),
133        CFSTR("mpt"),
134        CFSTR("msi"),
135        CFSTR("ogg"),
136        CFSTR("otf"),
137        CFSTR("pct"),
138        CFSTR("pdf"),
139        CFSTR("pfa"),
140        CFSTR("pfb"),
141        CFSTR("pic"),
142        CFSTR("pict"),
143        CFSTR("pkg"),
144        CFSTR("png"),
145        CFSTR("pot"),
146        CFSTR("pps"),
147        CFSTR("ppt"),
148        CFSTR("ps"),
149        CFSTR("psd"),
150        CFSTR("qt"),
151        CFSTR("qti"),
152        CFSTR("qtif"),
153        CFSTR("qwd"),
154        CFSTR("qwt"),
155        CFSTR("qxb"),
156        CFSTR("qxd"),
157        CFSTR("qxl"),
158        CFSTR("qxp"),
159        CFSTR("qxt"),
160        CFSTR("ra"),
161        CFSTR("ram"),
162        CFSTR("rm"),
163        CFSTR("rmi"),
164        CFSTR("rmp"),
165        CFSTR("scpt"),
166        CFSTR("sit"),
167        CFSTR("sitx"),
168        CFSTR("snd"),
169        CFSTR("so"),
170        CFSTR("swf"),
171        CFSTR("tar"),
172        CFSTR("tif"),
173        CFSTR("tiff"),
174        CFSTR("ttf"),
175        CFSTR("wav"),
176        CFSTR("wcm"),
177        CFSTR("wdb"),
178        CFSTR("wks"),
179        CFSTR("wm"),
180        CFSTR("wma"),
181        CFSTR("wmd"),
182        CFSTR("wmf"),
183        CFSTR("wmv"),
184        CFSTR("wmx"),
185        CFSTR("wmz"),
186        CFSTR("wpd"),
187        CFSTR("wpl"),
188        CFSTR("wps"),
189        CFSTR("wvx"),
190        CFSTR("xla"),
191        CFSTR("xlc"),
192        CFSTR("xlm"),
193        CFSTR("xls"),
194        CFSTR("xlt"),
195        CFSTR("xlw"),
196        CFSTR("xps"),
197        CFSTR("zip")
198    };
199    return CFSetCreate(kCFAllocatorDefault, (const void **)&extensions, sizeof(extensions)/sizeof(CFStringRef), &kCFTypeSetCallBacks);
200}
201
202// <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about
203// When we disabled content sniffing for file URLs we caused problems with these 100+ extensions that CoreTypes
204// doesn't know about.
205// If CoreTypes is ever brought up to speed we can remove this table and associated code.
206static CFDictionaryRef createExtensionToMIMETypeMap()
207{
208    CFStringRef keys[] = {
209        CFSTR("ai"),
210        CFSTR("asc"),
211        CFSTR("bcpio"),
212        CFSTR("bmp"),
213        CFSTR("cdf"),
214        CFSTR("class"),
215        CFSTR("cpgz"),
216        CFSTR("cpio"),
217        CFSTR("cpt"),
218        CFSTR("csh"),
219        CFSTR("css"),
220        CFSTR("dcr"),
221        CFSTR("dir"),
222        CFSTR("dmg"),
223        CFSTR("dms"),
224        CFSTR("dvi"),
225        CFSTR("dxr"),
226        CFSTR("eps"),
227        CFSTR("etx"),
228        CFSTR("ez"),
229        CFSTR("fdf"),
230        CFSTR("fla"),
231        CFSTR("fp"),
232        CFSTR("fp2"),
233        CFSTR("fp3"),
234        CFSTR("fp4"),
235        CFSTR("fp5"),
236        CFSTR("fp6"),
237        CFSTR("hdf"),
238        CFSTR("ice"),
239        CFSTR("ico"),
240        CFSTR("ics"),
241        CFSTR("ief"),
242        CFSTR("iges"),
243        CFSTR("igs"),
244        CFSTR("iso"),
245        CFSTR("jhtml"),
246        CFSTR("latex"),
247        CFSTR("lha"),
248        CFSTR("lzh"),
249        CFSTR("m3u"),
250        CFSTR("m4p"),
251        CFSTR("mac"),
252        CFSTR("man"),
253        CFSTR("me"),
254        CFSTR("mesh"),
255        CFSTR("mif"),
256        CFSTR("movie"),
257        CFSTR("mp2"),
258        CFSTR("mpga"),
259        CFSTR("ms"),
260        CFSTR("msh"),
261        CFSTR("mxu"),
262        CFSTR("nc"),
263        CFSTR("oda"),
264        CFSTR("pbm"),
265        CFSTR("pcx"),
266        CFSTR("pdb"),
267        CFSTR("pgm"),
268        CFSTR("pgn"),
269        CFSTR("pls"),
270        CFSTR("pnm"),
271        CFSTR("pnt"),
272        CFSTR("pntg"),
273        CFSTR("ppm"),
274        CFSTR("ras"),
275        CFSTR("rgb"),
276        CFSTR("roff"),
277        CFSTR("rpm"),
278        CFSTR("rtx"),
279        CFSTR("sgm"),
280        CFSTR("sgml"),
281        CFSTR("sh"),
282        CFSTR("shar"),
283        CFSTR("silo"),
284        CFSTR("skd"),
285        CFSTR("skm"),
286        CFSTR("skp"),
287        CFSTR("skt"),
288        CFSTR("smi"),
289        CFSTR("so"),
290        CFSTR("spl"),
291        CFSTR("src"),
292        CFSTR("sv4cpio"),
293        CFSTR("sv4crc"),
294        CFSTR("swf"),
295        CFSTR("t"),
296        CFSTR("targa"),
297        CFSTR("tcl"),
298        CFSTR("tex"),
299        CFSTR("texi"),
300        CFSTR("texinfo"),
301        CFSTR("tgz"),
302        CFSTR("torrent"),
303        CFSTR("tr"),
304        CFSTR("tsv"),
305        CFSTR("ustar"),
306        CFSTR("vcd"),
307        CFSTR("vrml"),
308        CFSTR("wbmp"),
309        CFSTR("wbxml"),
310        CFSTR("webarchive"),
311        CFSTR("wmd"),
312        CFSTR("wml"),
313        CFSTR("wmlc"),
314        CFSTR("wmls"),
315        CFSTR("wmlsc"),
316        CFSTR("wrl"),
317        CFSTR("xdp"),
318        CFSTR("xfd"),
319        CFSTR("xfdf"),
320        CFSTR("xpm"),
321        CFSTR("xsl"),
322        CFSTR("xwd"),
323        CFSTR("xyz"),
324        CFSTR("z")
325    };
326
327    CFStringRef values[] = {
328        CFSTR("application/postscript"),
329        CFSTR("text/plain"),
330        CFSTR("application/x-bcpio"),
331        CFSTR("image/bmp"),
332        CFSTR("application/x-netcdf"),
333        CFSTR("application/octet-stream"),
334        CFSTR("application/x-gzip"),
335        CFSTR("application/x-cpio"),
336        CFSTR("application/mac-compactpro"),
337        CFSTR("application/x-csh"),
338        CFSTR("text/css"),
339        CFSTR("application/x-director"),
340        CFSTR("application/x-director"),
341        CFSTR("application/x-diskcopy"),
342        CFSTR("application/octet-stream"),
343        CFSTR("application/x-dvi"),
344        CFSTR("application/x-director"),
345        CFSTR("application/postscript"),
346        CFSTR("text/x-setext"),
347        CFSTR("application/andrew-inset"),
348        CFSTR("application/vnd.fdf"),
349        CFSTR("application/octet-stream"),
350        CFSTR("application/x-filemaker"),
351        CFSTR("application/x-filemaker"),
352        CFSTR("application/x-filemaker"),
353        CFSTR("application/x-filemaker"),
354        CFSTR("application/x-filemaker"),
355        CFSTR("application/x-filemaker"),
356        CFSTR("application/x-hdf"),
357        CFSTR("x-conference/x-cooltalk"),
358        CFSTR("image/x-icon"),
359        CFSTR("text/calendar"),
360        CFSTR("image/ief"),
361        CFSTR("model/iges"),
362        CFSTR("model/iges"),
363        CFSTR("application/octet-stream"),
364        CFSTR("text/html"),
365        CFSTR("application/x-latex"),
366        CFSTR("application/octet-stream"),
367        CFSTR("application/octet-stream"),
368        CFSTR("audio/x-mpegurl"),
369        CFSTR("audio/x-m4p"),
370        CFSTR("image/x-macpaint"),
371        CFSTR("application/x-troff-man"),
372        CFSTR("application/x-troff-me"),
373        CFSTR("model/mesh"),
374        CFSTR("application/vnd.mif"),
375        CFSTR("video/x-sgi-movie"),
376        CFSTR("audio/mpeg"),
377        CFSTR("audio/mpeg"),
378        CFSTR("application/x-troff-ms"),
379        CFSTR("model/mesh"),
380        CFSTR("video/vnd.mpegurl"),
381        CFSTR("application/x-netcdf"),
382        CFSTR("application/oda"),
383        CFSTR("image/x-portable-bitmap"),
384        CFSTR("image/x-pcx"),
385        CFSTR("chemical/x-pdb"),
386        CFSTR("image/x-portable-graymap"),
387        CFSTR("application/x-chess-pgn"),
388        CFSTR("audio/scpls"),
389        CFSTR("image/x-portable-anymap"),
390        CFSTR("image/x-macpaint"),
391        CFSTR("image/x-macpaint"),
392        CFSTR("image/x-portable-pixmap"),
393        CFSTR("image/x-cmu-raster"),
394        CFSTR("image/x-rgb"),
395        CFSTR("application/x-troff"),
396        CFSTR("audio/x-pn-realaudio-plugin"),
397        CFSTR("text/richtext"),
398        CFSTR("text/sgml"),
399        CFSTR("text/sgml"),
400        CFSTR("application/x-sh"),
401        CFSTR("application/x-shar"),
402        CFSTR("model/mesh"),
403        CFSTR("application/x-koan"),
404        CFSTR("application/x-koan"),
405        CFSTR("application/x-koan"),
406        CFSTR("application/x-koan"),
407        CFSTR("application/x-diskcopy"),
408        CFSTR("application/octet-stream"),
409        CFSTR("application/x-futuresplash"),
410        CFSTR("application/x-wais-source"),
411        CFSTR("application/x-sv4cpio"),
412        CFSTR("application/x-sv4crc"),
413        CFSTR("application/x-shockwave-flash"),
414        CFSTR("application/x-troff"),
415        CFSTR("image/x-targa"),
416        CFSTR("application/x-tcl"),
417        CFSTR("application/x-tex"),
418        CFSTR("application/x-texinfo"),
419        CFSTR("application/x-texinfo"),
420        CFSTR("application/x-gzip"),
421        CFSTR("application/x-bittorrent"),
422        CFSTR("application/x-troff"),
423        CFSTR("text/tab-separated-values"),
424        CFSTR("application/x-ustar"),
425        CFSTR("application/x-cdlink"),
426        CFSTR("model/vrml"),
427        CFSTR("image/vnd.wap.wbmp"),
428        CFSTR("application/vnd.wap.wbxml"),
429        CFSTR("application/x-webarchive"),
430        CFSTR("application/x-ms-wmd"),
431        CFSTR("text/vnd.wap.wml"),
432        CFSTR("application/vnd.wap.wmlc"),
433        CFSTR("text/vnd.wap.wmlscript"),
434        CFSTR("application/vnd.wap.wmlscriptc"),
435        CFSTR("model/vrml"),
436        CFSTR("application/vnd.adobe.xdp+xml"),
437        CFSTR("application/vnd.adobe.xfd+xml"),
438        CFSTR("application/vnd.adobe.xfdf"),
439        CFSTR("image/x-xpixmap"),
440        CFSTR("text/xml"),
441        CFSTR("image/x-xwindowdump"),
442        CFSTR("chemical/x-xyz"),
443        CFSTR("application/x-compress")
444    };
445
446    ASSERT(sizeof(keys) == sizeof(values));
447    return CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, (const void**)&values, sizeof(keys)/sizeof(CFStringRef), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
448}
449
450static RetainPtr<CFStringRef> mimeTypeFromUTITree(CFStringRef uti)
451{
452    // Check if this UTI has a MIME type.
453    RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
454    if (mimeType)
455        return mimeType.get();
456
457    // If not, walk the ancestory of this UTI via its "ConformsTo" tags and return the first MIME type we find.
458    RetainPtr<CFDictionaryRef> decl(AdoptCF, UTTypeCopyDeclaration(uti));
459    if (!decl)
460        return nil;
461    CFTypeRef value = CFDictionaryGetValue(decl.get(), kUTTypeConformsToKey);
462    if (!value)
463        return nil;
464    CFTypeID typeID = CFGetTypeID(value);
465
466    if (typeID == CFStringGetTypeID())
467        return mimeTypeFromUTITree((CFStringRef)value);
468
469    if (typeID == CFArrayGetTypeID()) {
470        CFArrayRef newTypes = (CFArrayRef)value;
471        CFIndex count = CFArrayGetCount(newTypes);
472        for (CFIndex i = 0; i < count; ++i) {
473            CFTypeRef object = CFArrayGetValueAtIndex(newTypes, i);
474            if (CFGetTypeID(object) != CFStringGetTypeID())
475                continue;
476
477            if (RetainPtr<CFStringRef> mimeType = mimeTypeFromUTITree((CFStringRef)object))
478                return mimeType;
479        }
480    }
481
482    return nil;
483}
484
485void adjustMIMETypeIfNecessary(CFURLResponseRef cfResponse)
486{
487    RetainPtr<CFStringRef> result = wkGetCFURLResponseMIMEType(cfResponse);
488    RetainPtr<CFStringRef> originalResult = result;
489
490    if (!result) {
491        CFURLRef url = wkGetCFURLResponseURL(cfResponse);
492        NSURL *nsURL = (NSURL *)url;
493        if ([nsURL isFileURL]) {
494            RetainPtr<CFStringRef> extension(AdoptCF, CFURLCopyPathExtension(url));
495            if (extension) {
496                // <rdar://problem/7007389> CoreTypes UTI map is missing 100+ file extensions that GateKeeper knew about
497                // When this radar is resolved, we can remove this file:// url specific code.
498                static CFDictionaryRef extensionMap = createExtensionToMIMETypeMap();
499                CFMutableStringRef mutableExtension = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, extension.get());
500                CFStringLowercase(mutableExtension, NULL);
501                extension.adoptCF(mutableExtension);
502                result = (CFStringRef) CFDictionaryGetValue(extensionMap, extension.get());
503
504                if (!result) {
505                    // If the Gatekeeper-based map doesn't have a MIME type, we'll try to figure out what it should be by
506                    // looking up the file extension in the UTI maps.
507                    RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension.get(), 0));
508                    result = mimeTypeFromUTITree(uti.get());
509                }
510            }
511        }
512    }
513
514    if (!result) {
515        static CFStringRef defaultMIMETypeString = WebCore::defaultMIMEType().createCFString();
516        result = defaultMIMETypeString;
517    }
518
519    // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream
520    // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types.
521    if (CFStringCompare(result.get(), CFSTR("application/octet-stream"), 0) == kCFCompareEqualTo) {
522        CFHTTPMessageRef message = wkGetCFURLResponseHTTPResponse(cfResponse);
523        if (message) {
524            RetainPtr<CFStringRef> contentType(AdoptCF, CFHTTPMessageCopyHeaderFieldValue(message, CFSTR("Content-Type")));
525            if (contentType && CFStringHasPrefix(contentType.get(), CFSTR("text/plain"))) {
526                static CFSetRef binaryExtensions = createBinaryExtensionsSet();
527                RetainPtr<NSString> suggestedFilename(AdoptNS, (NSString *)wkCopyCFURLResponseSuggestedFilename(cfResponse));
528                if (!CFSetContainsValue(binaryExtensions, (CFStringRef) [[suggestedFilename.get() pathExtension] lowercaseString]))
529                    result = CFSTR("text/plain");
530            }
531        }
532    }
533
534#ifdef BUILDING_ON_LEOPARD
535    // Workaround for <rdar://problem/5539824>
536    if (CFStringCompare(result.get(), CFSTR("text/xml"), 0) == kCFCompareEqualTo)
537        result = CFSTR("application/xml");
538#endif
539
540    if (result != originalResult)
541        wkSetCFURLResponseMIMEType(cfResponse, result.get());
542}
543
544}
545