Reviewed by Alice.
[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 <WebKit/DOMPrivate.h>
68 #import <WebKitSystemInterface.h>
69 #import "WebDocumentLoadStateMac.h"
70
71 @interface WebDataSourcePrivate : NSObject
72 {
73     @public
74     
75     WebDocumentLoadStateMac *loadState;
76    
77     id <WebDocumentRepresentation> representation;
78     
79     BOOL loadingFromPageCache;
80     WebUnarchivingState *unarchivingState;
81     NSMutableDictionary *subresources;
82     
83     // The time when the data source was told to start loading.
84     double loadingStartedTime;
85     
86     BOOL primaryLoadComplete;
87         
88     BOOL isClientRedirect;
89     
90     NSString *pageTitle;
91     
92     NSString *encoding;
93     NSString *overrideEncoding;
94     
95     BOOL representationFinishedLoading;
96     
97     // The action that triggered loading of this data source -
98     // we keep this around for the benefit of the various policy
99     // handlers.
100     NSDictionary *triggeringAction;
101     
102     // The last request that we checked click policy for - kept around
103     // so we can avoid asking again needlessly.
104     NSURLRequest *lastCheckedRequest;
105     
106     // We retain all the received responses so we can play back the
107     // WebResourceLoadDelegate messages if the item is loaded from the
108     // page cache.
109     NSMutableArray *responses;
110     BOOL stopRecordingResponses;    
111 }
112
113 @end
114
115 @implementation WebDataSourcePrivate 
116
117 - (void)dealloc
118 {
119     ASSERT(![loadState isLoading]);
120
121     [loadState release];
122     
123     [representation release];
124     [pageTitle release];
125     [triggeringAction release];
126     [lastCheckedRequest release];
127     [responses release];
128     [unarchivingState release];
129
130     [super dealloc];
131 }
132
133 @end
134
135 @interface WebDataSource (WebFileInternal)
136 @end
137
138 @implementation WebDataSource (WebFileInternal)
139
140 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
141 {
142     [_private->representation release];
143     _private->representation = [representation retain];
144     _private->representationFinishedLoading = NO;
145 }
146
147 - (void)_prepareForLoadStart
148 {
149     ASSERT(![_private->loadState isStopping]);
150     [self _setPrimaryLoadComplete:NO];
151     ASSERT([self webFrame] != nil);
152     [_private->loadState clearErrors];
153     
154     // Mark the start loading time.
155     _private->loadingStartedTime = CFAbsoluteTimeGetCurrent();
156     
157     [_private->loadState setLoading:YES];
158     [[self _webView] _progressStarted:[self webFrame]];
159     [[self _webView] _didStartProvisionalLoadForFrame:[self webFrame]];
160     [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
161                                      didStartProvisionalLoadForFrame:[self webFrame]];
162 }
163
164 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class class, NSArray *supportTypes)
165 {
166     NSEnumerator *enumerator = [supportTypes objectEnumerator];
167     ASSERT(enumerator != nil);
168     NSString *mime = nil;
169     while ((mime = [enumerator nextObject]) != nil) {
170         // Don't clobber previously-registered classes.
171         if ([allTypes objectForKey:mime] == nil)
172             [allTypes setObject:class forKey:mime];
173     }
174 }
175
176 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
177 {
178     Class repClass;
179     return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
180 }
181
182 - (void)_addResponse:(NSURLResponse *)r
183 {
184     if (!_private->stopRecordingResponses) {
185         if (!_private->responses)
186             _private->responses = [[NSMutableArray alloc] init];
187         [_private->responses addObject: r];
188     }
189 }
190
191 @end
192
193 @implementation WebDataSource (WebPrivate)
194
195 - (NSError *)_mainDocumentError
196 {
197     return [_private->loadState mainDocumentError];
198 }
199
200 - (void)_addSubframeArchives:(NSArray *)subframeArchives
201 {
202     NSEnumerator *enumerator = [subframeArchives objectEnumerator];
203     WebArchive *archive;
204     while ((archive = [enumerator nextObject]) != nil)
205         [self _addToUnarchiveState:archive];
206 }
207
208 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
209 {
210     if ([URL isFileURL]) {
211         NSString *path = [[URL path] stringByResolvingSymlinksInPath];
212         return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
213     }
214     
215     WebResource *resource = [self subresourceForURL:URL];
216     if (resource) {
217         return [resource _fileWrapperRepresentation];
218     }
219     
220     NSCachedURLResponse *cachedResponse = [[self _webView] _cachedResponseForURL:URL];
221     if (cachedResponse) {
222         NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
223         [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
224         return wrapper;
225     }
226     
227     return nil;
228 }
229
230 @end
231
232 @implementation WebDataSource (WebInternal)
233
234 - (void)_finishedLoading
235 {
236     _private->representationFinishedLoading = YES;
237     [[self representation] finishedLoadingWithDataSource:self];
238 }
239
240 - (void)_receivedData:(NSData *)data
241 {
242     [[self representation] receivedData:data withDataSource:self];
243     [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
244 }
245
246 - (void)_setMainDocumentError:(NSError *)error
247 {
248     if (!_private->representationFinishedLoading) {
249         _private->representationFinishedLoading = YES;
250         [[self representation] receivedError:error withDataSource:self];
251     }
252 }
253
254 - (void)_clearUnarchivingState
255 {
256     [_private->unarchivingState release];
257     _private->unarchivingState = nil;
258 }
259
260 - (void)_revertToProvisionalState
261 {
262     [self _setRepresentation:nil];
263 }
264
265 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
266 {
267     static NSMutableDictionary *repTypes = nil;
268     static BOOL addedImageTypes = NO;
269     
270     if (!repTypes) {
271         repTypes = [[NSMutableDictionary alloc] init];
272         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedNonImageMIMETypes]);
273         
274         // Since this is a "secret default" we don't both registering it.
275         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
276         if (!omitPDFSupport)
277             addTypesFromClass(repTypes, [WebPDFRepresentation class], [WebPDFRepresentation supportedMIMETypes]);
278     }
279     
280     if (!addedImageTypes && !allowImageTypeOmission) {
281         addTypesFromClass(repTypes, [WebHTMLRepresentation class], [WebHTMLRepresentation supportedImageMIMETypes]);
282         addedImageTypes = YES;
283     }
284     
285     return repTypes;
286 }
287
288 - (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener
289 {
290     WebView *wv = [self _webView];
291     [[wv _policyDelegateForwarder] webView:wv decidePolicyForMIMEType:MIMEType
292                                    request:[self request]
293                                      frame:[self webFrame]
294                           decisionListener:listener];
295 }
296
297 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
298 {
299     // MOVABLE
300     WebFrameBridge *bridge = [[self webFrame] _bridge];
301     
302     // Retain the bridge because the stop may release the last reference to it.
303     [bridge retain];
304     
305     if (isComplete) {
306         // FIXME: Don't want to do this if an entirely new load is going, so should check
307         // that both data sources on the frame are either self or nil.
308         // Can't call [self _bridge] because we might not have commited yet
309         [bridge stop];
310         // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice.  See <rdar://problem/4258008>
311         if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
312             [bridge handleFallbackContent];
313     }
314     
315     [bridge release];
316     
317     [[self webFrame] _receivedMainResourceError:error];
318     [_private->loadState mainReceivedError:error complete:isComplete];
319 }
320
321 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr) proxy
322 {
323     [WebDownload _downloadWithLoadingConnection:connection
324                                         request:request
325                                        response:r
326                                        delegate:[[self _webView] downloadDelegate]
327                                           proxy:proxy];
328 }
329
330 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
331 {
332     WebView *webView = [self _webView];
333     
334     [webView _completeProgressForIdentifier:identifier];
335     
336     if (error)
337         [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:self];
338 }
339
340 - (void)_didFinishLoadingForResource:(id)identifier
341 {
342     WebView *webView = [self _webView];
343     
344     [webView _completeProgressForIdentifier:identifier];    
345     
346     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
347         [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
348     else
349         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:self];
350 }
351
352 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
353 {
354     WebView *webView = [self _webView];
355     
356     [webView _incrementProgressForIdentifier:identifier data:data];
357     
358     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
359         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
360     else
361         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:self];
362 }
363
364 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
365 {
366     WebView *webView = [self _webView];
367     
368     [self _addResponse:r];
369     
370     [webView _incrementProgressForIdentifier:identifier response:r];
371     
372     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
373         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
374     else
375         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:self];
376 }
377
378 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
379 {
380     WebView *webView = [self _webView];
381     
382     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
383         [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
384     else
385         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:self];
386 }
387
388 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
389 {
390     WebView *webView = [self _webView];
391     
392     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
393         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
394     else
395         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:self];
396 }
397
398 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
399 {
400     WebView *webView = [self _webView];
401     
402     [clientRequest _web_setHTTPUserAgent:[webView userAgentForURL:[clientRequest URL]]];
403     
404     if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
405         return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
406     else
407         return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:self];
408 }        
409
410 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
411 {
412     WebView *webView = [self _webView];
413     
414     // The identifier is released after the last callback, rather than in dealloc
415     // to avoid potential cycles.
416     if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
417         return [[[webView resourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
418     else
419         return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:self] retain];
420 }
421
422 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
423 {
424     return [_private->unarchivingState archivedResourceForURL:URL];
425 }
426
427 - (void)_startLoading
428 {
429     [self _prepareForLoadStart];
430     
431     if ([[_private->loadState frameLoader] isLoadingMainResource])
432         return;
433     
434     _private->loadingFromPageCache = NO;
435     
436     id identifier;
437     id resourceLoadDelegate = [[self _webView] resourceLoadDelegate];
438     if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
439         identifier = [resourceLoadDelegate webView:[self _webView] identifierForInitialRequest:[_private->loadState originalRequest] fromDataSource:self];
440     else
441         identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[self _webView] identifierForInitialRequest:[_private->loadState originalRequest] fromDataSource:self];
442     
443     if (![[_private->loadState frameLoader] startLoadingMainResourceWithRequest:[_private->loadState request] identifier:identifier])
444         [_private->loadState updateLoading];
445 }
446
447 - (void)_stopRecordingResponses
448 {
449     _private->stopRecordingResponses = YES;
450 }
451
452 - (double)_loadingStartedTime
453 {
454     return _private->loadingStartedTime;
455 }
456
457 - (void)_replaceSelectionWithArchive:(WebArchive *)archive selectReplacement:(BOOL)selectReplacement
458 {
459     DOMDocumentFragment *fragment = [self _documentFragmentWithArchive:archive];
460     if (fragment)
461         [[self _bridge] replaceSelectionWithFragment:fragment selectReplacement:selectReplacement smartReplace:NO matchStyle:NO];
462 }
463
464 - (DOMDocumentFragment *)_documentFragmentWithArchive:(WebArchive *)archive
465 {
466     ASSERT(archive);
467     WebResource *mainResource = [archive mainResource];
468     if (mainResource) {
469         NSString *MIMEType = [mainResource MIMEType];
470         if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
471             NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
472             // FIXME: seems poor form to do this as a side effect of getting a document fragment
473             [self _addToUnarchiveState:archive];
474             DOMDocumentFragment *fragment = [[self _bridge] documentFragmentWithMarkupString:markupString baseURLString:[[mainResource URL] _web_originalDataAsString]];
475             [markupString release];
476             return fragment;
477         } else if ([[WebFrameBridge supportedImageResourceMIMETypes] containsObject:MIMEType]) {
478             return [self _documentFragmentWithImageResource:mainResource];
479             
480         }
481     }
482     return nil;
483 }
484
485 - (DOMDocumentFragment *)_documentFragmentWithImageResource:(WebResource *)resource
486 {
487     DOMElement *imageElement = [self _imageElementWithImageResource:resource];
488     if (!imageElement)
489         return 0;
490     DOMDocumentFragment *fragment = [[[self _bridge] DOMDocument] createDocumentFragment];
491     [fragment appendChild:imageElement];
492     return fragment;
493 }
494
495 - (DOMElement *)_imageElementWithImageResource:(WebResource *)resource
496 {
497     if (!resource)
498         return 0;
499     
500     [self addSubresource:resource];
501     
502     DOMElement *imageElement = [[[self _bridge] DOMDocument] createElement:@"img"];
503     
504     // FIXME: calling _web_originalDataAsString on a file URL returns an absolute path. Workaround this.
505     NSURL *URL = [resource URL];
506     [imageElement setAttribute:@"src" value:[URL isFileURL] ? [URL absoluteString] : [URL _web_originalDataAsString]];
507     
508     return imageElement;
509 }
510
511 - (NSString *)_title
512 {
513     return _private->pageTitle;
514 }
515
516 // May return nil if not initialized with a URL.
517 - (NSURL *)_URL
518 {
519     return [[self request] URL];
520 }
521
522 - (void)_loadFromPageCache:(NSDictionary *)pageCache
523 {
524     [self _prepareForLoadStart];
525     _private->loadingFromPageCache = YES;
526     [_private->loadState setCommitted:YES];
527     [[self webFrame] _commitProvisionalLoad:pageCache];
528 }
529
530 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
531 {
532     return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
533 }
534
535 - (void)_setIsClientRedirect:(BOOL)flag
536 {
537     _private->isClientRedirect = flag;
538 }
539
540 - (void)_setLastCheckedRequest:(NSURLRequest *)request
541 {
542     NSURLRequest *oldRequest = _private->lastCheckedRequest;
543     _private->lastCheckedRequest = [request copy];
544     [oldRequest release];
545 }
546
547 - (NSURLRequest *)_lastCheckedRequest
548 {
549     // It's OK not to make a copy here because we know the caller
550     // isn't going to modify this request
551     return [[_private->lastCheckedRequest retain] autorelease];
552 }
553
554 - (WebFrameBridge *)_bridge
555 {
556     ASSERT([_private->loadState isCommitted]);
557     return [[self webFrame] _bridge];
558 }
559
560 - (WebView *)_webView
561 {
562     return [[[_private->loadState frameLoader] webFrame] webView];
563 }
564
565 - (NSDictionary *)_triggeringAction
566 {
567     return [[_private->triggeringAction retain] autorelease];
568 }
569
570 - (void)_setTriggeringAction:(NSDictionary *)action
571 {
572     [action retain];
573     [_private->triggeringAction release];
574     _private->triggeringAction = action;
575 }
576
577 - (BOOL)_isDocumentHTML
578 {
579     NSString *MIMEType = [[self response] MIMEType];
580     return [WebView canShowMIMETypeAsHTML:MIMEType];
581 }
582
583 - (void)_stopLoadingWithError:(NSError *)error
584 {
585     [[_private->loadState frameLoader] stopLoadingWithError:error];
586 }
587
588 - (void)_setPrimaryLoadComplete:(BOOL)flag
589 {
590     _private->primaryLoadComplete = flag;
591     
592     if (flag) {
593         if ([[_private->loadState frameLoader] isLoadingMainResource]) {
594             [_private->loadState setMainResourceData:[[_private->loadState frameLoader] mainResourceData]];
595             [[_private->loadState frameLoader] releaseMainResourceLoader];
596         }
597         
598         [_private->loadState updateLoading];
599
600         if ([WebScriptDebugServer listenerCount])
601             [[WebScriptDebugServer sharedScriptDebugServer] webView:[[self webFrame] webView] didLoadMainResourceForDataSource:self];
602     }
603 }
604
605 - (NSArray *)_responses
606 {
607     return _private->responses;
608 }
609
610 - (BOOL)_loadingFromPageCache
611 {
612     return _private->loadingFromPageCache;
613 }
614
615 -(void)_makeRepresentation
616 {
617     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
618     
619     // Check if the data source was already bound?
620     if (![[self representation] isKindOfClass:repClass]) {
621         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
622         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
623         [newRep release];
624     }
625     
626     [_private->representation setDataSource:self];
627 }
628
629 - (BOOL)_isClientRedirect
630 {
631     return _private->isClientRedirect;
632 }
633
634 - (NSURL *)_URLForHistory
635 {
636     // Return the URL to be used for history and B/F list.
637     // Returns nil for WebDataProtocol URLs that aren't alternates 
638     // for unreachable URLs, because these can't be stored in history.
639     NSURL *URL = [[_private->loadState originalRequestCopy] URL];
640     if ([WebDataProtocol _webIsDataProtocolURL:URL])
641         URL = [[_private->loadState originalRequestCopy] _webDataRequestUnreachableURL];
642     
643     return [URL _webkit_canonicalize];
644 }
645
646 - (void)_addToUnarchiveState:(WebArchive *)archive
647 {
648     if (!_private->unarchivingState)
649         _private->unarchivingState = [[WebUnarchivingState alloc] init];
650     [_private->unarchivingState addArchive:archive];
651 }
652
653 - (void)_setOverrideEncoding:(NSString *)overrideEncoding
654 {
655     NSString *copy = [overrideEncoding copy];
656     [_private->overrideEncoding release];
657     _private->overrideEncoding = copy;
658 }
659
660 - (NSString *)_overrideEncoding
661 {
662     return [[_private->overrideEncoding copy] autorelease];
663 }
664
665 - (void)_setTitle:(NSString *)title
666 {
667     NSString *trimmed;
668     if (title == nil) {
669         trimmed = nil;
670     } else {
671         trimmed = [title _webkit_stringByTrimmingWhitespace];
672         if ([trimmed length] == 0)
673             trimmed = nil;
674     }
675     if (trimmed == nil) {
676         if (_private->pageTitle == nil)
677             return;
678     } else {
679         if ([_private->pageTitle isEqualToString:trimmed])
680             return;
681     }
682     
683     if (!trimmed || [trimmed length] == 0)
684         return;
685     
686     [[self _webView] _willChangeValueForKey:_WebMainFrameTitleKey];
687     [_private->pageTitle release];
688     _private->pageTitle = [trimmed copy];
689     [[self _webView] _didChangeValueForKey:_WebMainFrameTitleKey];
690     
691     // The title doesn't get communicated to the WebView until we are committed.
692     if ([_private->loadState isCommitted]) {
693         NSURL *URLForHistory = [self _URLForHistory];
694         if (URLForHistory != nil) {
695             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
696             [entry setTitle: _private->pageTitle];
697             
698             // Must update the entries in the back-forward list too.  This must go through the WebFrame because
699             // it has the right notion of the current b/f item.
700             [[self webFrame] _setTitle:_private->pageTitle];
701             
702             [[self _webView] setMainFrameDocumentReady:YES];    // update observers with new DOMDocument
703             [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
704                                                    didReceiveTitle:_private->pageTitle
705                                                           forFrame:[self webFrame]];
706         }
707     }
708 }
709
710 - (WebDocumentLoadState *)_documentLoadState
711 {
712     return _private->loadState;
713 }
714
715 - (id)_initWithDocumentLoadState:(WebDocumentLoadStateMac *)loadState
716 {
717     self = [super init];
718     if (!self) {
719         return nil;
720     }
721     
722     _private = [[WebDataSourcePrivate alloc] init];
723     
724     _private->loadState = [loadState retain];
725         
726     LOG(Loading, "creating datasource for %@", [[_private->loadState request] URL]);
727     WKSupportsMultipartXMixedReplace([_private->loadState request]);
728     
729     ++WebDataSourceCount;
730     
731     return self;
732     
733 }
734
735 @end
736
737 @implementation WebDataSource
738
739 -(id)initWithRequest:(NSURLRequest *)request
740 {
741     return [self _initWithDocumentLoadState:[[WebDocumentLoadState alloc] initWithRequest:request]];
742 }
743
744 - (void)dealloc
745 {
746     ASSERT([[_private->loadState frameLoader] activeDataSource] != self || ![[_private->loadState frameLoader] isLoading]);
747
748     --WebDataSourceCount;
749     
750     [_private release];
751     
752     [super dealloc];
753 }
754
755 - (void)finalize
756 {
757     --WebDataSourceCount;
758
759     [super finalize];
760 }
761
762 - (NSData *)data
763 {
764     return [_private->loadState mainResourceData];
765 }
766
767 - (id <WebDocumentRepresentation>)representation
768 {
769     return _private->representation;
770 }
771
772 - (WebFrame *)webFrame
773 {
774     return [[_private->loadState frameLoader] webFrame];
775 }
776
777 -(NSURLRequest *)initialRequest
778 {
779     NSURLRequest *clientRequest = [[_private->loadState originalRequest] _webDataRequestExternalRequest];
780     if (!clientRequest)
781         clientRequest = [_private->loadState originalRequest];
782     return clientRequest;
783 }
784
785 -(NSMutableURLRequest *)request
786 {
787     return [_private->loadState request];
788 }
789
790 - (NSURLResponse *)response
791 {
792     return [_private->loadState response];
793 }
794
795 - (NSString *)textEncodingName
796 {
797     NSString *textEncodingName = [self _overrideEncoding];
798
799     if (!textEncodingName)
800         textEncodingName = [[self response] textEncodingName];
801
802     return textEncodingName;
803 }
804
805 // Returns YES if there are any pending loads.
806 - (BOOL)isLoading
807 {
808     // Once a frame has loaded, we no longer need to consider subresources,
809     // but we still need to consider subframes.
810     if ([[[self webFrame] _frameLoader] state] != WebFrameStateComplete) {
811         if (!_private->primaryLoadComplete && [_private->loadState isLoading])
812             return YES;
813         if ([[_private->loadState frameLoader] isLoadingSubresources])
814             return YES;
815         if (![[[self webFrame] _bridge] doneProcessingData])
816             return YES;
817     }
818
819     return [[self webFrame] _subframeIsLoading];
820 }
821
822 // Returns nil or the page title.
823 - (NSString *)pageTitle
824 {
825     return [[self representation] title];
826 }
827
828 - (NSURL *)unreachableURL
829 {
830     return [[_private->loadState originalRequest] _webDataRequestUnreachableURL];
831 }
832
833 - (WebArchive *)webArchive
834 {
835     // it makes no sense to grab a WebArchive from an uncommitted document.
836     if (![_private->loadState isCommitted])
837         return nil;
838
839     return [WebArchiver archiveFrame:[self webFrame]];
840 }
841
842 - (WebResource *)mainResource
843 {
844     NSURLResponse *response = [self response];
845     return [[[WebResource alloc] initWithData:[self data]
846                                           URL:[response URL] 
847                                      MIMEType:[response MIMEType]
848                              textEncodingName:[response textEncodingName]
849                                     frameName:[[self webFrame] name]] autorelease];
850 }
851
852 - (NSArray *)subresources
853 {
854     NSArray *datas;
855     NSArray *responses;
856     [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
857     ASSERT([datas count] == [responses count]);
858
859     NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
860     for (unsigned i = 0; i < [datas count]; ++i) {
861         NSURLResponse *response = [responses objectAtIndex:i];
862         [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
863     }
864
865     return [subresources autorelease];
866 }
867
868 - (WebResource *)subresourceForURL:(NSURL *)URL
869 {
870     NSData *data;
871     NSURLResponse *response;
872     if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
873         return nil;
874
875     return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
876 }
877
878 - (void)addSubresource:(WebResource *)subresource
879 {
880     if (subresource) {
881         if (!_private->unarchivingState)
882             _private->unarchivingState = [[WebUnarchivingState alloc] init];
883         [_private->unarchivingState addResource:subresource];
884     }
885 }
886
887 @end