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