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