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