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