Reviewed by Adele.
[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 "WebDOMOperationsPrivate.h"
34 #import "WebDataProtocol.h"
35 #import "WebDataSourceInternal.h"
36 #import "WebDefaultResourceLoadDelegate.h"
37 #import "WebDocument.h"
38 #import "WebDownloadInternal.h"
39 #import "WebFrameBridge.h"
40 #import "WebFrameInternal.h"
41 #import "WebFrameLoader.h"
42 #import "WebFrameLoadDelegate.h"
43 #import "WebFrameView.h"
44 #import "WebHTMLRepresentation.h"
45 #import "WebHTMLViewPrivate.h"
46 #import "WebHistory.h"
47 #import "WebHistoryItemPrivate.h"
48 #import "WebIconDatabasePrivate.h"
49 #import "WebKitErrorsPrivate.h"
50 #import "WebKitLogging.h"
51 #import "WebKitNSStringExtras.h"
52 #import "WebKitStatisticsPrivate.h"
53 #import "WebNSObjectExtras.h"
54 #import "WebNSURLExtras.h"
55 #import "WebNSURLRequestExtras.h"
56 #import "WebPDFRepresentation.h"
57 #import "WebPreferences.h"
58 #import "WebResourceLoadDelegate.h"
59 #import "WebResourcePrivate.h"
60 #import "WebScriptDebugServerPrivate.h"
61 #import "WebUnarchivingState.h"
62 #import "WebViewInternal.h"
63 #import <Foundation/NSURLConnection.h>
64 #import <Foundation/NSURLRequest.h>
65 #import <JavaScriptCore/Assertions.h>
66 #import <WebKit/DOMHTML.h>
67 #import <WebKitSystemInterface.h>
68 #import "WebDocumentLoadState.h"
69
70 @interface WebDataSourcePrivate : NSObject
71 {
72     @public
73     
74     WebDocumentLoadState *loadState;
75     
76     id <WebDocumentRepresentation> representation;
77     
78     // A reference to actual request used to create the data source.
79     // This should only be used by the resourceLoadDelegate's
80     // identifierForInitialRequest:fromDatasource: method.  It is
81     // not guaranteed to remain unchanged, as requests are mutable.
82     NSURLRequest *originalRequest;
83     
84     // A copy of the original request used to create the data source.
85     // We have to copy the request because requests are mutable.
86     NSURLRequest *originalRequestCopy;
87     
88     // The 'working' request for this datasource.  It may be mutated
89     // several times from the original request to include additional
90     // headers, cookie information, canonicalization and redirects.
91     NSMutableURLRequest *request;
92     
93     NSURLResponse *response;
94     
95     // The time when the data source was told to start loading.
96     double loadingStartedTime;
97     
98     BOOL primaryLoadComplete;
99     
100     BOOL stopping;
101     
102     BOOL isClientRedirect;
103     
104     NSString *pageTitle;
105     
106     NSString *encoding;
107     NSString *overrideEncoding;
108     
109     // Error associated with main document.
110     NSError *mainDocumentError;
111     
112     BOOL gotFirstByte; // got first byte
113     BOOL committed; // This data source has been committed
114     BOOL representationFinishedLoading;
115     
116     BOOL defersCallbacks;
117     
118     NSURL *iconURL;
119     
120     // The action that triggered loading of this data source -
121     // we keep this around for the benefit of the various policy
122     // handlers.
123     NSDictionary *triggeringAction;
124     
125     // The last request that we checked click policy for - kept around
126     // so we can avoid asking again needlessly.
127     NSURLRequest *lastCheckedRequest;
128     
129     // We retain all the received responses so we can play back the
130     // WebResourceLoadDelegate messages if the item is loaded from the
131     // page cache.
132     NSMutableArray *responses;
133     BOOL stopRecordingResponses;
134     
135     BOOL loadingFromPageCache;
136     
137     WebFrame *webFrame;
138     
139     NSMutableDictionary *subresources;
140     
141     WebUnarchivingState *unarchivingState;
142     
143     BOOL supportsMultipartContent;
144 }
145
146 @end
147
148 @implementation WebDataSourcePrivate 
149
150 - (void)dealloc
151 {
152     [loadState release];
153     
154     [representation release];
155     [request release];
156     [originalRequest release];
157     [originalRequestCopy release];
158     [pageTitle release];
159     [response release];
160     [mainDocumentError release];
161     [iconURL release];
162     [triggeringAction release];
163     [lastCheckedRequest release];
164     [responses release];
165     [webFrame release];
166     [unarchivingState release];
167
168     [super dealloc];
169 }
170
171 @end
172
173 @interface WebDataSource (WebFileInternal)
174 @end
175
176 @implementation WebDataSource (WebFileInternal)
177
178 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
179 {
180     [_private->representation release];
181     _private->representation = [representation retain];
182     _private->representationFinishedLoading = NO;
183 }
184
185 - (void)_loadIcon
186 {
187     // Don't load an icon if 1) this is not the main frame 2) we ended in error
188     // 3) they aren't saved by the DB
189     if ([self webFrame] != [[self _webView] mainFrame] || _private->mainDocumentError || ![[WebIconDatabase sharedIconDatabase] _isEnabled])
190         return;
191
192     if (!_private->iconURL) {
193         // No icon URL from the LINK tag so try the server's root.
194         // This is only really a feature of http or https, so don't try this with other protocols.
195         NSString *scheme = [[self _URL] scheme];
196         if([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]){
197             _private->iconURL = [[[NSURL _web_URLWithDataAsString:@"/favicon.ico"
198                                                     relativeToURL:[self _URL]] absoluteURL] retain];
199         }
200     }
201
202     if (_private->iconURL != nil) {
203         // If we have the icon already, we'll still see if we're manually reloading or if the icon is expired
204         // If so, kick off a reload of the icon
205         // If we don't have the icon already, kick off the initial load
206         if ([[WebIconDatabase sharedIconDatabase] _hasEntryForIconURL:[_private->iconURL _web_originalDataAsString]]) {
207             [[_private->webFrame _frameLoader] _updateIconDatabaseWithURL:_private->iconURL];
208             if ([[self webFrame] _loadType] == WebFrameLoadTypeReload || [[WebIconDatabase sharedIconDatabase] isIconExpiredForIconURL:[_private->iconURL _web_originalDataAsString]])
209                 [[WebIconDatabase sharedIconDatabase] loadIconFromURL:[_private->iconURL _web_originalDataAsString]];
210             else
211                 [[_private->webFrame _frameLoader] _notifyIconChanged:_private->iconURL];
212         } else {
213             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:_private->iconURL];
214             [[self webFrame] _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
215             [[_private->webFrame _frameLoader] loadIconWithRequest:request];
216             [request release];
217         }
218     }
219 }
220
221 - (NSError *)_cancelledError
222 {
223     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
224                                       code:NSURLErrorCancelled
225                                        URL:[self _URL]];
226 }
227
228 - (void)_setMainDocumentError: (NSError *)error
229 {
230     [error retain];
231     [_private->mainDocumentError release];
232     _private->mainDocumentError = error;
233     
234     if (!_private->representationFinishedLoading) {
235         _private->representationFinishedLoading = YES;
236         [[self representation] receivedError:error withDataSource:self];
237     }
238 }
239
240 - (void)_clearErrors
241 {
242     [_private->mainDocumentError release];
243     _private->mainDocumentError = nil;
244 }
245
246 - (void)_prepareForLoadStart
247 {
248     ASSERT(![self _isStopping]);
249     [self _setPrimaryLoadComplete:NO];
250     ASSERT([self webFrame] != nil);
251     [self _clearErrors];
252     
253     // Mark the start loading time.
254     _private->loadingStartedTime = CFAbsoluteTimeGetCurrent();
255     
256     [[self _webView] _progressStarted:[self webFrame]];
257     [[self _webView] _didStartProvisionalLoadForFrame:[self webFrame]];
258     [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
259                                      didStartProvisionalLoadForFrame:[self webFrame]];
260 }
261
262 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class class, NSArray *supportTypes)
263 {
264     NSEnumerator *enumerator = [supportTypes objectEnumerator];
265     ASSERT(enumerator != nil);
266     NSString *mime = nil;
267     while ((mime = [enumerator nextObject]) != nil) {
268         // Don't clobber previously-registered classes.
269         if ([allTypes objectForKey:mime] == nil)
270             [allTypes setObject:class forKey:mime];
271     }
272 }
273
274 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
275 {
276     Class repClass;
277     return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
278 }
279
280 - (void)_commitIfReady
281 {
282     if (_private->gotFirstByte && !_private->committed) {
283         _private->committed = TRUE;
284         [[self webFrame] _commitProvisionalLoad:nil];
285     }
286 }
287
288 - (void)_commitLoadWithData:(NSData *)data
289 {
290     // Both unloading the old page and parsing the new page may execute JavaScript which destroys the datasource
291     // by starting a new load, so retain temporarily.
292     [self retain];
293     [self _commitIfReady];
294     [[self representation] receivedData:data withDataSource:self];
295     [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
296     [self release];
297 }
298
299 - (BOOL)_doesProgressiveLoadWithMIMEType:(NSString *)MIMEType
300 {
301     return [[self webFrame] _loadType] != WebFrameLoadTypeReplace || [MIMEType isEqualToString:@"text/html"];
302 }
303
304 - (void)_addResponse:(NSURLResponse *)r
305 {
306     if (!_private->stopRecordingResponses) {
307         if (!_private->responses)
308             _private->responses = [[NSMutableArray alloc] init];
309         [_private->responses addObject: r];
310     }
311 }
312
313 - (void)_revertToProvisionalState
314 {
315     [self _setRepresentation:nil];
316     [[_private->webFrame _frameLoader] setupForReplace];
317     _private->committed = NO;
318 }
319
320 @end
321
322 @implementation WebDataSource (WebPrivate)
323
324 - (NSError *)_mainDocumentError
325 {
326     return _private->mainDocumentError;
327 }
328
329 - (void)_addSubframeArchives:(NSArray *)subframeArchives
330 {
331     NSEnumerator *enumerator = [subframeArchives objectEnumerator];
332     WebArchive *archive;
333     while ((archive = [enumerator nextObject]) != nil)
334         [self _addToUnarchiveState:archive];
335 }
336
337 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
338 {
339     if ([URL isFileURL]) {
340         NSString *path = [[URL path] stringByResolvingSymlinksInPath];
341         return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
342     }
343     
344     WebResource *resource = [self subresourceForURL:URL];
345     if (resource) {
346         return [resource _fileWrapperRepresentation];
347     }
348     
349     NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
350     if (cachedResponse) {
351         NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
352         [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
353         return wrapper;
354     }
355     
356     return nil;
357 }
358
359 @end
360
361 @implementation WebDataSource (WebInternal)
362
363 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
364 {
365     static NSMutableDictionary *repTypes = nil;
366     static BOOL addedImageTypes = NO;
367     
368     if (!repTypes) {
369         repTypes = [[NSMutableDictionary alloc] init];
370         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
371         
372         // Since this is a "secret default" we don't both registering it.
373         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
374         if (!omitPDFSupport)
375             addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
376     }
377     
378     if (!addedImageTypes && !allowImageTypeOmission) {
379         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
380         addedImageTypes = YES;
381     }
382     
383     return repTypes;
384 }
385
386 - (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener
387 {
388     WebView *wv = [self _webView];
389     [[wv _policyDelegateForwarder] webView:wv decidePolicyForMIMEType:MIMEType
390                                    request:[self request]
391                                      frame:[self webFrame]
392                           decisionListener:listener];
393 }
394
395 - (void)_finishedLoading
396 {
397     _private->gotFirstByte = YES;
398     [self _commitIfReady];
399     
400     _private->representationFinishedLoading = YES;
401     [[self representation] finishedLoadingWithDataSource:self];
402     [[self _bridge] end];
403 }
404
405 - (void)_setResponse:(NSURLResponse *)response
406 {
407     [_private->response release];
408     _private->response = [response retain];
409 }
410
411 - (void)_setRequest:(NSURLRequest *)request
412 {
413     ASSERT_ARG(request, request != _private->request);
414     
415     // Replacing an unreachable URL with alternate content looks like a server-side
416     // redirect at this point, but we can replace a committed dataSource.
417     BOOL handlingUnreachableURL = [request _webDataRequestUnreachableURL] != nil;
418     if (handlingUnreachableURL) {
419         _private->committed = NO;
420     }
421     
422     // We should never be getting a redirect callback after the data
423     // source is committed, except in the unreachable URL case. It 
424     // would be a WebFoundation bug if it sent a redirect callback after commit.
425     ASSERT(!_private->committed);
426     
427     NSURLRequest *oldRequest = _private->request;
428     
429     _private->request = [request mutableCopy];
430     
431     // Only send webView:didReceiveServerRedirectForProvisionalLoadForFrame: if URL changed.
432     // Also, don't send it when replacing unreachable URLs with alternate content.
433     if (!handlingUnreachableURL && ![[oldRequest URL] isEqual: [request URL]]) {
434         LOG(Redirect, "Server redirect to: %@", [request URL]);
435         [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
436             didReceiveServerRedirectForProvisionalLoadForFrame:[self webFrame]];
437     }
438     
439     [oldRequest release];
440 }
441
442 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
443 {
444     if (!_private->gotFirstByte)
445         return;
446     
447     WebFrame *frame = [self webFrame];
448     NSString *oldMIMEType = [[self response] MIMEType];
449     
450     if (![self _doesProgressiveLoadWithMIMEType:oldMIMEType]) {
451         [self _revertToProvisionalState];
452         [self _commitLoadWithData:[self data]];
453     }
454     
455     _private->representationFinishedLoading = YES;
456     [[self representation] finishedLoadingWithDataSource:self];
457     [[self _bridge] end];
458     
459     [frame _setLoadType:WebFrameLoadTypeReplace];
460     _private->gotFirstByte = NO;
461     
462     if ([self _doesProgressiveLoadWithMIMEType:newMIMEType])
463         [self _revertToProvisionalState];
464     
465     [[_private->webFrame _frameLoader] stopLoadingSubresources];
466     [[_private->webFrame _frameLoader] stopLoadingPlugIns];
467     [_private->unarchivingState release];
468 }
469
470 -(void)_receivedData:(NSData *)data
471 {    
472     _private->gotFirstByte = YES;
473     
474     if ([self _doesProgressiveLoadWithMIMEType:[[self response] MIMEType]])
475         [self _commitLoadWithData:data];
476 }
477
478 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
479 {
480     // MOVABLE
481     WebFrameBridge *bridge = [[self webFrame] _bridge];
482     
483     // Retain the bridge because the stop may release the last reference to it.
484     [bridge retain];
485     
486     if (isComplete) {
487         // FIXME: Don't want to do this if an entirely new load is going, so should check
488         // that both data sources on the frame are either self or nil.
489         // Can't call [self _bridge] because we might not have commited yet
490         [bridge stop];
491         // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice.  See <rdar://problem/4258008>
492         if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
493             [bridge handleFallbackContent];
494     }
495     
496     [bridge release];
497     
498     [[self webFrame] _receivedMainResourceError:error];
499     [self _mainReceivedError:error complete:isComplete];
500 }
501
502 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
503 {
504     if (![self webFrame])
505         return;
506     
507     [self _setMainDocumentError:error];
508     
509     if (isComplete) {
510         [self _setPrimaryLoadComplete:YES];
511         [[self webFrame] _checkLoadComplete];
512     }
513 }
514
515 - (BOOL)_defersCallbacks
516 {
517     return _private->defersCallbacks;
518 }
519
520 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr) proxy
521 {
522     [WebDownload _downloadWithLoadingConnection:connection
523                                         request:request
524                                        response:r
525                                        delegate:[[self _webView] downloadDelegate]
526                                           proxy:proxy];
527 }
528
529 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
530 {
531     WebView *webView = [self _webView];
532     
533     [webView _completeProgressForIdentifier:identifier];
534     
535     if (error)
536         [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:self];
537 }
538
539 - (void)_didFinishLoadingForResource:(id)identifier
540 {
541     WebView *webView = [self _webView];
542     
543     [webView _completeProgressForIdentifier:identifier];    
544     
545     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
546         [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
547     else
548         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
549 }
550
551 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
552 {
553     WebView *webView = [self _webView];
554     
555     [webView _incrementProgressForIdentifier:identifier data:data];
556     
557     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
558         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
559     else
560         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
561 }
562
563 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
564 {
565     WebView *webView = [self _webView];
566     
567     [self _addResponse:r];
568     
569     [webView _incrementProgressForIdentifier:identifier response:r];
570     
571     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
572         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
573     else
574         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
575 }
576
577 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
578 {
579     WebView *webView = [self _webView];
580     
581     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
582         [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
583     else
584         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
585 }
586
587 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
588 {
589     WebView *webView = [self _webView];
590     
591     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
592         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
593     else
594         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
595 }
596
597 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
598 {
599     WebView *webView = [self _webView];
600     
601     [clientRequest _web_setHTTPUserAgent:[webView userAgentForURL:[clientRequest URL]]];
602     
603     if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
604         return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
605     else
606         return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
607 }        
608
609 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
610 {
611     WebView *webView = [self _webView];
612     
613     // The identifier is released after the last callback, rather than in dealloc
614     // to avoid potential cycles.
615     if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
616         return [[[webView resourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
617     else
618         return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
619 }
620
621 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
622 {
623     return [_private->unarchivingState archivedResourceForURL:URL];
624 }
625
626 - (void)_startLoading
627 {
628     [self _prepareForLoadStart];
629     
630     if ([[_private->webFrame _frameLoader] isLoadingMainResource])
631         return;
632     
633     _private->loadingFromPageCache = NO;
634     
635     id identifier;
636     id resourceLoadDelegate = [[self _webView] resourceLoadDelegate];
637     if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
638         identifier = [resourceLoadDelegate webView:[self _webView] identifierForInitialRequest:_private->originalRequest fromDataSource:self];
639     else
640         identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[self _webView] identifierForInitialRequest:_private->originalRequest fromDataSource:self];
641     
642     [[_private->webFrame _frameLoader] startLoadingMainResourceWithRequest:_private->request identifier:identifier];
643 }
644
645 - (void)_stopRecordingResponses
646 {
647     _private->stopRecordingResponses = YES;
648 }
649
650 - (double)_loadingStartedTime
651 {
652     return _private->loadingStartedTime;
653 }
654
655 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
656 {
657     DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
658     if (fragment)
659         [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
660 }
661
662 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
663 {
664     ASSERT(archive);
665     WebResource *mainResource = [archive mainResource];
666     if (mainResource) {
667         NSString *MIMEType = [mainResource MIMEType];
668         if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
669             NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
670             // FIXME: seems poor form to do this as a side effect of getting a document fragment
671             [self _addToUnarchiveState:archive];
672             DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
673             [markupString release];
674             return fragment;
675         } else if ([[WebFrameBridge supportedImageResourceMIMETypes] containsObject:MIMEType]) {
676             return [self _documentFragmentWithImageResource:mainResource];
677             
678         }
679     }
680     return nil;
681 }
682
683 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
684 {
685     DOMElement *imageElement = [self _imageElementWithImageResource:resource];
686     if (!imageElement)
687         return 0;
688     DOMDocumentFragment *fragment = [[[self _bridge] DOMDocument] createDocumentFragment];
689     [fragment appendChild:imageElement];
690     return fragment;
691 }
692
693 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
694 {
695     if (!resource)
696         return 0;
697     
698     [self addSubresource:resource];
699     
700     DOMElement *imageElement = [[[self _bridge] DOMDocument] createElement:@"img"];
701     
702     // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
703     NSURL *URL = [resource URL];
704     [imageElement setAttribute:@"src" :[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
705     
706     return imageElement;
707 }
708
709 - (NSString *)_title
710 {
711     return _private->pageTitle;
712 }
713
714 - (BOOL)_isStopping
715 {
716     return _private->stopping;
717 }
718
719 - (void)_setWebFrame:(WebFrame *)frame
720 {
721     [frame retain];
722     [_private->webFrame release];
723     _private->webFrame = frame;
724
725     [_private->loadState setFrameLoader:[frame _frameLoader]];
726     
727     [self _defersCallbacksChanged];
728     // no need to do _defersCallbacksChanged for subframes since they too
729     // will be or have been told of their WebFrame
730 }
731
732 // May return nil if not initialized with a URL.
733 - (NSURL *)_URL
734 {
735     return [[self request] URL];
736 }
737
738 - (void)_loadFromPageCache:(NSDictionary *)pageCache
739 {
740     [self _prepareForLoadStart];
741     _private->loadingFromPageCache = YES;
742     _private->committed = TRUE;
743     [[self webFrame] _commitProvisionalLoad:pageCache];
744 }
745
746 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
747 {
748     return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
749 }
750
751 - (void)_setIsClientRedirect:(BOOL)flag
752 {
753     _private->isClientRedirect = flag;
754 }
755
756 - (void)_setURL:(NSURL *)URL
757 {
758     NSMutableURLRequest *newOriginalRequest = [_private->originalRequestCopy mutableCopy];
759     [_private->originalRequestCopy release];
760     [newOriginalRequest setURL:URL];
761     _private->originalRequestCopy = newOriginalRequest;
762     
763     NSMutableURLRequest *newRequest = [_private->request mutableCopy];
764     [_private->request release];
765     [newRequest setURL:URL];
766     _private->request = newRequest;
767 }
768
769 - (void)_setLastCheckedRequest:(NSURLRequest *)request
770 {
771     NSURLRequest *oldRequest = _private->lastCheckedRequest;
772     _private->lastCheckedRequest = [request copy];
773     [oldRequest release];
774 }
775
776 - (void)_defersCallbacksChanged
777 {
778     BOOL defers = [[self _webView] defersCallbacks];
779     
780     if (defers == _private->defersCallbacks) {
781         return;
782     }
783     
784     _private->defersCallbacks = defers;
785     [[_private->webFrame _frameLoader] setDefersCallbacks:defers];
786 }
787
788 - (NSURLRequest *)_lastCheckedRequest
789 {
790     // It's OK not to make a copy here because we know the caller
791     // isn't going to modify this request
792     return [[_private->lastCheckedRequest retain] autorelease];
793 }
794
795 // Cancels the data source's pending loads.  Conceptually, a data source only loads
796 // one document at a time, but one document may have many related resources. 
797 // _stopLoading will stop all loads initiated by the data source, 
798 // but not loads initiated by child frames' data sources -- that's the WebFrame's job.
799 - (void)_stopLoading
800 {
801     // Always attempt to stop the icon loader because it may still be loading after the data source
802     // is done loading and not stopping it can cause a world leak.
803     [[_private->webFrame _frameLoader] stopLoadingIcon];
804     
805     // The same goes for the bridge/part, which may still be parsing.
806     if (_private->committed)
807         [[self _bridge] stopLoading];
808     
809     if (![[_private->webFrame _frameLoader] isLoading])
810         return;
811     
812     [self retain];
813     
814     _private->stopping = YES;
815     
816     if ([[_private->webFrame _frameLoader] isLoadingMainResource]) {
817         // Stop the main resource loader and let it send the cancelled message.
818         [[_private->webFrame _frameLoader] cancelMainResourceLoad];
819     } else if ([[_private->webFrame _frameLoader] isLoadingSubresources]) {
820         // The main resource loader already finished loading. Set the cancelled error on the 
821         // document and let the subresourceLoaders send individual cancelled messages below.
822         [self _setMainDocumentError:[self _cancelledError]];
823     } else {
824         // If there are no resource loaders, we need to manufacture a cancelled message.
825         // (A back/forward navigation has no resource loaders because its resources are cached.)
826         [self _mainReceivedError:[self _cancelledError] complete:YES];
827     }
828     
829     [[_private->webFrame _frameLoader] stopLoadingSubresources];
830     [[_private->webFrame _frameLoader] stopLoadingPlugIns];
831     
832     _private->stopping = NO;
833     
834     [self release];
835 }
836
837 - (WebFrameBridge *)_bridge
838 {
839     ASSERT(_private->committed);
840     return [[self webFrame] _bridge];
841 }
842
843 - (WebView *)_webView
844 {
845     return [_private->webFrame webView];
846 }
847
848 - (NSDictionary *)_triggeringAction
849 {
850     return [[_private->triggeringAction retain] autorelease];
851 }
852
853 - (void)_setTriggeringAction:(NSDictionary *)action
854 {
855     [action retain];
856     [_private->triggeringAction release];
857     _private->triggeringAction = action;
858 }
859
860 - (void)__adoptRequest:(NSMutableURLRequest *)request
861 {
862     if (request != _private->request){
863         [_private->request release];
864         _private->request = [request retain];
865     }
866 }
867
868 - (BOOL)_isDocumentHTML
869 {
870     NSString *MIMEType = [[self response] MIMEType];
871     return [WebView canShowMIMETypeAsHTML:MIMEType];
872 }
873
874 - (void)_stopLoadingWithError:(NSError *)error
875 {
876     [[_private->webFrame _frameLoader] stopLoadingWithError:error];
877 }
878
879 - (void)_setPrimaryLoadComplete:(BOOL)flag
880 {
881     _private->primaryLoadComplete = flag;
882     
883     if (flag) {
884         // FIXME: We could actually load it as soon as we've parsed
885         // the HEAD section, or determined there isn't one - but
886         // there's no callback for that.
887         [self _loadIcon];
888         
889         if ([[_private->webFrame _frameLoader] isLoadingMainResource]) {
890             [_private->loadState setMainResourceData:[[_private->webFrame _frameLoader] mainResourceData]];
891             [[_private->webFrame _frameLoader] releaseMainResourceLoader];
892         }
893         
894         if ([WebScriptDebugServer listenerCount])
895             [[WebScriptDebugServer sharedScriptDebugServer] webView:[[self webFrame] webView] didLoadMainResourceForDataSource:self];
896     }
897 }
898
899 - (NSArray *)_responses
900 {
901     return _private->responses;
902 }
903
904 - (BOOL)_loadingFromPageCache
905 {
906     return _private->loadingFromPageCache;
907 }
908
909 -(void)_makeRepresentation
910 {
911     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
912     
913     // Check if the data source was already bound?
914     if (![[self representation] isKindOfClass:repClass]) {
915         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
916         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
917         [newRep release];
918     }
919     
920     [_private->representation setDataSource:self];
921 }
922
923 - (BOOL)_isClientRedirect
924 {
925     return _private->isClientRedirect;
926 }
927
928
929 - (NSURLRequest *)_originalRequest
930 {
931     return _private->originalRequestCopy;
932 }
933
934 - (NSURL *)_URLForHistory
935 {
936     // Return the URL to be used for history and B/F list.
937     // Returns nil for WebDataProtocol URLs that aren't alternates 
938     // for unreachable URLs, because these can't be stored in history.
939     NSURL *URL = [_private->originalRequestCopy URL];
940     if ([WebDataProtocol _webIsDataProtocolURL:URL]) {
941         URL = [_private->originalRequestCopy _webDataRequestUnreachableURL];
942     }
943     
944     return [URL _webkit_canonicalize];
945 }
946
947 - (void)_addToUnarchiveState:(WebArchive *)archive
948 {
949     if (!_private->unarchivingState)
950         _private->unarchivingState = [[WebUnarchivingState alloc] init];
951     [_private->unarchivingState addArchive:archive];
952 }
953
954 - (void)_setOverrideEncoding:(NSString *)overrideEncoding
955 {
956     NSString *copy = [overrideEncoding copy];
957     [_private->overrideEncoding release];
958     _private->overrideEncoding = copy;
959 }
960
961 - (void)_setIconURL:(NSURL *)URL
962 {
963     // Lower priority than typed icon, so ignore this if we already have an iconURL.
964     if (_private->iconURL == nil) {
965         [_private->iconURL release];
966         _private->iconURL = [URL retain];
967     }
968 }
969
970 - (void)_setIconURL:(NSURL *)URL withType:(NSString *)iconType
971 {
972     // FIXME: Should check to make sure the type is one we know how to handle.
973     [_private->iconURL release];
974     _private->iconURL = [URL retain];
975 }
976
977 - (NSString *)_overrideEncoding
978 {
979     return [[_private->overrideEncoding copy] autorelease];
980 }
981
982 - (void)_setTitle:(NSString *)title
983 {
984     NSString *trimmed;
985     if (title == nil) {
986         trimmed = nil;
987     } else {
988         trimmed = [title _webkit_stringByTrimmingWhitespace];
989         if ([trimmed length] == 0)
990             trimmed = nil;
991     }
992     if (trimmed == nil) {
993         if (_private->pageTitle == nil)
994             return;
995     } else {
996         if ([_private->pageTitle isEqualToString:trimmed])
997             return;
998     }
999     
1000     if (!trimmed || [trimmed length] == 0)
1001         return;
1002     
1003     [[self _webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1004     [_private->pageTitle release];
1005     _private->pageTitle = [trimmed copy];
1006     [[self _webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1007     
1008     // The title doesn't get communicated to the WebView until we are committed.
1009     if (_private->committed) {
1010         NSURL *URLForHistory = [self _URLForHistory];
1011         if (URLForHistory != nil) {
1012             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
1013             [entry setTitle: _private->pageTitle];
1014             
1015             // Must update the entries in the back-forward list too.  This must go through the WebFrame because
1016             // it has the right notion of the current b/f item.
1017             [[self webFrame] _setTitle:_private->pageTitle];
1018             
1019             [[self _webView] setMainFrameDocumentReady:YES];    // update observers with new DOMDocument
1020             [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
1021                                                    didReceiveTitle:_private->pageTitle
1022                                                           forFrame:[self webFrame]];
1023         }
1024     }
1025 }
1026
1027 @end
1028
1029 @implementation WebDataSource
1030
1031 -(id)initWithRequest:(NSURLRequest *)request
1032 {
1033     self = [super init];
1034     if (!self) {
1035         return nil;
1036     }
1037     
1038     _private = [[WebDataSourcePrivate alloc] init];
1039     
1040     _private->loadState = [[WebDocumentLoadState alloc] initWithRequest:request];
1041     
1042     _private->originalRequest = [request retain];
1043     _private->originalRequestCopy = [request copy];
1044     
1045     LOG(Loading, "creating datasource for %@", [request URL]);
1046     _private->request = [_private->originalRequest mutableCopy];
1047     _private->supportsMultipartContent = WKSupportsMultipartXMixedReplace(_private->request);
1048
1049     ++WebDataSourceCount;
1050     
1051     return self;
1052 }
1053
1054 - (void)dealloc
1055 {
1056     ASSERT([[_private->webFrame _frameLoader] activeDataSource] != self || ![[_private->webFrame _frameLoader] isLoading]);
1057
1058     --WebDataSourceCount;
1059     
1060     [_private release];
1061     
1062     [super dealloc];
1063 }
1064
1065 - (void)finalize
1066 {
1067     --WebDataSourceCount;
1068
1069     [super finalize];
1070 }
1071
1072 - (NSData *)data
1073 {
1074     return [_private->loadState mainResourceData];
1075 }
1076
1077 - (id <WebDocumentRepresentation>)representation
1078 {
1079     return _private->representation;
1080 }
1081
1082 - (WebFrame *)webFrame
1083 {
1084     return _private->webFrame;
1085 }
1086
1087 -(NSURLRequest *)initialRequest
1088 {
1089     NSURLRequest *clientRequest = [_private->originalRequest _webDataRequestExternalRequest];
1090     if (!clientRequest)
1091         clientRequest = _private->originalRequest;
1092     return clientRequest;
1093 }
1094
1095 -(NSMutableURLRequest *)request
1096 {
1097     NSMutableURLRequest *clientRequest = [_private->request _webDataRequestExternalRequest];
1098     if (!clientRequest)
1099         clientRequest = _private->request;
1100     return clientRequest;
1101 }
1102
1103 - (NSURLResponse *)response
1104 {
1105     return _private->response;
1106 }
1107
1108 - (NSString *)textEncodingName
1109 {
1110     NSString *textEncodingName = [self _overrideEncoding];
1111
1112     if (!textEncodingName)
1113         textEncodingName = [[self response] textEncodingName];
1114
1115     return textEncodingName;
1116 }
1117
1118 // Returns YES if there are any pending loads.
1119 - (BOOL)isLoading
1120 {
1121     // Once a frame has loaded, we no longer need to consider subresources,
1122     // but we still need to consider subframes.
1123     if ([[[self webFrame] _frameLoader] state] != WebFrameStateComplete) {
1124         if (!_private->primaryLoadComplete && [[_private->webFrame _frameLoader] isLoading])
1125             return YES;
1126         if ([[_private->webFrame _frameLoader] isLoadingSubresources])
1127             return YES;
1128         if (![[[self webFrame] _bridge] doneProcessingData])
1129             return YES;
1130     }
1131
1132     return [[self webFrame] _subframeIsLoading];
1133 }
1134
1135 // Returns nil or the page title.
1136 - (NSString *)pageTitle
1137 {
1138     return [[self representation] title];
1139 }
1140
1141 - (NSURL *)unreachableURL
1142 {
1143     return [_private->originalRequest _webDataRequestUnreachableURL];
1144 }
1145
1146 - (WebArchive *)webArchive
1147 {
1148     // it makes no sense to grab a WebArchive from an uncommitted document.
1149     if (!_private->committed)
1150         return nil;
1151
1152     return [WebArchiver archiveFrame:[self webFrame]];
1153 }
1154
1155 - (WebResource *)mainResource
1156 {
1157     NSURLResponse *response = [self response];
1158     return [[[WebResource alloc] initWithData:[self data]
1159                                           URL:[response URL] 
1160                                      MIMEType:[response MIMEType]
1161                              textEncodingName:[response textEncodingName]
1162                                     frameName:[[self webFrame] name]] autorelease];
1163 }
1164
1165 - (NSArray *)subresources
1166 {
1167     NSArray *datas;
1168     NSArray *responses;
1169     [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
1170     ASSERT([datas count] == [responses count]);
1171
1172     NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
1173     for (unsigned i = 0; i < [datas count]; ++i) {
1174         NSURLResponse *response = [responses objectAtIndex:i];
1175         [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
1176     }
1177
1178     return [subresources autorelease];
1179 }
1180
1181 - (WebResource *)subresourceForURL:(NSURL *)URL
1182 {
1183     NSData *data;
1184     NSURLResponse *response;
1185     if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
1186         return nil;
1187
1188     return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
1189 }
1190
1191 - (void)addSubresource:(WebResource *)subresource
1192 {
1193     if (subresource) {
1194         if (!_private->unarchivingState)
1195             _private->unarchivingState = [[WebUnarchivingState alloc] init];
1196         [_private->unarchivingState addResource:subresource];
1197     }
1198 }
1199
1200 @end