8cf5d651b13da82a102be3849f46b1b9e1a51f19
[WebKit-https.git] / WebKit / Loader / WebFrameLoader.m
1 /*
2  * Copyright (C) 2006 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 "WebFrameLoader.h"
30
31 #import "WebDataProtocol.h"
32 #import "WebDataSourceInternal.h"
33 #import "WebDocumentLoaderMac.h"
34 #import "WebDownloadInternal.h"
35 #import "WebFrameBridge.h"
36 #import "WebFrameInternal.h"
37 #import "WebFrameLoadDelegate.h"
38 #import "WebHistory.h"
39 #import "WebIconDatabasePrivate.h"
40 #import "WebKitErrorsPrivate.h"
41 #import "WebKitLogging.h"
42 #import "WebKitNSStringExtras.h"
43 #import "WebMainResourceLoader.h"
44 #import "WebNSDictionaryExtras.h"
45 #import "WebNSURLExtras.h"
46 #import "WebPreferences.h"
47 #import "WebResourcePrivate.h"
48 #import "WebResourceLoadDelegate.h"
49 #import "WebDefaultResourceLoadDelegate.h"
50 #import "WebScriptDebugServerPrivate.h"
51 #import "WebViewInternal.h"
52 #import <JavaScriptCore/Assertions.h>
53 #import <WebKit/DOMHTML.h>
54
55 @implementation WebFrameLoader
56
57 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
58 {
59     self = [super init];
60     if (self) {
61         client = c;
62         state = WebFrameStateCommittedPage;
63     }
64     return self;    
65 }
66
67 - (void)dealloc
68 {
69     // FIXME: should these even exist?
70     [mainResourceLoader release];
71     [subresourceLoaders release];
72     [plugInStreamLoaders release];
73     [documentLoader release];
74     [provisionalDocumentLoader release];
75  
76     ASSERT(!policyDocumentLoader);
77     
78     [super dealloc];
79 }
80
81 - (WebDocumentLoader *)activeDocumentLoader
82 {
83     if (state == WebFrameStateProvisional)
84         return provisionalDocumentLoader;
85     
86     return documentLoader;    
87 }
88
89 - (WebDataSource *)activeDataSource
90 {
91     return [client _dataSourceForDocumentLoader:[self activeDocumentLoader]];
92 }
93
94 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
95 {
96     return [[self activeDataSource] _archivedSubresourceForURL:URL];
97 }
98
99 - (void)addPlugInStreamLoader:(WebLoader *)loader
100 {
101     if (!plugInStreamLoaders)
102         plugInStreamLoaders = [[NSMutableArray alloc] init];
103     [plugInStreamLoaders addObject:loader];
104     [[self activeDocumentLoader] setLoading:YES];
105 }
106
107 - (void)removePlugInStreamLoader:(WebLoader *)loader
108 {
109     [plugInStreamLoaders removeObject:loader];
110     [[self activeDocumentLoader] updateLoading];
111 }    
112
113 - (void)defersCallbacksChanged
114 {
115     [self setDefersCallbacks:[[client webView] defersCallbacks]];
116 }
117
118 - (BOOL)defersCallbacks
119 {
120     return [[client webView] defersCallbacks];
121 }
122
123 - (void)setDefersCallbacks:(BOOL)defers
124 {
125     [mainResourceLoader setDefersCallbacks:defers];
126     
127     NSEnumerator *e = [subresourceLoaders objectEnumerator];
128     WebLoader *loader;
129     while ((loader = [e nextObject]))
130         [loader setDefersCallbacks:defers];
131     
132     e = [plugInStreamLoaders objectEnumerator];
133     while ((loader = [e nextObject]))
134         [loader setDefersCallbacks:defers];
135
136     [self deliverArchivedResourcesAfterDelay];
137 }
138
139 - (void)stopLoadingPlugIns
140 {
141     [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
142     [plugInStreamLoaders removeAllObjects];   
143 }
144
145 - (BOOL)isLoadingMainResource
146 {
147     return mainResourceLoader != nil;
148 }
149
150 - (BOOL)isLoadingSubresources
151 {
152     return [subresourceLoaders count];
153 }
154
155 - (BOOL)isLoadingPlugIns
156 {
157     return [plugInStreamLoaders count];
158 }
159
160 - (BOOL)isLoading
161 {
162     return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
163 }
164
165 - (void)stopLoadingSubresources
166 {
167     NSArray *loaders = [subresourceLoaders copy];
168     [loaders makeObjectsPerformSelector:@selector(cancel)];
169     [loaders release];
170     [subresourceLoaders removeAllObjects];
171 }
172
173 - (void)addSubresourceLoader:(WebLoader *)loader
174 {
175     ASSERT(!provisionalDocumentLoader);
176     if (subresourceLoaders == nil)
177         subresourceLoaders = [[NSMutableArray alloc] init];
178     [subresourceLoaders addObject:loader];
179     [[self activeDocumentLoader] setLoading:YES];
180 }
181
182 - (void)removeSubresourceLoader:(WebLoader *)loader
183 {
184     [subresourceLoaders removeObject:loader];
185     [[self activeDocumentLoader] updateLoading];
186 }
187
188 - (NSData *)mainResourceData
189 {
190     return [mainResourceLoader resourceData];
191 }
192
193 - (void)releaseMainResourceLoader
194 {
195     [mainResourceLoader release];
196     mainResourceLoader = nil;
197 }
198
199 - (void)cancelMainResourceLoad
200 {
201     [mainResourceLoader cancel];
202 }
203
204 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
205 {
206     mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
207     
208     [mainResourceLoader setIdentifier:identifier];
209     [client _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
210     if (![mainResourceLoader loadWithRequest:request]) {
211         // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
212         // should it be caught by other parts of WebKit or other parts of the app?
213         LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
214         [mainResourceLoader release];
215         mainResourceLoader = nil;
216         return NO;
217     }
218     
219     return YES;
220 }
221
222 - (void)stopLoadingWithError:(NSError *)error
223 {
224     [mainResourceLoader cancelWithError:error];
225 }
226
227 - (WebDataSource *)dataSource
228 {
229     return [client _dataSourceForDocumentLoader:documentLoader]; 
230 }
231
232 - (void)setDocumentLoader:(WebDocumentLoader *)loader
233 {
234     if (loader == nil && documentLoader == nil)
235         return;
236     
237     ASSERT(loader != documentLoader);
238     
239     [client _prepareForDataSourceReplacement];
240     [documentLoader detachFromFrameLoader];
241     
242     [loader retain];
243     [documentLoader release];
244     documentLoader = loader;
245 }
246
247 - (WebDocumentLoader *)documentLoader
248 {
249     return documentLoader;
250 }
251
252 - (WebDataSource *)policyDataSource
253 {
254     return [client _dataSourceForDocumentLoader:policyDocumentLoader];     
255 }
256
257 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
258 {
259     if (policyDocumentLoader == loader)
260         return;
261
262     if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
263         [policyDocumentLoader detachFromFrameLoader];
264
265     [policyDocumentLoader release];
266     [loader retain];
267     policyDocumentLoader = loader;
268 }
269    
270 - (void)clearDataSource
271 {
272     [self setDocumentLoader:nil];
273 }
274
275 - (WebDataSource *)provisionalDataSource 
276 {
277     return [client _dataSourceForDocumentLoader:provisionalDocumentLoader]; 
278 }
279
280 - (WebDocumentLoader *)provisionalDocumentLoader
281 {
282     return provisionalDocumentLoader;
283 }
284
285 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
286 {
287     ASSERT(!loader || !provisionalDocumentLoader);
288
289     if (provisionalDocumentLoader != documentLoader)
290         [provisionalDocumentLoader detachFromFrameLoader];
291
292     [loader retain];
293     [provisionalDocumentLoader release];
294     provisionalDocumentLoader = loader;
295 }
296
297 - (void)_clearProvisionalDataSource
298 {
299     [self setProvisionalDocumentLoader:nil];
300 }
301
302 - (WebFrameState)state
303 {
304     return state;
305 }
306
307 #ifndef NDEBUG
308 static const char * const stateNames[] = {
309     "WebFrameStateProvisional",
310     "WebFrameStateCommittedPage",
311     "WebFrameStateComplete"
312 };
313 #endif
314
315 static CFAbsoluteTime _timeOfLastCompletedLoad;
316
317 + (CFAbsoluteTime)timeOfLastCompletedLoad
318 {
319     return _timeOfLastCompletedLoad;
320 }
321
322 - (void)provisionalLoadStarted
323 {
324     firstLayoutDone = NO;
325     [[client _bridge] provisionalLoadStarted];
326
327     [client _provisionalLoadStarted];
328 }
329
330 - (void)_setState:(WebFrameState)newState
331 {
332     LOG(Loading, "%@:  transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
333     if ([client webView])
334         LOG(Timing, "%@:  transition from %s to %s, %f seconds since start of document load", [client name], stateNames[state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[[client webView] mainFrame] dataSource] _documentLoader] loadingStartedTime]);
335     
336     if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
337         LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoader] loadingStartedTime]);
338     
339     state = newState;
340     
341     if (state == WebFrameStateProvisional)
342         [self provisionalLoadStarted];
343     else if (state == WebFrameStateComplete) {
344         [client _frameLoadCompleted];
345         [self frameLoadCompleted];
346         _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
347         [[self documentLoader] stopRecordingResponses];
348     }
349 }
350
351 - (void)clearProvisionalLoad
352 {
353     [self setProvisionalDocumentLoader:nil];
354     [[client webView] _progressCompleted:client];
355     [self _setState:WebFrameStateComplete];
356 }
357
358 - (void)markLoadComplete
359 {
360     [self _setState:WebFrameStateComplete];
361 }
362
363 - (void)commitProvisionalLoad
364 {
365     [self stopLoadingSubresources];
366     [self stopLoadingPlugIns];
367
368     [self setDocumentLoader:provisionalDocumentLoader];
369     [self setProvisionalDocumentLoader:nil];
370     [self _setState:WebFrameStateCommittedPage];
371 }
372
373 - (void)stopLoadingSubframes
374 {
375     for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
376         [[(WebFrameBridge *)child loader] stopLoading];
377 }
378
379 - (void)stopLoading
380 {
381     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
382     if (isStoppingLoad)
383         return;
384     
385     isStoppingLoad = YES;
386     
387     [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
388     
389     [self stopLoadingSubframes];
390     [provisionalDocumentLoader stopLoading];
391     [documentLoader stopLoading];
392     [self _clearProvisionalDataSource];
393     [self clearArchivedResources];
394
395     isStoppingLoad = NO;    
396 }
397
398 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
399 - (void)startLoading
400 {
401     [provisionalDocumentLoader prepareForLoadStart];
402         
403     if ([self isLoadingMainResource])
404         return;
405         
406     [[self provisionalDataSource] _setLoadingFromPageCache:NO];
407         
408     id identifier;
409     id resourceLoadDelegate = [[client webView] resourceLoadDelegate];
410     if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
411         identifier = [resourceLoadDelegate webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDataSource:[self provisionalDataSource]];
412     else
413         identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDataSource:[self provisionalDataSource]];
414     
415     if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
416         [provisionalDocumentLoader updateLoading];
417 }
418
419 - (void)startProvisionalLoad:(WebDataSource *)ds
420 {
421     [self setProvisionalDocumentLoader:[ds _documentLoader]];
422     [self _setState:WebFrameStateProvisional];
423 }
424
425 - (void)setupForReplace
426 {
427     [self _setState:WebFrameStateProvisional];
428     WebDocumentLoader *old = provisionalDocumentLoader;
429     provisionalDocumentLoader = documentLoader;
430     documentLoader = nil;
431     [old release];
432     
433     [client _detachChildren];
434 }
435
436 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
437 {
438     WebView *webView = [client webView];
439         
440     // The identifier is released after the last callback, rather than in dealloc
441     // to avoid potential cycles.
442     if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
443         return [[[webView resourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
444     else
445         return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
446 }
447
448 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
449 {
450     WebView *webView = [client webView];
451     
452     [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
453     
454     if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
455         return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
456     else
457         return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
458 }
459
460 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
461 {
462     WebView *webView = [client webView];
463     
464     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
465         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
466     else
467         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
468 }
469
470 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
471 {
472     WebView *webView = [client webView];
473     
474     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
475         [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
476     else
477         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
478     
479 }
480
481 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
482 {
483     WebView *webView = [client webView];
484     
485     [[self activeDocumentLoader] addResponse:r];
486     
487     [webView _incrementProgressForIdentifier:identifier response:r];
488     
489     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
490         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
491     else
492         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
493 }
494
495 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
496 {
497     WebView *webView = [client webView];
498     
499     [webView _incrementProgressForIdentifier:identifier data:data];
500     
501     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
502         [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
503     else
504         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
505 }
506
507 - (void)_didFinishLoadingForResource:(id)identifier
508 {    
509     WebView *webView = [client webView];
510     
511     [webView _completeProgressForIdentifier:identifier];    
512     
513     if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
514         [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
515     else
516         [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
517 }
518
519 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
520 {
521     WebView *webView = [client webView];
522         
523     [webView _completeProgressForIdentifier:identifier];
524         
525     if (error)
526         [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:[self activeDataSource]];
527 }
528
529 - (BOOL)_privateBrowsingEnabled
530 {
531     return [[[client webView] preferences] privateBrowsingEnabled];
532 }
533
534 - (void)_finishedLoadingResource
535 {
536     [client _checkLoadComplete];
537 }
538
539 - (void)_receivedError:(NSError *)error
540 {
541     [client _checkLoadComplete];
542 }
543
544 - (NSURLRequest *)_originalRequest
545 {
546     return [[self activeDocumentLoader] originalRequestCopy];
547 }
548
549 - (WebFrame *)webFrame
550 {
551     return client;
552 }
553
554 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
555 {
556     WebDocumentLoader *loader = [self activeDocumentLoader];
557     [loader retain];
558     
559     WebFrameBridge *bridge = [client _bridge];
560     
561     // Retain the bridge because the stop may release the last reference to it.
562     [bridge retain];
563  
564     WebFrame *cli = [client retain];
565    
566     if (isComplete) {
567         // FIXME: Don't want to do this if an entirely new load is going, so should check
568         // that both data sources on the frame are either self or nil.
569         // Can't call [self _bridge] because we might not have commited yet
570         [bridge stop];
571         // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice.  See <rdar://problem/4258008>
572         if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
573             [bridge handleFallbackContent];
574     }
575     
576     if ([self state] == WebFrameStateProvisional) {
577         NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
578         [bridge didNotOpenURL:failedURL];
579         [client _invalidateCurrentItemPageCache];
580         
581         // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
582         // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
583         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are definitely
584         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
585         // has ended.
586         if (sentRedirectNotification)
587             [self clientRedirectCancelledOrFinished:NO];
588     }
589     
590     
591     [loader mainReceivedError:error complete:isComplete];
592
593     [bridge release];
594     [cli release];
595     [loader release];
596 }
597
598 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
599 {
600     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
601     // the redirect succeeded.  We should either rename this API, or add a new method, like
602     // -webView:didFinishClientRedirectForFrame:
603     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
604                             didCancelClientRedirectForFrame:client];
605     if (!cancelWithLoadInProgress)
606         quickRedirectComing = NO;
607     
608     sentRedirectNotification = NO;
609     
610     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
611 }
612
613 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
614 {
615     LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
616     
617     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
618                              willPerformClientRedirectToURL:URL
619                                                       delay:seconds
620                                                    fireDate:date
621                                                    forFrame:client];
622     
623     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
624     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
625     sentRedirectNotification = YES;
626     
627     // If a "quick" redirect comes in an, we set a special mode so we treat the next
628     // load as part of the same navigation.
629     
630     if (!documentLoader || isJavaScriptFormAction) {
631         // If we don't have a dataSource, we have no "original" load on which to base a redirect,
632         // so we better just treat the redirect as a normal load.
633         quickRedirectComing = NO;
634         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
635     } else {
636         quickRedirectComing = lockHistory;
637         LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
638     }
639 }
640
641 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
642 {
643     return !(([currentURL fragment] || [destinationURL fragment]) &&
644              [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
645 }
646
647 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
648 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(WebFrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
649 {
650     BOOL isFormSubmission = (values != nil);
651     
652     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
653     [request setValue:[[client webView] userAgentForURL:[request URL]] forHTTPHeaderField:@"Referer"];
654     [self _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
655     if (_loadType == WebFrameLoadTypeReload) {
656         [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
657     }
658     
659     // I believe this is never called with LoadSame.  If it is, we probably want to set the cache
660     // policy of LoadFromOrigin, but I didn't test that.
661     ASSERT(_loadType != WebFrameLoadTypeSame);
662     
663     NSDictionary *action = [client _actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
664     WebFormState *formState = nil;
665     if (form && values)
666         formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
667     
668     if (target != nil) {
669         WebFrame *targetFrame = [client findFrameNamed:target];
670         if (targetFrame != nil) {
671             [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
672         } else {
673             [self checkNewWindowPolicyForRequest:request
674                                           action:action
675                                        frameName:target
676                                        formState:formState
677                                          andCall:self
678                                     withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
679         }
680         [request release];
681         [formState release];
682         return;
683     }
684     
685     WebDataSource *oldDataSource = [[self dataSource] retain];
686     
687     BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
688     
689     // Make sure to do scroll to anchor processing even if the URL is
690     // exactly the same so pages with '#' links and DHTML side effects
691     // work properly.
692     if (!isFormSubmission
693         && _loadType != WebFrameLoadTypeReload
694         && _loadType != WebFrameLoadTypeSame
695         && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
696         
697         // We don't want to just scroll if a link from within a
698         // frameset is trying to reload the frameset into _top.
699         && ![[client _bridge] isFrameSet]) {
700         
701         // Just do anchor navigation within the existing content.
702         
703         // We don't do this if we are submitting a form, explicitly reloading,
704         // currently displaying a frameset, or if the new URL does not have a fragment.
705         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
706         
707         // FIXME: What about load types other than Standard and Reload?
708         
709         [[oldDataSource _documentLoader] setTriggeringAction:action];
710         [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
711         [self checkNavigationPolicyForRequest:request
712                                                     dataSource:oldDataSource formState:formState
713                                                        andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
714     } else {
715         // must grab this now, since this load may stop the previous load and clear this flag
716         BOOL isRedirect = quickRedirectComing;
717         [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
718         if (isRedirect) {
719             LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [client name], self, (int)isRedirect);
720             quickRedirectComing = NO;
721             [provisionalDocumentLoader setIsClientRedirect:YES];
722         } else if (sameURL) {
723             // Example of this case are sites that reload the same URL with a different cookie
724             // driving the generated content, or a master frame with links that drive a target
725             // frame, where the user has clicked on the same link repeatedly.
726             [self setLoadType:WebFrameLoadTypeSame];
727         }            
728     }
729     
730     [request release];
731     [oldDataSource release];
732     [formState release];
733 }
734
735 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
736 {
737     if (!request)
738         return;
739     
740     NSURL *URL = [request URL];
741     
742     BOOL isRedirect = quickRedirectComing;
743     LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
744     quickRedirectComing = NO;
745     
746     [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
747     if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
748         // NB: must happen after _setURL, since we add based on the current request.
749         // Must also happen before we openURL and displace the scroll position, since
750         // adding the BF item will save away scroll state.
751         
752         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
753         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
754         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
755         // though its load is not yet done.  I think this all works out OK, for one because
756         // we have already saved away the scroll and doc state for the long slow load,
757         // but it's not an obvious case.
758
759         [client _addHistoryItemForFragmentScroll];
760     }
761     
762     [[client _bridge] scrollToAnchorWithURL:URL];
763     
764     if (!isRedirect) {
765         // This will clear previousItem from the rest of the frame tree tree that didn't
766         // doing any loading.  We need to make a pass on this now, since for anchor nav
767         // we'll not go through a real load and reach Completed state
768         [client _checkLoadComplete];
769     }
770     
771     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
772                         didChangeLocationWithinPageForFrame:client];
773
774     [client _didFinishLoad];
775 }
776
777 - (void)closeOldDataSources
778 {
779     // FIXME: is it important for this traversal to be postorder instead of preorder?
780     // FIXME: add helpers for postorder traversal?
781     for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
782         [[(WebFrameBridge *)child loader] closeOldDataSources];
783     
784     if (documentLoader)
785         [[[client webView] _frameLoadDelegateForwarder] webView:[client webView] willCloseFrame:client];
786     [[client webView] setMainFrameDocumentReady:NO];  // stop giving out the actual DOMDocument to observers
787 }
788
789 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
790 {
791     bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
792     
793     WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
794     NSURLResponse *response = [provisionalDataSource response];
795     
796     NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
797         ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
798     
799     if (loadType != WebFrameLoadTypeReplace)
800         [self closeOldDataSources];
801     
802     if (!pageCache)
803         [provisionalDataSource _makeRepresentation];
804     
805     [client _transitionToCommitted:pageCache];
806     
807     // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
808     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
809     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
810     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
811     if (sentRedirectNotification)
812         [self clientRedirectCancelledOrFinished:NO];
813     
814     NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];        
815     NSURL *URL = baseURL ? baseURL : [response URL];
816     
817     if (!URL || [URL _web_isEmpty])
818         URL = [NSURL URLWithString:@"about:blank"];    
819     
820     [[client _bridge] openURL:URL
821                      reload:reload 
822                 contentType:[response MIMEType]
823                     refresh:[headers objectForKey:@"Refresh"]
824                lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
825                   pageCache:pageCache];
826     
827     [client _opened];
828     
829     [provisionalDataSource release];
830 }
831
832 - (NSURLRequest *)initialRequest
833 {
834     return [[self activeDataSource] initialRequest];
835 }
836
837 - (void)_receivedData:(NSData *)data
838 {
839     [[self activeDocumentLoader] receivedData:data];
840 }
841
842 - (void)_setRequest:(NSURLRequest *)request
843 {
844     [[self activeDocumentLoader] setRequest:request];
845 }
846
847 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
848 {
849     [WebDownload _downloadWithLoadingConnection:connection
850                                         request:request
851                                        response:r
852                                        delegate:[[client webView] downloadDelegate]
853                                           proxy:proxy];
854 }
855
856 - (WebFrameBridge *)bridge
857 {
858     return [client _bridge];
859 }
860
861 - (void)_handleFallbackContent
862 {
863     [[self bridge] handleFallbackContent];
864 }
865
866 - (BOOL)_isStopping
867 {
868     return [[self activeDocumentLoader] isStopping];
869 }
870
871 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
872 {
873     [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
874 }
875
876 - (void)_setResponse:(NSURLResponse *)response
877 {
878     [[self activeDocumentLoader] setResponse:response];
879 }
880
881 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
882 {
883     [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
884 }
885
886 - (void)_finishedLoading
887 {
888     WebDataSource *ds = [self activeDataSource];
889     
890     [self retain];
891     [[self activeDocumentLoader] finishedLoading];
892
893     if ([ds _mainDocumentError] || ![ds webFrame]) {
894         [self release];
895         return;
896     }
897
898     [[self activeDocumentLoader] setPrimaryLoadComplete:YES];
899     if ([WebScriptDebugServer listenerCount])
900         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
901     [client _checkLoadComplete];
902
903     [self release];
904 }
905
906 - (void)_notifyIconChanged:(NSURL *)iconURL
907 {
908     ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
909     ASSERT(client == [[client webView] mainFrame]);
910
911     [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
912     
913     NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
914     
915     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
916                                                didReceiveIcon:icon
917                                                      forFrame:client];
918     
919     [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
920 }
921
922 - (NSURL *)_URL
923 {
924     return [[self activeDataSource] _URL];
925 }
926
927 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
928 {
929     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
930                                       code:NSURLErrorCancelled
931                                        URL:[request URL]];
932 }
933
934 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
935 {
936     return [NSError _webKitErrorWithDomain:NSURLErrorDomain
937                                                 code:NSURLErrorFileDoesNotExist
938                                                  URL:[response URL]];    
939 }
940
941 - (void)clearArchivedResources
942 {
943     [pendingArchivedResources removeAllObjects];
944     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
945 }
946
947 - (void)deliverArchivedResources
948 {
949     if (![pendingArchivedResources count] || [self defersCallbacks])
950         return;
951         
952     NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
953     WebLoader *loader;
954     while ((loader = [keyEnum nextObject])) {
955         WebResource *resource = [pendingArchivedResources objectForKey:loader];
956         [loader didReceiveResponse:[resource _response]];
957         NSData *data = [resource data];
958         [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
959         [loader didFinishLoading];
960     }
961     
962     [pendingArchivedResources removeAllObjects];
963 }
964
965 - (void)deliverArchivedResourcesAfterDelay
966 {
967     if (![pendingArchivedResources count] || [self defersCallbacks])
968         return;
969     
970     [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
971 }
972
973 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
974 {
975     return [a caseInsensitiveCompare:b] == NSOrderedSame;
976 }
977
978 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
979 // FIXME: It would be nice to eventually to share this code somehow.
980 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
981 {
982     NSURLRequestCachePolicy policy = [theRequest cachePolicy];
983     
984     if (policy == NSURLRequestReturnCacheDataElseLoad) {
985         return YES;
986     } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
987         return YES;
988     } else if (policy == NSURLRequestReloadIgnoringCacheData) {
989         return NO;
990     } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
991         return NO;
992     } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
993         return NO;
994     } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
995         return NO;
996     } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
997         return NO;
998     } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
999         return NO;
1000     } else {
1001         return YES;
1002     }
1003 }
1004
1005 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
1006 {
1007     if (WKGetNSURLResponseMustRevalidate(theResponse)) {
1008         return NO;
1009     } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
1010         return NO;
1011     } else {
1012         return YES;
1013     }
1014 }
1015
1016 - (NSMutableDictionary *)pendingArchivedResources
1017 {
1018     if (!pendingArchivedResources)
1019         pendingArchivedResources = [[NSMutableDictionary alloc] init];
1020     
1021     return pendingArchivedResources;
1022 }
1023
1024 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
1025 {
1026     if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
1027         WebResource *resource = [self _archivedSubresourceForURL:originalURL];
1028         if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
1029             [[self pendingArchivedResources] _webkit_setObject:resource forUncopiedKey:loader];
1030             // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
1031             [self deliverArchivedResourcesAfterDelay];
1032             return YES;
1033         }
1034     }
1035     return NO;
1036 }
1037
1038 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
1039 {
1040     return [pendingArchivedResources objectForKey:loader] != nil;
1041 }
1042
1043 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
1044 {
1045     [pendingArchivedResources removeObjectForKey:loader];
1046     
1047     if (![pendingArchivedResources count])
1048         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
1049 }
1050
1051 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1052 {
1053     [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
1054 }
1055
1056 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
1057 {
1058     [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];    
1059 }
1060
1061 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1062 {
1063     return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1064 }
1065
1066 - (BOOL)isHostedByObjectElement
1067 {
1068     // Handle <object> fallback for error cases.            
1069     DOMHTMLElement *hostElement = [client frameElement];
1070     return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1071 }
1072
1073 - (BOOL)isLoadingMainFrame
1074 {
1075     return [client _isMainFrame];
1076 }
1077
1078 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1079 {
1080     return [WebView canShowMIMEType:MIMEType];
1081 }
1082
1083 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1084 {
1085     return [WebView _representationExistsForURLScheme:URLScheme];
1086 }
1087
1088 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1089 {
1090     return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1091 }
1092
1093 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1094 {
1095     [self checkNavigationPolicyForRequest:newRequest
1096                               dataSource:[self activeDataSource]
1097                                 formState:nil
1098                                   andCall:obj
1099                              withSelector:sel];
1100 }
1101
1102 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1103 {
1104     WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1105     listener = l;
1106     
1107     [l retain];
1108
1109     [[[client webView] _policyDelegateForwarder] webView:[client webView] decidePolicyForMIMEType:MIMEType
1110                                                  request:[[self activeDocumentLoader] request]
1111                                                    frame:client
1112                                         decisionListener:listener];
1113     [l release];
1114 }
1115
1116 - (void)cancelContentPolicy
1117 {
1118     [listener _invalidate];
1119     [listener release];
1120     listener = nil;
1121 }
1122
1123 static inline BOOL isBackForwardLoadType(WebFrameLoadType type)
1124 {
1125     switch (type) {
1126         case WebFrameLoadTypeStandard:
1127         case WebFrameLoadTypeReload:
1128         case WebFrameLoadTypeReloadAllowingStaleData:
1129         case WebFrameLoadTypeSame:
1130         case WebFrameLoadTypeInternal:
1131         case WebFrameLoadTypeReplace:
1132             return false;
1133         case WebFrameLoadTypeBack:
1134         case WebFrameLoadTypeForward:
1135         case WebFrameLoadTypeIndexedBackForward:
1136             return true;
1137     }
1138     ASSERT_NOT_REACHED();
1139     return false;
1140 }
1141
1142 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1143 {
1144     NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1145     if (unreachableURL == nil)
1146         return NO;
1147     
1148     if (!isBackForwardLoadType(policyLoadType))
1149         return NO;
1150     
1151     // We only treat unreachableURLs specially during the delegate callbacks
1152     // for provisional load errors and navigation policy decisions. The former
1153     // case handles well-formed URLs that can't be loaded, and the latter
1154     // case handles malformed URLs and unknown schemes. Loading alternate content
1155     // at other times behaves like a standard load.
1156     WebDataSource *compareDataSource = nil;
1157     if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1158         compareDataSource = [self policyDataSource];
1159     else if (delegateIsHandlingProvisionalLoadError)
1160         compareDataSource = [self provisionalDataSource];
1161     
1162     return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
1163 }
1164
1165 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1166 {
1167     WebFrameLoadType type;
1168     
1169     ASSERT(!policyDocumentLoader);
1170     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1171     WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1172
1173     NSMutableURLRequest *r = [newDataSource request];
1174     [client _addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1175     if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1176         [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1177         type = WebFrameLoadTypeSame;
1178     } else
1179         type = WebFrameLoadTypeStandard;
1180     
1181     [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1182     [newDataSource _addToUnarchiveState:archive];
1183     
1184     // When we loading alternate content for an unreachable URL that we're
1185     // visiting in the b/f list, we treat it as a reload so the b/f list 
1186     // is appropriately maintained.
1187     if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1188         ASSERT(type == WebFrameLoadTypeStandard);
1189         type = WebFrameLoadTypeReload;
1190     }
1191     
1192     [self loadDataSource:newDataSource withLoadType:type formState:nil];
1193 }
1194
1195 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1196 {
1197     ASSERT(!policyDocumentLoader);
1198     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1199     WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1200
1201     [policyDocumentLoader setTriggeringAction:action];
1202     [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1203
1204     [self loadDataSource:newDataSource withLoadType:type formState:formState];
1205 }
1206
1207 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1208 {
1209     WebDataSource *ds = [self dataSource];
1210     if (ds == nil)
1211         return;
1212
1213     NSMutableURLRequest *request = [[ds request] mutableCopy];
1214     NSURL *unreachableURL = [ds unreachableURL];
1215     if (unreachableURL != nil)
1216         [request setURL:unreachableURL];
1217
1218     [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1219     ASSERT(!policyDocumentLoader);
1220     policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1221     WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1222     [request release];
1223     
1224     [policyDocumentLoader setOverrideEncoding:encoding];
1225
1226     [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
1227 }
1228
1229 - (void)reload
1230 {
1231     WebDataSource *ds = [self dataSource];
1232     if (ds == nil)
1233         return;
1234
1235     NSMutableURLRequest *initialRequest = [ds request];
1236     
1237     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1238     // Reloading in this case will lose the current contents (see 4151001).
1239     if ([[[[ds request] URL] absoluteString] length] == 0)
1240         return;
1241
1242     // Replace error-page URL with the URL we were trying to reach.
1243     NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1244     if (unreachableURL != nil)
1245         initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1246     
1247     ASSERT(!policyDocumentLoader);
1248     policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1249     WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1250     NSMutableURLRequest *request = [newDataSource request];
1251
1252     [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1253
1254     // If we're about to rePOST, set up action so the app can warn the user
1255     if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
1256         NSDictionary *action = [client _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
1257         [policyDocumentLoader setTriggeringAction:action];
1258     }
1259
1260     [policyDocumentLoader setOverrideEncoding:[[ds _documentLoader] overrideEncoding]];
1261     
1262     [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
1263 }
1264
1265 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1266 {
1267     [client _didReceiveServerRedirectForProvisionalLoadForFrame];
1268 }
1269
1270 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1271 {
1272     [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1273 }
1274
1275 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1276 {
1277     [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1278 }
1279
1280 - (BOOL)isReplacing
1281 {
1282     return loadType == WebFrameLoadTypeReplace;
1283 }
1284
1285 - (void)setReplacing
1286 {
1287     loadType = WebFrameLoadTypeReplace;
1288 }
1289
1290 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1291 {
1292     [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1293 }
1294
1295 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1296 {
1297     [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1298 }
1299
1300 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1301 {
1302     [loader setPrimaryLoadComplete:YES];
1303     if ([WebScriptDebugServer listenerCount])
1304         [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1305     [client _checkLoadComplete];
1306 }
1307
1308 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1309 {
1310     [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1311 }
1312
1313 - (void)prepareForLoadStart
1314 {
1315     [[client webView] _progressStarted:client];
1316     [[client webView] _didStartProvisionalLoadForFrame:client];
1317     [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1318                                didStartProvisionalLoadForFrame:client];    
1319 }
1320
1321 - (BOOL)subframeIsLoading
1322 {
1323     return [client _subframeIsLoading];
1324 }
1325
1326 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1327 {
1328     // FIXME: should do this only in main frame case, right?
1329     [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1330 }
1331
1332 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1333 {
1334     // FIXME: should do this only in main frame case, right?
1335     [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1336
1337     // The title doesn't get communicated to the WebView until we are committed.
1338     if ([loader isCommitted]) {
1339         NSURL *URLForHistory = [[client _dataSourceForDocumentLoader:loader] _URLForHistory];
1340         if (URLForHistory != nil) {
1341             WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
1342             [entry setTitle:[loader title]];
1343         
1344             // Must update the entries in the back-forward list too.  This must go through the WebFrame because
1345             // it has the right notion of the current b/f item.
1346             [client _setTitle:[loader title]];
1347         
1348             [[client webView] setMainFrameDocumentReady:YES];    // update observers with new DOMDocument
1349             [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1350                                                       didReceiveTitle:[loader title]
1351                                                              forFrame:client];
1352         }
1353     }
1354 }
1355
1356 - (WebFrameLoadType)loadType
1357 {
1358     return loadType;
1359 }
1360
1361 - (void)setLoadType:(WebFrameLoadType)type
1362 {
1363     loadType = type;
1364 }
1365
1366 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1367 {
1368     [listener _invalidate];
1369     [listener release];
1370     listener = nil;
1371
1372     NSURLRequest *request = policyRequest;
1373     NSString *frameName = policyFrameName;
1374     id target = policyTarget;
1375     SEL selector = policySelector;
1376     WebFormState *formState = policyFormState;
1377
1378     policyRequest = nil;
1379     policyFrameName = nil;
1380     policyTarget = nil;
1381     policySelector = nil;
1382     policyFormState = nil;
1383
1384     if (call) {
1385         if (frameName)
1386             objc_msgSend(target, selector, nil, nil, nil);
1387         else
1388             objc_msgSend(target, selector, nil, nil);
1389     }
1390
1391     [request release];
1392     [frameName release];
1393     [target release];
1394     [formState release];
1395 }
1396
1397 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1398 {
1399     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1400         _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1401
1402     policyRequest = [request retain];
1403     policyTarget = [target retain];
1404     policyFrameName = [frameName retain];
1405     policySelector = selector;
1406     listener = [decisionListener retain];
1407     policyFormState = [formState retain];
1408
1409     WebView *wv = [client webView];
1410     [[wv _policyDelegateForwarder] webView:wv
1411             decidePolicyForNewWindowAction:action
1412                                    request:request
1413                               newFrameName:frameName
1414                           decisionListener:decisionListener];
1415     
1416     [decisionListener release];
1417 }
1418
1419 - (void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1420 {
1421     NSURLRequest *request = [[policyRequest retain] autorelease];
1422     NSString *frameName = [[policyFrameName retain] autorelease];
1423     id target = [[policyTarget retain] autorelease];
1424     SEL selector = policySelector;
1425     WebFormState *formState = [[policyFormState retain] autorelease];
1426
1427     // will release policy* objects, hence the above retains
1428     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1429
1430     BOOL shouldContinue = NO;
1431
1432     switch (policy) {
1433     case WebPolicyIgnore:
1434         break;
1435     case WebPolicyDownload:
1436         // FIXME: should download full request
1437         [[client webView] _downloadURL:[request URL]];
1438         break;
1439     case WebPolicyUse:
1440         shouldContinue = YES;
1441         break;
1442     default:
1443         ASSERT_NOT_REACHED();
1444     }
1445
1446     objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1447 }
1448
1449 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1450                              dataSource:(WebDataSource *)dataSource
1451                               formState:(WebFormState *)formState
1452                                 andCall:(id)target
1453                            withSelector:(SEL)selector
1454 {
1455     NSDictionary *action = [[dataSource _documentLoader] triggeringAction];
1456     if (action == nil) {
1457         action = [client _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1458         [[dataSource _documentLoader]  setTriggeringAction:action];
1459     }
1460         
1461     // Don't ask more than once for the same request or if we are loading an empty URL.
1462     // This avoids confusion on the part of the client.
1463     if ([request isEqual:[[dataSource _documentLoader] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1464         [target performSelector:selector withObject:request withObject:nil];
1465         return;
1466     }
1467     
1468     // We are always willing to show alternate content for unreachable URLs;
1469     // treat it like a reload so it maintains the right state for b/f list.
1470     if ([request _webDataRequestUnreachableURL] != nil) {
1471         if (isBackForwardLoadType(policyLoadType))
1472             policyLoadType = WebFrameLoadTypeReload;
1473         [target performSelector:selector withObject:request withObject:nil];
1474         return;
1475     }
1476     
1477     [[dataSource _documentLoader] setLastCheckedRequest:request];
1478
1479     WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1480     
1481     ASSERT(policyRequest == nil);
1482     policyRequest = [request retain];
1483     ASSERT(policyTarget == nil);
1484     policyTarget = [target retain];
1485     policySelector = selector;
1486     ASSERT(listener == nil);
1487     listener = [decisionListener retain];
1488     ASSERT(policyFormState == nil);
1489     policyFormState = [formState retain];
1490
1491     WebView *wv = [client webView];
1492     delegateIsDecidingNavigationPolicy = YES;
1493     [[wv _policyDelegateForwarder] webView:wv
1494            decidePolicyForNavigationAction:action
1495                                    request:request
1496                                      frame:client
1497                           decisionListener:decisionListener];
1498     delegateIsDecidingNavigationPolicy = NO;
1499     
1500     [decisionListener release];
1501 }
1502
1503 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1504 {
1505     NSURLRequest *request = [[policyRequest retain] autorelease];
1506     id target = [[policyTarget retain] autorelease];
1507     SEL selector = policySelector;
1508     WebFormState *formState = [[policyFormState retain] autorelease];
1509     
1510     // will release policy* objects, hence the above retains
1511     [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1512
1513     BOOL shouldContinue = NO;
1514
1515     switch (policy) {
1516     case WebPolicyIgnore:
1517         break;
1518     case WebPolicyDownload:
1519         // FIXME: should download full request
1520         [[client webView] _downloadURL:[request URL]];
1521         break;
1522     case WebPolicyUse:
1523         if (![WebView _canHandleRequest:request]) {
1524             [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1525         } else {
1526             shouldContinue = YES;
1527         }
1528         break;
1529     default:
1530         ASSERT_NOT_REACHED();
1531     }
1532
1533     [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1534 }
1535
1536 // Called after the FormsDelegate is done processing willSubmitForm:
1537 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1538 {
1539     if (listener) {
1540         [listener _invalidate];
1541         [listener release];
1542         listener = nil;
1543     }
1544     [self startLoading];
1545 }
1546
1547 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1548 {
1549     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1550     // nil policyDataSource because loading the alternate page will have passed
1551     // through this method already, nested; otherwise, policyDataSource should still be set.
1552     ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1553
1554     BOOL isTargetItem = [client _provisionalItemIsTarget];
1555
1556     // Two reasons we can't continue:
1557     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
1558     //       is the user responding Cancel to the form repost nag sheet.
1559     //    2) User responded Cancel to an alert popped up by the before unload event handler.
1560     // The "before unload" event handler runs only for the main frame.
1561     BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1562
1563     if (!canContinue) {
1564         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
1565         // need to report that the client redirect was cancelled.
1566         if (quickRedirectComing)
1567             [self clientRedirectCancelledOrFinished:NO];
1568
1569         [self setPolicyDocumentLoader:nil];
1570
1571         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
1572         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
1573         // we only do this when punting a navigation for the target frame or top-level frame.  
1574         if ((isTargetItem || [[client webView] mainFrame] == client) && isBackForwardLoadType(policyLoadType))
1575             [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1576
1577         return;
1578     }
1579     
1580     WebFrameLoadType type = policyLoadType;
1581     WebDataSource *dataSource = [[self policyDataSource] retain];
1582     
1583     [self stopLoading];
1584     loadType = type;
1585
1586     [self startProvisionalLoad:dataSource];
1587
1588     [dataSource release];
1589     [self setPolicyDocumentLoader:nil];
1590     
1591     if (client == [[client webView] mainFrame])
1592         LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1593
1594     if (type == WebFrameLoadTypeForward || type == WebFrameLoadTypeBack || type == WebFrameLoadTypeIndexedBackForward) {
1595         if ([client _loadProvisionalItemFromPageCache])
1596             return;
1597     }
1598
1599     if (formState) {
1600         // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1601         // mechanism across the willSubmitForm callout.
1602         listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1603         [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1604     } 
1605     else {
1606         [self continueAfterWillSubmitForm:WebPolicyUse];
1607     }
1608 }
1609
1610 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1611 {
1612     ASSERT([client webView] != nil);
1613
1614     // Unfortunately the view must be non-nil, this is ultimately due
1615     // to parser requiring a FrameView.  We should fix this dependency.
1616
1617     ASSERT([client frameView] != nil);
1618
1619     policyLoadType = type;
1620
1621     WebDocumentLoaderMac *loader = (WebDocumentLoaderMac *)[newDataSource _documentLoader];
1622
1623     WebFrame *parentFrame = [client parentFrame];
1624     if (parentFrame)
1625         [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1626
1627     [loader setFrameLoader:self];
1628     [loader setDataSource:newDataSource];
1629
1630     [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1631
1632     [self setPolicyDocumentLoader:loader];
1633
1634     [self checkNavigationPolicyForRequest:[newDataSource request]
1635                                dataSource:newDataSource
1636                                 formState:formState
1637                                   andCall:self
1638                              withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1639 }
1640
1641 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1642 {
1643     NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1644     WebView *wv = [client webView];
1645     delegateIsHandlingUnimplementablePolicy = YES;
1646     [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:client];    
1647     delegateIsHandlingUnimplementablePolicy = NO;
1648 }
1649
1650 - (BOOL)delegateIsHandlingProvisionalLoadError
1651 {
1652     return delegateIsHandlingProvisionalLoadError;
1653 }
1654
1655 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1656 {
1657     delegateIsHandlingProvisionalLoadError = is;
1658 }
1659
1660 - (void)didFirstLayout
1661 {
1662     if ([[client webView] backForwardList]) {
1663         if (loadType == WebFrameLoadTypeForward || loadType == WebFrameLoadTypeBack || loadType == WebFrameLoadTypeIndexedBackForward)
1664             [client _restoreScrollPositionAndViewState];
1665     }
1666     
1667     firstLayoutDone = YES;
1668
1669     WebView *wv = [client webView];
1670     [[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:client];
1671 }
1672
1673 - (void)frameLoadCompleted
1674 {
1675     // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1676     if ([self dataSource])
1677         firstLayoutDone = YES;
1678 }
1679
1680 - (BOOL)firstLayoutDone
1681 {
1682     return firstLayoutDone;
1683 }
1684
1685 - (BOOL)isQuickRedirectComing
1686 {
1687     return quickRedirectComing;
1688 }
1689
1690 @end