18a1169917097f0d3b0634a5e37f18899f38dd88
[WebKit-https.git] / WebKit / WebView / WebDataSource.m
1 /*
2  * Copyright (C) 2005 Apple Computer, 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 "WebDataSource.h"
30
31 #import "WebArchive.h"
32 #import "WebArchiver.h"
33 #import "WebDataProtocol.h"
34 #import "WebDataSourceInternal.h"
35 #import "WebDefaultResourceLoadDelegate.h"
36 #import "WebDocument.h"
37 #import "WebFrameBridge.h"
38 #import "WebFrameInternal.h"
39 #import "WebFrameLoader.h"
40 #import "WebFrameLoadDelegate.h"
41 #import "WebHTMLRepresentation.h"
42 #import "WebKitErrorsPrivate.h"
43 #import "WebKitLogging.h"
44 #import "WebKitStatisticsPrivate.h"
45 #import "WebNSURLExtras.h"
46 #import "WebNSURLRequestExtras.h"
47 #import "WebPDFRepresentation.h"
48 #import "WebResourceLoadDelegate.h"
49 #import "WebResourcePrivate.h"
50 #import "WebUnarchivingState.h"
51 #import "WebViewInternal.h"
52 #import <JavaScriptCore/Assertions.h>
53 #import <WebKit/DOMHTML.h>
54 #import <WebKit/DOMPrivate.h>
55 #import <WebKitSystemInterface.h>
56 #import "WebDocumentLoaderMac.h"
57
58 @interface WebDataSourcePrivate : NSObject
59 {
60     @public
61     
62     WebDocumentLoaderMac *loader;
63    
64     id <WebDocumentRepresentation> representation;
65     
66     BOOL loadingFromPageCache;
67     WebUnarchivingState *unarchivingState;
68     NSMutableDictionary *subresources;
69     BOOL representationFinishedLoading;
70 }
71
72 @end
73
74 @implementation WebDataSourcePrivate 
75
76 - (void)dealloc
77 {
78     ASSERT(![loader isLoading]);
79
80     [loader release];
81     
82     [representation release];
83     [unarchivingState release];
84
85     [super dealloc];
86 }
87
88 @end
89
90 @interface WebDataSource (WebFileInternal)
91 @end
92
93 @implementation WebDataSource (WebFileInternal)
94
95 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
96 {
97     [_private->representation release];
98     _private->representation = [representation retain];
99     _private->representationFinishedLoading = NO;
100 }
101
102 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class class, NSArray *supportTypes)
103 {
104     NSEnumerator *enumerator = [supportTypes objectEnumerator];
105     ASSERT(enumerator != nil);
106     NSString *mime = nil;
107     while ((mime = [enumerator nextObject]) != nil) {
108         // Don't clobber previously-registered classes.
109         if ([allTypes objectForKey:mime] == nil)
110             [allTypes setObject:class forKey:mime];
111     }
112 }
113
114 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
115 {
116     Class repClass;
117     return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
118 }
119
120 @end
121
122 @implementation WebDataSource (WebPrivate)
123
124 - (NSError *)_mainDocumentError
125 {
126     return [_private->loader mainDocumentError];
127 }
128
129 - (void)_addSubframeArchives:(NSArray *)subframeArchives
130 {
131     NSEnumerator *enumerator = [subframeArchives objectEnumerator];
132     WebArchive *archive;
133     while ((archive = [enumerator nextObject]) != nil)
134         [self _addToUnarchiveState:archive];
135 }
136
137 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
138 {
139     if ([URL isFileURL]) {
140         NSString *path = [[URL path] stringByResolvingSymlinksInPath];
141         return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
142     }
143     
144     WebResource *resource = [self subresourceForURL:URL];
145     if (resource)
146         return [resource _fileWrapperRepresentation];
147     
148     NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
149     if (cachedResponse) {
150         NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
151         [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
152         return wrapper;
153     }
154     
155     return nil;
156 }
157
158 @end
159
160 @implementation WebDataSource (WebInternal)
161
162 - (void)_finishedLoading
163 {
164     _private->representationFinishedLoading = YES;
165     [[self representation] finishedLoadingWithDataSource:self];
166 }
167
168 - (void)_receivedData:(NSData *)data
169 {
170     [[self representation] receivedData:data withDataSource:self];
171     [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
172 }
173
174 - (void)_setMainDocumentError:(NSError *)error
175 {
176     if (!_private->representationFinishedLoading) {
177         _private->representationFinishedLoading = YES;
178         [[self representation] receivedError:error withDataSource:self];
179     }
180 }
181
182 - (void)_setLoadingFromPageCache:(BOOL)loadingFromPageCache
183 {
184     _private->loadingFromPageCache = loadingFromPageCache;
185 }
186
187 - (void)_clearUnarchivingState
188 {
189     [_private->unarchivingState release];
190     _private->unarchivingState = nil;
191 }
192
193 - (void)_revertToProvisionalState
194 {
195     [self _setRepresentation:nil];
196 }
197
198 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
199 {
200     static NSMutableDictionary *repTypes = nil;
201     static BOOL addedImageTypes = NO;
202     
203     if (!repTypes) {
204         repTypes = [[NSMutableDictionary alloc] init];
205         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
206         
207         // Since this is a "secret default" we don't both registering it.
208         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
209         if (!omitPDFSupport)
210             addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
211     }
212     
213     if (!addedImageTypes && !allowImageTypeOmission) {
214         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
215         addedImageTypes = YES;
216     }
217     
218     return repTypes;
219 }
220
221 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
222 {
223     return [_private->unarchivingState archivedResourceForURL:URL];
224 }
225
226 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
227 {
228     DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
229     if (fragment)
230         [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
231 }
232
233 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
234 {
235     ASSERT(archive);
236     WebResource *mainResource = [archive mainResource];
237     if (mainResource) {
238         NSString *MIMEType = [mainResource MIMEType];
239         if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
240             NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
241             // FIXME: seems poor form to do this as a side effect of getting a document fragment
242             [self _addToUnarchiveState:archive];
243             DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
244             [markupString release];
245             return fragment;
246         } else if ([[WebFrameBridge supportedImageResourceMIMETypes] containsObject:MIMEType]) {
247             return [self _documentFragmentWithImageResource:mainResource];
248             
249         }
250     }
251     return nil;
252 }
253
254 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
255 {
256     DOMElement *imageElement = [self _imageElementWithImageResource:resource];
257     if (!imageElement)
258         return 0;
259     DOMDocumentFragment *fragment = [[[self _bridge] DOMDocument] createDocumentFragment];
260     [fragment appendChild:imageElement];
261     return fragment;
262 }
263
264 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
265 {
266     if (!resource)
267         return 0;
268     
269     [self addSubresource:resource];
270     
271     DOMElement *imageElement = [[[self _bridge] DOMDocument] createElement:@"img"];
272     
273     // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
274     NSURL *URL = [resource URL];
275     [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
276     
277     return imageElement;
278 }
279
280 // May return nil if not initialized with a URL.
281 - (NSURL *)_URL
282 {
283     return [_private->loader URL];
284 }
285
286 - (void)_loadFromPageCache:(NSDictionary *)pageCache
287 {
288     [_private->loader prepareForLoadStart];
289     _private->loadingFromPageCache = YES;
290     [_private->loader setCommitted:YES];
291     [[_private->loader frameLoader] commitProvisionalLoad:pageCache];
292 }
293
294 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
295 {
296     return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
297 }
298
299 - (WebFrameBridge *)_bridge
300 {
301     ASSERT([_private->loader isCommitted]);
302     return [[self webFrame] _bridge];
303 }
304
305 - (WebView *)_webView
306 {
307     return [[[_private->loader frameLoader] webFrame] webView];
308 }
309
310 - (BOOL)_isDocumentHTML
311 {
312     NSString *MIMEType = [[self response] MIMEType];
313     return [WebView canShowMIMETypeAsHTML:MIMEType];
314 }
315
316 - (BOOL)_loadingFromPageCache
317 {
318     return _private->loadingFromPageCache;
319 }
320
321 -(void)_makeRepresentation
322 {
323     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
324     
325     // Check if the data source was already bound?
326     if (![[self representation] isKindOfClass:repClass]) {
327         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
328         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
329         [newRep release];
330     }
331     
332     [_private->representation setDataSource:self];
333 }
334
335 - (NSURL *)_URLForHistory
336 {
337     // Return the URL to be used for history and B/F list.
338     // Returns nil for WebDataProtocol URLs that aren't alternates 
339     // for unreachable URLs, because these can't be stored in history.
340     NSURL *URL = [[_private->loader originalRequestCopy] URL];
341     if ([WebDataProtocol _webIsDataProtocolURL:URL])
342         URL = [[_private->loader originalRequestCopy] _webDataRequestUnreachableURL];
343     
344     return [URL _webkit_canonicalize];
345 }
346
347 - (void)_addToUnarchiveState:(WebArchive *)archive
348 {
349     if (!_private->unarchivingState)
350         _private->unarchivingState = [[WebUnarchivingState alloc] init];
351     [_private->unarchivingState addArchive:archive];
352 }
353
354 - (WebDocumentLoader *)_documentLoader
355 {
356     return _private->loader;
357 }
358
359 - (id)_initWithDocumentLoader:(WebDocumentLoaderMac *)loader
360 {
361     self = [super init];
362     if (!self) {
363         return nil;
364     }
365     
366     _private = [[WebDataSourcePrivate alloc] init];
367     
368     _private->loader = [loader retain];
369         
370     LOG(Loading, "creating datasource for %@", [[_private->loader request] URL]);
371     
372     ++WebDataSourceCount;
373     
374     return self;    
375 }
376
377 @end
378
379 @implementation WebDataSource
380
381 -(id)initWithRequest:(NSURLRequest *)request
382 {
383     return [self _initWithDocumentLoader:[[WebDocumentLoader alloc] initWithRequest:request]];
384 }
385
386 - (void)dealloc
387 {
388     --WebDataSourceCount;
389     
390     [_private release];
391     
392     [super dealloc];
393 }
394
395 - (void)finalize
396 {
397     --WebDataSourceCount;
398
399     [super finalize];
400 }
401
402 - (NSData *)data
403 {
404     return [_private->loader mainResourceData];
405 }
406
407 - (id <WebDocumentRepresentation>)representation
408 {
409     return _private->representation;
410 }
411
412 - (WebFrame *)webFrame
413 {
414     return [[_private->loader frameLoader] webFrame];
415 }
416
417 -(NSURLRequest *)initialRequest
418 {
419     return [_private->loader initialRequest];
420 }
421
422 -(NSMutableURLRequest *)request
423 {
424     return [_private->loader request];
425 }
426
427 - (NSURLResponse *)response
428 {
429     return [_private->loader response];
430 }
431
432 - (NSString *)textEncodingName
433 {
434     NSString *textEncodingName = [_private->loader overrideEncoding];
435
436     if (!textEncodingName)
437         textEncodingName = [[self response] textEncodingName];
438
439     return textEncodingName;
440 }
441
442 - (BOOL)isLoading
443 {
444     return [_private->loader isLoadingInAPISense];
445 }
446
447 // Returns nil or the page title.
448 - (NSString *)pageTitle
449 {
450     return [[self representation] title];
451 }
452
453 - (NSURL *)unreachableURL
454 {
455     return [_private->loader unreachableURL];
456 }
457
458 - (WebArchive *)webArchive
459 {
460     // it makes no sense to grab a WebArchive from an uncommitted document.
461     if (![_private->loader isCommitted])
462         return nil;
463
464     return [WebArchiver archiveFrame:[self webFrame]];
465 }
466
467 - (WebResource *)mainResource
468 {
469     NSURLResponse *response = [self response];
470     return [[[WebResource alloc] initWithData:[self data]
471                                           URL:[response URL] 
472                                      MIMEType:[response MIMEType]
473                              textEncodingName:[response textEncodingName]
474                                     frameName:[[self webFrame] name]] autorelease];
475 }
476
477 - (NSArray *)subresources
478 {
479     NSArray *datas;
480     NSArray *responses;
481     [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
482     ASSERT([datas count] == [responses count]);
483
484     NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
485     for (unsigned i = 0; i < [datas count]; ++i) {
486         NSURLResponse *response = [responses objectAtIndex:i];
487         [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
488     }
489
490     return [subresources autorelease];
491 }
492
493 - (WebResource *)subresourceForURL:(NSURL *)URL
494 {
495     NSData *data;
496     NSURLResponse *response;
497     if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
498         return nil;
499
500     return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
501 }
502
503 - (void)addSubresource:(WebResource *)subresource
504 {
505     if (subresource) {
506         if (!_private->unarchivingState)
507             _private->unarchivingState = [[WebUnarchivingState alloc] init];
508         [_private->unarchivingState addResource:subresource];
509     }
510 }
511
512 @end