2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #import "WebFrameLoader.h"
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>
55 @implementation WebFrameLoader
57 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
62 state = WebFrameStateCommittedPage;
69 // FIXME: should these even exist?
70 [mainResourceLoader release];
71 [subresourceLoaders release];
72 [plugInStreamLoaders release];
73 [documentLoader release];
74 [provisionalDocumentLoader release];
76 ASSERT(!policyDocumentLoader);
81 - (WebDocumentLoader *)activeDocumentLoader
83 if (state == WebFrameStateProvisional)
84 return provisionalDocumentLoader;
86 return documentLoader;
89 - (WebDataSource *)activeDataSource
91 return [client _dataSourceForDocumentLoader:[self activeDocumentLoader]];
94 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
96 return [[self activeDataSource] _archivedSubresourceForURL:URL];
99 - (void)addPlugInStreamLoader:(WebLoader *)loader
101 if (!plugInStreamLoaders)
102 plugInStreamLoaders = [[NSMutableArray alloc] init];
103 [plugInStreamLoaders addObject:loader];
104 [[self activeDocumentLoader] setLoading:YES];
107 - (void)removePlugInStreamLoader:(WebLoader *)loader
109 [plugInStreamLoaders removeObject:loader];
110 [[self activeDocumentLoader] updateLoading];
113 - (void)defersCallbacksChanged
115 [self setDefersCallbacks:[[client webView] defersCallbacks]];
118 - (BOOL)defersCallbacks
120 return [[client webView] defersCallbacks];
123 - (void)setDefersCallbacks:(BOOL)defers
125 [mainResourceLoader setDefersCallbacks:defers];
127 NSEnumerator *e = [subresourceLoaders objectEnumerator];
129 while ((loader = [e nextObject]))
130 [loader setDefersCallbacks:defers];
132 e = [plugInStreamLoaders objectEnumerator];
133 while ((loader = [e nextObject]))
134 [loader setDefersCallbacks:defers];
136 [self deliverArchivedResourcesAfterDelay];
139 - (void)stopLoadingPlugIns
141 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
142 [plugInStreamLoaders removeAllObjects];
145 - (BOOL)isLoadingMainResource
147 return mainResourceLoader != nil;
150 - (BOOL)isLoadingSubresources
152 return [subresourceLoaders count];
155 - (BOOL)isLoadingPlugIns
157 return [plugInStreamLoaders count];
162 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
165 - (void)stopLoadingSubresources
167 NSArray *loaders = [subresourceLoaders copy];
168 [loaders makeObjectsPerformSelector:@selector(cancel)];
170 [subresourceLoaders removeAllObjects];
173 - (void)addSubresourceLoader:(WebLoader *)loader
175 ASSERT(!provisionalDocumentLoader);
176 if (subresourceLoaders == nil)
177 subresourceLoaders = [[NSMutableArray alloc] init];
178 [subresourceLoaders addObject:loader];
179 [[self activeDocumentLoader] setLoading:YES];
182 - (void)removeSubresourceLoader:(WebLoader *)loader
184 [subresourceLoaders removeObject:loader];
185 [[self activeDocumentLoader] updateLoading];
188 - (NSData *)mainResourceData
190 return [mainResourceLoader resourceData];
193 - (void)releaseMainResourceLoader
195 [mainResourceLoader release];
196 mainResourceLoader = nil;
199 - (void)cancelMainResourceLoad
201 [mainResourceLoader cancel];
204 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
206 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
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;
222 - (void)stopLoadingWithError:(NSError *)error
224 [mainResourceLoader cancelWithError:error];
227 - (WebDataSource *)dataSource
229 return [client _dataSourceForDocumentLoader:documentLoader];
232 - (void)setDocumentLoader:(WebDocumentLoader *)loader
234 if (loader == nil && documentLoader == nil)
237 ASSERT(loader != documentLoader);
239 [client _prepareForDataSourceReplacement];
240 [documentLoader detachFromFrameLoader];
243 [documentLoader release];
244 documentLoader = loader;
247 - (WebDocumentLoader *)documentLoader
249 return documentLoader;
252 - (WebDataSource *)policyDataSource
254 return [client _dataSourceForDocumentLoader:policyDocumentLoader];
257 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
259 if (policyDocumentLoader == loader)
262 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
263 [policyDocumentLoader detachFromFrameLoader];
265 [policyDocumentLoader release];
267 policyDocumentLoader = loader;
270 - (void)clearDataSource
272 [self setDocumentLoader:nil];
275 - (WebDataSource *)provisionalDataSource
277 return [client _dataSourceForDocumentLoader:provisionalDocumentLoader];
280 - (WebDocumentLoader *)provisionalDocumentLoader
282 return provisionalDocumentLoader;
285 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
287 ASSERT(!loader || !provisionalDocumentLoader);
289 if (provisionalDocumentLoader != documentLoader)
290 [provisionalDocumentLoader detachFromFrameLoader];
293 [provisionalDocumentLoader release];
294 provisionalDocumentLoader = loader;
297 - (void)_clearProvisionalDataSource
299 [self setProvisionalDocumentLoader:nil];
302 - (WebFrameState)state
308 static const char * const stateNames[] = {
309 "WebFrameStateProvisional",
310 "WebFrameStateCommittedPage",
311 "WebFrameStateComplete"
315 static CFAbsoluteTime _timeOfLastCompletedLoad;
317 + (CFAbsoluteTime)timeOfLastCompletedLoad
319 return _timeOfLastCompletedLoad;
322 - (void)provisionalLoadStarted
324 firstLayoutDone = NO;
325 [[client _bridge] provisionalLoadStarted];
327 [client _provisionalLoadStarted];
330 - (void)_setState:(WebFrameState)newState
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]);
336 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
337 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoader] loadingStartedTime]);
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];
351 - (void)clearProvisionalLoad
353 [self setProvisionalDocumentLoader:nil];
354 [[client webView] _progressCompleted:client];
355 [self _setState:WebFrameStateComplete];
358 - (void)markLoadComplete
360 [self _setState:WebFrameStateComplete];
363 - (void)commitProvisionalLoad
365 [self stopLoadingSubresources];
366 [self stopLoadingPlugIns];
368 [self setDocumentLoader:provisionalDocumentLoader];
369 [self setProvisionalDocumentLoader:nil];
370 [self _setState:WebFrameStateCommittedPage];
373 - (void)stopLoadingSubframes
375 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
376 [[(WebFrameBridge *)child loader] stopLoading];
381 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
385 isStoppingLoad = YES;
387 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
389 [self stopLoadingSubframes];
390 [provisionalDocumentLoader stopLoading];
391 [documentLoader stopLoading];
392 [self _clearProvisionalDataSource];
393 [self clearArchivedResources];
398 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
401 [provisionalDocumentLoader prepareForLoadStart];
403 if ([self isLoadingMainResource])
406 [[self provisionalDataSource] _setLoadingFromPageCache:NO];
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]];
413 identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDataSource:[self provisionalDataSource]];
415 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
416 [provisionalDocumentLoader updateLoading];
419 - (void)startProvisionalLoad:(WebDataSource *)ds
421 [self setProvisionalDocumentLoader:[ds _documentLoader]];
422 [self _setState:WebFrameStateProvisional];
425 - (void)setupForReplace
427 [self _setState:WebFrameStateProvisional];
428 WebDocumentLoader *old = provisionalDocumentLoader;
429 provisionalDocumentLoader = documentLoader;
430 documentLoader = nil;
433 [client _detachChildren];
436 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
438 WebView *webView = [client webView];
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];
445 return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
448 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
450 WebView *webView = [client webView];
452 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
454 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
455 return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
457 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
460 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
462 WebView *webView = [client webView];
464 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
465 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
467 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
470 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
472 WebView *webView = [client webView];
474 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
475 [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
477 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
481 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
483 WebView *webView = [client webView];
485 [[self activeDocumentLoader] addResponse:r];
487 [webView _incrementProgressForIdentifier:identifier response:r];
489 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
490 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
492 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
495 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
497 WebView *webView = [client webView];
499 [webView _incrementProgressForIdentifier:identifier data:data];
501 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
502 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
504 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
507 - (void)_didFinishLoadingForResource:(id)identifier
509 WebView *webView = [client webView];
511 [webView _completeProgressForIdentifier:identifier];
513 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
514 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
516 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
519 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
521 WebView *webView = [client webView];
523 [webView _completeProgressForIdentifier:identifier];
526 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:[self activeDataSource]];
529 - (BOOL)_privateBrowsingEnabled
531 return [[[client webView] preferences] privateBrowsingEnabled];
534 - (void)_finishedLoadingResource
536 [client _checkLoadComplete];
539 - (void)_receivedError:(NSError *)error
541 [client _checkLoadComplete];
544 - (NSURLRequest *)_originalRequest
546 return [[self activeDocumentLoader] originalRequestCopy];
549 - (WebFrame *)webFrame
554 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
556 WebDocumentLoader *loader = [self activeDocumentLoader];
559 WebFrameBridge *bridge = [client _bridge];
561 // Retain the bridge because the stop may release the last reference to it.
564 WebFrame *cli = [client retain];
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
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];
576 if ([self state] == WebFrameStateProvisional) {
577 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
578 [bridge didNotOpenURL:failedURL];
579 [client _invalidateCurrentItemPageCache];
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
586 if (sentRedirectNotification)
587 [self clientRedirectCancelledOrFinished:NO];
591 [loader mainReceivedError:error complete:isComplete];
598 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
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;
608 sentRedirectNotification = NO;
610 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
613 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
615 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
617 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
618 willPerformClientRedirectToURL:URL
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;
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.
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);
636 quickRedirectComing = lockHistory;
637 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
641 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
643 return !(([currentURL fragment] || [destinationURL fragment]) &&
644 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
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
650 BOOL isFormSubmission = (values != nil);
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];
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);
663 NSDictionary *action = [client _actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
664 WebFormState *formState = nil;
666 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
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];
673 [self checkNewWindowPolicyForRequest:request
678 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
685 WebDataSource *oldDataSource = [[self dataSource] retain];
687 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
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
692 if (!isFormSubmission
693 && _loadType != WebFrameLoadTypeReload
694 && _loadType != WebFrameLoadTypeSame
695 && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
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]) {
701 // Just do anchor navigation within the existing content.
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.
707 // FIXME: What about load types other than Standard and Reload?
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:)];
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];
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];
731 [oldDataSource release];
735 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
740 NSURL *URL = [request URL];
742 BOOL isRedirect = quickRedirectComing;
743 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
744 quickRedirectComing = NO;
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.
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.
759 [client _addHistoryItemForFragmentScroll];
762 [[client _bridge] scrollToAnchorWithURL:URL];
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];
771 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
772 didChangeLocationWithinPageForFrame:client];
774 [client _didFinishLoad];
777 - (void)closeOldDataSources
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];
785 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView] willCloseFrame:client];
786 [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
789 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
791 bool reload = loadType == WebFrameLoadTypeReload || loadType == WebFrameLoadTypeReloadAllowingStaleData;
793 WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
794 NSURLResponse *response = [provisionalDataSource response];
796 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
797 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
799 if (loadType != WebFrameLoadTypeReplace)
800 [self closeOldDataSources];
803 [provisionalDataSource _makeRepresentation];
805 [client _transitionToCommitted:pageCache];
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];
814 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
815 NSURL *URL = baseURL ? baseURL : [response URL];
817 if (!URL || [URL _web_isEmpty])
818 URL = [NSURL URLWithString:@"about:blank"];
820 [[client _bridge] openURL:URL
822 contentType:[response MIMEType]
823 refresh:[headers objectForKey:@"Refresh"]
824 lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
825 pageCache:pageCache];
829 [provisionalDataSource release];
832 - (NSURLRequest *)initialRequest
834 return [[self activeDataSource] initialRequest];
837 - (void)_receivedData:(NSData *)data
839 [[self activeDocumentLoader] receivedData:data];
842 - (void)_setRequest:(NSURLRequest *)request
844 [[self activeDocumentLoader] setRequest:request];
847 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
849 [WebDownload _downloadWithLoadingConnection:connection
852 delegate:[[client webView] downloadDelegate]
856 - (WebFrameBridge *)bridge
858 return [client _bridge];
861 - (void)_handleFallbackContent
863 [[self bridge] handleFallbackContent];
868 return [[self activeDocumentLoader] isStopping];
871 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
873 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
876 - (void)_setResponse:(NSURLResponse *)response
878 [[self activeDocumentLoader] setResponse:response];
881 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
883 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
886 - (void)_finishedLoading
888 WebDataSource *ds = [self activeDataSource];
891 [[self activeDocumentLoader] finishedLoading];
893 if ([ds _mainDocumentError] || ![ds webFrame]) {
898 [[self activeDocumentLoader] setPrimaryLoadComplete:YES];
899 if ([WebScriptDebugServer listenerCount])
900 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
901 [client _checkLoadComplete];
906 - (void)_notifyIconChanged:(NSURL *)iconURL
908 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
909 ASSERT(client == [[client webView] mainFrame]);
911 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
913 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
915 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
919 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
924 return [[self activeDataSource] _URL];
927 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
929 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
930 code:NSURLErrorCancelled
934 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
936 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
937 code:NSURLErrorFileDoesNotExist
941 - (void)clearArchivedResources
943 [pendingArchivedResources removeAllObjects];
944 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
947 - (void)deliverArchivedResources
949 if (![pendingArchivedResources count] || [self defersCallbacks])
952 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
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];
962 [pendingArchivedResources removeAllObjects];
965 - (void)deliverArchivedResourcesAfterDelay
967 if (![pendingArchivedResources count] || [self defersCallbacks])
970 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
973 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
975 return [a caseInsensitiveCompare:b] == NSOrderedSame;
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
982 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
984 if (policy == NSURLRequestReturnCacheDataElseLoad) {
986 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
988 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
990 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
992 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
994 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
996 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
998 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
1005 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
1007 if (WKGetNSURLResponseMustRevalidate(theResponse)) {
1009 } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
1016 - (NSMutableDictionary *)pendingArchivedResources
1018 if (!pendingArchivedResources)
1019 pendingArchivedResources = [[NSMutableDictionary alloc] init];
1021 return pendingArchivedResources;
1024 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
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];
1038 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
1040 return [pendingArchivedResources objectForKey:loader] != nil;
1043 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
1045 [pendingArchivedResources removeObjectForKey:loader];
1047 if (![pendingArchivedResources count])
1048 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
1051 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1053 [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
1056 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
1058 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
1061 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1063 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1066 - (BOOL)isHostedByObjectElement
1068 // Handle <object> fallback for error cases.
1069 DOMHTMLElement *hostElement = [client frameElement];
1070 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1073 - (BOOL)isLoadingMainFrame
1075 return [client _isMainFrame];
1078 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1080 return [WebView canShowMIMEType:MIMEType];
1083 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1085 return [WebView _representationExistsForURLScheme:URLScheme];
1088 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1090 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1093 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1095 [self checkNavigationPolicyForRequest:newRequest
1096 dataSource:[self activeDataSource]
1102 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1104 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1109 [[[client webView] _policyDelegateForwarder] webView:[client webView] decidePolicyForMIMEType:MIMEType
1110 request:[[self activeDocumentLoader] request]
1112 decisionListener:listener];
1116 - (void)cancelContentPolicy
1118 [listener _invalidate];
1123 static inline BOOL isBackForwardLoadType(WebFrameLoadType type)
1126 case WebFrameLoadTypeStandard:
1127 case WebFrameLoadTypeReload:
1128 case WebFrameLoadTypeReloadAllowingStaleData:
1129 case WebFrameLoadTypeSame:
1130 case WebFrameLoadTypeInternal:
1131 case WebFrameLoadTypeReplace:
1133 case WebFrameLoadTypeBack:
1134 case WebFrameLoadTypeForward:
1135 case WebFrameLoadTypeIndexedBackForward:
1138 ASSERT_NOT_REACHED();
1142 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1144 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1145 if (unreachableURL == nil)
1148 if (!isBackForwardLoadType(policyLoadType))
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];
1162 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
1165 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1167 WebFrameLoadType type;
1169 ASSERT(!policyDocumentLoader);
1170 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1171 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
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;
1179 type = WebFrameLoadTypeStandard;
1181 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1182 [newDataSource _addToUnarchiveState:archive];
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;
1192 [self loadDataSource:newDataSource withLoadType:type formState:nil];
1195 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1197 ASSERT(!policyDocumentLoader);
1198 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1199 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1201 [policyDocumentLoader setTriggeringAction:action];
1202 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1204 [self loadDataSource:newDataSource withLoadType:type formState:formState];
1207 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1209 WebDataSource *ds = [self dataSource];
1213 NSMutableURLRequest *request = [[ds request] mutableCopy];
1214 NSURL *unreachableURL = [ds unreachableURL];
1215 if (unreachableURL != nil)
1216 [request setURL:unreachableURL];
1218 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1219 ASSERT(!policyDocumentLoader);
1220 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1221 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1224 [policyDocumentLoader setOverrideEncoding:encoding];
1226 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
1231 WebDataSource *ds = [self dataSource];
1235 NSMutableURLRequest *initialRequest = [ds request];
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)
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];
1247 ASSERT(!policyDocumentLoader);
1248 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1249 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1250 NSMutableURLRequest *request = [newDataSource request];
1252 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
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];
1260 [policyDocumentLoader setOverrideEncoding:[[ds _documentLoader] overrideEncoding]];
1262 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
1265 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1267 [client _didReceiveServerRedirectForProvisionalLoadForFrame];
1270 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1272 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1275 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1277 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1282 return loadType == WebFrameLoadTypeReplace;
1285 - (void)setReplacing
1287 loadType = WebFrameLoadTypeReplace;
1290 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1292 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1295 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1297 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1300 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1302 [loader setPrimaryLoadComplete:YES];
1303 if ([WebScriptDebugServer listenerCount])
1304 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1305 [client _checkLoadComplete];
1308 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1310 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1313 - (void)prepareForLoadStart
1315 [[client webView] _progressStarted:client];
1316 [[client webView] _didStartProvisionalLoadForFrame:client];
1317 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1318 didStartProvisionalLoadForFrame:client];
1321 - (BOOL)subframeIsLoading
1323 return [client _subframeIsLoading];
1326 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1328 // FIXME: should do this only in main frame case, right?
1329 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1332 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1334 // FIXME: should do this only in main frame case, right?
1335 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
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]];
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]];
1348 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1349 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1350 didReceiveTitle:[loader title]
1356 - (WebFrameLoadType)loadType
1361 - (void)setLoadType:(WebFrameLoadType)type
1366 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1368 [listener _invalidate];
1372 NSURLRequest *request = policyRequest;
1373 NSString *frameName = policyFrameName;
1374 id target = policyTarget;
1375 SEL selector = policySelector;
1376 WebFormState *formState = policyFormState;
1378 policyRequest = nil;
1379 policyFrameName = nil;
1381 policySelector = nil;
1382 policyFormState = nil;
1386 objc_msgSend(target, selector, nil, nil, nil);
1388 objc_msgSend(target, selector, nil, nil);
1392 [frameName release];
1394 [formState release];
1397 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1399 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1400 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1402 policyRequest = [request retain];
1403 policyTarget = [target retain];
1404 policyFrameName = [frameName retain];
1405 policySelector = selector;
1406 listener = [decisionListener retain];
1407 policyFormState = [formState retain];
1409 WebView *wv = [client webView];
1410 [[wv _policyDelegateForwarder] webView:wv
1411 decidePolicyForNewWindowAction:action
1413 newFrameName:frameName
1414 decisionListener:decisionListener];
1416 [decisionListener release];
1419 - (void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
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];
1427 // will release policy* objects, hence the above retains
1428 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1430 BOOL shouldContinue = NO;
1433 case WebPolicyIgnore:
1435 case WebPolicyDownload:
1436 // FIXME: should download full request
1437 [[client webView] _downloadURL:[request URL]];
1440 shouldContinue = YES;
1443 ASSERT_NOT_REACHED();
1446 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1449 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1450 dataSource:(WebDataSource *)dataSource
1451 formState:(WebFormState *)formState
1453 withSelector:(SEL)selector
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];
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];
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];
1477 [[dataSource _documentLoader] setLastCheckedRequest:request];
1479 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
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];
1491 WebView *wv = [client webView];
1492 delegateIsDecidingNavigationPolicy = YES;
1493 [[wv _policyDelegateForwarder] webView:wv
1494 decidePolicyForNavigationAction:action
1497 decisionListener:decisionListener];
1498 delegateIsDecidingNavigationPolicy = NO;
1500 [decisionListener release];
1503 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1505 NSURLRequest *request = [[policyRequest retain] autorelease];
1506 id target = [[policyTarget retain] autorelease];
1507 SEL selector = policySelector;
1508 WebFormState *formState = [[policyFormState retain] autorelease];
1510 // will release policy* objects, hence the above retains
1511 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1513 BOOL shouldContinue = NO;
1516 case WebPolicyIgnore:
1518 case WebPolicyDownload:
1519 // FIXME: should download full request
1520 [[client webView] _downloadURL:[request URL]];
1523 if (![WebView _canHandleRequest:request]) {
1524 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1526 shouldContinue = YES;
1530 ASSERT_NOT_REACHED();
1533 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1536 // Called after the FormsDelegate is done processing willSubmitForm:
1537 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1540 [listener _invalidate];
1544 [self startLoading];
1547 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
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);
1554 BOOL isTargetItem = [client _provisionalItemIsTarget];
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]);
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];
1569 [self setPolicyDocumentLoader:nil];
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];
1580 WebFrameLoadType type = policyLoadType;
1581 WebDataSource *dataSource = [[self policyDataSource] retain];
1586 [self startProvisionalLoad:dataSource];
1588 [dataSource release];
1589 [self setPolicyDocumentLoader:nil];
1591 if (client == [[client webView] mainFrame])
1592 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1594 if (type == WebFrameLoadTypeForward || type == WebFrameLoadTypeBack || type == WebFrameLoadTypeIndexedBackForward) {
1595 if ([client _loadProvisionalItemFromPageCache])
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];
1606 [self continueAfterWillSubmitForm:WebPolicyUse];
1610 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1612 ASSERT([client webView] != nil);
1614 // Unfortunately the view must be non-nil, this is ultimately due
1615 // to parser requiring a FrameView. We should fix this dependency.
1617 ASSERT([client frameView] != nil);
1619 policyLoadType = type;
1621 WebDocumentLoaderMac *loader = (WebDocumentLoaderMac *)[newDataSource _documentLoader];
1623 WebFrame *parentFrame = [client parentFrame];
1625 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1627 [loader setFrameLoader:self];
1628 [loader setDataSource:newDataSource];
1630 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1632 [self setPolicyDocumentLoader:loader];
1634 [self checkNavigationPolicyForRequest:[newDataSource request]
1635 dataSource:newDataSource
1638 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1641 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
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;
1650 - (BOOL)delegateIsHandlingProvisionalLoadError
1652 return delegateIsHandlingProvisionalLoadError;
1655 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1657 delegateIsHandlingProvisionalLoadError = is;
1660 - (void)didFirstLayout
1662 if ([[client webView] backForwardList]) {
1663 if (loadType == WebFrameLoadTypeForward || loadType == WebFrameLoadTypeBack || loadType == WebFrameLoadTypeIndexedBackForward)
1664 [client _restoreScrollPositionAndViewState];
1667 firstLayoutDone = YES;
1669 WebView *wv = [client webView];
1670 [[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:client];
1673 - (void)frameLoadCompleted
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;
1680 - (BOOL)firstLayoutDone
1682 return firstLayoutDone;
1685 - (BOOL)isQuickRedirectComing
1687 return quickRedirectComing;