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 "WebIconDatabasePrivate.h"
45 #import "WebKitErrorsPrivate.h"
46 #import "WebKitLogging.h"
47 #import "WebNSURLExtras.h"
48 #import "WebNSURLRequestExtras.h"
49 #import "WebResourcePrivate.h"
50 #import "WebScriptDebugServerPrivate.h"
51 #import "WebViewInternal.h"
53 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
55 return [a caseInsensitiveCompare:b] == NSOrderedSame;
58 BOOL isBackForwardLoadType(FrameLoadType type)
61 case FrameLoadTypeStandard:
62 case FrameLoadTypeReload:
63 case FrameLoadTypeReloadAllowingStaleData:
64 case FrameLoadTypeSame:
65 case FrameLoadTypeInternal:
66 case FrameLoadTypeReplace:
68 case FrameLoadTypeBack:
69 case FrameLoadTypeForward:
70 case FrameLoadTypeIndexedBackForward:
77 @implementation WebFrameLoader
79 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
84 state = WebFrameStateCommittedPage;
91 // FIXME: should these even exist?
92 [mainResourceLoader release];
93 [subresourceLoaders release];
94 [plugInStreamLoaders release];
95 [documentLoader release];
96 [provisionalDocumentLoader release];
98 ASSERT(!policyDocumentLoader);
103 - (WebDocumentLoader *)activeDocumentLoader
105 if (state == WebFrameStateProvisional)
106 return provisionalDocumentLoader;
108 return documentLoader;
111 - (WebDataSource *)activeDataSource
113 return [client _dataSourceForDocumentLoader:[self activeDocumentLoader]];
116 - (void)addPlugInStreamLoader:(WebLoader *)loader
118 if (!plugInStreamLoaders)
119 plugInStreamLoaders = [[NSMutableArray alloc] init];
120 [plugInStreamLoaders addObject:loader];
121 [[self activeDocumentLoader] setLoading:YES];
124 - (void)removePlugInStreamLoader:(WebLoader *)loader
126 [plugInStreamLoaders removeObject:loader];
127 [[self activeDocumentLoader] updateLoading];
130 - (void)defersCallbacksChanged
132 BOOL defers = [[client webView] defersCallbacks];
133 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
134 [[frame _frameLoader] setDefersCallbacks:defers];
137 - (BOOL)defersCallbacks
139 return [[client webView] defersCallbacks];
142 - (void)setDefersCallbacks:(BOOL)defers
144 [mainResourceLoader setDefersCallbacks:defers];
146 NSEnumerator *e = [subresourceLoaders objectEnumerator];
148 while ((loader = [e nextObject]))
149 [loader setDefersCallbacks:defers];
151 e = [plugInStreamLoaders objectEnumerator];
152 while ((loader = [e nextObject]))
153 [loader setDefersCallbacks:defers];
155 [self deliverArchivedResourcesAfterDelay];
158 - (void)stopLoadingPlugIns
160 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
161 [plugInStreamLoaders removeAllObjects];
164 - (BOOL)isLoadingMainResource
166 return mainResourceLoader != nil;
169 - (BOOL)isLoadingSubresources
171 return [subresourceLoaders count];
174 - (BOOL)isLoadingPlugIns
176 return [plugInStreamLoaders count];
181 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
184 - (void)stopLoadingSubresources
186 NSArray *loaders = [subresourceLoaders copy];
187 [loaders makeObjectsPerformSelector:@selector(cancel)];
189 [subresourceLoaders removeAllObjects];
192 - (void)addSubresourceLoader:(WebLoader *)loader
194 ASSERT(!provisionalDocumentLoader);
195 if (subresourceLoaders == nil)
196 subresourceLoaders = [[NSMutableArray alloc] init];
197 [subresourceLoaders addObject:loader];
198 [[self activeDocumentLoader] setLoading:YES];
201 - (void)removeSubresourceLoader:(WebLoader *)loader
203 [subresourceLoaders removeObject:loader];
204 [[self activeDocumentLoader] updateLoading];
207 - (NSData *)mainResourceData
209 return [mainResourceLoader resourceData];
212 - (void)releaseMainResourceLoader
214 [mainResourceLoader release];
215 mainResourceLoader = nil;
218 - (void)cancelMainResourceLoad
220 [mainResourceLoader cancel];
223 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
225 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
227 [mainResourceLoader setIdentifier:identifier];
228 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
229 if (![mainResourceLoader loadWithRequest:request]) {
230 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
231 // should it be caught by other parts of WebKit or other parts of the app?
232 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
233 [mainResourceLoader release];
234 mainResourceLoader = nil;
241 - (void)stopLoadingWithError:(NSError *)error
243 [mainResourceLoader cancelWithError:error];
246 - (WebDataSource *)dataSource
248 return [client _dataSourceForDocumentLoader:documentLoader];
251 - (void)setDocumentLoader:(WebDocumentLoader *)loader
253 if (loader == nil && documentLoader == nil)
256 ASSERT(loader != documentLoader);
258 [client _prepareForDataSourceReplacement];
259 [documentLoader detachFromFrameLoader];
262 [documentLoader release];
263 documentLoader = loader;
266 - (WebDocumentLoader *)documentLoader
268 return documentLoader;
271 - (WebDataSource *)policyDataSource
273 return [client _dataSourceForDocumentLoader:policyDocumentLoader];
276 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
278 if (policyDocumentLoader == loader)
281 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
282 [policyDocumentLoader detachFromFrameLoader];
284 [policyDocumentLoader release];
286 policyDocumentLoader = loader;
289 - (WebDataSource *)provisionalDataSource
291 return [client _dataSourceForDocumentLoader:provisionalDocumentLoader];
294 - (WebDocumentLoader *)provisionalDocumentLoader
296 return provisionalDocumentLoader;
299 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
301 ASSERT(!loader || !provisionalDocumentLoader);
303 if (provisionalDocumentLoader != documentLoader)
304 [provisionalDocumentLoader detachFromFrameLoader];
307 [provisionalDocumentLoader release];
308 provisionalDocumentLoader = loader;
311 - (WebFrameState)state
317 static const char * const stateNames[] = {
318 "WebFrameStateProvisional",
319 "WebFrameStateCommittedPage",
320 "WebFrameStateComplete"
324 static CFAbsoluteTime _timeOfLastCompletedLoad;
326 + (CFAbsoluteTime)timeOfLastCompletedLoad
328 return _timeOfLastCompletedLoad;
331 - (void)provisionalLoadStarted
333 firstLayoutDone = NO;
334 [[client _bridge] provisionalLoadStarted];
336 [client _provisionalLoadStarted];
339 - (void)setState:(WebFrameState)newState
341 LOG(Loading, "%@: transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
342 if ([client webView])
343 LOG(Timing, "%@: transition from %s to %s, %f seconds since start of document load",
344 [client name], stateNames[state], stateNames[newState],
345 CFAbsoluteTimeGetCurrent() - [[[[[client webView] mainFrame] dataSource] _documentLoader] loadingStartedTime]);
347 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
348 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoader] loadingStartedTime]);
352 if (state == WebFrameStateProvisional)
353 [self provisionalLoadStarted];
354 else if (state == WebFrameStateComplete) {
355 [self frameLoadCompleted];
356 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
357 [[self documentLoader] stopRecordingResponses];
361 - (void)clearProvisionalLoad
363 [self setProvisionalDocumentLoader:nil];
364 [[client webView] _progressCompleted:client];
365 [self setState:WebFrameStateComplete];
368 - (void)markLoadComplete
370 [self setState:WebFrameStateComplete];
373 - (void)commitProvisionalLoad
375 [self stopLoadingSubresources];
376 [self stopLoadingPlugIns];
378 [self setDocumentLoader:provisionalDocumentLoader];
379 [self setProvisionalDocumentLoader:nil];
380 [self setState:WebFrameStateCommittedPage];
383 - (void)stopLoadingSubframes
385 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
386 [[(WebFrameBridge *)child frameLoader] stopLoading];
391 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
395 isStoppingLoad = YES;
397 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
399 [self stopLoadingSubframes];
400 [provisionalDocumentLoader stopLoading];
401 [documentLoader stopLoading];
402 [self setProvisionalDocumentLoader:nil];
403 [self clearArchivedResources];
408 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
411 [provisionalDocumentLoader prepareForLoadStart];
413 if ([self isLoadingMainResource])
416 [[self provisionalDataSource] _setLoadingFromPageCache:NO];
418 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
420 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
421 [provisionalDocumentLoader updateLoading];
424 - (void)startProvisionalLoad:(WebDataSource *)ds
426 [self setProvisionalDocumentLoader:[ds _documentLoader]];
427 [self setState:WebFrameStateProvisional];
430 - (void)setupForReplace
432 [self setState:WebFrameStateProvisional];
433 WebDocumentLoader *old = provisionalDocumentLoader;
434 provisionalDocumentLoader = documentLoader;
435 documentLoader = nil;
438 [self detachChildren];
441 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
443 // FIXME: why retain here, but not in the other place this happens?
445 // The identifier is released after the last callback, rather than in dealloc,
446 // to avoid potential cycles.
447 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
450 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
452 WebView *webView = [client webView];
453 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
454 return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
457 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
459 [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
462 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
464 [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
467 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
469 [[self activeDocumentLoader] addResponse:r];
471 [[client webView] _incrementProgressForIdentifier:identifier response:r];
472 [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
475 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
477 WebView *webView = [client webView];
478 [webView _incrementProgressForIdentifier:identifier data:data];
480 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
483 - (void)_didFinishLoadingForResource:(id)identifier
485 WebView *webView = [client webView];
486 [webView _completeProgressForIdentifier:identifier];
487 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
490 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
492 WebView *webView = [client webView];
494 [webView _completeProgressForIdentifier:identifier];
497 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
500 - (BOOL)_privateBrowsingEnabled
502 return [client _privateBrowsingEnabled];
505 - (void)_finishedLoadingResource
507 [self checkLoadComplete];
510 - (void)_receivedError:(NSError *)error
512 [self checkLoadComplete];
515 - (NSURLRequest *)_originalRequest
517 return [[self activeDocumentLoader] originalRequestCopy];
520 - (WebFrame *)webFrame
525 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
527 WebDocumentLoader *loader = [self activeDocumentLoader];
530 WebFrameBridge *bridge = [client _bridge];
532 // Retain the bridge because the stop may release the last reference to it.
535 WebFrame *cli = [client retain];
538 // FIXME: Don't want to do this if an entirely new load is going, so should check
539 // that both data sources on the frame are either self or nil.
540 // Can't call _bridge because we might not have commited yet
542 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
543 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
544 [bridge handleFallbackContent];
547 if ([self state] == WebFrameStateProvisional) {
548 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
549 [bridge didNotOpenURL:failedURL];
550 [client _invalidateCurrentItemPageCache];
552 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
553 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
554 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
555 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
557 if (sentRedirectNotification)
558 [self clientRedirectCancelledOrFinished:NO];
562 [loader mainReceivedError:error complete:isComplete];
569 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
571 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
572 // the redirect succeeded. We should either rename this API, or add a new method, like
573 // -webView:didFinishClientRedirectForFrame:
574 [client _dispatchDidCancelClientRedirectForFrame];
576 if (!cancelWithLoadInProgress)
577 quickRedirectComing = NO;
579 sentRedirectNotification = NO;
581 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
584 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
586 LOG(Redirect, "%@(%p) Client redirect to: %@, [self dataSource] = %p, lockHistory = %d, isJavaScriptFormAction = %d", [client name], self, URL, [self dataSource], (int)lockHistory, (int)isJavaScriptFormAction);
588 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
590 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
591 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
592 sentRedirectNotification = YES;
594 // If a "quick" redirect comes in an, we set a special mode so we treat the next
595 // load as part of the same navigation.
597 if (!documentLoader || isJavaScriptFormAction) {
598 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
599 // so we better just treat the redirect as a normal load.
600 quickRedirectComing = NO;
601 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
603 quickRedirectComing = lockHistory;
604 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
608 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
610 return !(([currentURL fragment] || [destinationURL fragment]) &&
611 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
614 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
615 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
617 BOOL isFormSubmission = (values != nil);
619 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
620 [request setValue:[[client webView] userAgentForURL:[request URL]] forHTTPHeaderField:@"Referer"];
621 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
622 if (_loadType == FrameLoadTypeReload)
623 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
625 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
626 // policy of LoadFromOrigin, but I didn't test that.
627 ASSERT(_loadType != FrameLoadTypeSame);
629 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
630 WebFormState *formState = nil;
632 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
635 WebFrame *targetFrame = [client findFrameNamed:target];
636 if (targetFrame != nil) {
637 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
639 [self checkNewWindowPolicyForRequest:request
644 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
651 WebDataSource *oldDataSource = [[self dataSource] retain];
653 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
655 // Make sure to do scroll to anchor processing even if the URL is
656 // exactly the same so pages with '#' links and DHTML side effects
658 if (!isFormSubmission
659 && _loadType != FrameLoadTypeReload
660 && _loadType != FrameLoadTypeSame
661 && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
663 // We don't want to just scroll if a link from within a
664 // frameset is trying to reload the frameset into _top.
665 && ![[client _bridge] isFrameSet]) {
667 // Just do anchor navigation within the existing content.
669 // We don't do this if we are submitting a form, explicitly reloading,
670 // currently displaying a frameset, or if the new URL does not have a fragment.
671 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
673 // FIXME: What about load types other than Standard and Reload?
675 [[oldDataSource _documentLoader] setTriggeringAction:action];
676 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
677 [self checkNavigationPolicyForRequest:request
678 dataSource:oldDataSource formState:formState
679 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
681 // must grab this now, since this load may stop the previous load and clear this flag
682 BOOL isRedirect = quickRedirectComing;
683 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
685 LOG(Redirect, "%@(%p) _private->quickRedirectComing was %d", [client name], self, (int)isRedirect);
686 quickRedirectComing = NO;
687 [provisionalDocumentLoader setIsClientRedirect:YES];
688 } else if (sameURL) {
689 // Example of this case are sites that reload the same URL with a different cookie
690 // driving the generated content, or a master frame with links that drive a target
691 // frame, where the user has clicked on the same link repeatedly.
692 [self setLoadType:FrameLoadTypeSame];
697 [oldDataSource release];
701 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
706 NSURL *URL = [request URL];
708 BOOL isRedirect = quickRedirectComing;
709 LOG(Redirect, "%@(%p) _private->quickRedirectComing = %d", [client name], self, (int)quickRedirectComing);
710 quickRedirectComing = NO;
712 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
713 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
714 // NB: must happen after _setURL, since we add based on the current request.
715 // Must also happen before we openURL and displace the scroll position, since
716 // adding the BF item will save away scroll state.
718 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
719 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
720 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
721 // though its load is not yet done. I think this all works out OK, for one because
722 // we have already saved away the scroll and doc state for the long slow load,
723 // but it's not an obvious case.
725 [client _addHistoryItemForFragmentScroll];
728 [[client _bridge] scrollToAnchorWithURL:URL];
731 // This will clear previousItem from the rest of the frame tree tree that didn't
732 // doing any loading. We need to make a pass on this now, since for anchor nav
733 // we'll not go through a real load and reach Completed state
734 [self checkLoadComplete];
737 [client _dispatchDidChangeLocationWithinPageForFrame];
738 [client _didFinishLoad];
741 - (void)closeOldDataSources
743 // FIXME: is it important for this traversal to be postorder instead of preorder?
744 // FIXME: add helpers for postorder traversal?
745 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
746 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
749 [client _dispatchWillCloseFrame];
751 [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
754 // Called after we send an openURL:... down to WebCore.
757 if ([self loadType] == FrameLoadTypeStandard && [[[self dataSource] _documentLoader] isClientRedirect])
758 [client _updateHistoryAfterClientRedirect];
760 if ([[self dataSource] _loadingFromPageCache]) {
761 // Force a layout to update view size and thereby update scrollbars.
762 [client _forceLayout];
764 NSArray *responses = [[self documentLoader] responses];
765 NSURLResponse *response;
766 int i, count = [responses count];
767 for (i = 0; i < count; i++) {
768 response = [responses objectAtIndex: i];
769 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
772 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
773 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
774 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
778 [client _loadedFromPageCache];
780 [[self documentLoader] setPrimaryLoadComplete:YES];
782 // FIXME: Why only this frame and not parent frames?
783 [self checkLoadCompleteForThisFrame];
787 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
789 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
791 WebDataSource *provisionalDataSource = [[self provisionalDataSource] retain];
792 NSURLResponse *response = [provisionalDataSource response];
794 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
795 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
797 if (loadType != FrameLoadTypeReplace)
798 [self closeOldDataSources];
801 [provisionalDataSource _makeRepresentation];
803 [self transitionToCommitted:pageCache];
805 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
806 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
807 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
808 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
809 if (sentRedirectNotification)
810 [self clientRedirectCancelledOrFinished:NO];
812 NSURL *baseURL = [[provisionalDataSource request] _webDataRequestBaseURL];
813 NSURL *URL = baseURL ? baseURL : [response URL];
815 if (!URL || [URL _web_isEmpty])
816 URL = [NSURL URLWithString:@"about:blank"];
818 [[client _bridge] openURL:URL
820 contentType:[response MIMEType]
821 refresh:[headers objectForKey:@"Refresh"]
822 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
823 pageCache:pageCache];
827 [provisionalDataSource release];
830 - (NSURLRequest *)initialRequest
832 return [[self activeDataSource] initialRequest];
835 - (void)_receivedData:(NSData *)data
837 [[self activeDocumentLoader] receivedData:data];
840 - (void)_setRequest:(NSURLRequest *)request
842 [[self activeDocumentLoader] setRequest:request];
845 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
846 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
848 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
851 - (WebFrameBridge *)bridge
853 return [client _bridge];
856 - (void)_handleFallbackContent
858 [[self bridge] handleFallbackContent];
863 return [[self activeDocumentLoader] isStopping];
866 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
868 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
871 - (void)_setResponse:(NSURLResponse *)response
873 [[self activeDocumentLoader] setResponse:response];
876 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
878 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
881 - (void)_finishedLoading
883 WebDataSource *ds = [self activeDataSource];
885 WebFrameBridge *bridge = [self bridge];
888 [[self activeDocumentLoader] finishedLoading];
890 if ([ds _mainDocumentError] || ![ds webFrame]) {
895 [[self activeDocumentLoader] setPrimaryLoadComplete:YES];
896 if ([WebScriptDebugServer listenerCount])
897 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
898 [self checkLoadComplete];
903 - (void)_notifyIconChanged:(NSURL *)iconURL
905 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
906 ASSERT(client == [[client webView] mainFrame]);
908 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
910 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
912 [client _dispatchDidReceiveIcon:icon];
914 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
919 return [[self activeDataSource] _URL];
922 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
924 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
927 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
929 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist URL:[response URL]];
932 - (void)clearArchivedResources
934 [pendingArchivedResources removeAllObjects];
935 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
938 - (void)deliverArchivedResources
940 if (![pendingArchivedResources count] || [self defersCallbacks])
943 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
945 while ((loader = [keyEnum nextObject])) {
946 WebResource *resource = [pendingArchivedResources objectForKey:loader];
947 [loader didReceiveResponse:[resource _response]];
948 NSData *data = [resource data];
949 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
950 [loader didFinishLoading];
953 [pendingArchivedResources removeAllObjects];
956 - (void)deliverArchivedResourcesAfterDelay
958 if (![pendingArchivedResources count] || [self defersCallbacks])
961 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
964 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
965 // FIXME: It would be nice to eventually to share this code somehow.
966 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
968 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
970 if (policy == NSURLRequestReturnCacheDataElseLoad) {
972 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
974 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
976 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
978 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
980 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
982 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
984 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
991 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
993 if (wkGetNSURLResponseMustRevalidate(response))
995 if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
1000 - (NSMutableDictionary *)pendingArchivedResources
1002 if (!pendingArchivedResources)
1003 pendingArchivedResources = [[NSMutableDictionary alloc] init];
1005 return pendingArchivedResources;
1008 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
1010 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
1011 WebResource *resource = [[self activeDataSource] _archivedSubresourceForURL:originalURL];
1012 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
1013 CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
1014 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
1015 [self deliverArchivedResourcesAfterDelay];
1022 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
1024 return [pendingArchivedResources objectForKey:loader] != nil;
1027 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
1029 [pendingArchivedResources removeObjectForKey:loader];
1031 if (![pendingArchivedResources count])
1032 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
1035 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
1037 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
1040 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1042 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1045 - (BOOL)isHostedByObjectElement
1047 // Handle <object> fallback for error cases.
1048 DOMHTMLElement *hostElement = [client frameElement];
1049 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1052 - (BOOL)isLoadingMainFrame
1054 return [client _isMainFrame];
1057 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1059 return [WebView canShowMIMEType:MIMEType];
1062 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1064 return [WebView _representationExistsForURLScheme:URLScheme];
1067 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1069 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1072 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1074 [self checkNavigationPolicyForRequest:newRequest
1075 dataSource:[self activeDataSource]
1081 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1083 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1088 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1093 - (void)cancelContentPolicy
1095 [listener _invalidate];
1100 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1102 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1103 if (unreachableURL == nil)
1106 if (!isBackForwardLoadType(policyLoadType))
1109 // We only treat unreachableURLs specially during the delegate callbacks
1110 // for provisional load errors and navigation policy decisions. The former
1111 // case handles well-formed URLs that can't be loaded, and the latter
1112 // case handles malformed URLs and unknown schemes. Loading alternate content
1113 // at other times behaves like a standard load.
1114 WebDataSource *compareDataSource = nil;
1115 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1116 compareDataSource = [self policyDataSource];
1117 else if (delegateIsHandlingProvisionalLoadError)
1118 compareDataSource = [self provisionalDataSource];
1120 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
1123 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1127 ASSERT(!policyDocumentLoader);
1128 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1129 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1131 NSMutableURLRequest *r = [newDataSource request];
1132 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1133 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1134 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1135 type = FrameLoadTypeSame;
1137 type = FrameLoadTypeStandard;
1139 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1140 [newDataSource _addToUnarchiveState:archive];
1142 // When we loading alternate content for an unreachable URL that we're
1143 // visiting in the b/f list, we treat it as a reload so the b/f list
1144 // is appropriately maintained.
1145 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1146 ASSERT(type == FrameLoadTypeStandard);
1147 type = FrameLoadTypeReload;
1150 [self loadDataSource:newDataSource withLoadType:type formState:nil];
1153 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1155 ASSERT(!policyDocumentLoader);
1156 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1157 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1159 [policyDocumentLoader setTriggeringAction:action];
1160 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1162 [self loadDataSource:newDataSource withLoadType:type formState:formState];
1165 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1167 WebDataSource *ds = [self dataSource];
1171 NSMutableURLRequest *request = [[ds request] mutableCopy];
1172 NSURL *unreachableURL = [ds unreachableURL];
1173 if (unreachableURL != nil)
1174 [request setURL:unreachableURL];
1176 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1177 ASSERT(!policyDocumentLoader);
1178 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1179 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1182 [policyDocumentLoader setOverrideEncoding:encoding];
1184 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1189 WebDataSource *ds = [self dataSource];
1193 NSMutableURLRequest *initialRequest = [ds request];
1195 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1196 // Reloading in this case will lose the current contents (see 4151001).
1197 if ([[[[ds request] URL] absoluteString] length] == 0)
1200 // Replace error-page URL with the URL we were trying to reach.
1201 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1202 if (unreachableURL != nil)
1203 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1205 ASSERT(!policyDocumentLoader);
1206 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1207 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1208 NSMutableURLRequest *request = [newDataSource request];
1210 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1212 // If we're about to rePOST, set up action so the app can warn the user
1213 if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1214 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeFormResubmitted
1215 event:nil originalURL:[request URL]];
1216 [policyDocumentLoader setTriggeringAction:action];
1219 [policyDocumentLoader setOverrideEncoding:[[ds _documentLoader] overrideEncoding]];
1221 [self loadDataSource:newDataSource withLoadType:FrameLoadTypeReload formState:nil];
1224 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1226 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1229 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1231 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1234 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1236 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1241 return loadType == FrameLoadTypeReplace;
1244 - (void)setReplacing
1246 loadType = FrameLoadTypeReplace;
1249 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1251 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1254 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1256 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1259 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1261 [loader setPrimaryLoadComplete:YES];
1262 if ([WebScriptDebugServer listenerCount])
1263 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1264 [self checkLoadComplete];
1267 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1269 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1272 - (void)prepareForLoadStart
1274 [[client webView] _progressStarted:client];
1275 [[client webView] _didStartProvisionalLoadForFrame:client];
1276 [client _dispatchDidStartProvisionalLoadForFrame];
1279 - (BOOL)subframeIsLoading
1281 // It's most likely that the last added frame is the last to load so we walk backwards.
1282 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1283 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1288 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1290 // FIXME: should do this only in main frame case, right?
1291 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1294 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1296 // FIXME: should do this only in main frame case, right?
1297 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1299 // The title doesn't get communicated to the WebView until we are committed.
1300 if ([loader isCommitted]) {
1301 NSURL *URLForHistory = [[client _dataSourceForDocumentLoader:loader] _URLForHistory];
1302 if (URLForHistory != nil) {
1303 // Must update the entries in the back-forward list too.
1304 // This must go through the WebFrame because it has the right notion of the current b/f item.
1305 [client _setTitle:[loader title] forURL:URLForHistory];
1306 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1308 [client _dispatchDidReceiveTitle:[loader title]];
1313 - (FrameLoadType)loadType
1318 - (void)setLoadType:(FrameLoadType)type
1323 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1325 [listener _invalidate];
1329 NSURLRequest *request = policyRequest;
1330 NSString *frameName = policyFrameName;
1331 id target = policyTarget;
1332 SEL selector = policySelector;
1333 WebFormState *formState = policyFormState;
1335 policyRequest = nil;
1336 policyFrameName = nil;
1338 policySelector = nil;
1339 policyFormState = nil;
1343 objc_msgSend(target, selector, nil, nil, nil);
1345 objc_msgSend(target, selector, nil, nil);
1349 [frameName release];
1351 [formState release];
1354 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1356 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1357 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1359 policyRequest = [request retain];
1360 policyTarget = [target retain];
1361 policyFrameName = [frameName retain];
1362 policySelector = selector;
1363 listener = [decisionListener retain];
1364 policyFormState = [formState retain];
1366 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1368 [decisionListener release];
1371 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1373 NSURLRequest *request = [[policyRequest retain] autorelease];
1374 NSString *frameName = [[policyFrameName retain] autorelease];
1375 id target = [[policyTarget retain] autorelease];
1376 SEL selector = policySelector;
1377 WebFormState *formState = [[policyFormState retain] autorelease];
1379 // will release policy* objects, hence the above retains
1380 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1382 BOOL shouldContinue = NO;
1385 case WebPolicyIgnore:
1387 case WebPolicyDownload:
1388 // FIXME: should download full request
1389 [[client webView] _downloadURL:[request URL]];
1392 shouldContinue = YES;
1395 ASSERT_NOT_REACHED();
1398 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1401 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1402 dataSource:(WebDataSource *)dataSource
1403 formState:(WebFormState *)formState
1405 withSelector:(SEL)selector
1407 NSDictionary *action = [[dataSource _documentLoader] triggeringAction];
1408 if (action == nil) {
1409 action = [self actionInformationForNavigationType:WebNavigationTypeOther
1410 event:nil originalURL:[request URL]];
1411 [[dataSource _documentLoader] setTriggeringAction:action];
1414 // Don't ask more than once for the same request or if we are loading an empty URL.
1415 // This avoids confusion on the part of the client.
1416 if ([request isEqual:[[dataSource _documentLoader] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1417 [target performSelector:selector withObject:request withObject:nil];
1421 // We are always willing to show alternate content for unreachable URLs;
1422 // treat it like a reload so it maintains the right state for b/f list.
1423 if ([request _webDataRequestUnreachableURL] != nil) {
1424 if (isBackForwardLoadType(policyLoadType))
1425 policyLoadType = FrameLoadTypeReload;
1426 [target performSelector:selector withObject:request withObject:nil];
1430 [[dataSource _documentLoader] setLastCheckedRequest:request];
1432 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1434 ASSERT(policyRequest == nil);
1435 policyRequest = [request retain];
1436 ASSERT(policyTarget == nil);
1437 policyTarget = [target retain];
1438 policySelector = selector;
1439 ASSERT(listener == nil);
1440 listener = [decisionListener retain];
1441 ASSERT(policyFormState == nil);
1442 policyFormState = [formState retain];
1444 delegateIsDecidingNavigationPolicy = YES;
1445 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1446 delegateIsDecidingNavigationPolicy = NO;
1448 [decisionListener release];
1451 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1453 NSURLRequest *request = [[policyRequest retain] autorelease];
1454 id target = [[policyTarget retain] autorelease];
1455 SEL selector = policySelector;
1456 WebFormState *formState = [[policyFormState retain] autorelease];
1458 // will release policy* objects, hence the above retains
1459 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1461 BOOL shouldContinue = NO;
1464 case WebPolicyIgnore:
1466 case WebPolicyDownload:
1467 // FIXME: should download full request
1468 [[client webView] _downloadURL:[request URL]];
1471 if (![WebView _canHandleRequest:request]) {
1472 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1474 shouldContinue = YES;
1478 ASSERT_NOT_REACHED();
1481 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1484 // Called after the FormsDelegate is done processing willSubmitForm:
1485 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1488 [listener _invalidate];
1492 [self startLoading];
1495 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1497 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1498 // nil policyDataSource because loading the alternate page will have passed
1499 // through this method already, nested; otherwise, policyDataSource should still be set.
1500 ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1502 BOOL isTargetItem = [client _provisionalItemIsTarget];
1504 // Two reasons we can't continue:
1505 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1506 // is the user responding Cancel to the form repost nag sheet.
1507 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1508 // The "before unload" event handler runs only for the main frame.
1509 BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1512 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1513 // need to report that the client redirect was cancelled.
1514 if (quickRedirectComing)
1515 [self clientRedirectCancelledOrFinished:NO];
1517 [self setPolicyDocumentLoader:nil];
1519 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1520 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1521 // we only do this when punting a navigation for the target frame or top-level frame.
1522 if ((isTargetItem || [[client webView] mainFrame] == client) && isBackForwardLoadType(policyLoadType))
1523 [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1528 FrameLoadType type = policyLoadType;
1529 WebDataSource *dataSource = [[self policyDataSource] retain];
1534 [self startProvisionalLoad:dataSource];
1536 [dataSource release];
1537 [self setPolicyDocumentLoader:nil];
1539 if (client == [[client webView] mainFrame])
1540 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1542 if (isBackForwardLoadType(type)) {
1543 if ([client _loadProvisionalItemFromPageCache])
1548 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1549 // mechanism across the willSubmitForm callout.
1550 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1551 [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1554 [self continueAfterWillSubmitForm:WebPolicyUse];
1558 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1560 ASSERT([client webView] != nil);
1562 // Unfortunately the view must be non-nil, this is ultimately due
1563 // to parser requiring a FrameView. We should fix this dependency.
1565 ASSERT([client frameView] != nil);
1567 policyLoadType = type;
1569 WebDocumentLoaderMac *loader = (WebDocumentLoaderMac *)[newDataSource _documentLoader];
1571 WebFrame *parentFrame = [client parentFrame];
1573 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1575 [loader setFrameLoader:self];
1576 [loader setDataSource:newDataSource];
1578 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1580 [self setPolicyDocumentLoader:loader];
1582 [self checkNavigationPolicyForRequest:[newDataSource request]
1583 dataSource:newDataSource
1586 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1589 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1591 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1592 delegateIsHandlingUnimplementablePolicy = YES;
1593 [client _dispatchUnableToImplementPolicyWithError:error];
1594 delegateIsHandlingUnimplementablePolicy = NO;
1597 - (void)didFirstLayout
1599 if ([[client webView] backForwardList]) {
1600 if (isBackForwardLoadType(loadType))
1601 [client _restoreScrollPositionAndViewState];
1604 firstLayoutDone = YES;
1605 [client _dispatchDidFirstLayoutInFrame];
1608 - (void)frameLoadCompleted
1610 [client _frameLoadCompleted];
1612 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1613 if ([self dataSource])
1614 firstLayoutDone = YES;
1617 - (BOOL)firstLayoutDone
1619 return firstLayoutDone;
1622 - (BOOL)isQuickRedirectComing
1624 return quickRedirectComing;
1627 - (void)transitionToCommitted:(NSDictionary *)pageCache
1629 ASSERT([client webView] != nil);
1631 switch ([self state]) {
1632 case WebFrameStateProvisional:
1635 case WebFrameStateCommittedPage:
1636 case WebFrameStateComplete:
1640 ASSERT_NOT_REACHED();
1645 [client _setCopiesOnScroll];
1646 [client _updateHistoryForCommit];
1648 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1649 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1650 // or the two will stomp each other.
1651 WebDataSource *pd = [self provisionalDataSource];
1652 [[client _bridge] closeURL];
1653 if (pd != [self provisionalDataSource])
1656 [self commitProvisionalLoad];
1658 // Handle adding the URL to the back/forward list.
1659 WebDataSource *ds = [self dataSource];
1660 NSString *ptitle = [ds pageTitle];
1663 case WebFrameLoadTypeForward:
1664 case WebFrameLoadTypeBack:
1665 case WebFrameLoadTypeIndexedBackForward:
1666 if ([[client webView] backForwardList]) {
1667 [client _updateHistoryForBackForwardNavigation];
1669 // Create a document view for this document, or used the cached view.
1671 [client _setDocumentViewFromPageCache:pageCache];
1673 [client _makeDocumentView];
1677 case WebFrameLoadTypeReload:
1678 case WebFrameLoadTypeSame:
1679 case WebFrameLoadTypeReplace:
1680 [client _updateHistoryForReload];
1681 [client _makeDocumentView];
1684 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1685 case WebFrameLoadTypeReloadAllowingStaleData:
1686 [client _makeDocumentView];
1689 case WebFrameLoadTypeStandard:
1690 [client _updateHistoryForStandardLoad];
1691 [client _makeDocumentView];
1694 case WebFrameLoadTypeInternal:
1695 [client _updateHistoryForInternalLoad];
1696 [client _makeDocumentView];
1699 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1700 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1702 ASSERT_NOT_REACHED();
1705 // Tell the client we've committed this URL.
1706 ASSERT([[client frameView] documentView] != nil);
1707 [[client webView] _didCommitLoadForFrame:client];
1708 [client _dispatchDidCommitLoadForFrame];
1710 // If we have a title let the WebView know about it.
1712 [client _dispatchDidReceiveTitle:ptitle];
1715 - (void)checkLoadCompleteForThisFrame
1717 ASSERT([client webView] != nil);
1719 switch ([self state]) {
1720 case WebFrameStateProvisional: {
1721 if (delegateIsHandlingProvisionalLoadError)
1724 WebDataSource *pd = [[self provisionalDataSource] retain];
1726 LOG(Loading, "%@: checking complete in WebFrameStateProvisional", [client name]);
1727 // If we've received any errors we may be stuck in the provisional state and actually complete.
1728 NSError *error = [pd _mainDocumentError];
1730 // Check all children first.
1731 LOG(Loading, "%@: checking complete, current state WebFrameStateProvisional", [client name]);
1732 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1733 BOOL shouldReset = YES;
1734 if (![pd isLoading]) {
1735 LOG(Loading, "%@: checking complete in WebFrameStateProvisional, load done", [client name]);
1736 [[client webView] _didFailProvisionalLoadWithError:error forFrame:client];
1737 delegateIsHandlingProvisionalLoadError = YES;
1738 [client _dispatchDidFailProvisionalLoadWithError:error];
1740 delegateIsHandlingProvisionalLoadError = NO;
1741 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1743 // FIXME: can stopping loading here possibly have
1744 // any effect, if isLoading is false, which it
1745 // must be, to be in this branch of the if? And is it ok to just do
1746 // a full-on stopLoading?
1747 [self stopLoadingSubframes];
1748 [[pd _documentLoader] stopLoading];
1750 // Finish resetting the load state, but only if another load hasn't been started by the
1751 // delegate callback.
1752 if (pd == [self provisionalDataSource])
1753 [self clearProvisionalLoad];
1755 NSURL *unreachableURL = [[self provisionalDataSource] unreachableURL];
1756 if (unreachableURL != nil && [unreachableURL isEqual:[[pd request] URL]])
1761 [client _resetAfterLoadError:resetToken];
1763 [client _doNotResetAfterLoadError:resetToken];
1769 case WebFrameStateCommittedPage: {
1770 WebDataSource *ds = [self dataSource];
1772 if (![ds isLoading]) {
1773 WebFrameView *thisView = [client frameView];
1774 NSView <WebDocumentView> *thisDocumentView = [thisView documentView];
1775 ASSERT(thisDocumentView != nil);
1777 [self markLoadComplete];
1779 // FIXME: Is this subsequent work important if we already navigated away?
1780 // Maybe there are bugs because of that, or extra work we can skip because
1781 // the new page is ready.
1783 // Tell the just loaded document to layout. This may be necessary
1784 // for non-html content that needs a layout message.
1785 if (!([[self dataSource] _isDocumentHTML])) {
1786 [thisDocumentView setNeedsLayout:YES];
1787 [thisDocumentView layout];
1788 [thisDocumentView setNeedsDisplay:YES];
1791 // If the user had a scroll point scroll to it. This will override
1792 // the anchor point. After much discussion it was decided by folks
1793 // that the user scroll point should override the anchor point.
1794 if ([[client webView] backForwardList]) {
1795 switch ([self loadType]) {
1796 case WebFrameLoadTypeForward:
1797 case WebFrameLoadTypeBack:
1798 case WebFrameLoadTypeIndexedBackForward:
1799 case WebFrameLoadTypeReload:
1800 [client _restoreScrollPositionAndViewState];
1803 case WebFrameLoadTypeStandard:
1804 case WebFrameLoadTypeInternal:
1805 case WebFrameLoadTypeReloadAllowingStaleData:
1806 case WebFrameLoadTypeSame:
1807 case WebFrameLoadTypeReplace:
1812 ASSERT_NOT_REACHED();
1817 NSError *error = [ds _mainDocumentError];
1819 [[client webView] _didFailLoadWithError:error forFrame:client];
1820 [client _dispatchDidFailLoadWithError:error];
1821 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1823 [[client webView] _didFinishLoadForFrame:client];
1824 [client _dispatchDidFinishLoadForFrame];
1825 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:nil];
1828 [[client webView] _progressCompleted:client];
1835 case WebFrameStateComplete:
1836 LOG(Loading, "%@: checking complete, current state WebFrameStateComplete", [client name]);
1837 // Even if already complete, we might have set a previous item on a frame that
1838 // didn't do any data loading on the past transaction. Make sure to clear these out.
1839 [client _frameLoadCompleted];
1843 ASSERT_NOT_REACHED();
1846 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1851 WebFrameBridge *bridge = [self bridge];
1854 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1858 WebFrameBridge *mainBridge = [mainFrame _bridge];
1859 [mainBridge retain];
1861 [mainBridge setName:frameName];
1863 [mainFrame _dispatchShow];
1865 [mainBridge setOpener:bridge];
1866 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1868 [mainBridge release];
1874 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1876 if (response != nil)
1877 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1880 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1883 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1885 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1888 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1890 ASSERT(request != nil);
1892 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1893 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1895 if (newRequest == nil)
1896 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1903 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1905 if (frameName == nil) {
1906 [client loadRequest:request];
1910 WebFrame *frame = [client findFrameNamed:frameName];
1912 [frame loadRequest:request];
1916 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeOther
1917 event:nil originalURL:[request URL]];
1918 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1919 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1922 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1923 data:(NSArray *)postData contentType:(NSString *)contentType
1924 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1926 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1927 // This prevents a potential bug which may cause a page with a form that uses itself
1928 // as an action to be returned from the cache without submitting.
1930 // FIXME: Where's the code that implements what the comment above says?
1932 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1933 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1934 [request _web_setHTTPReferrer:referrer];
1935 [request setHTTPMethod:@"POST"];
1936 webSetHTTPBody(request, postData);
1937 [request _web_setHTTPContentType:contentType];
1939 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1940 WebFormState *formState = nil;
1942 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:client];
1944 if (target != nil) {
1945 WebFrame *targetFrame = [client findFrameNamed:target];
1946 if (targetFrame != nil)
1947 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1949 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1950 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1952 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1955 [formState release];
1958 - (void)detachChildren
1960 // FIXME: is it really necessary to do this in reverse order any more?
1961 WebFrame *child = [client _lastChildFrame];
1962 WebFrame *prev = [child _previousSiblingFrame];
1963 for (; child; child = prev, prev = [child _previousSiblingFrame])
1964 [[child _frameLoader] detachFromParent];
1967 - (void)detachFromParent
1969 WebFrameBridge *bridge = [[self bridge] retain];
1973 [client _detachedFromParent1];
1974 [self detachChildren];
1975 [client _detachedFromParent2];
1976 [self setDocumentLoader:nil];
1977 [client _detachedFromParent3];
1978 [[[client parentFrame] _bridge] removeChild:bridge];
1980 NSObject <WebFrameLoaderClient>* c = [client retain];
1982 [c _detachedFromParent4];
1988 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1990 [request _web_setHTTPUserAgent:[[client webView] userAgentForURL:[request URL]]];
1992 if ([self loadType] == FrameLoadTypeReload)
1993 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1995 // Don't set the cookie policy URL if it's already been set.
1996 if ([request mainDocumentURL] == nil) {
1997 if (mainResource && (client == [[client webView] mainFrame] || f))
1998 [request setMainDocumentURL:[request URL]];
2000 [request setMainDocumentURL:[[[[client webView] mainFrame] dataSource] _URL]];
2004 [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"];
2007 - (void)safeLoadURL:(NSURL *)URL
2009 // Call the bridge because this is where our security checks are made.
2010 [[self bridge] loadURL:URL
2011 referrer:[[[[self dataSource] request] URL] _web_originalDataAsString]
2015 triggeringEvent:[NSApp currentEvent]
2020 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
2022 WebNavigationType navType;
2023 if (isFormSubmission) {
2024 navType = WebNavigationTypeFormSubmitted;
2025 } else if (event == nil) {
2026 if (type == FrameLoadTypeReload)
2027 navType = WebNavigationTypeReload;
2028 else if (isBackForwardLoadType(type))
2029 navType = WebNavigationTypeBackForward;
2031 navType = WebNavigationTypeOther;
2033 navType = WebNavigationTypeLinkClicked;
2035 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
2038 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
2040 switch ([event type]) {
2041 case NSLeftMouseDown:
2042 case NSRightMouseDown:
2043 case NSOtherMouseDown:
2045 case NSRightMouseUp:
2046 case NSOtherMouseUp: {
2047 NSView *topViewInEventWindow = [[event window] contentView];
2048 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
2049 while (viewContainingPoint != nil) {
2050 if ([viewContainingPoint isKindOfClass:[WebView class]])
2052 viewContainingPoint = [viewContainingPoint superview];
2054 if (viewContainingPoint != nil) {
2055 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
2056 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
2057 return [NSDictionary dictionaryWithObjectsAndKeys:
2058 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
2059 elementInfo, WebActionElementKey,
2060 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
2061 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
2062 URL, WebActionOriginalURLKey,
2070 return [NSDictionary dictionaryWithObjectsAndKeys:
2071 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
2072 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
2073 URL, WebActionOriginalURLKey,
2078 // Called every time a resource is completely loaded, or an error is received.
2079 - (void)checkLoadComplete
2081 ASSERT([client webView] != nil);
2084 for (WebFrame *frame = client; frame; frame = parent) {
2086 [[frame _frameLoader] checkLoadCompleteForThisFrame];
2087 parent = [frame parentFrame];