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 "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>
56 @implementation WebFrameLoader
58 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
63 state = WebFrameStateCommittedPage;
70 // FIXME: should these even exist?
71 [mainResourceLoader release];
72 [subresourceLoaders release];
73 [plugInStreamLoaders release];
74 [documentLoader release];
75 [provisionalDocumentLoader release];
77 ASSERT(!policyDocumentLoader);
82 - (WebDocumentLoader *)activeDocumentLoader
84 if (state == WebFrameStateProvisional)
85 return provisionalDocumentLoader;
87 return documentLoader;
90 - (WebDataSource *)activeDataSource
92 return [client _dataSourceForDocumentLoader:[self activeDocumentLoader]];
95 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
97 return [[self activeDataSource] _archivedSubresourceForURL:URL];
100 - (void)addPlugInStreamLoader:(WebLoader *)loader
102 if (!plugInStreamLoaders)
103 plugInStreamLoaders = [[NSMutableArray alloc] init];
104 [plugInStreamLoaders addObject:loader];
105 [[self activeDocumentLoader] setLoading:YES];
108 - (void)removePlugInStreamLoader:(WebLoader *)loader
110 [plugInStreamLoaders removeObject:loader];
111 [[self activeDocumentLoader] updateLoading];
114 - (void)defersCallbacksChanged
116 [self setDefersCallbacks:[[client webView] defersCallbacks]];
119 - (BOOL)defersCallbacks
121 return [[client webView] defersCallbacks];
124 - (void)setDefersCallbacks:(BOOL)defers
126 [mainResourceLoader setDefersCallbacks:defers];
128 NSEnumerator *e = [subresourceLoaders objectEnumerator];
130 while ((loader = [e nextObject]))
131 [loader setDefersCallbacks:defers];
133 e = [plugInStreamLoaders objectEnumerator];
134 while ((loader = [e nextObject]))
135 [loader setDefersCallbacks:defers];
137 [self deliverArchivedResourcesAfterDelay];
140 - (void)stopLoadingPlugIns
142 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
143 [plugInStreamLoaders removeAllObjects];
146 - (BOOL)isLoadingMainResource
148 return mainResourceLoader != nil;
151 - (BOOL)isLoadingSubresources
153 return [subresourceLoaders count];
156 - (BOOL)isLoadingPlugIns
158 return [plugInStreamLoaders count];
163 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
166 - (void)stopLoadingSubresources
168 NSArray *loaders = [subresourceLoaders copy];
169 [loaders makeObjectsPerformSelector:@selector(cancel)];
171 [subresourceLoaders removeAllObjects];
174 - (void)addSubresourceLoader:(WebLoader *)loader
176 ASSERT(!provisionalDocumentLoader);
177 if (subresourceLoaders == nil)
178 subresourceLoaders = [[NSMutableArray alloc] init];
179 [subresourceLoaders addObject:loader];
180 [[self activeDocumentLoader] setLoading:YES];
183 - (void)removeSubresourceLoader:(WebLoader *)loader
185 [subresourceLoaders removeObject:loader];
186 [[self activeDocumentLoader] updateLoading];
189 - (NSData *)mainResourceData
191 return [mainResourceLoader resourceData];
194 - (void)releaseMainResourceLoader
196 [mainResourceLoader release];
197 mainResourceLoader = nil;
200 - (void)cancelMainResourceLoad
202 [mainResourceLoader cancel];
205 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
207 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
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;
223 - (void)stopLoadingWithError:(NSError *)error
225 [mainResourceLoader cancelWithError:error];
228 - (WebDataSource *)dataSource
230 return [client _dataSourceForDocumentLoader:documentLoader];
233 - (void)setDocumentLoader:(WebDocumentLoader *)loader
235 if (loader == nil && documentLoader == nil)
238 ASSERT(loader != documentLoader);
240 [client _prepareForDataSourceReplacement];
241 [documentLoader detachFromFrameLoader];
244 [documentLoader release];
245 documentLoader = loader;
248 - (WebDocumentLoader *)documentLoader
250 return documentLoader;
253 - (WebDataSource *)policyDataSource
255 return [client _dataSourceForDocumentLoader:policyDocumentLoader];
258 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
260 if (policyDocumentLoader == loader)
263 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
264 [policyDocumentLoader detachFromFrameLoader];
266 [policyDocumentLoader release];
268 policyDocumentLoader = loader;
271 - (void)clearDataSource
273 [self setDocumentLoader:nil];
276 - (WebDataSource *)provisionalDataSource
278 return [client _dataSourceForDocumentLoader:provisionalDocumentLoader];
281 - (WebDocumentLoader *)provisionalDocumentLoader
283 return provisionalDocumentLoader;
286 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
288 ASSERT(!loader || !provisionalDocumentLoader);
290 if (provisionalDocumentLoader != documentLoader)
291 [provisionalDocumentLoader detachFromFrameLoader];
294 [provisionalDocumentLoader release];
295 provisionalDocumentLoader = loader;
298 - (void)_clearProvisionalDataSource
300 [self setProvisionalDocumentLoader:nil];
303 - (WebFrameState)state
309 static const char * const stateNames[] = {
310 "WebFrameStateProvisional",
311 "WebFrameStateCommittedPage",
312 "WebFrameStateComplete"
316 static CFAbsoluteTime _timeOfLastCompletedLoad;
318 + (CFAbsoluteTime)timeOfLastCompletedLoad
320 return _timeOfLastCompletedLoad;
323 - (void)provisionalLoadStarted
325 firstLayoutDone = NO;
326 [[client _bridge] provisionalLoadStarted];
328 [client _provisionalLoadStarted];
331 - (void)_setState:(WebFrameState)newState
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]);
337 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
338 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoader] loadingStartedTime]);
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];
352 - (void)clearProvisionalLoad
354 [self setProvisionalDocumentLoader:nil];
355 [[client webView] _progressCompleted:client];
356 [self _setState:WebFrameStateComplete];
359 - (void)markLoadComplete
361 [self _setState:WebFrameStateComplete];
364 - (void)commitProvisionalLoad
366 [self stopLoadingSubresources];
367 [self stopLoadingPlugIns];
369 [self setDocumentLoader:provisionalDocumentLoader];
370 [self setProvisionalDocumentLoader:nil];
371 [self _setState:WebFrameStateCommittedPage];
374 - (void)stopLoadingSubframes
376 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
377 [[(WebFrameBridge *)child loader] stopLoading];
382 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
386 isStoppingLoad = YES;
388 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
390 [self stopLoadingSubframes];
391 [provisionalDocumentLoader stopLoading];
392 [documentLoader stopLoading];
393 [self _clearProvisionalDataSource];
394 [self clearArchivedResources];
399 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
402 [provisionalDocumentLoader prepareForLoadStart];
404 if ([self isLoadingMainResource])
407 [[self provisionalDataSource] _setLoadingFromPageCache:NO];
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]];
414 identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDataSource:[self provisionalDataSource]];
416 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
417 [provisionalDocumentLoader updateLoading];
420 - (void)startProvisionalLoad:(WebDataSource *)ds
422 [self setProvisionalDocumentLoader:[ds _documentLoader]];
423 [self _setState:WebFrameStateProvisional];
426 - (void)setupForReplace
428 [self _setState:WebFrameStateProvisional];
429 WebDocumentLoader *old = provisionalDocumentLoader;
430 provisionalDocumentLoader = documentLoader;
431 documentLoader = nil;
434 [client _detachChildren];
437 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
439 WebView *webView = [client webView];
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];
446 return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
449 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
451 WebView *webView = [client webView];
453 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
455 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
456 return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
458 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
461 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
463 WebView *webView = [client webView];
465 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
466 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
468 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
471 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
473 WebView *webView = [client webView];
475 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
476 [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
478 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
482 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
484 WebView *webView = [client webView];
486 [[self activeDocumentLoader] addResponse:r];
488 [webView _incrementProgressForIdentifier:identifier response:r];
490 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
491 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
493 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
496 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
498 WebView *webView = [client webView];
500 [webView _incrementProgressForIdentifier:identifier data:data];
502 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
503 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
505 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
508 - (void)_didFinishLoadingForResource:(id)identifier
510 WebView *webView = [client webView];
512 [webView _completeProgressForIdentifier:identifier];
514 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
515 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
517 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
520 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
522 WebView *webView = [client webView];
524 [webView _completeProgressForIdentifier:identifier];
527 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:[self activeDataSource]];
530 - (BOOL)_privateBrowsingEnabled
532 return [[[client webView] preferences] privateBrowsingEnabled];
535 - (void)_finishedLoadingResource
537 [client _checkLoadComplete];
540 - (void)_receivedError:(NSError *)error
542 [client _checkLoadComplete];
545 - (NSURLRequest *)_originalRequest
547 return [[self activeDocumentLoader] originalRequestCopy];
550 - (WebFrame *)webFrame
555 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
557 WebDocumentLoader *loader = [self activeDocumentLoader];
560 WebFrameBridge *bridge = [client _bridge];
562 // Retain the bridge because the stop may release the last reference to it.
565 WebFrame *cli = [client retain];
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
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];
577 if ([self state] == WebFrameStateProvisional) {
578 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
579 [bridge didNotOpenURL:failedURL];
580 [client _invalidateCurrentItemPageCache];
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
587 if (sentRedirectNotification)
588 [self clientRedirectCancelledOrFinished:NO];
592 [loader mainReceivedError:error complete:isComplete];
599 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
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;
609 sentRedirectNotification = NO;
611 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
614 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
616 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
618 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
619 willPerformClientRedirectToURL:URL
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;
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.
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);
637 quickRedirectComing = lockHistory;
638 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
642 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
644 return !(([currentURL fragment] || [destinationURL fragment]) &&
645 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
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
651 BOOL isFormSubmission = (values != nil);
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];
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);
664 NSDictionary *action = [client _actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
665 WebFormState *formState = nil;
667 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
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];
674 [self checkNewWindowPolicyForRequest:request
679 withSelector:@selector(_continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
686 WebDataSource *oldDataSource = [[self dataSource] retain];
688 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
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
693 if (!isFormSubmission
694 && _loadType != FrameLoadTypeReload
695 && _loadType != FrameLoadTypeSame
696 && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
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]) {
702 // Just do anchor navigation within the existing content.
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.
708 // FIXME: What about load types other than Standard and Reload?
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:)];
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];
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];
732 [oldDataSource release];
736 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
741 NSURL *URL = [request URL];
743 BOOL isRedirect = quickRedirectComing;
744 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
745 quickRedirectComing = NO;
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.
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.
760 [client _addHistoryItemForFragmentScroll];
763 [[client _bridge] scrollToAnchorWithURL:URL];
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];
772 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
773 didChangeLocationWithinPageForFrame:client];
775 [client _didFinishLoad];
778 - (void)closeOldDataSources
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];
786 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView] willCloseFrame:client];
787 [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
790 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
792 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
794 WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
795 NSURLResponse *response = [provisionalDataSource response];
797 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
798 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
800 if (loadType != FrameLoadTypeReplace)
801 [self closeOldDataSources];
804 [provisionalDataSource _makeRepresentation];
806 [client _transitionToCommitted:pageCache];
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];
815 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
816 NSURL *URL = baseURL ? baseURL : [response URL];
818 if (!URL || [URL _web_isEmpty])
819 URL = [NSURL URLWithString:@"about:blank"];
821 [[client _bridge] openURL:URL
823 contentType:[response MIMEType]
824 refresh:[headers objectForKey:@"Refresh"]
825 lastModified:(pageCache ? nil : WKGetNSURLResponseLastModifiedDate(response))
826 pageCache:pageCache];
830 [provisionalDataSource release];
833 - (NSURLRequest *)initialRequest
835 return [[self activeDataSource] initialRequest];
838 - (void)_receivedData:(NSData *)data
840 [[self activeDocumentLoader] receivedData:data];
843 - (void)_setRequest:(NSURLRequest *)request
845 [[self activeDocumentLoader] setRequest:request];
848 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
850 [WebDownload _downloadWithLoadingConnection:connection
853 delegate:[[client webView] downloadDelegate]
857 - (WebFrameBridge *)bridge
859 return [client _bridge];
862 - (void)_handleFallbackContent
864 [[self bridge] handleFallbackContent];
869 return [[self activeDocumentLoader] isStopping];
872 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
874 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
877 - (void)_setResponse:(NSURLResponse *)response
879 [[self activeDocumentLoader] setResponse:response];
882 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
884 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
887 - (void)_finishedLoading
889 WebDataSource *ds = [self activeDataSource];
892 [[self activeDocumentLoader] finishedLoading];
894 if ([ds _mainDocumentError] || ![ds webFrame]) {
899 [[self activeDocumentLoader] setPrimaryLoadComplete:YES];
900 if ([WebScriptDebugServer listenerCount])
901 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
902 [client _checkLoadComplete];
907 - (void)_notifyIconChanged:(NSURL *)iconURL
909 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
910 ASSERT(client == [[client webView] mainFrame]);
912 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
914 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
916 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
920 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
925 return [[self activeDataSource] _URL];
928 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
930 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
931 code:NSURLErrorCancelled
935 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
937 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
938 code:NSURLErrorFileDoesNotExist
942 - (void)clearArchivedResources
944 [pendingArchivedResources removeAllObjects];
945 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
948 - (void)deliverArchivedResources
950 if (![pendingArchivedResources count] || [self defersCallbacks])
953 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
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];
963 [pendingArchivedResources removeAllObjects];
966 - (void)deliverArchivedResourcesAfterDelay
968 if (![pendingArchivedResources count] || [self defersCallbacks])
971 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
974 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
976 return [a caseInsensitiveCompare:b] == NSOrderedSame;
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
983 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
985 if (policy == NSURLRequestReturnCacheDataElseLoad) {
987 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
989 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
991 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
993 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
995 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
997 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
999 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
1006 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
1008 if (WKGetNSURLResponseMustRevalidate(theResponse)) {
1010 } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
1017 - (NSMutableDictionary *)pendingArchivedResources
1019 if (!pendingArchivedResources)
1020 pendingArchivedResources = [[NSMutableDictionary alloc] init];
1022 return pendingArchivedResources;
1025 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
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];
1039 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
1041 return [pendingArchivedResources objectForKey:loader] != nil;
1044 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
1046 [pendingArchivedResources removeObjectForKey:loader];
1048 if (![pendingArchivedResources count])
1049 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
1052 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1054 [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
1057 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
1059 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
1062 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1064 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1067 - (BOOL)isHostedByObjectElement
1069 // Handle <object> fallback for error cases.
1070 DOMHTMLElement *hostElement = [client frameElement];
1071 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1074 - (BOOL)isLoadingMainFrame
1076 return [client _isMainFrame];
1079 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1081 return [WebView canShowMIMEType:MIMEType];
1084 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1086 return [WebView _representationExistsForURLScheme:URLScheme];
1089 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1091 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1094 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1096 [self checkNavigationPolicyForRequest:newRequest
1097 dataSource:[self activeDataSource]
1103 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1105 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1110 [[[client webView] _policyDelegateForwarder] webView:[client webView] decidePolicyForMIMEType:MIMEType
1111 request:[[self activeDocumentLoader] request]
1113 decisionListener:listener];
1117 - (void)cancelContentPolicy
1119 [listener _invalidate];
1124 static inline BOOL isBackForwardLoadType(FrameLoadType type)
1127 case FrameLoadTypeStandard:
1128 case FrameLoadTypeReload:
1129 case FrameLoadTypeReloadAllowingStaleData:
1130 case FrameLoadTypeSame:
1131 case FrameLoadTypeInternal:
1132 case FrameLoadTypeReplace:
1134 case FrameLoadTypeBack:
1135 case FrameLoadTypeForward:
1136 case FrameLoadTypeIndexedBackForward:
1139 ASSERT_NOT_REACHED();
1143 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1145 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1146 if (unreachableURL == nil)
1149 if (!isBackForwardLoadType(policyLoadType))
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];
1163 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
1166 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1170 ASSERT(!policyDocumentLoader);
1171 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1172 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
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;
1180 type = FrameLoadTypeStandard;
1182 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1183 [newDataSource _addToUnarchiveState:archive];
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;
1193 [self loadDataSource:newDataSource withLoadType:type formState:nil];
1196 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1198 ASSERT(!policyDocumentLoader);
1199 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1200 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1202 [policyDocumentLoader setTriggeringAction:action];
1203 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1205 [self loadDataSource:newDataSource withLoadType:type formState:formState];
1208 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1210 WebDataSource *ds = [self dataSource];
1214 NSMutableURLRequest *request = [[ds request] mutableCopy];
1215 NSURL *unreachableURL = [ds unreachableURL];
1216 if (unreachableURL != nil)
1217 [request setURL:unreachableURL];
1219 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1220 ASSERT(!policyDocumentLoader);
1221 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1222 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1225 [policyDocumentLoader setOverrideEncoding:encoding];
1227 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1232 WebDataSource *ds = [self dataSource];
1236 NSMutableURLRequest *initialRequest = [ds request];
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)
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];
1248 ASSERT(!policyDocumentLoader);
1249 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1250 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1251 NSMutableURLRequest *request = [newDataSource request];
1253 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
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];
1261 [policyDocumentLoader setOverrideEncoding:[[ds _documentLoader] overrideEncoding]];
1263 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReload formState:nil];
1266 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1268 [client _didReceiveServerRedirectForProvisionalLoadForFrame];
1271 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1273 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1276 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1278 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1283 return loadType == FrameLoadTypeReplace;
1286 - (void)setReplacing
1288 loadType = FrameLoadTypeReplace;
1291 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1293 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1296 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1298 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1301 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1303 [loader setPrimaryLoadComplete:YES];
1304 if ([WebScriptDebugServer listenerCount])
1305 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1306 [client _checkLoadComplete];
1309 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1311 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1314 - (void)prepareForLoadStart
1316 [[client webView] _progressStarted:client];
1317 [[client webView] _didStartProvisionalLoadForFrame:client];
1318 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1319 didStartProvisionalLoadForFrame:client];
1322 - (BOOL)subframeIsLoading
1324 return [client _subframeIsLoading];
1327 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1329 // FIXME: should do this only in main frame case, right?
1330 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1333 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1335 // FIXME: should do this only in main frame case, right?
1336 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
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]];
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]];
1349 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1350 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1351 didReceiveTitle:[loader title]
1357 - (FrameLoadType)loadType
1362 - (void)setLoadType:(FrameLoadType)type
1367 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1369 [listener _invalidate];
1373 NSURLRequest *request = policyRequest;
1374 NSString *frameName = policyFrameName;
1375 id target = policyTarget;
1376 SEL selector = policySelector;
1377 WebFormState *formState = policyFormState;
1379 policyRequest = nil;
1380 policyFrameName = nil;
1382 policySelector = nil;
1383 policyFormState = nil;
1387 objc_msgSend(target, selector, nil, nil, nil);
1389 objc_msgSend(target, selector, nil, nil);
1393 [frameName release];
1395 [formState release];
1398 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1400 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1401 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1403 policyRequest = [request retain];
1404 policyTarget = [target retain];
1405 policyFrameName = [frameName retain];
1406 policySelector = selector;
1407 listener = [decisionListener retain];
1408 policyFormState = [formState retain];
1410 WebView *wv = [client webView];
1411 [[wv _policyDelegateForwarder] webView:wv
1412 decidePolicyForNewWindowAction:action
1414 newFrameName:frameName
1415 decisionListener:decisionListener];
1417 [decisionListener release];
1420 - (void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
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];
1428 // will release policy* objects, hence the above retains
1429 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1431 BOOL shouldContinue = NO;
1434 case WebPolicyIgnore:
1436 case WebPolicyDownload:
1437 // FIXME: should download full request
1438 [[client webView] _downloadURL:[request URL]];
1441 shouldContinue = YES;
1444 ASSERT_NOT_REACHED();
1447 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1450 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1451 dataSource:(WebDataSource *)dataSource
1452 formState:(WebFormState *)formState
1454 withSelector:(SEL)selector
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];
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];
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];
1478 [[dataSource _documentLoader] setLastCheckedRequest:request];
1480 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
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];
1492 WebView *wv = [client webView];
1493 delegateIsDecidingNavigationPolicy = YES;
1494 [[wv _policyDelegateForwarder] webView:wv
1495 decidePolicyForNavigationAction:action
1498 decisionListener:decisionListener];
1499 delegateIsDecidingNavigationPolicy = NO;
1501 [decisionListener release];
1504 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1506 NSURLRequest *request = [[policyRequest retain] autorelease];
1507 id target = [[policyTarget retain] autorelease];
1508 SEL selector = policySelector;
1509 WebFormState *formState = [[policyFormState retain] autorelease];
1511 // will release policy* objects, hence the above retains
1512 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1514 BOOL shouldContinue = NO;
1517 case WebPolicyIgnore:
1519 case WebPolicyDownload:
1520 // FIXME: should download full request
1521 [[client webView] _downloadURL:[request URL]];
1524 if (![WebView _canHandleRequest:request]) {
1525 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1527 shouldContinue = YES;
1531 ASSERT_NOT_REACHED();
1534 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1537 // Called after the FormsDelegate is done processing willSubmitForm:
1538 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1541 [listener _invalidate];
1545 [self startLoading];
1548 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
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);
1555 BOOL isTargetItem = [client _provisionalItemIsTarget];
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]);
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];
1570 [self setPolicyDocumentLoader:nil];
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];
1581 FrameLoadType type = policyLoadType;
1582 WebDataSource *dataSource = [[self policyDataSource] retain];
1587 [self startProvisionalLoad:dataSource];
1589 [dataSource release];
1590 [self setPolicyDocumentLoader:nil];
1592 if (client == [[client webView] mainFrame])
1593 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1595 if (type == FrameLoadTypeForward || type == FrameLoadTypeBack || type == FrameLoadTypeIndexedBackForward) {
1596 if ([client _loadProvisionalItemFromPageCache])
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];
1607 [self continueAfterWillSubmitForm:WebPolicyUse];
1611 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1613 ASSERT([client webView] != nil);
1615 // Unfortunately the view must be non-nil, this is ultimately due
1616 // to parser requiring a FrameView. We should fix this dependency.
1618 ASSERT([client frameView] != nil);
1620 policyLoadType = type;
1622 WebDocumentLoaderMac *loader = (WebDocumentLoaderMac *)[newDataSource _documentLoader];
1624 WebFrame *parentFrame = [client parentFrame];
1626 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1628 [loader setFrameLoader:self];
1629 [loader setDataSource:newDataSource];
1631 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1633 [self setPolicyDocumentLoader:loader];
1635 [self checkNavigationPolicyForRequest:[newDataSource request]
1636 dataSource:newDataSource
1639 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1642 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
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;
1651 - (BOOL)delegateIsHandlingProvisionalLoadError
1653 return delegateIsHandlingProvisionalLoadError;
1656 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1658 delegateIsHandlingProvisionalLoadError = is;
1661 - (void)didFirstLayout
1663 if ([[client webView] backForwardList]) {
1664 if (loadType == FrameLoadTypeForward || loadType == FrameLoadTypeBack || loadType == FrameLoadTypeIndexedBackForward)
1665 [client _restoreScrollPositionAndViewState];
1668 firstLayoutDone = YES;
1670 WebView *wv = [client webView];
1671 [[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:client];
1674 - (void)frameLoadCompleted
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;
1681 - (BOOL)firstLayoutDone
1683 return firstLayoutDone;
1686 - (BOOL)isQuickRedirectComing
1688 return quickRedirectComing;