9d17c7f3b29c2d81a3fbed9df7aed4ecf495842b
[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 - (void)_setWebFrame:(WebFrame *)frame
517 {
518     [self retain];
519
520     [_private->loadState setFrameLoader:[frame _frameLoader]];
521     if (frame)
522         [_private->loadState setDataSource:self];
523     
524     [self release];
525 }
526
527 // May return nil if not initialized with a URL.
528 - (NSURL *)_URL
529 {
530     return [[self request] URL];
531 }
532
533 - (void)_loadFromPageCache:(NSDictionary *)pageCache
534 {
535     [self _prepareForLoadStart];
536     _private->loadingFromPageCache = YES;
537     [_private->loadState setCommitted:YES];
538     [[self webFrame] _commitProvisionalLoad:pageCache];
539 }
540
541 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
542 {
543     return [_private->unarchivingState popSubframeArchiveWithFrameName:frameName];
544 }
545
546 - (void)_setIsClientRedirect:(BOOL)flag
547 {
548     _private->isClientRedirect = flag;
549 }
550
551 - (void)_setLastCheckedRequest:(NSURLRequest *)request
552 {
553     NSURLRequest *oldRequest = _private->lastCheckedRequest;
554     _private->lastCheckedRequest = [request copy];
555     [oldRequest release];
556 }
557
558 - (NSURLRequest *)_lastCheckedRequest
559 {
560     // It's OK not to make a copy here because we know the caller
561     // isn't going to modify this request
562     return [[_private->lastCheckedRequest retain] autorelease];
563 }
564
565 - (WebFrameBridge *)_bridge
566 {
567     ASSERT([_private->loadState isCommitted]);
568     return [[self webFrame] _bridge];
569 }
570
571 - (WebView *)_webView
572 {
573     return [[[_private->loadState frameLoader] webFrame] webView];
574 }
575
576 - (NSDictionary *)_triggeringAction
577 {
578     return [[_private->triggeringAction retain] autorelease];
579 }
580
581 - (void)_setTriggeringAction:(NSDictionary *)action
582 {
583     [action retain];
584     [_private->triggeringAction release];
585     _private->triggeringAction = action;
586 }
587
588 - (BOOL)_isDocumentHTML
589 {
590     NSString *MIMEType = [[self response] MIMEType];
591     return [WebView canShowMIMETypeAsHTML:MIMEType];
592 }
593
594 - (void)_stopLoadingWithError:(NSError *)error
595 {
596     [[_private->loadState frameLoader] stopLoadingWithError:error];
597 }
598
599 - (void)_setPrimaryLoadComplete:(BOOL)flag
600 {
601     _private->primaryLoadComplete = flag;
602     
603     if (flag) {
604         if ([[_private->loadState frameLoader] isLoadingMainResource]) {
605             [_private->loadState setMainResourceData:[[_private->loadState frameLoader] mainResourceData]];
606             [[_private->loadState frameLoader] releaseMainResourceLoader];
607         }
608         
609         [_private->loadState updateLoading];
610
611         if ([WebScriptDebugServer listenerCount])
612             [[WebScriptDebugServer sharedScriptDebugServer] webView:[[self webFrame] webView] didLoadMainResourceForDataSource:self];
613     }
614 }
615
616 - (NSArray *)_responses
617 {
618     return _private->responses;
619 }
620
621 - (BOOL)_loadingFromPageCache
622 {
623     return _private->loadingFromPageCache;
624 }
625
626 -(void)_makeRepresentation
627 {
628     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
629     
630     // Check if the data source was already bound?
631     if (![[self representation] isKindOfClass:repClass]) {
632         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
633         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
634         [newRep release];
635     }
636     
637     [_private->representation setDataSource:self];
638 }
639
640 - (BOOL)_isClientRedirect
641 {
642     return _private->isClientRedirect;
643 }
644
645 - (NSURL *)_URLForHistory
646 {
647     // Return the URL to be used for history and B/F list.
648     // Returns nil for WebDataProtocol URLs that aren't alternates 
649     // for unreachable URLs, because these can't be stored in history.
650     NSURL *URL = [[_private->loadState originalRequestCopy] URL];
651     if ([WebDataProtocol _webIsDataProtocolURL:URL])
652         URL = [[_private->loadState originalRequestCopy] _webDataRequestUnreachableURL];
653     
654     return [URL _webkit_canonicalize];
655 }
656
657 - (void)_addToUnarchiveState:(WebArchive *)archive
658 {
659     if (!_private->unarchivingState)
660         _private->unarchivingState = [[WebUnarchivingState alloc] init];
661     [_private->unarchivingState addArchive:archive];
662 }
663
664 - (void)_setOverrideEncoding:(NSString *)overrideEncoding
665 {
666     NSString *copy = [overrideEncoding copy];
667     [_private->overrideEncoding release];
668     _private->overrideEncoding = copy;
669 }
670
671 - (NSString *)_overrideEncoding
672 {
673     return [[_private->overrideEncoding copy] autorelease];
674 }
675
676 - (void)_setTitle:(NSString *)title
677 {
678     NSString *trimmed;
679     if (title == nil) {
680         trimmed = nil;
681     } else {
682         trimmed = [title _webkit_stringByTrimmingWhitespace];
683         if ([trimmed length] == 0)
684             trimmed = nil;
685     }
686     if (trimmed == nil) {
687         if (_private->pageTitle == nil)
688             return;
689     } else {
690         if ([_private->pageTitle isEqualToString:trimmed])
691             return;
692     }
693     
694     if (!trimmed || [trimmed length] == 0)
695         return;
696     
697     [[self _webView] _willChangeValueForKey:_WebMainFrameTitleKey];
698     [_private->pageTitle release];
699     _private->pageTitle = [trimmed copy];
700     [[self _webView] _didChangeValueForKey:_WebMainFrameTitleKey];
701     
702     // The title doesn't get communicated to the WebView until we are committed.
703     if ([_private->loadState isCommitted]) {
704         NSURL *URLForHistory = [self _URLForHistory];
705         if (URLForHistory != nil) {
706             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
707             [entry setTitle: _private->pageTitle];
708             
709             // Must update the entries in the back-forward list too.  This must go through the WebFrame because
710             // it has the right notion of the current b/f item.
711             [[self webFrame] _setTitle:_private->pageTitle];
712             
713             [[self _webView] setMainFrameDocumentReady:YES];    // update observers with new DOMDocument
714             [[[self _webView] _frameLoadDelegateForwarder] webView:[self _webView]
715                                                    didReceiveTitle:_private->pageTitle
716                                                           forFrame:[self webFrame]];
717         }
718     }
719 }
720
721 - (WebDocumentLoadState *)_documentLoadState
722 {
723     return _private->loadState;
724 }
725
726 - (id)_initWithDocumentLoadState:(WebDocumentLoadStateMac *)loadState
727 {
728     self = [super init];
729     if (!self) {
730         return nil;
731     }
732     
733     _private = [[WebDataSourcePrivate alloc] init];
734     
735     _private->loadState = [loadState retain];
736         
737     LOG(Loading, "creating datasource for %@", [[_private->loadState request] URL]);
738     WKSupportsMultipartXMixedReplace([_private->loadState request]);
739     
740     ++WebDataSourceCount;
741     
742     return self;
743     
744 }
745
746 @end
747
748 @implementation WebDataSource
749
750 -(id)initWithRequest:(NSURLRequest *)request
751 {
752     return [self _initWithDocumentLoadState:[[WebDocumentLoadState alloc] initWithRequest:request]];
753 }
754
755 - (void)dealloc
756 {
757     ASSERT([[_private->loadState frameLoader] activeDataSource] != self || ![[_private->loadState frameLoader] isLoading]);
758
759     --WebDataSourceCount;
760     
761     [_private release];
762     
763     [super dealloc];
764 }
765
766 - (void)finalize
767 {
768     --WebDataSourceCount;
769
770     [super finalize];
771 }
772
773 - (NSData *)data
774 {
775     return [_private->loadState mainResourceData];
776 }
777
778 - (id <WebDocumentRepresentation>)representation
779 {
780     return _private->representation;
781 }
782
783 - (WebFrame *)webFrame
784 {
785     return [[_private->loadState frameLoader] webFrame];
786 }
787
788 -(NSURLRequest *)initialRequest
789 {
790     NSURLRequest *clientRequest = [[_private->loadState originalRequest] _webDataRequestExternalRequest];
791     if (!clientRequest)
792         clientRequest = [_private->loadState originalRequest];
793     return clientRequest;
794 }
795
796 -(NSMutableURLRequest *)request
797 {
798     return [_private->loadState request];
799 }
800
801 - (NSURLResponse *)response
802 {
803     return [_private->loadState response];
804 }
805
806 - (NSString *)textEncodingName
807 {
808     NSString *textEncodingName = [self _overrideEncoding];
809
810     if (!textEncodingName)
811         textEncodingName = [[self response] textEncodingName];
812
813     return textEncodingName;
814 }
815
816 // Returns YES if there are any pending loads.
817 - (BOOL)isLoading
818 {
819     // Once a frame has loaded, we no longer need to consider subresources,
820     // but we still need to consider subframes.
821     if ([[[self webFrame] _frameLoader] state] != WebFrameStateComplete) {
822         if (!_private->primaryLoadComplete && [_private->loadState isLoading])
823             return YES;
824         if ([[_private->loadState frameLoader] isLoadingSubresources])
825             return YES;
826         if (![[[self webFrame] _bridge] doneProcessingData])
827             return YES;
828     }
829
830     return [[self webFrame] _subframeIsLoading];
831 }
832
833 // Returns nil or the page title.
834 - (NSString *)pageTitle
835 {
836     return [[self representation] title];
837 }
838
839 - (NSURL *)unreachableURL
840 {
841     return [[_private->loadState originalRequest] _webDataRequestUnreachableURL];
842 }
843
844 - (WebArchive *)webArchive
845 {
846     // it makes no sense to grab a WebArchive from an uncommitted document.
847     if (![_private->loadState isCommitted])
848         return nil;
849
850     return [WebArchiver archiveFrame:[self webFrame]];
851 }
852
853 - (WebResource *)mainResource
854 {
855     NSURLResponse *response = [self response];
856     return [[[WebResource alloc] initWithData:[self data]
857                                           URL:[response URL] 
858                                      MIMEType:[response MIMEType]
859                              textEncodingName:[response textEncodingName]
860                                     frameName:[[self webFrame] name]] autorelease];
861 }
862
863 - (NSArray *)subresources
864 {
865     NSArray *datas;
866     NSArray *responses;
867     [[self _bridge] getAllResourceDatas:&datas andResponses:&responses];
868     ASSERT([datas count] == [responses count]);
869
870     NSMutableArray *subresources = [[NSMutableArray alloc] initWithCapacity:[datas count]];
871     for (unsigned i = 0; i < [datas count]; ++i) {
872         NSURLResponse *response = [responses objectAtIndex:i];
873         [subresources addObject:[[[WebResource alloc] _initWithData:[datas objectAtIndex:i] URL:[response URL] response:response] autorelease]];
874     }
875
876     return [subresources autorelease];
877 }
878
879 - (WebResource *)subresourceForURL:(NSURL *)URL
880 {
881     NSData *data;
882     NSURLResponse *response;
883     if (![[self _bridge] getData:&data andResponse:&response forURL:URL])
884         return nil;
885
886     return [[[WebResource alloc] _initWithData:data URL:URL response:response] autorelease];
887 }
888
889 - (void)addSubresource:(WebResource *)subresource
890 {
891     if (subresource) {
892         if (!_private->unarchivingState)
893             _private->unarchivingState = [[WebUnarchivingState alloc] init];
894         [_private->unarchivingState addResource:subresource];
895     }
896 }
897
898 @end