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