Reviewed by Darin.
[WebKit-https.git] / WebKit / WebView.subproj / WebDataSource.m
1 /*      
2         WebDataSource.m
3         Copyright 2001, 2002, Apple, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebDataSourcePrivate.h>
7
8 #import <WebKit/DOMHTML.h>
9 #import <WebKit/WebAssertions.h>
10 #import <WebKit/WebArchive.h>
11 #import <WebKit/WebBridge.h>
12 #import <WebKit/WebDataProtocol.h>
13 #import <WebKit/WebDefaultResourceLoadDelegate.h>
14 #import <WebKit/WebDocument.h>
15 #import <WebKit/WebDOMOperationsPrivate.h>
16 #import <WebKit/WebException.h>
17 #import <WebKit/WebFrameLoadDelegate.h>
18 #import <WebKit/WebFramePrivate.h>
19 #import <WebKit/WebFrameViewPrivate.h>
20 #import <WebKit/WebHistory.h>
21 #import <WebKit/WebHistoryItemPrivate.h>
22 #import <WebKit/WebHTMLRepresentation.h>
23 #import <WebKit/WebHTMLViewPrivate.h>
24 #import <WebKit/WebIconDatabasePrivate.h>
25 #import <WebKit/WebIconLoader.h>
26 #import <WebKit/WebImageRendererFactory.h>
27 #import <WebKit/WebImageRepresentation.h>
28 #import <WebKit/WebImageView.h>
29 #import <WebKit/WebKitErrorsPrivate.h>
30 #import <WebKit/WebKitLogging.h>
31 #import <WebKit/WebKitStatisticsPrivate.h>
32 #import <WebKit/WebMainResourceClient.h>
33 #import <WebKit/WebNSURLExtras.h>
34 #import <WebKit/WebResourceLoadDelegate.h>
35 #import <WebKit/WebResourcePrivate.h>
36 #import <WebKit/WebTextRepresentation.h>
37 #import <WebKit/WebViewPrivate.h>
38
39 #import <Foundation/NSDictionary_NSURLExtras.h>
40 #import <Foundation/NSString_NSURLExtras.h>
41 #import <Foundation/NSURLConnection.h>
42 #import <Foundation/NSURLFileTypeMappings.h>
43 #import <Foundation/NSURLRequest.h>
44 #import <Foundation/NSURLResponsePrivate.h>
45
46 @implementation WebDataSourcePrivate 
47
48 - (void)dealloc
49 {
50     // The WebView is only retained while loading, but this object is also
51     // retained while loading, so no need to release here
52     ASSERT(!loading);
53
54     [resourceData release];
55     [representation release];
56     [request release];
57     [originalRequest release];
58     [originalRequestCopy release];
59     [mainClient release];
60     [subresourceClients release];
61     [plugInStreamClients release];
62     [pageTitle release];
63     [response release];
64     [mainDocumentError release];
65     [iconLoader setDelegate:nil];
66     [iconLoader release];
67     [iconURL release];
68     [ourBackForwardItems release];
69     [triggeringAction release];
70     [lastCheckedRequest release];
71     [responses release];
72     [webFrame release];
73     [subresources release];
74     [pendingSubframeArchives release];
75
76     [super dealloc];
77 }
78
79 @end
80
81 @implementation WebDataSource (WebPrivate)
82
83 - (NSArray *)subresources
84 {
85     return [_private->subresources allValues];
86 }
87
88 - (WebResource *)subresourceForURL:(NSURL *)URL
89 {
90     return [_private->subresources objectForKey:[URL _web_originalDataAsString]];
91 }
92
93 - (void)addSubresource:(WebResource *)subresource
94 {
95     [_private->subresources setObject:subresource forKey:[[subresource URL] _web_originalDataAsString]];
96 }
97
98 - (void)addSubresources:(NSArray *)subresources
99 {
100     NSEnumerator *enumerator = [subresources objectEnumerator];
101     WebResource *subresource;
102     while ((subresource = [enumerator nextObject]) != nil) {
103         [self addSubresource:subresource];
104     }
105 }
106
107 - (NSFileWrapper *)_fileWrapperForURL:(NSURL *)URL
108 {
109     if ([URL isFileURL]) {
110         NSString *path = [[URL path] stringByResolvingSymlinksInPath];
111         return [[[NSFileWrapper alloc] initWithPath:path] autorelease];
112     }
113     
114     WebResource *resource = [self subresourceForURL:URL];
115     if (resource) {
116         return [resource _fileWrapperRepresentation];
117     }
118         
119     NSCachedURLResponse *cachedResponse = [_private->webView _cachedResponseForURL:URL];
120     if (cachedResponse) {
121         NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
122         [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
123         return wrapper;
124     }
125     
126     return nil;
127 }
128
129 - (WebArchive *)_archiveWithMarkupString:(NSString *)markupString nodes:(NSArray *)nodes
130
131     WebFrame *frame = [self webFrame];
132     NSURLResponse *response = [self response];
133     WebResource *mainResource = [[WebResource alloc] initWithData:[markupString dataUsingEncoding:NSUTF8StringEncoding]
134                                                               URL:[response URL] 
135                                                          MIMEType:[response MIMEType]
136                                                  textEncodingName:@"UTF-8"
137                                                         frameName:[frame name]];
138     
139     NSMutableArray *subframeArchives = [[NSMutableArray alloc] init];
140     NSMutableArray *subresources = [[NSMutableArray alloc] init];
141     NSEnumerator *enumerator = [nodes objectEnumerator];
142     DOMNode *node;
143     while ((node = [enumerator nextObject]) != nil) {
144         if ([node isKindOfClass:[DOMHTMLFrameElement class]] || [node isKindOfClass:[DOMHTMLIFrameElement class]]) {
145             [subframeArchives addObject:[[[[(DOMHTMLFrameElement *)node contentDocument] webFrame] dataSource] _archive]];
146         } else {
147             NSEnumerator *enumerator = [[node _subresourceURLs] objectEnumerator];
148             NSURL *URL;
149             while ((URL = [enumerator nextObject]) != nil) {
150                 WebResource *subresource = [self subresourceForURL:URL];
151                 if (subresource) {
152                     [subresources addObject:subresource];
153                 } else {
154                     ERROR("Failed to archive subresource for %@", URL);
155                 }
156             }
157         }
158     }
159     
160     WebArchive *archive = [[[WebArchive alloc] initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives] autorelease];
161     [mainResource release];
162     [subresources release];
163     [subframeArchives release];
164     
165     return archive;
166 }
167
168 - (WebArchive *)_archive
169 {
170     if ([[self representation] conformsToProtocol:@protocol(WebDocumentDOM)]) {
171         return [[(id <WebDocumentDOM>)[self representation] DOMDocument] webArchive];
172     } else {
173         NSURLResponse *response = [self response];
174         WebResource *mainResource = [[WebResource alloc] initWithData:[self data]
175                                                                   URL:[response URL] 
176                                                              MIMEType:[response MIMEType]
177                                                      textEncodingName:[response textEncodingName]
178                                                             frameName:[[self webFrame] name]];
179         WebArchive *archive = [[[WebArchive alloc] initWithMainResource:mainResource subresources:nil subframeArchives:nil] autorelease];
180         [mainResource release];
181         return archive;
182     }
183 }
184
185 - (void)_addSubframeArchives:(NSArray *)subframeArchives
186 {
187     if (_private->pendingSubframeArchives == nil) {
188         _private->pendingSubframeArchives = [[NSMutableDictionary alloc] init];
189     }
190     
191     NSEnumerator *enumerator = [subframeArchives objectEnumerator];
192     WebArchive *archive;
193     while ((archive = [enumerator nextObject]) != nil) {
194         NSString *frameName = [[archive mainResource] frameName];
195         if (frameName) {
196             [_private->pendingSubframeArchives setObject:archive forKey:frameName];
197         }
198     }
199 }
200
201 - (WebArchive *)_popSubframeArchiveWithName:(NSString *)frameName
202 {
203     ASSERT(frameName != nil);
204     
205     WebArchive *archive = [[[_private->pendingSubframeArchives objectForKey:frameName] retain] autorelease];
206     if (archive != nil) {
207         [_private->pendingSubframeArchives removeObjectForKey:frameName];
208     }
209     return archive;
210 }
211
212 - (void)_replaceSelectionWithMarkupString:(NSString *)markupString baseURL:(NSURL *)baseURL
213 {
214     if ([markupString length] > 0) {
215         [[self _bridge] replaceSelectionWithMarkupString:markupString baseURLString:[baseURL _web_originalDataAsString]];
216     }
217 }
218
219 - (void)_replaceSelectionWithImageResource:(WebResource *)resource
220 {
221     ASSERT(resource);
222     [self addSubresource:resource];
223     [self _replaceSelectionWithMarkupString:[NSString stringWithFormat:@"<IMG SRC=\"%@\">", [[resource URL] _web_originalDataAsString]] baseURL:nil];
224 }
225
226 - (BOOL)_replaceSelectionWithArchive:(WebArchive *)archive
227 {
228     ASSERT(archive);
229     WebResource *mainResource = [archive mainResource];
230     if (mainResource) {
231         NSString *MIMEType = [mainResource MIMEType];
232         if ([WebView canShowMIMETypeAsHTML:MIMEType]) {
233             NSString *markupString = [[NSString alloc] initWithData:[mainResource data] encoding:NSUTF8StringEncoding];
234             [self addSubresources:[archive subresources]];
235             [self _addSubframeArchives:[archive subframeArchives]];
236             [self _replaceSelectionWithMarkupString:markupString baseURL:[mainResource URL]];
237             [markupString release];
238             return YES;
239         } else if ([[[WebImageRendererFactory sharedFactory] supportedMIMETypes] containsObject:MIMEType]) {
240             [self _replaceSelectionWithImageResource:mainResource];
241             return YES;
242         }
243     }
244     return NO;
245 }
246
247 - (WebView *)_webView
248 {
249     return _private->webView;
250 }
251
252 - (void)_setRepresentation: (id<WebDocumentRepresentation>)representation
253 {
254     [_private->representation release];
255     _private->representation = [representation retain];
256 }
257
258 - (void)_setLoading:(BOOL)loading
259 {
260     ASSERT_ARG(loading, loading == NO || loading == YES);
261
262     if (_private->loading == loading) {
263         return;
264     }
265     
266     _private->loading = loading;
267     
268     if (loading) {
269         [self retain];
270         [_private->webView retain];
271     } else {
272         [_private->webView release];
273         // FIXME: It would be cleanest to set webView to nil here. Keeping a non-retained reference
274         // to the WebView is dangerous. But WebSubresourceClient actually depends on this non-retained
275         // reference when starting loads after the data source has stoppped loading.
276         [self release];
277     }
278 }
279
280 - (void)_updateLoading
281 {
282     [self _setLoading:_private->mainClient || [_private->subresourceClients count]];
283 }
284
285 - (void)_setWebView: (WebView *)webView
286 {
287     if (_private->loading) {
288         [webView retain];
289         [_private->webView release];
290     }
291     _private->webView = webView;
292     
293     [self _defersCallbacksChanged];
294 }
295
296 - (void)_setPrimaryLoadComplete: (BOOL)flag
297 {
298     _private->primaryLoadComplete = flag;
299     
300     if (flag) {
301         // FIXME: We could actually load it as soon as we've parsed
302         // the HEAD section, or determined there isn't one - but
303         // there's no callback for that.
304         [self _loadIcon];
305
306         [_private->mainClient release];
307         _private->mainClient = 0; 
308         [self _updateLoading];
309     }
310 }
311
312 - (void)_startLoading
313 {
314     [self _startLoading: nil];
315 }
316
317
318 // Cancels any pending loads.  A data source is conceptually only ever loading
319 // one document at a time, although one document may have many related
320 // resources.  stopLoading will stop all loads related to the data source.  This
321 // method will also stop loads that may be loading in child frames.
322 - (void)_stopLoading
323 {
324     [self _recursiveStopLoading];
325 }
326
327
328 - (void)_startLoading: (NSDictionary *)pageCache
329 {
330     ASSERT([self _isStopping] == NO);
331
332     [self _setPrimaryLoadComplete: NO];
333     
334     ASSERT([self webFrame] != nil);
335     
336     [self _clearErrors];
337     
338     // Mark the start loading time.
339     _private->loadingStartedTime = CFAbsoluteTimeGetCurrent();
340     
341     [self _setLoading:YES];
342
343     [_private->webView _progressStarted:[self webFrame]];
344     
345     [_private->webView _didStartProvisionalLoadForFrame:[self webFrame]];
346     [[_private->webView _frameLoadDelegateForwarder] webView:_private->webView
347                                      didStartProvisionalLoadForFrame:[self webFrame]];
348
349     if (pageCache){
350         _private->loadingFromPageCache = YES;
351         [self _commitIfReady: pageCache];
352     } else if (!_private->mainClient) {
353         _private->loadingFromPageCache = NO;
354         
355         id identifier;
356         id resourceLoadDelegate = [_private->webView resourceLoadDelegate];
357         if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
358             identifier = [resourceLoadDelegate webView:_private->webView identifierForInitialRequest:_private->originalRequest fromDataSource:self];
359         else
360             identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:_private->webView identifierForInitialRequest:_private->originalRequest fromDataSource:self];
361             
362         _private->mainClient = [[WebMainResourceClient alloc] initWithDataSource:self];
363         [_private->mainClient setIdentifier: identifier];
364         [[self webFrame] _addExtraFieldsToRequest:_private->request alwaysFromRequest: NO];
365         if (![_private->mainClient loadWithRequest:_private->request]) {
366             ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level",
367                 [_private->request URL]);
368             [_private->mainClient release];
369             _private->mainClient = nil;
370             [self _updateLoading];
371         }
372     }
373 }
374
375 - (void)_addSubresourceClient:(WebBaseResourceHandleDelegate *)client
376 {
377     if (_private->subresourceClients == nil) {
378         _private->subresourceClients = [[NSMutableArray alloc] init];
379     }
380     [_private->subresourceClients addObject:client];
381     [self _setLoading:YES];
382 }
383
384 - (void)_removeSubresourceClient:(WebBaseResourceHandleDelegate *)client
385 {
386     [_private->subresourceClients removeObject:client];
387     [self _updateLoading];
388 }
389
390 - (void)_addPlugInStreamClient:(WebBaseResourceHandleDelegate *)client
391 {
392     if (_private->plugInStreamClients == nil) {
393         _private->plugInStreamClients = [[NSMutableArray alloc] init];
394     }
395     [_private->plugInStreamClients addObject:client];
396     [self _setLoading:YES];
397 }
398
399 - (void)_removePlugInStreamClient:(WebBaseResourceHandleDelegate *)client
400 {
401     [_private->plugInStreamClients removeObject:client];
402     [self _updateLoading];
403 }
404
405 - (BOOL)_isStopping
406 {
407     return _private->stopping;
408 }
409
410 - (void)_stopLoadingInternal
411 {
412     // Always attempt to stop the icon loader because it may still be loading after the data source
413     // is done loading and not stopping it can cause a world leak.
414     [_private->iconLoader stopLoading];
415
416     if (!_private->loading) {
417         return;
418     }
419
420     _private->stopping = YES;
421
422     if(_private->mainClient){
423         // Stop the main handle and let it set the cancelled error.
424         [_private->mainClient cancel];
425     }else{
426         // Main handle is already done. Set the cancelled error.
427         NSError *cancelledError = [NSError _webKitErrorWithDomain:NSURLErrorDomain
428                                                              code:NSURLErrorCancelled
429                                                               URL:[self _URL]];
430         [self _setMainDocumentError:cancelledError];
431     }
432     
433     NSArray *clients = [_private->subresourceClients copy];
434     [clients makeObjectsPerformSelector:@selector(cancel)];
435     [clients release];
436     
437     if (_private->committed) {
438         [[self _bridge] closeURL];        
439     }
440 }
441
442 - (void)_recursiveStopLoading
443 {
444     [self retain];
445     
446     // We depend on the WebView in the webFrame method and we release it in _stopLoading,
447     // so call webFrame first so we don't send a message the released WebView (3129503).
448     [[[self webFrame] childFrames] makeObjectsPerformSelector:@selector(stopLoading)];
449     [self _stopLoadingInternal];
450     
451     [self release];
452 }
453
454 - (double)_loadingStartedTime
455 {
456     return _private->loadingStartedTime;
457 }
458
459 - (NSURL *)_URLForHistory
460 {
461     // Return the URL to be used for history and B/F list.
462     // Returns nil for WebDataProtocol URLs that aren't alternates 
463     // for unreachable URLs, because these can't be stored in history.
464     NSURL *URL = [_private->originalRequestCopy URL];
465     if ([WebDataProtocol _webIsDataProtocolURL:URL]) {
466         URL = [_private->originalRequestCopy _webDataRequestUnreachableURL];
467     }
468     
469     return [URL _webkit_canonicalize];
470 }
471
472 - (void)_setTitle:(NSString *)title
473 {
474     NSString *trimmed;
475     if (title == nil) {
476         trimmed = nil;
477     } else {
478         trimmed = [title _web_stringByTrimmingWhitespace];
479         if ([trimmed length] == 0)
480             trimmed = nil;
481     }
482     if (trimmed == nil) {
483         if (_private->pageTitle == nil)
484             return;
485     } else {
486         if ([_private->pageTitle isEqualToString:trimmed])
487             return;
488     }
489     
490     if (!trimmed || [trimmed length] == 0)
491         return;
492         
493     [_private->webView _willChangeValueForKey: _WebMainFrameTitleKey];
494     [_private->pageTitle release];
495     _private->pageTitle = [trimmed copy];
496     [_private->webView _didChangeValueForKey: _WebMainFrameTitleKey];
497     
498     // The title doesn't get communicated to the WebView until we are committed.
499     if (_private->committed) {
500         NSURL *URLForHistory = [self _URLForHistory];
501         if (URLForHistory != nil) {
502             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
503             [entry setTitle: _private->pageTitle];
504             
505             // Must update the entries in the back-forward list too.
506             [_private->ourBackForwardItems makeObjectsPerformSelector:@selector(setTitle:) withObject:_private->pageTitle];
507             
508             [[_private->webView _frameLoadDelegateForwarder] webView:_private->webView
509                                                      didReceiveTitle:_private->pageTitle
510                                                             forFrame:[self webFrame]];
511         }
512     }
513 }
514
515 - (NSString *)_title
516 {
517     return _private->pageTitle;
518 }
519
520 - (void)_setURL:(NSURL *)URL
521 {
522     NSMutableURLRequest *newOriginalRequest = [_private->originalRequestCopy mutableCopy];
523     [_private->originalRequestCopy release];
524     [newOriginalRequest setURL:URL];
525     _private->originalRequestCopy = newOriginalRequest;
526
527     NSMutableURLRequest *newRequest = [_private->request mutableCopy];
528     [_private->request release];
529     [newRequest setURL:URL];
530     _private->request = newRequest;
531 }
532
533 - (void)__adoptRequest:(NSMutableURLRequest *)request
534 {
535     if (request != _private->request){
536         [_private->request release];
537         _private->request = [request retain];
538     }
539 }
540
541 - (void)_setRequest:(NSURLRequest *)request
542 {
543     ASSERT_ARG(request, request != _private->request);
544     
545     // Replacing an unreachable URL with alternate content looks like a server-side
546     // redirect at this point, but we can replace a committed dataSource.
547     BOOL handlingUnreachableURL = [request _webDataRequestUnreachableURL] != nil;
548     if (handlingUnreachableURL) {
549         _private->committed = NO;
550     }
551     
552     // We should never be getting a redirect callback after the data
553     // source is committed, except in the unreachable URL case. It 
554     // would be a WebFoundation bug if it sent a redirect callback after commit.
555     ASSERT(!_private->committed);
556
557     NSURLRequest *oldRequest = _private->request;
558
559     _private->request = [request mutableCopy];
560
561     // Only send webView:didReceiveServerRedirectForProvisionalLoadForFrame: if URL changed.
562     // Also, don't send it when replacing unreachable URLs with alternate content.
563     if (!handlingUnreachableURL && ![[oldRequest URL] isEqual: [request URL]]) {
564         LOG(Redirect, "Server redirect to: %@", [request URL]);
565         [[_private->webView _frameLoadDelegateForwarder] webView:_private->webView
566                       didReceiveServerRedirectForProvisionalLoadForFrame:[self webFrame]];
567     }
568         
569     [oldRequest release];
570 }
571
572 - (void)_setResponse:(NSURLResponse *)response
573 {
574     [_private->response release];
575     _private->response = [response retain];
576 }
577
578 - (void)_setOverrideEncoding:(NSString *)overrideEncoding
579 {
580     NSString *copy = [overrideEncoding copy];
581     [_private->overrideEncoding release];
582     _private->overrideEncoding = copy;
583 }
584
585 - (NSString *)_overrideEncoding
586 {
587     return [[_private->overrideEncoding copy] autorelease];
588 }
589
590 - (void)_setIsClientRedirect:(BOOL)flag
591 {
592     _private->isClientRedirect = flag;
593 }
594
595 - (BOOL)_isClientRedirect
596 {
597     return _private->isClientRedirect;
598 }
599
600 - (void)_addBackForwardItem:(WebHistoryItem *)item
601 {
602     if (!item) {
603         return;
604     }
605     if (!_private->ourBackForwardItems) {
606         _private->ourBackForwardItems = [[NSMutableArray alloc] initWithCapacity:1];
607     }
608     if ([_private->ourBackForwardItems indexOfObjectIdenticalTo:item] == NSNotFound) {
609         [_private->ourBackForwardItems addObject:item];
610     }
611 }
612
613 - (void)_addBackForwardItems:(NSArray *)items
614 {
615     if (!items || [items count] == 0) {
616         return;
617     }
618     if (!_private->ourBackForwardItems) {
619         _private->ourBackForwardItems = [items mutableCopy];
620     } else {
621         [_private->ourBackForwardItems addObjectsFromArray:items];
622     }
623 }
624
625 - (NSArray *)_backForwardItems
626 {
627     return _private->ourBackForwardItems;
628 }
629
630 - (void)_setMainDocumentError: (NSError *)error
631 {
632     [error retain];
633     [_private->mainDocumentError release];
634     _private->mainDocumentError = error;
635
636     [[self representation] receivedError:error withDataSource:self];
637 }
638
639 - (void)_clearErrors
640 {
641     [_private->mainDocumentError release];
642     _private->mainDocumentError = nil;
643 }
644
645 + (NSMutableDictionary *)_repTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
646 {
647     static NSMutableDictionary *repTypes = nil;
648     static BOOL addedImageTypes;
649     
650     if (!repTypes) {
651         repTypes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
652             [WebHTMLRepresentation class], @"text/html",
653             [WebHTMLRepresentation class], @"text/xml",
654             [WebHTMLRepresentation class], @"application/xml",
655             [WebHTMLRepresentation class], @"application/xhtml+xml",
656             [WebHTMLRepresentation class], @"application/x-webarchive",
657             [WebTextRepresentation class], @"text/",
658             [WebTextRepresentation class], @"application/x-javascript",
659             nil];
660     }
661     
662     if (!addedImageTypes && !allowImageTypeOmission) {
663         NSEnumerator *enumerator = [[WebImageView supportedImageMIMETypes] objectEnumerator];
664         NSString *mime;
665         while ((mime = [enumerator nextObject]) != nil) {
666             // Don't clobber previously-registered rep classes.
667             if ([repTypes objectForKey:mime] == nil) {
668                 [repTypes setObject:[WebImageRepresentation class] forKey:mime];
669             }
670         }
671         addedImageTypes = YES;
672     }
673     
674     return repTypes;
675 }
676
677 + (Class)_representationClassForMIMEType:(NSString *)MIMEType
678 {
679     Class repClass;
680     return [WebView _viewClass:nil andRepresentationClass:&repClass forMIMEType:MIMEType] ? repClass : nil;
681 }
682
683 - (WebBridge *)_bridge
684 {
685     ASSERT(_private->committed);
686     return [[self webFrame] _bridge];
687 }
688
689 - (BOOL)_isCommitted
690 {
691     return _private->committed;
692 }
693
694 - (void)_commitIfReady: (NSDictionary *)pageCache
695 {
696     if (_private->loadingFromPageCache || (_private->gotFirstByte && !_private->committed)) {
697         WebFrame *frame = [self webFrame];
698         WebFrameLoadType loadType = [frame _loadType];
699         bool reload = loadType == WebFrameLoadTypeReload
700             || loadType == WebFrameLoadTypeReloadAllowingStaleData;
701         
702         NSDictionary *headers = [_private->response isKindOfClass:[NSHTTPURLResponse class]]
703             ? [(NSHTTPURLResponse *)_private->response allHeaderFields] : nil;
704
705         [frame _closeOldDataSources];
706
707         LOG(Loading, "committed resource = %@", [[self request] URL]);
708         _private->committed = TRUE;
709         if (!pageCache)
710             [self _makeRepresentation];
711             
712         [frame _transitionToCommitted: pageCache];
713
714         NSURL *baseURL = [[self request] _webDataRequestBaseURL];        
715         NSURL *URL = nil;
716         
717         if (baseURL)
718             URL = baseURL;
719         else
720             URL = [_private->response URL];
721             
722         // WebCore will crash if given an empty URL here.
723         // FIXME: could use CFURL, when available, range API to save an allocation here
724         if (!URL || [URL _web_isEmpty])
725             URL = [NSURL URLWithString:@"about:blank"];
726
727         [[self _bridge] openURL:URL
728                          reload:reload 
729                     contentType:[_private->response MIMEType]
730                         refresh:[headers objectForKey:@"Refresh"]
731                    lastModified:(pageCache ? nil : [_private->response _lastModifiedDate])
732                       pageCache:pageCache];
733
734         [frame _opened];
735     }
736 }
737
738 - (void)_commitIfReady
739 {
740     [self _commitIfReady: nil];
741 }
742
743 -(void)_makeRepresentation
744 {
745     Class repClass = [[self class] _representationClassForMIMEType:[[self response] MIMEType]];
746     
747     // Check if the data source was already bound?
748     if (![[self representation] isKindOfClass:repClass]) {
749         id newRep = repClass != nil ? [[repClass alloc] init] : nil;
750         [self _setRepresentation:(id <WebDocumentRepresentation>)newRep];
751         [newRep release];
752     }
753
754     [_private->representation setDataSource:self];
755 }
756
757 -(void)_receivedData:(NSData *)data
758 {
759     if (!_private->resourceData) {
760         _private->resourceData = [[NSMutableData alloc] init];
761     }
762     ASSERT([_private->resourceData isKindOfClass:[NSMutableData class]]);
763     [_private->resourceData appendData:data];
764     
765     _private->gotFirstByte = YES;
766     [self _commitIfReady];
767
768     // parsing some of the page can result in running a script which
769     // could possibly destroy the frame and data source. So retain
770     // self temporarily.
771     [self retain];
772     [[self representation] receivedData:data withDataSource:self];
773     [[[[self webFrame] frameView] documentView] dataSourceUpdated:self];
774     [self release];
775 }
776
777 - (void)_setData:(NSData *)data
778 {
779     [data retain];
780     [_private->resourceData release];
781     _private->resourceData = (NSMutableData *)data;
782 }
783
784 - (void)_finishedLoading
785 {
786     _private->gotFirstByte = YES;
787     [self _commitIfReady];
788
789     [[self representation] finishedLoadingWithDataSource:self];
790 }
791
792 - (void)_receivedError:(NSError *)error complete:(BOOL)isComplete
793 {
794     if (!_private->committed) {
795         [[[self webFrame] _bridge] didNotOpenURL:[_private->originalRequestCopy URL]];
796     }
797     [[self _webView] _mainReceivedError:error
798                            fromDataSource:self
799                                  complete:isComplete];
800 }
801
802 - (void)_updateIconDatabaseWithURL:(NSURL *)iconURL
803 {
804     WebIconDatabase *iconDB = [WebIconDatabase sharedIconDatabase];
805
806     // Bind the URL of the original request and the final URL to the icon URL.
807     [iconDB _setIconURL:[iconURL _web_originalDataAsString] forURL:[[self _URL] _web_originalDataAsString]];
808     [iconDB _setIconURL:[iconURL _web_originalDataAsString] forURL:[[[self _originalRequest] URL] _web_originalDataAsString]];
809
810     
811     if ([self webFrame] == [_private->webView mainFrame])
812         [_private->webView _willChangeValueForKey:_WebMainFrameIconKey];
813     
814     NSImage *icon = [iconDB iconForURL:[[self _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
815     [[_private->webView _frameLoadDelegateForwarder] webView:_private->webView
816                                                       didReceiveIcon:icon
817                                                             forFrame:[self webFrame]];
818     
819     if ([self webFrame] == [_private->webView mainFrame])
820         [_private->webView _didChangeValueForKey:_WebMainFrameIconKey];
821 }
822
823 - (void)_iconLoaderReceivedPageIcon:(WebIconLoader *)iconLoader
824 {
825     [self _updateIconDatabaseWithURL:[iconLoader URL]];
826 }
827
828 - (void)_loadIcon
829 {
830     // Don't load an icon if 1) this is not the main frame 2) we ended in error 3) we already did 4) they aren't save by the DB.
831     if ([self webFrame] != [[self _webView] mainFrame] || _private->mainDocumentError || _private->iconLoader ||
832        ![[WebIconDatabase sharedIconDatabase] iconsAreSaved]) {
833         return;
834     }
835                 
836     if(!_private->iconURL){
837         // No icon URL from the LINK tag so try the server's root.
838         // This is only really a feature of http or https, so don't try this with other protocols.
839         NSString *scheme = [[self _URL] scheme];
840         if([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]){
841             _private->iconURL = [[[NSURL _web_URLWithDataAsString:@"/favicon.ico"
842                                               relativeToURL:[self _URL]] absoluteURL] retain];
843         }
844     }
845
846     if(_private->iconURL != nil){
847         if([[WebIconDatabase sharedIconDatabase] _hasIconForIconURL:[_private->iconURL _web_originalDataAsString]]){
848             [self _updateIconDatabaseWithURL:_private->iconURL];
849         }else{
850             ASSERT(!_private->iconLoader);
851             NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:_private->iconURL];
852             [[self webFrame] _addExtraFieldsToRequest:request alwaysFromRequest:NO];
853             _private->iconLoader = [[WebIconLoader alloc] initWithRequest:request];
854             [request release];
855             [_private->iconLoader setDelegate:self];
856             [_private->iconLoader setDataSource:self];
857             [_private->iconLoader startLoading];
858         }
859     }
860 }
861
862 - (void)_setIconURL:(NSURL *)URL
863 {
864     // Lower priority than typed icon, so ignore this if we already have an iconURL.
865     if (_private->iconURL == nil) {
866         [_private->iconURL release];
867         _private->iconURL = [URL retain];
868     }
869 }
870
871 - (void)_setIconURL:(NSURL *)URL withType:(NSString *)iconType
872 {
873     // FIXME: Should check to make sure the type is one we know how to handle.
874     [_private->iconURL release];
875     _private->iconURL = [URL retain];
876 }
877
878 - (void)_defersCallbacksChanged
879 {
880     BOOL defers = [_private->webView defersCallbacks];
881     
882     if (defers == _private->defersCallbacks) {
883         return;
884     }
885
886     _private->defersCallbacks = defers;
887     [_private->mainClient setDefersCallbacks:defers];
888
889     NSEnumerator *e = [_private->subresourceClients objectEnumerator];
890     WebBaseResourceHandleDelegate *client;
891     while ((client = [e nextObject])) {
892         [client setDefersCallbacks:defers];
893     }
894     e = [_private->plugInStreamClients objectEnumerator];
895     while ((client = [e nextObject])) {
896         [client setDefersCallbacks:defers];
897     }
898
899     // It's OK to use the internal version of getting the child
900     // frames, since undeferring callbacks will not do any immediate
901     // work, and so the set of frames can't change out from under us.
902     [[[self webFrame] _internalChildFrames] makeObjectsPerformSelector:@selector(_defersCallbacksChanged)];
903 }
904
905 - (NSURLRequest *)_originalRequest
906 {
907     return _private->originalRequestCopy;
908 }
909
910 - (void)_setTriggeringAction:(NSDictionary *)action
911 {
912     [action retain];
913     [_private->triggeringAction release];
914     _private->triggeringAction = action;
915 }
916
917 - (NSDictionary *)_triggeringAction
918 {
919     return [[_private->triggeringAction retain] autorelease];
920 }
921
922
923 - (NSURLRequest *)_lastCheckedRequest
924 {
925     // It's OK not to make a copy here because we know the caller
926     // isn't going to modify this request
927     return [[_private->lastCheckedRequest retain] autorelease];
928 }
929
930 - (void)_setLastCheckedRequest:(NSURLRequest *)request
931 {
932     NSURLRequest *oldRequest = _private->lastCheckedRequest;
933     _private->lastCheckedRequest = [request copy];
934     [oldRequest release];
935 }
936
937 - (void)_setJustOpenedForTargetedLink:(BOOL)justOpened
938 {
939     _private->justOpenedForTargetedLink = justOpened;
940 }
941
942 - (BOOL)_justOpenedForTargetedLink
943 {
944     return _private->justOpenedForTargetedLink;
945 }
946
947 - (void)_setStoredInPageCache:(BOOL)f
948 {
949     _private->storedInPageCache = f;
950 }
951
952 - (BOOL)_storedInPageCache
953 {
954     return _private->storedInPageCache;
955 }
956
957 - (BOOL)_loadingFromPageCache
958 {
959     return _private->loadingFromPageCache;
960 }
961
962 - (void)_addResponse: (NSURLResponse *)r
963 {
964     if (!_private->responses)
965         _private->responses = [[NSMutableArray alloc] init];
966     [_private->responses addObject: r];
967 }
968
969 - (NSArray *)_responses
970 {
971     return _private->responses;
972 }
973
974 - (void)_stopLoadingWithError:(NSError *)error
975 {
976     [_private->mainClient cancelWithError:error];
977 }
978
979 - (void)_setWebFrame:(WebFrame *)frame
980 {
981     [frame retain];
982     [_private->webFrame release];
983     _private->webFrame = frame;
984 }
985
986 // May return nil if not initialized with a URL.
987 - (NSURL *)_URL
988 {
989     return [[self request] URL];
990 }
991
992 - (NSString *)_stringWithData:(NSData *)data
993 {
994     NSString *textEncodingName = [self _overrideEncoding];
995
996     if(!textEncodingName){
997         textEncodingName = [[self response] textEncodingName];
998     }
999
1000     if(textEncodingName){
1001         return [WebBridge stringWithData:data textEncodingName:textEncodingName];
1002     }else{
1003         return [WebBridge stringWithData:data textEncoding:kCFStringEncodingISOLatin1];
1004     }
1005 }
1006
1007 - (NSError *)_mainDocumentError
1008 {
1009     return _private->mainDocumentError;
1010 }
1011
1012 - (BOOL)_isDocumentHTML
1013 {
1014     NSString *MIMEType = [[self response] MIMEType];
1015     return [WebView canShowMIMETypeAsHTML:MIMEType];
1016 }
1017
1018 @end
1019
1020 @implementation WebDataSource
1021
1022 -(id)initWithRequest:(NSURLRequest *)request
1023 {
1024     self = [super init];
1025     if (!self) {
1026         return nil;
1027     }
1028     
1029     _private = [[WebDataSourcePrivate alloc] init];
1030     _private->originalRequest = [request retain];
1031     _private->originalRequestCopy = [request copy];
1032     
1033     _private->subresources = [[NSMutableDictionary alloc] init];
1034     
1035     LOG(Loading, "creating datasource for %@", [request URL]);
1036     _private->request = [_private->originalRequest mutableCopy];
1037
1038     ++WebDataSourceCount;
1039     
1040     return self;
1041 }
1042
1043 - (void)dealloc
1044 {
1045     --WebDataSourceCount;
1046     
1047     [_private release];
1048     
1049     [super dealloc];
1050 }
1051
1052 - (NSData *)data
1053 {
1054     return _private->resourceData;
1055 }
1056
1057 - (id <WebDocumentRepresentation>) representation
1058 {
1059     return _private->representation;
1060 }
1061
1062 - (WebFrame *)webFrame
1063 {
1064     return _private->webFrame;
1065 }
1066
1067 -(NSURLRequest *)initialRequest
1068 {
1069     NSURLRequest *clientRequest = [_private->originalRequest _webDataRequestExternalRequest];
1070     if (!clientRequest)
1071         clientRequest = _private->originalRequest;
1072     return clientRequest;
1073 }
1074
1075 -(NSMutableURLRequest *)request
1076 {
1077     NSMutableURLRequest *clientRequest = [_private->request _webDataRequestExternalRequest];
1078     if (!clientRequest)
1079         clientRequest = _private->request;
1080     return clientRequest;
1081 }
1082
1083 - (NSURLResponse *)response
1084 {
1085     return _private->response;
1086 }
1087
1088 - (NSString *)textEncodingName
1089 {
1090     NSString *textEncodingName = [self _overrideEncoding];
1091
1092     if(!textEncodingName){
1093         textEncodingName = [[self response] textEncodingName];
1094     }
1095     return textEncodingName;
1096 }
1097
1098 // Returns YES if there are any pending loads.
1099 - (BOOL)isLoading
1100 {
1101     // Once a frame has loaded, we no longer need to consider subresources,
1102     // but we still need to consider subframes.
1103     if ([[self webFrame] _state] != WebFrameStateComplete) {
1104         if (!_private->primaryLoadComplete && _private->loading) {
1105             return YES;
1106         }
1107         if ([_private->subresourceClients count]) {
1108             return YES;
1109         }
1110     }
1111     
1112     // Put in the auto-release pool because it's common to call this from a run loop source,
1113     // and then the entire list of frames lasts until the next autorelease.
1114     NSAutoreleasePool *pool = [NSAutoreleasePool new];
1115
1116     // It's OK to use the internal version of getting the child
1117     // frames, since nothing we do here can possibly change the set of
1118     // frames.
1119     NSEnumerator *e = [[[self webFrame] _internalChildFrames] objectEnumerator];
1120     WebFrame *childFrame;
1121     while ((childFrame = [e nextObject])) {
1122         if ([[childFrame dataSource] isLoading] || [[childFrame provisionalDataSource] isLoading]) {
1123             break;
1124         }
1125     }
1126     [pool release];
1127     
1128     return childFrame != nil;
1129 }
1130
1131
1132 // Returns nil or the page title.
1133 - (NSString *)pageTitle
1134 {
1135     return [[self representation] title];
1136 }
1137
1138 - (NSURL *)unreachableURL
1139 {
1140     return [_private->originalRequest _webDataRequestUnreachableURL];
1141 }
1142
1143 @end