|
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 |