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