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