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