1/* 2 * Copyright (C) 2005, 2006, 2007, 2008 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 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 "WebResourceInternal.h" 30 31#import "WebFrameInternal.h" 32#import "WebKitLogging.h" 33#import "WebKitVersionChecks.h" 34#import "WebNSDictionaryExtras.h" 35#import "WebNSObjectExtras.h" 36#import "WebNSURLExtras.h" 37#import <JavaScriptCore/InitializeThreading.h> 38#import <wtf/PassRefPtr.h> 39#import <WebCore/ArchiveResource.h> 40#import <WebCore/LegacyWebArchive.h> 41#import <WebCore/RuntimeApplicationChecks.h> 42#import <WebCore/TextEncoding.h> 43#import <WebCore/ThreadCheck.h> 44#import <WebCore/WebCoreObjCExtras.h> 45#import <WebCore/WebCoreURLResponse.h> 46#import <wtf/MainThread.h> 47#import <wtf/RunLoop.h> 48 49using namespace WebCore; 50 51static NSString * const WebResourceDataKey = @"WebResourceData"; 52static NSString * const WebResourceFrameNameKey = @"WebResourceFrameName"; 53static NSString * const WebResourceMIMETypeKey = @"WebResourceMIMEType"; 54static NSString * const WebResourceURLKey = @"WebResourceURL"; 55static NSString * const WebResourceTextEncodingNameKey = @"WebResourceTextEncodingName"; 56static NSString * const WebResourceResponseKey = @"WebResourceResponse"; 57 58@interface WebResourcePrivate : NSObject { 59@public 60 ArchiveResource* coreResource; 61} 62- (instancetype)initWithCoreResource:(PassRefPtr<ArchiveResource>)coreResource; 63@end 64 65@implementation WebResourcePrivate 66 67+ (void)initialize 68{ 69#if !PLATFORM(IOS) 70 JSC::initializeThreading(); 71 WTF::initializeMainThreadToProcessMainThread(); 72 RunLoop::initializeMainRunLoop(); 73#endif 74 WebCoreObjCFinalizeOnMainThread(self); 75} 76 77- (instancetype)init 78{ 79 return [super init]; 80} 81 82- (instancetype)initWithCoreResource:(PassRefPtr<ArchiveResource>)passedResource 83{ 84 self = [super init]; 85 if (!self) 86 return nil; 87 // Acquire the PassRefPtr<>'s ref as our own manual ref 88 coreResource = passedResource.leakRef(); 89 return self; 90} 91 92- (void)dealloc 93{ 94 if (WebCoreObjCScheduleDeallocateOnMainThread([WebResourcePrivate class], self)) 95 return; 96 97 if (coreResource) 98 coreResource->deref(); 99 [super dealloc]; 100} 101 102- (void)finalize 103{ 104 if (coreResource) 105 coreResource->deref(); 106 [super finalize]; 107} 108 109@end 110 111@implementation WebResource 112 113- (instancetype)init 114{ 115 self = [super init]; 116 if (!self) 117 return nil; 118 _private = [[WebResourcePrivate alloc] init]; 119 return self; 120} 121 122- (instancetype)initWithData:(NSData *)data URL:(NSURL *)URL MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName 123{ 124 return [self _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:nil copyData:YES]; 125} 126 127- (instancetype)initWithCoder:(NSCoder *)decoder 128{ 129 WebCoreThreadViolationCheckRoundTwo(); 130 131 self = [super init]; 132 if (!self) 133 return nil; 134 135 NSData *data = nil; 136 NSURL *url = nil; 137 NSString *mimeType = nil, *textEncoding = nil, *frameName = nil; 138 NSURLResponse *response = nil; 139 140 @try { 141 id object = [decoder decodeObjectForKey:WebResourceDataKey]; 142 if ([object isKindOfClass:[NSData class]]) 143 data = object; 144 object = [decoder decodeObjectForKey:WebResourceURLKey]; 145 if ([object isKindOfClass:[NSURL class]]) 146 url = object; 147 object = [decoder decodeObjectForKey:WebResourceMIMETypeKey]; 148 if ([object isKindOfClass:[NSString class]]) 149 mimeType = object; 150 object = [decoder decodeObjectForKey:WebResourceTextEncodingNameKey]; 151 if ([object isKindOfClass:[NSString class]]) 152 textEncoding = object; 153 object = [decoder decodeObjectForKey:WebResourceFrameNameKey]; 154 if ([object isKindOfClass:[NSString class]]) 155 frameName = object; 156 object = [decoder decodeObjectForKey:WebResourceResponseKey]; 157 if ([object isKindOfClass:[NSURLResponse class]]) 158 response = object; 159 } @catch(id) { 160 [self release]; 161 return nil; 162 } 163 164 _private = [[WebResourcePrivate alloc] initWithCoreResource:ArchiveResource::create(SharedBuffer::wrapNSData(data), url, mimeType, textEncoding, frameName, response)]; 165 166 return self; 167} 168 169- (void)encodeWithCoder:(NSCoder *)encoder 170{ 171 ArchiveResource *resource = _private->coreResource; 172 173 NSData *data = nil; 174 NSURL *url = nil; 175 NSString *mimeType = nil, *textEncoding = nil, *frameName = nil; 176 NSURLResponse *response = nil; 177 178 if (resource) { 179 if (resource->data()) 180 data = resource->data()->createNSData().get(); 181 url = resource->url(); 182 mimeType = resource->mimeType(); 183 textEncoding = resource->textEncoding(); 184 frameName = resource->frameName(); 185 response = resource->response().nsURLResponse(); 186 } 187 [encoder encodeObject:data forKey:WebResourceDataKey]; 188 [encoder encodeObject:url forKey:WebResourceURLKey]; 189 [encoder encodeObject:mimeType forKey:WebResourceMIMETypeKey]; 190 [encoder encodeObject:textEncoding forKey:WebResourceTextEncodingNameKey]; 191 [encoder encodeObject:frameName forKey:WebResourceFrameNameKey]; 192 [encoder encodeObject:response forKey:WebResourceResponseKey]; 193} 194 195- (void)dealloc 196{ 197 [_private release]; 198 [super dealloc]; 199} 200 201- (id)copyWithZone:(NSZone *)zone 202{ 203 return [self retain]; 204} 205 206- (NSData *)data 207{ 208 WebCoreThreadViolationCheckRoundTwo(); 209 210 if (!_private->coreResource) 211 return nil; 212 if (!_private->coreResource->data()) 213 return nil; 214 return _private->coreResource->data()->createNSData().autorelease(); 215} 216 217- (NSURL *)URL 218{ 219 WebCoreThreadViolationCheckRoundTwo(); 220 221 if (!_private->coreResource) 222 return nil; 223 NSURL *url = _private->coreResource->url(); 224 return url; 225} 226 227- (NSString *)MIMEType 228{ 229 WebCoreThreadViolationCheckRoundTwo(); 230 231 if (!_private->coreResource) 232 return nil; 233 NSString *mimeType = _private->coreResource->mimeType(); 234 return mimeType; 235} 236 237- (NSString *)textEncodingName 238{ 239 WebCoreThreadViolationCheckRoundTwo(); 240 241 if (!_private->coreResource) 242 return nil; 243 NSString *textEncodingName = _private->coreResource->textEncoding(); 244 return textEncodingName; 245} 246 247- (NSString *)frameName 248{ 249 WebCoreThreadViolationCheckRoundTwo(); 250 251 if (!_private->coreResource) 252 return nil; 253 NSString *frameName = _private->coreResource->frameName(); 254 return frameName; 255} 256 257- (NSString *)description 258{ 259#if !PLATFORM(IOS) 260 return [NSString stringWithFormat:@"<%@ %@>", [self className], [self URL]]; 261#else 262 return [NSString stringWithFormat:@"<%@ %@>", NSStringFromClass([self class]), [self URL]]; 263#endif 264} 265 266@end 267 268@implementation WebResource (WebResourceInternal) 269 270- (id)_initWithCoreResource:(PassRefPtr<ArchiveResource>)coreResource 271{ 272 self = [super init]; 273 if (!self) 274 return nil; 275 276 ASSERT(coreResource); 277 278 // WebResources should not be init'ed with nil data, and doing so breaks certain uses of NSHTMLReader 279 // See <rdar://problem/5820157> for more info 280 if (!coreResource->data()) { 281 [self release]; 282 return nil; 283 } 284 285 _private = [[WebResourcePrivate alloc] initWithCoreResource:coreResource]; 286 287 return self; 288} 289 290- (WebCore::ArchiveResource *)_coreResource 291{ 292 return _private->coreResource; 293} 294 295@end 296 297@implementation WebResource (WebResourcePrivate) 298 299// SPI for Mail (5066325) 300// FIXME: This "ignoreWhenUnarchiving" concept is an ugly one - can we find a cleaner solution for those who need this SPI? 301- (void)_ignoreWhenUnarchiving 302{ 303 WebCoreThreadViolationCheckRoundTwo(); 304 305 if (!_private->coreResource) 306 return; 307 _private->coreResource->ignoreWhenUnarchiving(); 308} 309 310- (id)_initWithData:(NSData *)data 311 URL:(NSURL *)URL 312 MIMEType:(NSString *)MIMEType 313 textEncodingName:(NSString *)textEncodingName 314 frameName:(NSString *)frameName 315 response:(NSURLResponse *)response 316 copyData:(BOOL)copyData 317{ 318 WebCoreThreadViolationCheckRoundTwo(); 319 320 self = [super init]; 321 if (!self) 322 return nil; 323 324 if (!data || !URL || !MIMEType) { 325 [self release]; 326 return nil; 327 } 328 329 _private = [[WebResourcePrivate alloc] initWithCoreResource:ArchiveResource::create(SharedBuffer::wrapNSData(copyData ? [[data copy] autorelease] : data), URL, MIMEType, textEncodingName, frameName, response)]; 330 331 return self; 332} 333 334- (id)_initWithData:(NSData *)data URL:(NSURL *)URL response:(NSURLResponse *)response 335{ 336 // Pass NO for copyData since the data doesn't need to be copied since we know that callers will no longer modify it. 337 // Copying it will also cause a performance regression. 338 return [self _initWithData:data 339 URL:URL 340 MIMEType:[response MIMEType] 341 textEncodingName:[response textEncodingName] 342 frameName:nil 343 response:response 344 copyData:NO]; 345} 346 347- (NSString *)_suggestedFilename 348{ 349 WebCoreThreadViolationCheckRoundTwo(); 350 351 if (!_private->coreResource) 352 return nil; 353 NSString *suggestedFilename = _private->coreResource->response().suggestedFilename(); 354 return suggestedFilename; 355} 356 357#if !PLATFORM(IOS) 358- (NSFileWrapper *)_fileWrapperRepresentation 359{ 360 NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[self data]] autorelease]; 361 NSString *filename = [self _suggestedFilename]; 362 if (!filename || ![filename length]) 363 filename = [[self URL] _webkit_suggestedFilenameWithMIMEType:[self MIMEType]]; 364 [wrapper setPreferredFilename:filename]; 365 return wrapper; 366} 367#endif 368 369- (NSURLResponse *)_response 370{ 371 WebCoreThreadViolationCheckRoundTwo(); 372 373 NSURLResponse *response = nil; 374 if (_private->coreResource) 375 response = _private->coreResource->response().nsURLResponse(); 376 return response ? response : [[[NSURLResponse alloc] init] autorelease]; 377} 378 379- (NSString *)_stringValue 380{ 381 WebCoreThreadViolationCheckRoundTwo(); 382 383 WebCore::TextEncoding encoding; 384 if (_private->coreResource) 385 encoding = _private->coreResource->textEncoding(); 386 if (!encoding.isValid()) 387 encoding = WindowsLatin1Encoding(); 388 389 SharedBuffer* coreData = _private->coreResource ? _private->coreResource->data() : 0; 390 return encoding.decode(reinterpret_cast<const char*>(coreData ? coreData->data() : 0), coreData ? coreData->size() : 0); 391} 392 393@end 394