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 "WebDocumentLoader.h"
33 #import "WebFormDataStream.h"
34 #import "WebFrameBridge.h"
35 #import "WebFrameLoaderClient.h"
36 #import "WebMainResourceLoader.h"
37 #import <JavaScriptCore/Assertions.h>
38 #import <WebKit/DOMHTML.h>
39 #import <WebCore/WebCoreSystemInterface.h>
41 #import "WebDataSourceInternal.h"
42 #import "WebDocumentLoaderMac.h"
43 #import "WebFrameInternal.h"
44 #import "WebFrameViewInternal.h"
45 #import "WebHTMLView.h"
46 #import "WebIconDatabasePrivate.h"
47 #import "WebKitErrorsPrivate.h"
48 #import "WebKitLogging.h"
49 #import "WebNSURLExtras.h"
50 #import "WebNSURLRequestExtras.h"
51 #import "WebResourcePrivate.h"
52 #import "WebScriptDebugServerPrivate.h"
53 #import "WebViewInternal.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 - (void)addPlugInStreamLoader:(WebLoader *)loader
96 if (!plugInStreamLoaders)
97 plugInStreamLoaders = [[NSMutableArray alloc] init];
98 [plugInStreamLoaders addObject:loader];
99 [[self activeDocumentLoader] setLoading:YES];
102 - (void)removePlugInStreamLoader:(WebLoader *)loader
104 [plugInStreamLoaders removeObject:loader];
105 [[self activeDocumentLoader] updateLoading];
108 - (void)defersCallbacksChanged
110 BOOL defers = [[client webView] defersCallbacks];
111 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
112 [[frame _frameLoader] setDefersCallbacks:defers];
115 - (BOOL)defersCallbacks
117 return [[client webView] defersCallbacks];
120 - (void)setDefersCallbacks:(BOOL)defers
122 [mainResourceLoader setDefersCallbacks:defers];
124 NSEnumerator *e = [subresourceLoaders objectEnumerator];
126 while ((loader = [e nextObject]))
127 [loader setDefersCallbacks:defers];
129 e = [plugInStreamLoaders objectEnumerator];
130 while ((loader = [e nextObject]))
131 [loader setDefersCallbacks:defers];
133 [self deliverArchivedResourcesAfterDelay];
136 - (void)stopLoadingPlugIns
138 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
139 [plugInStreamLoaders removeAllObjects];
142 - (BOOL)isLoadingMainResource
144 return mainResourceLoader != nil;
147 - (BOOL)isLoadingSubresources
149 return [subresourceLoaders count];
152 - (BOOL)isLoadingPlugIns
154 return [plugInStreamLoaders count];
159 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
162 - (void)stopLoadingSubresources
164 NSArray *loaders = [subresourceLoaders copy];
165 [loaders makeObjectsPerformSelector:@selector(cancel)];
167 [subresourceLoaders removeAllObjects];
170 - (void)addSubresourceLoader:(WebLoader *)loader
172 ASSERT(!provisionalDocumentLoader);
173 if (subresourceLoaders == nil)
174 subresourceLoaders = [[NSMutableArray alloc] init];
175 [subresourceLoaders addObject:loader];
176 [[self activeDocumentLoader] setLoading:YES];
179 - (void)removeSubresourceLoader:(WebLoader *)loader
181 [subresourceLoaders removeObject:loader];
182 [[self activeDocumentLoader] updateLoading];
185 - (NSData *)mainResourceData
187 return [mainResourceLoader resourceData];
190 - (void)releaseMainResourceLoader
192 [mainResourceLoader release];
193 mainResourceLoader = nil;
196 - (void)cancelMainResourceLoad
198 [mainResourceLoader cancel];
201 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
203 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
205 [mainResourceLoader setIdentifier:identifier];
206 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
207 if (![mainResourceLoader loadWithRequest:request]) {
208 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
209 // should it be caught by other parts of WebKit or other parts of the app?
210 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
211 [mainResourceLoader release];
212 mainResourceLoader = nil;
219 - (void)stopLoadingWithError:(NSError *)error
221 [mainResourceLoader cancelWithError:error];
224 - (WebDataSource *)dataSource
226 return [client _dataSourceForDocumentLoader:documentLoader];
229 - (void)setDocumentLoader:(WebDocumentLoader *)loader
231 if (loader == nil && documentLoader == nil)
234 ASSERT(loader != documentLoader);
236 [client _prepareForDataSourceReplacement];
237 [documentLoader detachFromFrameLoader];
240 [documentLoader release];
241 documentLoader = loader;
244 - (WebDocumentLoader *)documentLoader
246 return documentLoader;
249 - (WebDataSource *)policyDataSource
251 return [client _dataSourceForDocumentLoader:policyDocumentLoader];
254 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
256 if (policyDocumentLoader == loader)
259 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
260 [policyDocumentLoader detachFromFrameLoader];
262 [policyDocumentLoader release];
264 policyDocumentLoader = loader;
267 - (WebDataSource *)provisionalDataSource
269 return [client _dataSourceForDocumentLoader:provisionalDocumentLoader];
272 - (WebDocumentLoader *)provisionalDocumentLoader
274 return provisionalDocumentLoader;
277 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
279 ASSERT(!loader || !provisionalDocumentLoader);
281 if (provisionalDocumentLoader != documentLoader)
282 [provisionalDocumentLoader detachFromFrameLoader];
285 [provisionalDocumentLoader release];
286 provisionalDocumentLoader = loader;
289 - (WebFrameState)state
295 static const char * const stateNames[] = {
296 "WebFrameStateProvisional",
297 "WebFrameStateCommittedPage",
298 "WebFrameStateComplete"
302 static CFAbsoluteTime _timeOfLastCompletedLoad;
304 + (CFAbsoluteTime)timeOfLastCompletedLoad
306 return _timeOfLastCompletedLoad;
309 - (void)provisionalLoadStarted
311 firstLayoutDone = NO;
312 [[client _bridge] provisionalLoadStarted];
314 [client _provisionalLoadStarted];
317 - (void)setState:(WebFrameState)newState
319 LOG(Loading, "%@: transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
320 if ([client webView])
321 LOG(Timing, "%@: transition from %s to %s, %f seconds since start of document load",
322 [client name], stateNames[state], stateNames[newState],
323 CFAbsoluteTimeGetCurrent() - [[[[[client webView] mainFrame] dataSource] _documentLoader] loadingStartedTime]);
325 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
326 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoader] loadingStartedTime]);
330 if (state == WebFrameStateProvisional)
331 [self provisionalLoadStarted];
332 else if (state == WebFrameStateComplete) {
333 [self frameLoadCompleted];
334 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
335 [[self documentLoader] stopRecordingResponses];
339 - (void)clearProvisionalLoad
341 [self setProvisionalDocumentLoader:nil];
342 [[client webView] _progressCompleted:client];
343 [self setState:WebFrameStateComplete];
346 - (void)markLoadComplete
348 [self setState:WebFrameStateComplete];
351 - (void)commitProvisionalLoad
353 [self stopLoadingSubresources];
354 [self stopLoadingPlugIns];
356 [self setDocumentLoader:provisionalDocumentLoader];
357 [self setProvisionalDocumentLoader:nil];
358 [self setState:WebFrameStateCommittedPage];
361 - (void)stopLoadingSubframes
363 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
364 [[(WebFrameBridge *)child frameLoader] stopLoading];
369 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
373 isStoppingLoad = YES;
375 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
377 [self stopLoadingSubframes];
378 [provisionalDocumentLoader stopLoading];
379 [documentLoader stopLoading];
380 [self setProvisionalDocumentLoader:nil];
381 [self clearArchivedResources];
386 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
389 [provisionalDocumentLoader prepareForLoadStart];
391 if ([self isLoadingMainResource])
394 [[self provisionalDataSource] _setLoadingFromPageCache:NO];
396 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
398 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
399 [provisionalDocumentLoader updateLoading];
402 - (void)startProvisionalLoad:(WebDataSource *)ds
404 [self setProvisionalDocumentLoader:[ds _documentLoader]];
405 [self setState:WebFrameStateProvisional];
408 - (void)setupForReplace
410 [self setState:WebFrameStateProvisional];
411 WebDocumentLoader *old = provisionalDocumentLoader;
412 provisionalDocumentLoader = documentLoader;
413 documentLoader = nil;
416 [self detachChildren];
419 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
421 // FIXME: why retain here, but not in the other place this happens?
423 // The identifier is released after the last callback, rather than in dealloc,
424 // to avoid potential cycles.
425 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
428 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
430 WebView *webView = [client webView];
431 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
432 return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
435 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
437 [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
440 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
442 [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
445 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
447 [[self activeDocumentLoader] addResponse:r];
449 [[client webView] _incrementProgressForIdentifier:identifier response:r];
450 [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
453 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
455 WebView *webView = [client webView];
456 [webView _incrementProgressForIdentifier:identifier data:data];
458 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
461 - (void)_didFinishLoadingForResource:(id)identifier
463 WebView *webView = [client webView];
464 [webView _completeProgressForIdentifier:identifier];
465 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
468 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
470 WebView *webView = [client webView];
472 [webView _completeProgressForIdentifier:identifier];
475 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
478 - (BOOL)_privateBrowsingEnabled
480 return [client _privateBrowsingEnabled];
483 - (void)_finishedLoadingResource
485 [self checkLoadComplete];
488 - (void)_receivedError:(NSError *)error
490 [self checkLoadComplete];
493 - (NSURLRequest *)_originalRequest
495 return [[self activeDocumentLoader] originalRequestCopy];
498 - (WebFrame *)webFrame
503 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
505 WebDocumentLoader *loader = [self activeDocumentLoader];
508 WebFrameBridge *bridge = [client _bridge];
510 // Retain the bridge because the stop may release the last reference to it.
513 WebFrame *cli = [client retain];
516 // FIXME: Don't want to do this if an entirely new load is going, so should check
517 // that both data sources on the frame are either self or nil.
518 // Can't call _bridge because we might not have commited yet
520 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
521 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
522 [bridge handleFallbackContent];
525 if ([self state] == WebFrameStateProvisional) {
526 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
527 [bridge didNotOpenURL:failedURL];
528 [client _invalidateCurrentItemPageCache];
530 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
531 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
532 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
533 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
535 if (sentRedirectNotification)
536 [self clientRedirectCancelledOrFinished:NO];
540 [loader mainReceivedError:error complete:isComplete];
547 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
549 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
550 // the redirect succeeded. We should either rename this API, or add a new method, like
551 // -webView:didFinishClientRedirectForFrame:
552 [client _dispatchDidCancelClientRedirectForFrame];
554 if (!cancelWithLoadInProgress)
555 quickRedirectComing = NO;
557 sentRedirectNotification = NO;
559 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
562 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
564 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
566 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
568 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
569 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
570 sentRedirectNotification = YES;
572 // If a "quick" redirect comes in an, we set a special mode so we treat the next
573 // load as part of the same navigation.
575 if (!documentLoader || isJavaScriptFormAction) {
576 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
577 // so we better just treat the redirect as a normal load.
578 quickRedirectComing = NO;
579 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
581 quickRedirectComing = lockHistory;
582 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
586 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
588 return !(([currentURL fragment] || [destinationURL fragment]) &&
589 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
592 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
593 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
595 BOOL isFormSubmission = (values != nil);
597 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
598 [request setValue:[[client webView] userAgentForURL:[request URL]] forHTTPHeaderField:@"Referer"];
599 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
600 if (_loadType == FrameLoadTypeReload)
601 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
603 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
604 // policy of LoadFromOrigin, but I didn't test that.
605 ASSERT(_loadType != FrameLoadTypeSame);
607 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
608 WebFormState *formState = nil;
610 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
613 WebFrame *targetFrame = [client findFrameNamed:target];
614 if (targetFrame != nil) {
615 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
617 [self checkNewWindowPolicyForRequest:request
622 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
629 WebDataSource *oldDataSource = [[self dataSource] retain];
631 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
633 // Make sure to do scroll to anchor processing even if the URL is
634 // exactly the same so pages with '#' links and DHTML side effects
636 if (!isFormSubmission
637 && _loadType != FrameLoadTypeReload
638 && _loadType != FrameLoadTypeSame
639 && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
641 // We don't want to just scroll if a link from within a
642 // frameset is trying to reload the frameset into _top.
643 && ![[client _bridge] isFrameSet]) {
645 // Just do anchor navigation within the existing content.
647 // We don't do this if we are submitting a form, explicitly reloading,
648 // currently displaying a frameset, or if the new URL does not have a fragment.
649 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
651 // FIXME: What about load types other than Standard and Reload?
653 [[oldDataSource _documentLoader] setTriggeringAction:action];
654 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
655 [self checkNavigationPolicyForRequest:request
656 dataSource:oldDataSource formState:formState
657 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
659 // must grab this now, since this load may stop the previous load and clear this flag
660 BOOL isRedirect = quickRedirectComing;
661 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
663 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [client name], self, (int)isRedirect);
664 quickRedirectComing = NO;
665 [provisionalDocumentLoader setIsClientRedirect:YES];
666 } else if (sameURL) {
667 // Example of this case are sites that reload the same URL with a different cookie
668 // driving the generated content, or a master frame with links that drive a target
669 // frame, where the user has clicked on the same link repeatedly.
670 [self setLoadType:FrameLoadTypeSame];
675 [oldDataSource release];
679 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
684 NSURL *URL = [request URL];
686 BOOL isRedirect = quickRedirectComing;
687 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
688 quickRedirectComing = NO;
690 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
691 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
692 // NB: must happen after _setURL, since we add based on the current request.
693 // Must also happen before we openURL and displace the scroll position, since
694 // adding the BF item will save away scroll state.
696 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
697 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
698 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
699 // though its load is not yet done. I think this all works out OK, for one because
700 // we have already saved away the scroll and doc state for the long slow load,
701 // but it's not an obvious case.
703 [client _addHistoryItemForFragmentScroll];
706 [[client _bridge] scrollToAnchorWithURL:URL];
709 // This will clear previousItem from the rest of the frame tree tree that didn't
710 // doing any loading. We need to make a pass on this now, since for anchor nav
711 // we'll not go through a real load and reach Completed state
712 [self checkLoadComplete];
715 [client _dispatchDidChangeLocationWithinPageForFrame];
716 [client _didFinishLoad];
719 - (void)closeOldDataSources
721 // FIXME: is it important for this traversal to be postorder instead of preorder?
722 // FIXME: add helpers for postorder traversal?
723 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
724 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
727 [client _dispatchWillCloseFrame];
729 [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
732 // Called after we send an openURL:... down to WebCore.
735 if ([self loadType] == FrameLoadTypeStandard && [[[self dataSource] _documentLoader] isClientRedirect])
736 [client _updateHistoryAfterClientRedirect];
738 if ([[self dataSource] _loadingFromPageCache]) {
739 // Force a layout to update view size and thereby update scrollbars.
740 NSView <WebDocumentView> *view = [[client frameView] documentView];
741 if ([view isKindOfClass:[WebHTMLView class]])
742 [(WebHTMLView *)view setNeedsToApplyStyles:YES];
743 [view setNeedsLayout: YES];
746 NSArray *responses = [[self documentLoader] responses];
747 NSURLResponse *response;
748 int i, count = [responses count];
749 for (i = 0; i < count; i++) {
750 response = [responses objectAtIndex: i];
751 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
754 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
755 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
756 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
760 [client _loadedFromPageCache];
762 [[self documentLoader] setPrimaryLoadComplete:YES];
764 // FIXME: Why only this frame and not parent frames?
765 [self checkLoadCompleteForThisFrame];
769 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
771 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
773 WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
774 NSURLResponse *response = [provisionalDataSource response];
776 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
777 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
779 if (loadType != FrameLoadTypeReplace)
780 [self closeOldDataSources];
783 [provisionalDataSource _makeRepresentation];
785 [self transitionToCommitted:pageCache];
787 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
788 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
789 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
790 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
791 if (sentRedirectNotification)
792 [self clientRedirectCancelledOrFinished:NO];
794 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
795 NSURL *URL = baseURL ? baseURL : [response URL];
797 if (!URL || [URL _web_isEmpty])
798 URL = [NSURL URLWithString:@"about:blank"];
800 [[client _bridge] openURL:URL
802 contentType:[response MIMEType]
803 refresh:[headers objectForKey:@"Refresh"]
804 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
805 pageCache:pageCache];
809 [provisionalDataSource release];
812 - (NSURLRequest *)initialRequest
814 return [[self activeDataSource] initialRequest];
817 - (void)_receivedData:(NSData *)data
819 [[self activeDocumentLoader] receivedData:data];
822 - (void)_setRequest:(NSURLRequest *)request
824 [[self activeDocumentLoader] setRequest:request];
827 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
828 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
830 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
833 - (WebFrameBridge *)bridge
835 return [client _bridge];
838 - (void)_handleFallbackContent
840 [[self bridge] handleFallbackContent];
845 return [[self activeDocumentLoader] isStopping];
848 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
850 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
853 - (void)_setResponse:(NSURLResponse *)response
855 [[self activeDocumentLoader] setResponse:response];
858 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
860 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
863 - (void)_finishedLoading
865 WebDataSource *ds = [self activeDataSource];
867 WebFrameBridge *bridge = [self bridge];
870 [[self activeDocumentLoader] finishedLoading];
872 if ([ds _mainDocumentError] || ![ds webFrame]) {
877 [[self activeDocumentLoader] setPrimaryLoadComplete:YES];
878 if ([WebScriptDebugServer listenerCount])
879 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
880 [self checkLoadComplete];
885 - (void)_notifyIconChanged:(NSURL *)iconURL
887 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
888 ASSERT(client == [[client webView] mainFrame]);
890 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
892 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
894 [client _dispatchDidReceiveIcon:icon];
896 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
901 return [[self activeDataSource] _URL];
904 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
906 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
907 code:NSURLErrorCancelled
911 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
913 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
914 code:NSURLErrorFileDoesNotExist
918 - (void)clearArchivedResources
920 [pendingArchivedResources removeAllObjects];
921 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
924 - (void)deliverArchivedResources
926 if (![pendingArchivedResources count] || [self defersCallbacks])
929 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
931 while ((loader = [keyEnum nextObject])) {
932 WebResource *resource = [pendingArchivedResources objectForKey:loader];
933 [loader didReceiveResponse:[resource _response]];
934 NSData *data = [resource data];
935 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
936 [loader didFinishLoading];
939 [pendingArchivedResources removeAllObjects];
942 - (void)deliverArchivedResourcesAfterDelay
944 if (![pendingArchivedResources count] || [self defersCallbacks])
947 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
950 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
952 return [a caseInsensitiveCompare:b] == NSOrderedSame;
955 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
956 // FIXME: It would be nice to eventually to share this code somehow.
957 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
959 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
961 if (policy == NSURLRequestReturnCacheDataElseLoad) {
963 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
965 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
967 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
969 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
971 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
973 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
975 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
982 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
984 if (wkGetNSURLResponseMustRevalidate(response))
986 if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
991 - (NSMutableDictionary *)pendingArchivedResources
993 if (!pendingArchivedResources)
994 pendingArchivedResources = [[NSMutableDictionary alloc] init];
996 return pendingArchivedResources;
999 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
1001 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
1002 WebResource *resource = [[self activeDataSource] _archivedSubresourceForURL:originalURL];
1003 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
1004 CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
1005 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
1006 [self deliverArchivedResourcesAfterDelay];
1013 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
1015 return [pendingArchivedResources objectForKey:loader] != nil;
1018 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
1020 [pendingArchivedResources removeObjectForKey:loader];
1022 if (![pendingArchivedResources count])
1023 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
1026 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
1028 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
1031 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1033 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1036 - (BOOL)isHostedByObjectElement
1038 // Handle <object> fallback for error cases.
1039 DOMHTMLElement *hostElement = [client frameElement];
1040 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1043 - (BOOL)isLoadingMainFrame
1045 return [client _isMainFrame];
1048 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1050 return [WebView canShowMIMEType:MIMEType];
1053 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1055 return [WebView _representationExistsForURLScheme:URLScheme];
1058 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1060 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1063 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1065 [self checkNavigationPolicyForRequest:newRequest
1066 dataSource:[self activeDataSource]
1072 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1074 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1079 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1084 - (void)cancelContentPolicy
1086 [listener _invalidate];
1091 BOOL isBackForwardLoadType(FrameLoadType type)
1094 case FrameLoadTypeStandard:
1095 case FrameLoadTypeReload:
1096 case FrameLoadTypeReloadAllowingStaleData:
1097 case FrameLoadTypeSame:
1098 case FrameLoadTypeInternal:
1099 case FrameLoadTypeReplace:
1101 case FrameLoadTypeBack:
1102 case FrameLoadTypeForward:
1103 case FrameLoadTypeIndexedBackForward:
1106 ASSERT_NOT_REACHED();
1110 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1112 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1113 if (unreachableURL == nil)
1116 if (!isBackForwardLoadType(policyLoadType))
1119 // We only treat unreachableURLs specially during the delegate callbacks
1120 // for provisional load errors and navigation policy decisions. The former
1121 // case handles well-formed URLs that can't be loaded, and the latter
1122 // case handles malformed URLs and unknown schemes. Loading alternate content
1123 // at other times behaves like a standard load.
1124 WebDataSource *compareDataSource = nil;
1125 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1126 compareDataSource = [self policyDataSource];
1127 else if (delegateIsHandlingProvisionalLoadError)
1128 compareDataSource = [self provisionalDataSource];
1130 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
1133 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1137 ASSERT(!policyDocumentLoader);
1138 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1139 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1141 NSMutableURLRequest *r = [newDataSource request];
1142 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1143 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1144 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1145 type = FrameLoadTypeSame;
1147 type = FrameLoadTypeStandard;
1149 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1150 [newDataSource _addToUnarchiveState:archive];
1152 // When we loading alternate content for an unreachable URL that we're
1153 // visiting in the b/f list, we treat it as a reload so the b/f list
1154 // is appropriately maintained.
1155 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1156 ASSERT(type == FrameLoadTypeStandard);
1157 type = FrameLoadTypeReload;
1160 [self loadDataSource:newDataSource withLoadType:type formState:nil];
1163 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1165 ASSERT(!policyDocumentLoader);
1166 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1167 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1169 [policyDocumentLoader setTriggeringAction:action];
1170 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1172 [self loadDataSource:newDataSource withLoadType:type formState:formState];
1175 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1177 WebDataSource *ds = [self dataSource];
1181 NSMutableURLRequest *request = [[ds request] mutableCopy];
1182 NSURL *unreachableURL = [ds unreachableURL];
1183 if (unreachableURL != nil)
1184 [request setURL:unreachableURL];
1186 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1187 ASSERT(!policyDocumentLoader);
1188 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1189 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1192 [policyDocumentLoader setOverrideEncoding:encoding];
1194 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1199 WebDataSource *ds = [self dataSource];
1203 NSMutableURLRequest *initialRequest = [ds request];
1205 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1206 // Reloading in this case will lose the current contents (see 4151001).
1207 if ([[[[ds request] URL] absoluteString] length] == 0)
1210 // Replace error-page URL with the URL we were trying to reach.
1211 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1212 if (unreachableURL != nil)
1213 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1215 ASSERT(!policyDocumentLoader);
1216 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1217 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1218 NSMutableURLRequest *request = [newDataSource request];
1220 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1222 // If we're about to rePOST, set up action so the app can warn the user
1223 if ([[request HTTPMethod] compare:@"POST" options:(NSCaseInsensitiveSearch | NSLiteralSearch)] == NSOrderedSame) {
1224 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeFormResubmitted
1225 event:nil originalURL:[request URL]];
1226 [policyDocumentLoader setTriggeringAction:action];
1229 [policyDocumentLoader setOverrideEncoding:[[ds _documentLoader] overrideEncoding]];
1231 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReload formState:nil];
1234 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1236 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1239 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1241 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1244 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1246 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1251 return loadType == FrameLoadTypeReplace;
1254 - (void)setReplacing
1256 loadType = FrameLoadTypeReplace;
1259 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1261 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1264 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1266 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1269 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1271 [loader setPrimaryLoadComplete:YES];
1272 if ([WebScriptDebugServer listenerCount])
1273 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1274 [self checkLoadComplete];
1277 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1279 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1282 - (void)prepareForLoadStart
1284 [[client webView] _progressStarted:client];
1285 [[client webView] _didStartProvisionalLoadForFrame:client];
1286 [client _dispatchDidStartProvisionalLoadForFrame];
1289 - (BOOL)subframeIsLoading
1291 // It's most likely that the last added frame is the last to load so we walk backwards.
1292 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1293 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1298 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1300 // FIXME: should do this only in main frame case, right?
1301 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1304 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1306 // FIXME: should do this only in main frame case, right?
1307 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1309 // The title doesn't get communicated to the WebView until we are committed.
1310 if ([loader isCommitted]) {
1311 NSURL *URLForHistory = [[client _dataSourceForDocumentLoader:loader] _URLForHistory];
1312 if (URLForHistory != nil) {
1313 // Must update the entries in the back-forward list too.
1314 // This must go through the WebFrame because it has the right notion of the current b/f item.
1315 [client _setTitle:[loader title] forURL:URLForHistory];
1316 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1318 [client _dispatchDidReceiveTitle:[loader title]];
1323 - (FrameLoadType)loadType
1328 - (void)setLoadType:(FrameLoadType)type
1333 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1335 [listener _invalidate];
1339 NSURLRequest *request = policyRequest;
1340 NSString *frameName = policyFrameName;
1341 id target = policyTarget;
1342 SEL selector = policySelector;
1343 WebFormState *formState = policyFormState;
1345 policyRequest = nil;
1346 policyFrameName = nil;
1348 policySelector = nil;
1349 policyFormState = nil;
1353 objc_msgSend(target, selector, nil, nil, nil);
1355 objc_msgSend(target, selector, nil, nil);
1359 [frameName release];
1361 [formState release];
1364 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1366 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1367 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1369 policyRequest = [request retain];
1370 policyTarget = [target retain];
1371 policyFrameName = [frameName retain];
1372 policySelector = selector;
1373 listener = [decisionListener retain];
1374 policyFormState = [formState retain];
1376 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1378 [decisionListener release];
1381 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1383 NSURLRequest *request = [[policyRequest retain] autorelease];
1384 NSString *frameName = [[policyFrameName retain] autorelease];
1385 id target = [[policyTarget retain] autorelease];
1386 SEL selector = policySelector;
1387 WebFormState *formState = [[policyFormState retain] autorelease];
1389 // will release policy* objects, hence the above retains
1390 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1392 BOOL shouldContinue = NO;
1395 case WebPolicyIgnore:
1397 case WebPolicyDownload:
1398 // FIXME: should download full request
1399 [[client webView] _downloadURL:[request URL]];
1402 shouldContinue = YES;
1405 ASSERT_NOT_REACHED();
1408 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1411 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1412 dataSource:(WebDataSource *)dataSource
1413 formState:(WebFormState *)formState
1415 withSelector:(SEL)selector
1417 NSDictionary *action = [[dataSource _documentLoader] triggeringAction];
1418 if (action == nil) {
1419 action = [self actionInformationForNavigationType:WebNavigationTypeOther
1420 event:nil originalURL:[request URL]];
1421 [[dataSource _documentLoader] setTriggeringAction:action];
1424 // Don't ask more than once for the same request or if we are loading an empty URL.
1425 // This avoids confusion on the part of the client.
1426 if ([request isEqual:[[dataSource _documentLoader] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1427 [target performSelector:selector withObject:request withObject:nil];
1431 // We are always willing to show alternate content for unreachable URLs;
1432 // treat it like a reload so it maintains the right state for b/f list.
1433 if ([request _webDataRequestUnreachableURL] != nil) {
1434 if (isBackForwardLoadType(policyLoadType))
1435 policyLoadType = FrameLoadTypeReload;
1436 [target performSelector:selector withObject:request withObject:nil];
1440 [[dataSource _documentLoader] setLastCheckedRequest:request];
1442 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1444 ASSERT(policyRequest == nil);
1445 policyRequest = [request retain];
1446 ASSERT(policyTarget == nil);
1447 policyTarget = [target retain];
1448 policySelector = selector;
1449 ASSERT(listener == nil);
1450 listener = [decisionListener retain];
1451 ASSERT(policyFormState == nil);
1452 policyFormState = [formState retain];
1454 delegateIsDecidingNavigationPolicy = YES;
1455 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1456 delegateIsDecidingNavigationPolicy = NO;
1458 [decisionListener release];
1461 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1463 NSURLRequest *request = [[policyRequest retain] autorelease];
1464 id target = [[policyTarget retain] autorelease];
1465 SEL selector = policySelector;
1466 WebFormState *formState = [[policyFormState retain] autorelease];
1468 // will release policy* objects, hence the above retains
1469 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1471 BOOL shouldContinue = NO;
1474 case WebPolicyIgnore:
1476 case WebPolicyDownload:
1477 // FIXME: should download full request
1478 [[client webView] _downloadURL:[request URL]];
1481 if (![WebView _canHandleRequest:request]) {
1482 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1484 shouldContinue = YES;
1488 ASSERT_NOT_REACHED();
1491 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1494 // Called after the FormsDelegate is done processing willSubmitForm:
1495 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1498 [listener _invalidate];
1502 [self startLoading];
1505 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1507 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1508 // nil policyDataSource because loading the alternate page will have passed
1509 // through this method already, nested; otherwise, policyDataSource should still be set.
1510 ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1512 BOOL isTargetItem = [client _provisionalItemIsTarget];
1514 // Two reasons we can't continue:
1515 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1516 // is the user responding Cancel to the form repost nag sheet.
1517 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1518 // The "before unload" event handler runs only for the main frame.
1519 BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1522 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1523 // need to report that the client redirect was cancelled.
1524 if (quickRedirectComing)
1525 [self clientRedirectCancelledOrFinished:NO];
1527 [self setPolicyDocumentLoader:nil];
1529 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1530 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1531 // we only do this when punting a navigation for the target frame or top-level frame.
1532 if ((isTargetItem || [[client webView] mainFrame] == client) && isBackForwardLoadType(policyLoadType))
1533 [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1538 FrameLoadType type = policyLoadType;
1539 WebDataSource *dataSource = [[self policyDataSource] retain];
1544 [self startProvisionalLoad:dataSource];
1546 [dataSource release];
1547 [self setPolicyDocumentLoader:nil];
1549 if (client == [[client webView] mainFrame])
1550 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1552 if (isBackForwardLoadType(type)) {
1553 if ([client _loadProvisionalItemFromPageCache])
1558 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1559 // mechanism across the willSubmitForm callout.
1560 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1561 [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1564 [self continueAfterWillSubmitForm:WebPolicyUse];
1568 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1570 ASSERT([client webView] != nil);
1572 // Unfortunately the view must be non-nil, this is ultimately due
1573 // to parser requiring a FrameView. We should fix this dependency.
1575 ASSERT([client frameView] != nil);
1577 policyLoadType = type;
1579 WebDocumentLoaderMac *loader = (WebDocumentLoaderMac *)[newDataSource _documentLoader];
1581 WebFrame *parentFrame = [client parentFrame];
1583 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1585 [loader setFrameLoader:self];
1586 [loader setDataSource:newDataSource];
1588 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1590 [self setPolicyDocumentLoader:loader];
1592 [self checkNavigationPolicyForRequest:[newDataSource request]
1593 dataSource:newDataSource
1596 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1599 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1601 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1602 delegateIsHandlingUnimplementablePolicy = YES;
1603 [client _dispatchUnableToImplementPolicyWithError:error];
1604 delegateIsHandlingUnimplementablePolicy = NO;
1607 - (void)didFirstLayout
1609 if ([[client webView] backForwardList]) {
1610 if (isBackForwardLoadType(loadType))
1611 [client _restoreScrollPositionAndViewState];
1614 firstLayoutDone = YES;
1615 [client _dispatchDidFirstLayoutInFrame];
1618 - (void)frameLoadCompleted
1620 [client _frameLoadCompleted];
1622 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1623 if ([self dataSource])
1624 firstLayoutDone = YES;
1627 - (BOOL)firstLayoutDone
1629 return firstLayoutDone;
1632 - (BOOL)isQuickRedirectComing
1634 return quickRedirectComing;
1637 - (void)transitionToCommitted:(NSDictionary *)pageCache
1639 ASSERT([client webView] != nil);
1641 switch ([self state]) {
1642 case WebFrameStateProvisional:
1645 case WebFrameStateCommittedPage:
1646 case WebFrameStateComplete:
1650 ASSERT_NOT_REACHED();
1655 [[[[client frameView] _scrollView] contentView] setCopiesOnScroll:YES];
1657 [client _updateHistoryForCommit];
1659 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1660 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1661 // or the two will stomp each other.
1662 WebDataSource *pd = [self provisionalDataSource];
1663 [[client _bridge] closeURL];
1664 if (pd != [self provisionalDataSource])
1667 [self commitProvisionalLoad];
1669 // Handle adding the URL to the back/forward list.
1670 WebDataSource *ds = [self dataSource];
1671 NSString *ptitle = [ds pageTitle];
1674 case WebFrameLoadTypeForward:
1675 case WebFrameLoadTypeBack:
1676 case WebFrameLoadTypeIndexedBackForward:
1677 if ([[client webView] backForwardList]) {
1678 [client _updateHistoryForBackForwardNavigation];
1680 // Create a document view for this document, or used the cached view.
1682 NSView <WebDocumentView> *cachedView = [pageCache objectForKey:WebPageCacheDocumentViewKey];
1683 ASSERT(cachedView != nil);
1684 [[client frameView] _setDocumentView:cachedView];
1686 [client _makeDocumentView];
1690 case WebFrameLoadTypeReload:
1691 case WebFrameLoadTypeSame:
1692 case WebFrameLoadTypeReplace:
1693 [client _updateHistoryForReload];
1694 [client _makeDocumentView];
1697 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1698 case WebFrameLoadTypeReloadAllowingStaleData:
1699 [client _makeDocumentView];
1702 case WebFrameLoadTypeStandard:
1703 [client _updateHistoryForStandardLoad];
1704 [client _makeDocumentView];
1707 case WebFrameLoadTypeInternal:
1708 [client _updateHistoryForInternalLoad];
1709 [client _makeDocumentView];
1712 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1713 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1715 ASSERT_NOT_REACHED();
1718 // Tell the client we've committed this URL.
1719 ASSERT([[client frameView] documentView] != nil);
1720 [[client webView] _didCommitLoadForFrame:client];
1721 [client _dispatchDidCommitLoadForFrame];
1723 // If we have a title let the WebView know about it.
1725 [client _dispatchDidReceiveTitle:ptitle];
1728 - (void)checkLoadCompleteForThisFrame
1730 ASSERT([client webView] != nil);
1732 switch ([self state]) {
1733 case WebFrameStateProvisional: {
1734 if (delegateIsHandlingProvisionalLoadError)
1737 WebDataSource *pd = [[self provisionalDataSource] retain];
1739 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [client name]);
1740 // If we've received any errors we may be stuck in the provisional state and actually complete.
1741 NSError *error = [pd _mainDocumentError];
1743 // Check all children first.
1744 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [client name]);
1745 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1746 BOOL shouldReset = YES;
1747 if (![pd isLoading]) {
1748 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [client name]);
1749 [[client webView] _didFailProvisionalLoadWithError:error forFrame:client];
1750 delegateIsHandlingProvisionalLoadError = YES;
1751 [client _dispatchDidFailProvisionalLoadWithError:error];
1753 delegateIsHandlingProvisionalLoadError = NO;
1754 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1756 // FIXME: can stopping loading here possibly have
1757 // any effect, if isLoading is false, which it
1758 // must be, to be in this branch of the if? And is it ok to just do
1759 // a full-on stopLoading?
1760 [self stopLoadingSubframes];
1761 [[pd _documentLoader] stopLoading];
1763 // Finish resetting the load state, but only if another load hasn't been started by the
1764 // delegate callback.
1765 if (pd == [self provisionalDataSource])
1766 [self clearProvisionalLoad];
1768 NSURL *unreachableURL = [[self provisionalDataSource] unreachableURL];
1769 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]])
1774 [client _resetAfterLoadError:resetToken];
1776 [client _doNotResetAfterLoadError:resetToken];
1782 case WebFrameStateCommittedPage: {
1783 WebDataSource *ds = [self dataSource];
1785 if (![ds isLoading]) {
1786 WebFrameView *thisView = [client frameView];
1787 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1788 ASSERT(thisDocumentView != nil);
1790 [self markLoadComplete];
1792 // FIXME: Is this subsequent work important if we already navigated away?
1793 // Maybe there are bugs because of that, or extra work we can skip because
1794 // the new page is ready.
1796 // Tell the just loaded document to layout. This may be necessary
1797 // for non-html content that needs a layout message.
1798 if (!([[self dataSource] _isDocumentHTML])) {
1799 [thisDocumentView setNeedsLayout:YES];
1800 [thisDocumentView layout];
1801 [thisDocumentView setNeedsDisplay:YES];
1804 // If the user had a scroll point scroll to it. This will override
1805 // the anchor point. After much discussion it was decided by folks
1806 // that the user scroll point should override the anchor point.
1807 if ([[client webView] backForwardList]) {
1808 switch ([self loadType]) {
1809 case WebFrameLoadTypeForward:
1810 case WebFrameLoadTypeBack:
1811 case WebFrameLoadTypeIndexedBackForward:
1812 case WebFrameLoadTypeReload:
1813 [client _restoreScrollPositionAndViewState];
1816 case WebFrameLoadTypeStandard:
1817 case WebFrameLoadTypeInternal:
1818 case WebFrameLoadTypeReloadAllowingStaleData:
1819 case WebFrameLoadTypeSame:
1820 case WebFrameLoadTypeReplace:
1825 ASSERT_NOT_REACHED();
1830 NSError *error = [ds _mainDocumentError];
1832 [[client webView] _didFailLoadWithError:error forFrame:client];
1833 [client _dispatchDidFailLoadWithError:error];
1834 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1836 [[client webView] _didFinishLoadForFrame:client];
1837 [client _dispatchDidFinishLoadForFrame];
1838 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:nil];
1841 [[client webView] _progressCompleted:client];
1848 case WebFrameStateComplete:
1849 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [client name]);
1850 // Even if already complete, we might have set a previous item on a frame that
1851 // didn't do any data loading on the past transaction. Make sure to clear these out.
1852 [client _frameLoadCompleted];
1856 ASSERT_NOT_REACHED();
1859 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1864 WebFrameBridge *bridge = [self bridge];
1867 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1871 WebFrameBridge *mainBridge = [mainFrame _bridge];
1872 [mainBridge retain];
1874 [mainBridge setName:frameName];
1876 [mainFrame _dispatchShow];
1878 [mainBridge setOpener:bridge];
1879 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1881 [mainBridge release];
1887 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1889 if (response != nil)
1890 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1893 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1896 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1898 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1901 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1903 ASSERT(request != nil);
1905 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1906 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1908 if (newRequest == nil)
1909 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1916 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1918 if (frameName == nil) {
1919 [client loadRequest:request];
1923 WebFrame *frame = [client findFrameNamed:frameName];
1925 [frame loadRequest:request];
1929 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeOther
1930 event:nil originalURL:[request URL]];
1931 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1932 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1935 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1936 data:(NSArray *)postData contentType:(NSString *)contentType
1937 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1939 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1940 // This prevents a potential bug which may cause a page with a form that uses itself
1941 // as an action to be returned from the cache without submitting.
1943 // FIXME: Where's the code that implements what the comment above says?
1945 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1946 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1947 [request _web_setHTTPReferrer:referrer];
1948 [request setHTTPMethod:@"POST"];
1949 webSetHTTPBody(request, postData);
1950 [request _web_setHTTPContentType:contentType];
1952 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1953 WebFormState *formState = nil;
1955 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
1957 if (target != nil) {
1958 WebFrame *targetFrame = [client findFrameNamed:target];
1959 if (targetFrame != nil)
1960 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1962 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1963 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1965 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1968 [formState release];
1971 - (void)detachChildren
1973 // FIXME: is it really necessary to do this in reverse order any more?
1974 WebFrame *child = [client _lastChildFrame];
1975 WebFrame *prev = [child _previousSiblingFrame];
1976 for (; child; child = prev, prev = [child _previousSiblingFrame])
1977 [[child _frameLoader] detachFromParent];
1980 - (void)detachFromParent
1982 WebFrameBridge *bridge = [[self bridge] retain];
1986 [client _detachedFromParent1];
1987 [self detachChildren];
1988 [client _detachedFromParent2];
1989 [self setDocumentLoader:nil];
1990 [client _detachedFromParent3];
1991 [[[client parentFrame] _bridge] removeChild:bridge];
1993 NSObject <WebFrameLoaderClient>* c = [client retain];
1995 [c _detachedFromParent4];
2001 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
2003 [request _web_setHTTPUserAgent:[[client webView] userAgentForURL:[request URL]]];
2005 if ([self loadType] == FrameLoadTypeReload)
2006 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
2008 // Don't set the cookie policy URL if it's already been set.
2009 if ([request mainDocumentURL] == nil) {
2010 if (mainResource && (client == [[client webView] mainFrame] || f))
2011 [request setMainDocumentURL:[request URL]];
2013 [request setMainDocumentURL:[[[[client webView] mainFrame] dataSource] _URL]];
2017 [request setValue:@"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" forHTTPHeaderField:@"Accept"];
2020 - (void)safeLoadURL:(NSURL *)URL
2022 // Call the bridge because this is where our security checks are made.
2023 [[self bridge] loadURL:URL
2024 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2028 triggeringEvent:[NSApp currentEvent]
2033 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
2035 WebNavigationType navType;
2036 if (isFormSubmission) {
2037 navType = WebNavigationTypeFormSubmitted;
2038 } else if (event == nil) {
2039 if (type == FrameLoadTypeReload)
2040 navType = WebNavigationTypeReload;
2041 else if (isBackForwardLoadType(type))
2042 navType = WebNavigationTypeBackForward;
2044 navType = WebNavigationTypeOther;
2046 navType = WebNavigationTypeLinkClicked;
2048 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
2051 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
2053 switch ([event type]) {
2054 case NSLeftMouseDown:
2055 case NSRightMouseDown:
2056 case NSOtherMouseDown:
2058 case NSRightMouseUp:
2059 case NSOtherMouseUp: {
2060 NSView *topViewInEventWindow = [[event window] contentView];
2061 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
2062 while (viewContainingPoint != nil) {
2063 if ([viewContainingPoint isKindOfClass:[WebView class]])
2065 viewContainingPoint = [viewContainingPoint superview];
2067 if (viewContainingPoint != nil) {
2068 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
2069 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
2070 return [NSDictionary dictionaryWithObjectsAndKeys:
2071 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
2072 elementInfo, WebActionElementKey,
2073 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
2074 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
2075 URL, WebActionOriginalURLKey,
2083 return [NSDictionary dictionaryWithObjectsAndKeys:
2084 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
2085 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
2086 URL, WebActionOriginalURLKey,
2091 // Called every time a resource is completely loaded, or an error is received.
2092 - (void)checkLoadComplete
2094 ASSERT([client webView] != nil);
2097 for (WebFrame *frame = client; frame; frame = parent) {
2099 [[frame _frameLoader] checkLoadCompleteForThisFrame];
2100 parent = [frame parentFrame];