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 "WebFormState.h"
35 #import "WebFrameBridge.h"
36 #import "WebFrameLoaderClient.h"
37 #import "WebMainResourceLoader.h"
38 #import <JavaScriptCore/Assertions.h>
39 #import <WebKit/DOMHTML.h>
40 #import <WebCore/WebCoreSystemInterface.h>
42 #import "WebDataSourceInternal.h"
43 #import "WebFrameInternal.h"
44 #import "WebIconDatabasePrivate.h"
45 #import "WebKitErrorsPrivate.h"
46 #import "WebNSURLExtras.h"
47 #import "WebResourcePrivate.h"
48 #import "WebViewInternal.h"
50 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
52 return [a caseInsensitiveCompare:b] == NSOrderedSame;
55 BOOL isBackForwardLoadType(FrameLoadType type)
58 case FrameLoadTypeStandard:
59 case FrameLoadTypeReload:
60 case FrameLoadTypeReloadAllowingStaleData:
61 case FrameLoadTypeSame:
62 case FrameLoadTypeInternal:
63 case FrameLoadTypeReplace:
65 case FrameLoadTypeBack:
66 case FrameLoadTypeForward:
67 case FrameLoadTypeIndexedBackForward:
74 @implementation WebFrameLoader
76 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
81 state = WebFrameStateCommittedPage;
88 // FIXME: should these even exist?
89 [mainResourceLoader release];
90 [subresourceLoaders release];
91 [plugInStreamLoaders release];
92 [documentLoader release];
93 [provisionalDocumentLoader release];
95 ASSERT(!policyDocumentLoader);
100 - (WebDocumentLoader *)activeDocumentLoader
102 if (state == WebFrameStateProvisional)
103 return provisionalDocumentLoader;
105 return documentLoader;
108 - (void)addPlugInStreamLoader:(WebLoader *)loader
110 if (!plugInStreamLoaders)
111 plugInStreamLoaders = [[NSMutableArray alloc] init];
112 [plugInStreamLoaders addObject:loader];
113 [[self activeDocumentLoader] setLoading:YES];
116 - (void)removePlugInStreamLoader:(WebLoader *)loader
118 [plugInStreamLoaders removeObject:loader];
119 [[self activeDocumentLoader] updateLoading];
122 - (void)defersCallbacksChanged
124 BOOL defers = [[client webView] defersCallbacks];
125 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
126 [[frame _frameLoader] setDefersCallbacks:defers];
129 - (BOOL)defersCallbacks
131 return [[client webView] defersCallbacks];
134 - (void)setDefersCallbacks:(BOOL)defers
136 [mainResourceLoader setDefersCallbacks:defers];
138 NSEnumerator *e = [subresourceLoaders objectEnumerator];
140 while ((loader = [e nextObject]))
141 [loader setDefersCallbacks:defers];
143 e = [plugInStreamLoaders objectEnumerator];
144 while ((loader = [e nextObject]))
145 [loader setDefersCallbacks:defers];
147 [self deliverArchivedResourcesAfterDelay];
150 - (void)stopLoadingPlugIns
152 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
153 [plugInStreamLoaders removeAllObjects];
156 - (BOOL)isLoadingMainResource
158 return mainResourceLoader != nil;
161 - (BOOL)isLoadingSubresources
163 return [subresourceLoaders count];
166 - (BOOL)isLoadingPlugIns
168 return [plugInStreamLoaders count];
173 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
176 - (void)stopLoadingSubresources
178 NSArray *loaders = [subresourceLoaders copy];
179 [loaders makeObjectsPerformSelector:@selector(cancel)];
181 [subresourceLoaders removeAllObjects];
184 - (void)addSubresourceLoader:(WebLoader *)loader
186 ASSERT(!provisionalDocumentLoader);
187 if (subresourceLoaders == nil)
188 subresourceLoaders = [[NSMutableArray alloc] init];
189 [subresourceLoaders addObject:loader];
190 [[self activeDocumentLoader] setLoading:YES];
193 - (void)removeSubresourceLoader:(WebLoader *)loader
195 [subresourceLoaders removeObject:loader];
196 [[self activeDocumentLoader] updateLoading];
199 - (NSData *)mainResourceData
201 return [mainResourceLoader resourceData];
204 - (void)releaseMainResourceLoader
206 [mainResourceLoader release];
207 mainResourceLoader = nil;
210 - (void)cancelMainResourceLoad
212 [mainResourceLoader cancel];
215 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
217 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
219 [mainResourceLoader setIdentifier:identifier];
220 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
221 if (![mainResourceLoader loadWithRequest:request]) {
222 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
223 // should it be caught by other parts of WebKit or other parts of the app?
224 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
225 [mainResourceLoader release];
226 mainResourceLoader = nil;
233 - (void)stopLoadingWithError:(NSError *)error
235 [mainResourceLoader cancelWithError:error];
238 - (void)setDocumentLoader:(WebDocumentLoader *)loader
240 if (loader == nil && documentLoader == nil)
243 ASSERT(loader != documentLoader);
245 [client _prepareForDataSourceReplacement];
246 [documentLoader detachFromFrameLoader];
249 [documentLoader release];
250 documentLoader = loader;
253 - (WebDocumentLoader *)documentLoader
255 return documentLoader;
258 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
260 if (policyDocumentLoader == loader)
263 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
264 [policyDocumentLoader detachFromFrameLoader];
266 [policyDocumentLoader release];
268 policyDocumentLoader = loader;
271 - (WebDocumentLoader *)provisionalDocumentLoader
273 return provisionalDocumentLoader;
276 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
278 ASSERT(!loader || !provisionalDocumentLoader);
280 if (provisionalDocumentLoader != documentLoader)
281 [provisionalDocumentLoader detachFromFrameLoader];
284 [provisionalDocumentLoader release];
285 provisionalDocumentLoader = loader;
288 - (WebFrameState)state
294 static const char * const stateNames[] = {
295 "WebFrameStateProvisional",
296 "WebFrameStateCommittedPage",
297 "WebFrameStateComplete"
301 static CFAbsoluteTime _timeOfLastCompletedLoad;
303 + (CFAbsoluteTime)timeOfLastCompletedLoad
305 return _timeOfLastCompletedLoad;
308 - (void)provisionalLoadStarted
310 firstLayoutDone = NO;
311 [[client _bridge] provisionalLoadStarted];
313 [client _provisionalLoadStarted];
316 - (void)setState:(WebFrameState)newState
320 if (state == WebFrameStateProvisional)
321 [self provisionalLoadStarted];
322 else if (state == WebFrameStateComplete) {
323 [self frameLoadCompleted];
324 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
325 [[self documentLoader] stopRecordingResponses];
329 - (void)clearProvisionalLoad
331 [self setProvisionalDocumentLoader:nil];
332 [[client webView] _progressCompleted:client];
333 [self setState:WebFrameStateComplete];
336 - (void)markLoadComplete
338 [self setState:WebFrameStateComplete];
341 - (void)commitProvisionalLoad
343 [self stopLoadingSubresources];
344 [self stopLoadingPlugIns];
346 [self setDocumentLoader:provisionalDocumentLoader];
347 [self setProvisionalDocumentLoader:nil];
348 [self setState:WebFrameStateCommittedPage];
351 - (void)stopLoadingSubframes
353 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
354 [[(WebFrameBridge *)child frameLoader] stopLoading];
359 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
363 isStoppingLoad = YES;
365 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
367 [self stopLoadingSubframes];
368 [provisionalDocumentLoader stopLoading];
369 [documentLoader stopLoading];
370 [self setProvisionalDocumentLoader:nil];
371 [self clearArchivedResources];
376 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
379 [provisionalDocumentLoader prepareForLoadStart];
381 if ([self isLoadingMainResource])
384 [client _clearLoadingFromPageCacheForDocumentLoader:provisionalDocumentLoader];
386 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
388 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
389 [provisionalDocumentLoader updateLoading];
392 - (void)startProvisionalLoad:(WebDocumentLoader *)loader
394 [self setProvisionalDocumentLoader:loader];
395 [self setState:WebFrameStateProvisional];
398 - (void)setupForReplace
400 [self setState:WebFrameStateProvisional];
401 WebDocumentLoader *old = provisionalDocumentLoader;
402 provisionalDocumentLoader = documentLoader;
403 documentLoader = nil;
406 [self detachChildren];
409 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
411 // FIXME: why retain here, but not in the other place this happens?
413 // The identifier is released after the last callback, rather than in dealloc,
414 // to avoid potential cycles.
415 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
418 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
420 WebView *webView = [client webView];
421 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
422 return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
425 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
427 [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
430 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
432 [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
435 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
437 [[self activeDocumentLoader] addResponse:r];
439 [[client webView] _incrementProgressForIdentifier:identifier response:r];
440 [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
443 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
445 WebView *webView = [client webView];
446 [webView _incrementProgressForIdentifier:identifier data:data];
448 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
451 - (void)_didFinishLoadingForResource:(id)identifier
453 WebView *webView = [client webView];
454 [webView _completeProgressForIdentifier:identifier];
455 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
458 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
460 WebView *webView = [client webView];
462 [webView _completeProgressForIdentifier:identifier];
465 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
468 - (BOOL)_privateBrowsingEnabled
470 return [client _privateBrowsingEnabled];
473 - (void)_finishedLoadingResource
475 [self checkLoadComplete];
478 - (void)_receivedError:(NSError *)error
480 [self checkLoadComplete];
483 - (NSURLRequest *)_originalRequest
485 return [[self activeDocumentLoader] originalRequestCopy];
488 - (WebFrame *)webFrame
493 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
495 WebDocumentLoader *loader = [self activeDocumentLoader];
498 WebFrameBridge *bridge = [client _bridge];
500 // Retain the bridge because the stop may release the last reference to it.
503 WebFrame *cli = [client retain];
506 // FIXME: Don't want to do this if an entirely new load is going, so should check
507 // that both data sources on the frame are either self or nil.
508 // Can't call _bridge because we might not have commited yet
510 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
511 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
512 [bridge handleFallbackContent];
515 if ([self state] == WebFrameStateProvisional) {
516 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
517 [bridge didNotOpenURL:failedURL];
518 [client _invalidateCurrentItemPageCache];
520 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
521 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
522 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
523 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
525 if (sentRedirectNotification)
526 [self clientRedirectCancelledOrFinished:NO];
530 [loader mainReceivedError:error complete:isComplete];
537 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
539 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
540 // the redirect succeeded. We should either rename this API, or add a new method, like
541 // -webView:didFinishClientRedirectForFrame:
542 [client _dispatchDidCancelClientRedirectForFrame];
544 if (!cancelWithLoadInProgress)
545 quickRedirectComing = NO;
547 sentRedirectNotification = NO;
550 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
552 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
554 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
555 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
556 sentRedirectNotification = YES;
558 // If a "quick" redirect comes in an, we set a special mode so we treat the next
559 // load as part of the same navigation.
561 if (!documentLoader || isJavaScriptFormAction) {
562 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
563 // so we better just treat the redirect as a normal load.
564 quickRedirectComing = NO;
566 quickRedirectComing = lockHistory;
570 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
572 return !(([currentURL fragment] || [destinationURL fragment]) &&
573 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
576 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
577 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
579 BOOL isFormSubmission = (values != nil);
581 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
582 [request setValue:referrer forHTTPHeaderField:@"Referer"];
583 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
584 if (_loadType == FrameLoadTypeReload)
585 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
587 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
588 // policy of LoadFromOrigin, but I didn't test that.
589 ASSERT(_loadType != FrameLoadTypeSame);
591 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
592 WebFormState *formState = nil;
594 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:[client _bridge]];
597 WebFrame *targetFrame = [client findFrameNamed:target];
598 if (targetFrame != nil) {
599 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
601 [self checkNewWindowPolicyForRequest:request
606 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
613 WebDocumentLoader *oldDocumentLoader = [documentLoader retain];
615 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
617 // Make sure to do scroll to anchor processing even if the URL is
618 // exactly the same so pages with '#' links and DHTML side effects
620 if (!isFormSubmission
621 && _loadType != FrameLoadTypeReload
622 && _loadType != FrameLoadTypeSame
623 && ![self shouldReloadForCurrent:URL andDestination:[[client _bridge] URL]]
625 // We don't want to just scroll if a link from within a
626 // frameset is trying to reload the frameset into _top.
627 && ![[client _bridge] isFrameSet]) {
629 // Just do anchor navigation within the existing content.
631 // We don't do this if we are submitting a form, explicitly reloading,
632 // currently displaying a frameset, or if the new URL does not have a fragment.
633 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
635 // FIXME: What about load types other than Standard and Reload?
637 [oldDocumentLoader setTriggeringAction:action];
638 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
639 [self checkNavigationPolicyForRequest:request
640 documentLoader:oldDocumentLoader formState:formState
641 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
643 // must grab this now, since this load may stop the previous load and clear this flag
644 BOOL isRedirect = quickRedirectComing;
645 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
647 quickRedirectComing = NO;
648 [provisionalDocumentLoader setIsClientRedirect:YES];
649 } else if (sameURL) {
650 // Example of this case are sites that reload the same URL with a different cookie
651 // driving the generated content, or a master frame with links that drive a target
652 // frame, where the user has clicked on the same link repeatedly.
653 [self setLoadType:FrameLoadTypeSame];
658 [oldDocumentLoader release];
662 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
667 NSURL *URL = [request URL];
669 BOOL isRedirect = quickRedirectComing;
670 quickRedirectComing = NO;
672 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
673 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
674 // NB: must happen after _setURL, since we add based on the current request.
675 // Must also happen before we openURL and displace the scroll position, since
676 // adding the BF item will save away scroll state.
678 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
679 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
680 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
681 // though its load is not yet done. I think this all works out OK, for one because
682 // we have already saved away the scroll and doc state for the long slow load,
683 // but it's not an obvious case.
685 [client _addHistoryItemForFragmentScroll];
688 [[client _bridge] scrollToAnchorWithURL:URL];
691 // This will clear previousItem from the rest of the frame tree tree that didn't
692 // doing any loading. We need to make a pass on this now, since for anchor nav
693 // we'll not go through a real load and reach Completed state
694 [self checkLoadComplete];
697 [client _dispatchDidChangeLocationWithinPageForFrame];
698 [client _didFinishLoad];
701 - (void)closeOldDataSources
703 // FIXME: is it important for this traversal to be postorder instead of preorder?
704 // FIXME: add helpers for postorder traversal?
705 for (WebCoreFrameBridge *child = [[client _bridge] firstChild]; child; child = [child nextSibling])
706 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
709 [client _dispatchWillCloseFrame];
711 [[client webView] setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
714 // Called after we send an openURL:... down to WebCore.
717 if ([self loadType] == FrameLoadTypeStandard && [documentLoader isClientRedirect])
718 [client _updateHistoryAfterClientRedirect];
720 if ([client _isDocumentLoaderLoadingFromPageCache:documentLoader]) {
721 // Force a layout to update view size and thereby update scrollbars.
722 [client _forceLayout];
724 NSArray *responses = [[self documentLoader] responses];
725 NSURLResponse *response;
726 int i, count = [responses count];
727 for (i = 0; i < count; i++) {
728 response = [responses objectAtIndex: i];
729 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
732 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
733 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
734 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
738 [client _loadedFromPageCache];
740 [[self documentLoader] setPrimaryLoadComplete:YES];
742 // FIXME: Why only this frame and not parent frames?
743 [self checkLoadCompleteForThisFrame];
747 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
749 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
751 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
753 NSURLResponse *response = [pdl response];
755 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
756 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
758 if (loadType != FrameLoadTypeReplace)
759 [self closeOldDataSources];
762 [client _makeRepresentationForDocumentLoader:pdl];
764 [self transitionToCommitted:pageCache];
766 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
767 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
768 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
769 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
770 if (sentRedirectNotification)
771 [self clientRedirectCancelledOrFinished:NO];
773 NSURL *baseURL = [[provisionalDocumentLoader request] _webDataRequestBaseURL];
774 NSURL *URL = baseURL ? baseURL : [response URL];
776 if (!URL || [URL _web_isEmpty])
777 URL = [NSURL URLWithString:@"about:blank"];
779 [[client _bridge] openURL:URL
781 contentType:[response MIMEType]
782 refresh:[headers objectForKey:@"Refresh"]
783 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
784 pageCache:pageCache];
791 - (NSURLRequest *)initialRequest
793 return [[self activeDocumentLoader] initialRequest];
796 - (void)_receivedData:(NSData *)data
798 [[self activeDocumentLoader] receivedData:data];
801 - (void)_setRequest:(NSURLRequest *)request
803 [[self activeDocumentLoader] setRequest:request];
806 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
807 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
809 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
812 - (WebFrameBridge *)bridge
814 return [client _bridge];
817 - (void)_handleFallbackContent
819 [[self bridge] handleFallbackContent];
824 return [[self activeDocumentLoader] isStopping];
827 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
829 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
832 - (void)_setResponse:(NSURLResponse *)response
834 [[self activeDocumentLoader] setResponse:response];
837 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
839 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
842 - (void)_finishedLoading
844 WebDocumentLoader *dl = [self activeDocumentLoader];
846 WebFrameBridge *bridge = [self bridge];
849 [dl finishedLoading];
851 if ([dl mainDocumentError] || ![dl frameLoader]) {
856 [dl setPrimaryLoadComplete:YES];
857 [client _dispatchDidLoadMainResourceForDocumentLoader:dl];
858 [self checkLoadComplete];
863 - (void)_notifyIconChanged:(NSURL *)iconURL
865 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
866 ASSERT(client == [[client webView] mainFrame]);
868 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
870 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDocumentLoader] URL] _web_originalDataAsString] withSize:WebIconSmallSize];
872 [client _dispatchDidReceiveIcon:icon];
874 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
879 return [[self activeDocumentLoader] URL];
882 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
884 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
887 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
889 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist URL:[response URL]];
892 - (void)clearArchivedResources
894 [pendingArchivedResources removeAllObjects];
895 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
898 - (void)deliverArchivedResources
900 if (![pendingArchivedResources count] || [self defersCallbacks])
903 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
905 while ((loader = [keyEnum nextObject])) {
906 WebResource *resource = [pendingArchivedResources objectForKey:loader];
907 [loader didReceiveResponse:[resource _response]];
908 NSData *data = [resource data];
909 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
910 [loader didFinishLoading];
913 [pendingArchivedResources removeAllObjects];
916 - (void)deliverArchivedResourcesAfterDelay
918 if (![pendingArchivedResources count] || [self defersCallbacks])
921 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
924 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
925 // FIXME: It would be nice to eventually to share this code somehow.
926 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
928 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
930 if (policy == NSURLRequestReturnCacheDataElseLoad) {
932 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
934 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
936 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
938 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
940 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
942 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
944 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
951 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
953 if (wkGetNSURLResponseMustRevalidate(response))
955 if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
960 - (NSMutableDictionary *)pendingArchivedResources
962 if (!pendingArchivedResources)
963 pendingArchivedResources = [[NSMutableDictionary alloc] init];
965 return pendingArchivedResources;
968 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
970 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
971 WebResource *resource = [client _archivedSubresourceForURL:originalURL fromDocumentLoader:[self activeDocumentLoader]];
972 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
973 CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
974 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
975 [self deliverArchivedResourcesAfterDelay];
982 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
984 return [pendingArchivedResources objectForKey:loader] != nil;
987 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
989 [pendingArchivedResources removeObjectForKey:loader];
991 if (![pendingArchivedResources count])
992 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
995 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
997 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
1000 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
1002 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
1005 - (BOOL)isHostedByObjectElement
1007 // Handle <object> fallback for error cases.
1008 DOMHTMLElement *hostElement = [client frameElement];
1009 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1012 - (BOOL)isLoadingMainFrame
1014 return [client _isMainFrame];
1017 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1019 return [WebView canShowMIMEType:MIMEType];
1022 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1024 return [WebView _representationExistsForURLScheme:URLScheme];
1027 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1029 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1032 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1034 [self checkNavigationPolicyForRequest:newRequest
1035 documentLoader:[self activeDocumentLoader]
1041 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1043 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1048 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1053 - (void)cancelContentPolicy
1055 [listener _invalidate];
1060 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1062 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1063 if (unreachableURL == nil)
1066 if (!isBackForwardLoadType(policyLoadType))
1069 // We only treat unreachableURLs specially during the delegate callbacks
1070 // for provisional load errors and navigation policy decisions. The former
1071 // case handles well-formed URLs that can't be loaded, and the latter
1072 // case handles malformed URLs and unknown schemes. Loading alternate content
1073 // at other times behaves like a standard load.
1074 WebDocumentLoader *compareDocumentLoader = nil;
1075 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1076 compareDocumentLoader = policyDocumentLoader;
1077 else if (delegateIsHandlingProvisionalLoadError)
1078 compareDocumentLoader = [self provisionalDocumentLoader];
1080 return compareDocumentLoader != nil && [unreachableURL isEqual:[[compareDocumentLoader request] URL]];
1083 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1087 ASSERT(!policyDocumentLoader);
1088 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1089 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1091 NSMutableURLRequest *r = [newDataSource request];
1092 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1093 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1094 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1095 type = FrameLoadTypeSame;
1097 type = FrameLoadTypeStandard;
1099 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1100 [newDataSource _addToUnarchiveState:archive];
1102 // When we loading alternate content for an unreachable URL that we're
1103 // visiting in the b/f list, we treat it as a reload so the b/f list
1104 // is appropriately maintained.
1105 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1106 ASSERT(type == FrameLoadTypeStandard);
1107 type = FrameLoadTypeReload;
1110 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:nil];
1113 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1115 ASSERT(!policyDocumentLoader);
1116 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1118 [policyDocumentLoader setTriggeringAction:action];
1119 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1121 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:formState];
1124 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1126 if (documentLoader == nil)
1129 NSMutableURLRequest *request = [[documentLoader request] mutableCopy];
1130 NSURL *unreachableURL = [documentLoader unreachableURL];
1131 if (unreachableURL != nil)
1132 [request setURL:unreachableURL];
1134 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1135 ASSERT(!policyDocumentLoader);
1136 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1139 [policyDocumentLoader setOverrideEncoding:encoding];
1141 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1146 if (documentLoader == nil)
1149 NSMutableURLRequest *initialRequest = [documentLoader request];
1151 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1152 // Reloading in this case will lose the current contents (see 4151001).
1153 if ([[[[documentLoader request] URL] absoluteString] length] == 0)
1156 // Replace error-page URL with the URL we were trying to reach.
1157 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1158 if (unreachableURL != nil)
1159 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1161 ASSERT(!policyDocumentLoader);
1162 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1163 NSMutableURLRequest *request = [policyDocumentLoader request];
1165 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1167 // If we're about to rePOST, set up action so the app can warn the user
1168 if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1169 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeFormResubmitted
1170 event:nil originalURL:[request URL]];
1171 [policyDocumentLoader setTriggeringAction:action];
1174 [policyDocumentLoader setOverrideEncoding:[documentLoader overrideEncoding]];
1176 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReload formState:nil];
1179 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1181 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1184 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1186 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1189 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1191 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1196 return loadType == FrameLoadTypeReplace;
1199 - (void)setReplacing
1201 loadType = FrameLoadTypeReplace;
1204 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1206 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1209 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1211 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1214 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1216 [loader setPrimaryLoadComplete:YES];
1217 [client _dispatchDidLoadMainResourceForDocumentLoader:[self activeDocumentLoader]];
1218 [self checkLoadComplete];
1221 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1223 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1226 - (void)prepareForLoadStart
1228 [[client webView] _progressStarted:client];
1229 [[client webView] _didStartProvisionalLoadForFrame:client];
1230 [client _dispatchDidStartProvisionalLoadForFrame];
1233 - (BOOL)subframeIsLoading
1235 // It's most likely that the last added frame is the last to load so we walk backwards.
1236 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1237 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1242 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1244 // FIXME: should do this only in main frame case, right?
1245 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1248 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1250 // FIXME: should do this only in main frame case, right?
1251 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1253 // The title doesn't get communicated to the WebView until we are committed.
1254 if ([loader isCommitted]) {
1255 NSURL *URLForHistory = [[client _dataSourceForDocumentLoader:loader] _URLForHistory];
1256 if (URLForHistory != nil) {
1257 // Must update the entries in the back-forward list too.
1258 // This must go through the WebFrame because it has the right notion of the current b/f item.
1259 [client _setTitle:[loader title] forURL:URLForHistory];
1260 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1262 [client _dispatchDidReceiveTitle:[loader title]];
1267 - (FrameLoadType)loadType
1272 - (void)setLoadType:(FrameLoadType)type
1277 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1279 [listener _invalidate];
1283 NSURLRequest *request = policyRequest;
1284 NSString *frameName = policyFrameName;
1285 id target = policyTarget;
1286 SEL selector = policySelector;
1287 WebFormState *formState = policyFormState;
1289 policyRequest = nil;
1290 policyFrameName = nil;
1292 policySelector = nil;
1293 policyFormState = nil;
1297 objc_msgSend(target, selector, nil, nil, nil);
1299 objc_msgSend(target, selector, nil, nil);
1303 [frameName release];
1305 [formState release];
1308 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1310 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1311 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1313 policyRequest = [request retain];
1314 policyTarget = [target retain];
1315 policyFrameName = [frameName retain];
1316 policySelector = selector;
1317 listener = [decisionListener retain];
1318 policyFormState = [formState retain];
1320 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1322 [decisionListener release];
1325 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1327 NSURLRequest *request = [[policyRequest retain] autorelease];
1328 NSString *frameName = [[policyFrameName retain] autorelease];
1329 id target = [[policyTarget retain] autorelease];
1330 SEL selector = policySelector;
1331 WebFormState *formState = [[policyFormState retain] autorelease];
1333 // will release policy* objects, hence the above retains
1334 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1336 BOOL shouldContinue = NO;
1339 case WebPolicyIgnore:
1341 case WebPolicyDownload:
1342 // FIXME: should download full request
1343 [[client webView] _downloadURL:[request URL]];
1346 shouldContinue = YES;
1349 ASSERT_NOT_REACHED();
1352 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1355 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1356 documentLoader:(WebDocumentLoader *)loader
1357 formState:(WebFormState *)formState
1359 withSelector:(SEL)selector
1361 NSDictionary *action = [loader triggeringAction];
1362 if (action == nil) {
1363 action = [self actionInformationForNavigationType:WebNavigationTypeOther
1364 event:nil originalURL:[request URL]];
1365 [loader setTriggeringAction:action];
1368 // Don't ask more than once for the same request or if we are loading an empty URL.
1369 // This avoids confusion on the part of the client.
1370 if ([request isEqual:[loader lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1371 [target performSelector:selector withObject:request withObject:nil];
1375 // We are always willing to show alternate content for unreachable URLs;
1376 // treat it like a reload so it maintains the right state for b/f list.
1377 if ([request _webDataRequestUnreachableURL] != nil) {
1378 if (isBackForwardLoadType(policyLoadType))
1379 policyLoadType = FrameLoadTypeReload;
1380 [target performSelector:selector withObject:request withObject:nil];
1384 [loader setLastCheckedRequest:request];
1386 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1388 ASSERT(policyRequest == nil);
1389 policyRequest = [request retain];
1390 ASSERT(policyTarget == nil);
1391 policyTarget = [target retain];
1392 policySelector = selector;
1393 ASSERT(listener == nil);
1394 listener = [decisionListener retain];
1395 ASSERT(policyFormState == nil);
1396 policyFormState = [formState retain];
1398 delegateIsDecidingNavigationPolicy = YES;
1399 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1400 delegateIsDecidingNavigationPolicy = NO;
1402 [decisionListener release];
1405 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1407 NSURLRequest *request = [[policyRequest retain] autorelease];
1408 id target = [[policyTarget retain] autorelease];
1409 SEL selector = policySelector;
1410 WebFormState *formState = [[policyFormState retain] autorelease];
1412 // will release policy* objects, hence the above retains
1413 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1415 BOOL shouldContinue = NO;
1418 case WebPolicyIgnore:
1420 case WebPolicyDownload:
1421 // FIXME: should download full request
1422 [[client webView] _downloadURL:[request URL]];
1425 if (![WebView _canHandleRequest:request]) {
1426 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1428 shouldContinue = YES;
1432 ASSERT_NOT_REACHED();
1435 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1438 // Called after the FormsDelegate is done processing willSubmitForm:
1439 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1442 [listener _invalidate];
1446 [self startLoading];
1449 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1451 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1452 // nil policyDataSource because loading the alternate page will have passed
1453 // through this method already, nested; otherwise, policyDataSource should still be set.
1454 ASSERT(policyDocumentLoader || [provisionalDocumentLoader unreachableURL] != nil);
1456 BOOL isTargetItem = [client _provisionalItemIsTarget];
1458 // Two reasons we can't continue:
1459 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1460 // is the user responding Cancel to the form repost nag sheet.
1461 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1462 // The "before unload" event handler runs only for the main frame.
1463 BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1466 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1467 // need to report that the client redirect was cancelled.
1468 if (quickRedirectComing)
1469 [self clientRedirectCancelledOrFinished:NO];
1471 [self setPolicyDocumentLoader:nil];
1473 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1474 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1475 // we only do this when punting a navigation for the target frame or top-level frame.
1476 if ((isTargetItem || [[client webView] mainFrame] == client) && isBackForwardLoadType(policyLoadType))
1477 [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1482 FrameLoadType type = policyLoadType;
1483 WebDocumentLoader *dl = [policyDocumentLoader retain];
1488 [self startProvisionalLoad:dl];
1491 [self setPolicyDocumentLoader:nil];
1493 if (isBackForwardLoadType(type)) {
1494 if ([client _loadProvisionalItemFromPageCache])
1499 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1500 // mechanism across the willSubmitForm callout.
1501 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1502 [[[client webView] _formDelegate] frame:client sourceFrame:[(WebFrameBridge *)[formState sourceFrame] webFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1505 [self continueAfterWillSubmitForm:WebPolicyUse];
1509 - (void)loadDocumentLoader:(WebDocumentLoader *)loader withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1511 ASSERT([client webView] != nil);
1513 // Unfortunately the view must be non-nil, this is ultimately due
1514 // to parser requiring a FrameView. We should fix this dependency.
1516 ASSERT([client frameView] != nil);
1518 policyLoadType = type;
1520 WebFrame *parentFrame = [client parentFrame];
1522 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1524 [loader setFrameLoader:self];
1526 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1528 [self setPolicyDocumentLoader:loader];
1530 [self checkNavigationPolicyForRequest:[loader request]
1531 documentLoader:loader
1534 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1537 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1539 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1540 delegateIsHandlingUnimplementablePolicy = YES;
1541 [client _dispatchUnableToImplementPolicyWithError:error];
1542 delegateIsHandlingUnimplementablePolicy = NO;
1545 - (void)didFirstLayout
1547 if ([[client webView] backForwardList]) {
1548 if (isBackForwardLoadType(loadType))
1549 [client _restoreScrollPositionAndViewState];
1552 firstLayoutDone = YES;
1553 [client _dispatchDidFirstLayoutInFrame];
1556 - (void)frameLoadCompleted
1558 [client _frameLoadCompleted];
1560 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1562 firstLayoutDone = YES;
1565 - (BOOL)firstLayoutDone
1567 return firstLayoutDone;
1570 - (BOOL)isQuickRedirectComing
1572 return quickRedirectComing;
1575 - (void)transitionToCommitted:(NSDictionary *)pageCache
1577 ASSERT([client webView] != nil);
1579 switch ([self state]) {
1580 case WebFrameStateProvisional:
1583 case WebFrameStateCommittedPage:
1584 case WebFrameStateComplete:
1588 ASSERT_NOT_REACHED();
1593 [client _setCopiesOnScroll];
1594 [client _updateHistoryForCommit];
1596 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1597 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1598 // or the two will stomp each other.
1599 WebDocumentLoader *pdl = provisionalDocumentLoader;
1600 [[client _bridge] closeURL];
1601 if (pdl != provisionalDocumentLoader)
1604 [self commitProvisionalLoad];
1606 // Handle adding the URL to the back/forward list.
1607 WebDocumentLoader *dl = documentLoader;
1608 NSString *ptitle = [dl title];
1611 case WebFrameLoadTypeForward:
1612 case WebFrameLoadTypeBack:
1613 case WebFrameLoadTypeIndexedBackForward:
1614 if ([[client webView] backForwardList]) {
1615 [client _updateHistoryForBackForwardNavigation];
1617 // Create a document view for this document, or used the cached view.
1619 [client _setDocumentViewFromPageCache:pageCache];
1621 [client _makeDocumentView];
1625 case WebFrameLoadTypeReload:
1626 case WebFrameLoadTypeSame:
1627 case WebFrameLoadTypeReplace:
1628 [client _updateHistoryForReload];
1629 [client _makeDocumentView];
1632 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1633 case WebFrameLoadTypeReloadAllowingStaleData:
1634 [client _makeDocumentView];
1637 case WebFrameLoadTypeStandard:
1638 [client _updateHistoryForStandardLoad];
1639 [client _makeDocumentView];
1642 case WebFrameLoadTypeInternal:
1643 [client _updateHistoryForInternalLoad];
1644 [client _makeDocumentView];
1647 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1648 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1650 ASSERT_NOT_REACHED();
1653 // Tell the client we've committed this URL.
1654 ASSERT([[client frameView] documentView] != nil);
1655 [[client webView] _didCommitLoadForFrame:client];
1656 [client _dispatchDidCommitLoadForFrame];
1658 // If we have a title let the WebView know about it.
1660 [client _dispatchDidReceiveTitle:ptitle];
1663 - (void)checkLoadCompleteForThisFrame
1665 ASSERT([client webView] != nil);
1667 switch ([self state]) {
1668 case WebFrameStateProvisional: {
1669 if (delegateIsHandlingProvisionalLoadError)
1672 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
1674 // If we've received any errors we may be stuck in the provisional state and actually complete.
1675 NSError *error = [pdl mainDocumentError];
1677 // Check all children first.
1678 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1679 BOOL shouldReset = YES;
1680 if (![pdl isLoadingInAPISense]) {
1681 [[client webView] _didFailProvisionalLoadWithError:error forFrame:client];
1682 delegateIsHandlingProvisionalLoadError = YES;
1683 [client _dispatchDidFailProvisionalLoadWithError:error];
1685 delegateIsHandlingProvisionalLoadError = NO;
1686 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1688 // FIXME: can stopping loading here possibly have
1689 // any effect, if isLoading is false, which it
1690 // must be, to be in this branch of the if? And is it ok to just do
1691 // a full-on stopLoading?
1692 [self stopLoadingSubframes];
1695 // Finish resetting the load state, but only if another load hasn't been started by the
1696 // delegate callback.
1697 if (pdl == provisionalDocumentLoader)
1698 [self clearProvisionalLoad];
1700 NSURL *unreachableURL = [provisionalDocumentLoader unreachableURL];
1701 if (unreachableURL != nil && [unreachableURL isEqual:[[pdl request] URL]])
1706 [client _resetAfterLoadError:resetToken];
1708 [client _doNotResetAfterLoadError:resetToken];
1714 case WebFrameStateCommittedPage: {
1715 WebDocumentLoader *dl = documentLoader;
1717 if (![dl isLoadingInAPISense]) {
1718 [self markLoadComplete];
1720 // FIXME: Is this subsequent work important if we already navigated away?
1721 // Maybe there are bugs because of that, or extra work we can skip because
1722 // the new page is ready.
1724 [client _forceLayoutForNonHTML];
1726 // If the user had a scroll point scroll to it. This will override
1727 // the anchor point. After much discussion it was decided by folks
1728 // that the user scroll point should override the anchor point.
1729 if ([[client webView] backForwardList]) {
1730 switch ([self loadType]) {
1731 case WebFrameLoadTypeForward:
1732 case WebFrameLoadTypeBack:
1733 case WebFrameLoadTypeIndexedBackForward:
1734 case WebFrameLoadTypeReload:
1735 [client _restoreScrollPositionAndViewState];
1738 case WebFrameLoadTypeStandard:
1739 case WebFrameLoadTypeInternal:
1740 case WebFrameLoadTypeReloadAllowingStaleData:
1741 case WebFrameLoadTypeSame:
1742 case WebFrameLoadTypeReplace:
1747 ASSERT_NOT_REACHED();
1752 NSError *error = [dl mainDocumentError];
1754 [[client webView] _didFailLoadWithError:error forFrame:client];
1755 [client _dispatchDidFailLoadWithError:error];
1756 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:error];
1758 [[client webView] _didFinishLoadForFrame:client];
1759 [client _dispatchDidFinishLoadForFrame];
1760 [[client _internalLoadDelegate] webFrame:client didFinishLoadWithError:nil];
1763 [[client webView] _progressCompleted:client];
1770 case WebFrameStateComplete:
1771 // Even if already complete, we might have set a previous item on a frame that
1772 // didn't do any data loading on the past transaction. Make sure to clear these out.
1773 [client _frameLoadCompleted];
1777 ASSERT_NOT_REACHED();
1780 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1785 WebFrameBridge *bridge = [self bridge];
1788 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1792 WebFrameBridge *mainBridge = [mainFrame _bridge];
1793 [mainBridge retain];
1795 [mainBridge setName:frameName];
1797 [mainFrame _dispatchShow];
1799 [mainBridge setOpener:bridge];
1800 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1802 [mainBridge release];
1808 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1810 if (response != nil)
1811 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1814 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1817 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1819 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1822 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1824 ASSERT(request != nil);
1826 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1827 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1829 if (newRequest == nil)
1830 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1837 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1839 if (frameName == nil) {
1840 [client loadRequest:request];
1844 WebFrame *frame = [client findFrameNamed:frameName];
1846 [frame loadRequest:request];
1850 NSDictionary *action = [self actionInformationForNavigationType:WebNavigationTypeOther
1851 event:nil originalURL:[request URL]];
1852 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1853 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1856 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1857 data:(NSArray *)postData contentType:(NSString *)contentType
1858 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1860 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1861 // This prevents a potential bug which may cause a page with a form that uses itself
1862 // as an action to be returned from the cache without submitting.
1864 // FIXME: Where's the code that implements what the comment above says?
1866 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1867 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1868 [request setValue:referrer forHTTPHeaderField:@"Referer"];
1869 [request setHTTPMethod:@"POST"];
1870 webSetHTTPBody(request, postData);
1871 [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
1873 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1874 WebFormState *formState = nil;
1876 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:[client _bridge]];
1878 if (target != nil) {
1879 WebFrame *targetFrame = [client findFrameNamed:target];
1880 if (targetFrame != nil)
1881 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1883 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1884 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1886 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1889 [formState release];
1892 - (void)detachChildren
1894 // FIXME: is it really necessary to do this in reverse order any more?
1895 WebFrame *child = [client _lastChildFrame];
1896 WebFrame *prev = [child _previousSiblingFrame];
1897 for (; child; child = prev, prev = [child _previousSiblingFrame])
1898 [[child _frameLoader] detachFromParent];
1901 - (void)detachFromParent
1903 WebFrameBridge *bridge = [[self bridge] retain];
1907 [client _detachedFromParent1];
1908 [self detachChildren];
1909 [client _detachedFromParent2];
1910 [self setDocumentLoader:nil];
1911 [client _detachedFromParent3];
1912 [[[client parentFrame] _bridge] removeChild:bridge];
1914 NSObject <WebFrameLoaderClient>* c = [client retain];
1916 [c _detachedFromParent4];
1922 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1924 [request setValue:[[client webView] userAgentForURL:[request URL]] forHTTPHeaderField:@"User-Agent"];
1926 if ([self loadType] == FrameLoadTypeReload)
1927 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1929 // Don't set the cookie policy URL if it's already been set.
1930 if ([request mainDocumentURL] == nil) {
1931 if (mainResource && (client == [[client webView] mainFrame] || f))
1932 [request setMainDocumentURL:[request URL]];
1934 [request setMainDocumentURL:[[[[client webView] mainFrame] dataSource] _URL]];
1938 [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"];
1941 - (void)safeLoadURL:(NSURL *)URL
1943 // Call the bridge because this is where our security checks are made.
1944 [[self bridge] loadURL:URL
1945 referrer:[[[documentLoader request] URL] _web_originalDataAsString]
1949 triggeringEvent:[NSApp currentEvent]
1954 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1956 WebNavigationType navType;
1957 if (isFormSubmission) {
1958 navType = WebNavigationTypeFormSubmitted;
1959 } else if (event == nil) {
1960 if (type == FrameLoadTypeReload)
1961 navType = WebNavigationTypeReload;
1962 else if (isBackForwardLoadType(type))
1963 navType = WebNavigationTypeBackForward;
1965 navType = WebNavigationTypeOther;
1967 navType = WebNavigationTypeLinkClicked;
1969 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
1972 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1974 switch ([event type]) {
1975 case NSLeftMouseDown:
1976 case NSRightMouseDown:
1977 case NSOtherMouseDown:
1979 case NSRightMouseUp:
1980 case NSOtherMouseUp: {
1981 NSView *topViewInEventWindow = [[event window] contentView];
1982 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1983 while (viewContainingPoint != nil) {
1984 if ([viewContainingPoint isKindOfClass:[WebView class]])
1986 viewContainingPoint = [viewContainingPoint superview];
1988 if (viewContainingPoint != nil) {
1989 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1990 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
1991 return [NSDictionary dictionaryWithObjectsAndKeys:
1992 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1993 elementInfo, WebActionElementKey,
1994 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1995 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1996 URL, WebActionOriginalURLKey,
2004 return [NSDictionary dictionaryWithObjectsAndKeys:
2005 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
2006 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
2007 URL, WebActionOriginalURLKey,
2012 // Called every time a resource is completely loaded, or an error is received.
2013 - (void)checkLoadComplete
2015 ASSERT([client webView] != nil);
2018 for (WebFrame *frame = client; frame; frame = parent) {
2020 [[frame _frameLoader] checkLoadCompleteForThisFrame];
2021 parent = [frame parentFrame];