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