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