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 "WebFrameLoaderClient.h"
36 #import "WebMainResourceLoader.h"
37 #import <JavaScriptCore/Assertions.h>
38 #import <WebKit/DOMHTML.h>
39 #import <WebCore/WebCoreFrameBridge.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)initWithFrame:(WebCoreFrameBridge *)bridge client:(WebFrame <WebFrameLoaderClient> *)c
82 state = WebFrameStateCommittedPage;
89 // FIXME: should these even exist?
90 [mainResourceLoader release];
91 [subresourceLoaders release];
92 [plugInStreamLoaders release];
93 [documentLoader release];
94 [provisionalDocumentLoader release];
96 ASSERT(!policyDocumentLoader);
101 - (WebDocumentLoader *)activeDocumentLoader
103 if (state == WebFrameStateProvisional)
104 return provisionalDocumentLoader;
106 return documentLoader;
109 - (void)addPlugInStreamLoader:(WebLoader *)loader
111 if (!plugInStreamLoaders)
112 plugInStreamLoaders = [[NSMutableArray alloc] init];
113 [plugInStreamLoaders addObject:loader];
114 [[self activeDocumentLoader] setLoading:YES];
117 - (void)removePlugInStreamLoader:(WebLoader *)loader
119 [plugInStreamLoaders removeObject:loader];
120 [[self activeDocumentLoader] updateLoading];
123 - (void)defersCallbacksChanged
125 BOOL defers = [frameBridge defersLoading];
126 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
127 [[frame _frameLoader] setDefersCallbacks:defers];
130 - (BOOL)defersCallbacks
132 return [frameBridge defersLoading];
135 - (void)setDefersCallbacks:(BOOL)defers
137 [mainResourceLoader setDefersCallbacks:defers];
139 NSEnumerator *e = [subresourceLoaders objectEnumerator];
141 while ((loader = [e nextObject]))
142 [loader setDefersCallbacks:defers];
144 e = [plugInStreamLoaders objectEnumerator];
145 while ((loader = [e nextObject]))
146 [loader setDefersCallbacks:defers];
148 [self deliverArchivedResourcesAfterDelay];
151 - (void)stopLoadingPlugIns
153 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
154 [plugInStreamLoaders removeAllObjects];
157 - (BOOL)isLoadingMainResource
159 return mainResourceLoader != nil;
162 - (BOOL)isLoadingSubresources
164 return [subresourceLoaders count];
167 - (BOOL)isLoadingPlugIns
169 return [plugInStreamLoaders count];
174 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
177 - (void)stopLoadingSubresources
179 NSArray *loaders = [subresourceLoaders copy];
180 [loaders makeObjectsPerformSelector:@selector(cancel)];
182 [subresourceLoaders removeAllObjects];
185 - (void)addSubresourceLoader:(WebLoader *)loader
187 ASSERT(!provisionalDocumentLoader);
188 if (subresourceLoaders == nil)
189 subresourceLoaders = [[NSMutableArray alloc] init];
190 [subresourceLoaders addObject:loader];
191 [[self activeDocumentLoader] setLoading:YES];
194 - (void)removeSubresourceLoader:(WebLoader *)loader
196 [subresourceLoaders removeObject:loader];
197 [[self activeDocumentLoader] updateLoading];
200 - (NSData *)mainResourceData
202 return [mainResourceLoader resourceData];
205 - (void)releaseMainResourceLoader
207 [mainResourceLoader release];
208 mainResourceLoader = nil;
211 - (void)cancelMainResourceLoad
213 [mainResourceLoader cancel];
216 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
218 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
220 [mainResourceLoader setIdentifier:identifier];
221 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
222 if (![mainResourceLoader loadWithRequest:request]) {
223 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
224 // should it be caught by other parts of WebKit or other parts of the app?
225 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
226 [mainResourceLoader release];
227 mainResourceLoader = nil;
234 - (void)stopLoadingWithError:(NSError *)error
236 [mainResourceLoader cancelWithError:error];
239 - (void)setDocumentLoader:(WebDocumentLoader *)loader
241 if (loader == nil && documentLoader == nil)
244 ASSERT(loader != documentLoader);
246 [client _prepareForDataSourceReplacement];
247 [documentLoader detachFromFrameLoader];
250 [documentLoader release];
251 documentLoader = loader;
254 - (WebDocumentLoader *)documentLoader
256 return documentLoader;
259 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
261 if (policyDocumentLoader == loader)
264 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
265 [policyDocumentLoader detachFromFrameLoader];
267 [policyDocumentLoader release];
269 policyDocumentLoader = loader;
272 - (WebDocumentLoader *)provisionalDocumentLoader
274 return provisionalDocumentLoader;
277 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
279 ASSERT(!loader || !provisionalDocumentLoader);
281 if (provisionalDocumentLoader != documentLoader)
282 [provisionalDocumentLoader detachFromFrameLoader];
285 [provisionalDocumentLoader release];
286 provisionalDocumentLoader = loader;
289 - (WebFrameState)state
295 static const char * const stateNames[] = {
296 "WebFrameStateProvisional",
297 "WebFrameStateCommittedPage",
298 "WebFrameStateComplete"
302 static CFAbsoluteTime _timeOfLastCompletedLoad;
304 + (CFAbsoluteTime)timeOfLastCompletedLoad
306 return _timeOfLastCompletedLoad;
309 - (void)provisionalLoadStarted
311 firstLayoutDone = NO;
312 [frameBridge provisionalLoadStarted];
314 [client _provisionalLoadStarted];
317 - (void)setState:(WebFrameState)newState
321 if (state == WebFrameStateProvisional)
322 [self provisionalLoadStarted];
323 else if (state == WebFrameStateComplete) {
324 [self frameLoadCompleted];
325 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
326 [[self documentLoader] stopRecordingResponses];
330 - (void)clearProvisionalLoad
332 [self setProvisionalDocumentLoader:nil];
333 [client _progressCompleted];
334 [self setState:WebFrameStateComplete];
337 - (void)markLoadComplete
339 [self setState:WebFrameStateComplete];
342 - (void)commitProvisionalLoad
344 [self stopLoadingSubresources];
345 [self stopLoadingPlugIns];
347 [self setDocumentLoader:provisionalDocumentLoader];
348 [self setProvisionalDocumentLoader:nil];
349 [self setState:WebFrameStateCommittedPage];
352 - (void)stopLoadingSubframes
354 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
355 [[(WebFrameBridge *)child frameLoader] stopLoading];
360 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
364 isStoppingLoad = YES;
366 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
368 [self stopLoadingSubframes];
369 [provisionalDocumentLoader stopLoading];
370 [documentLoader stopLoading];
371 [self setProvisionalDocumentLoader:nil];
372 [self clearArchivedResources];
377 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
380 [provisionalDocumentLoader prepareForLoadStart];
382 if ([self isLoadingMainResource])
385 [client _clearLoadingFromPageCacheForDocumentLoader:provisionalDocumentLoader];
387 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
389 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
390 [provisionalDocumentLoader updateLoading];
393 - (void)startProvisionalLoad:(WebDocumentLoader *)loader
395 [self setProvisionalDocumentLoader:loader];
396 [self setState:WebFrameStateProvisional];
399 - (void)setupForReplace
401 [self setState:WebFrameStateProvisional];
402 WebDocumentLoader *old = provisionalDocumentLoader;
403 provisionalDocumentLoader = documentLoader;
404 documentLoader = nil;
407 [self detachChildren];
410 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
412 // FIXME: why retain here, but not in the other place this happens?
414 // The identifier is released after the last callback, rather than in dealloc,
415 // to avoid potential cycles.
416 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
419 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
421 [clientRequest setValue:[frameBridge 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 _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 [client _incrementProgressForIdentifier:identifier data:data];
446 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
449 - (void)_didFinishLoadingForResource:(id)identifier
451 [client _completeProgressForIdentifier:identifier];
452 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
455 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
457 [client _completeProgressForIdentifier:identifier];
459 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
462 - (BOOL)_privateBrowsingEnabled
464 return [client _privateBrowsingEnabled];
467 - (void)_finishedLoadingResource
469 [self checkLoadComplete];
472 - (void)_receivedError:(NSError *)error
474 [self checkLoadComplete];
477 - (NSURLRequest *)_originalRequest
479 return [[self activeDocumentLoader] originalRequestCopy];
482 - (WebFrame *)webFrame
487 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
489 WebDocumentLoader *loader = [self activeDocumentLoader];
492 WebCoreFrameBridge *bridge = frameBridge;
494 // Retain the bridge because the stop may release the last reference to it.
497 WebFrame *cli = [client retain];
500 // FIXME: Don't want to do this if an entirely new load is going, so should check
501 // that both data sources on the frame are either self or nil.
502 // Can't call _bridge because we might not have commited yet
504 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
505 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
506 [bridge handleFallbackContent];
509 if ([self state] == WebFrameStateProvisional) {
510 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
511 [bridge didNotOpenURL:failedURL];
512 [client _invalidateCurrentItemPageCache];
514 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
515 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
516 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
517 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
519 if (sentRedirectNotification)
520 [self clientRedirectCancelledOrFinished:NO];
524 [loader mainReceivedError:error complete:isComplete];
531 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
533 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
534 // the redirect succeeded. We should either rename this API, or add a new method, like
535 // -webView:didFinishClientRedirectForFrame:
536 [client _dispatchDidCancelClientRedirectForFrame];
538 if (!cancelWithLoadInProgress)
539 quickRedirectComing = NO;
541 sentRedirectNotification = NO;
544 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
546 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
548 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
549 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
550 sentRedirectNotification = YES;
552 // If a "quick" redirect comes in an, we set a special mode so we treat the next
553 // load as part of the same navigation.
555 if (!documentLoader || isJavaScriptFormAction) {
556 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
557 // so we better just treat the redirect as a normal load.
558 quickRedirectComing = NO;
560 quickRedirectComing = lockHistory;
564 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
566 return !(([currentURL fragment] || [destinationURL fragment]) &&
567 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
570 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
571 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
573 BOOL isFormSubmission = (values != nil);
575 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
576 [request setValue:referrer forHTTPHeaderField:@"Referer"];
577 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
578 if (_loadType == FrameLoadTypeReload)
579 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
581 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
582 // policy of LoadFromOrigin, but I didn't test that.
583 ASSERT(_loadType != FrameLoadTypeSame);
585 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
586 WebFormState *formState = nil;
588 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
591 WebFrame *targetFrame = [client findFrameNamed:target];
592 if (targetFrame != nil) {
593 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
595 [self checkNewWindowPolicyForRequest:request
600 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
607 WebDocumentLoader *oldDocumentLoader = [documentLoader retain];
609 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
611 // Make sure to do scroll to anchor processing even if the URL is
612 // exactly the same so pages with '#' links and DHTML side effects
614 if (!isFormSubmission
615 && _loadType != FrameLoadTypeReload
616 && _loadType != FrameLoadTypeSame
617 && ![self shouldReloadForCurrent:URL andDestination:[frameBridge URL]]
619 // We don't want to just scroll if a link from within a
620 // frameset is trying to reload the frameset into _top.
621 && ![frameBridge isFrameSet]) {
623 // Just do anchor navigation within the existing content.
625 // We don't do this if we are submitting a form, explicitly reloading,
626 // currently displaying a frameset, or if the new URL does not have a fragment.
627 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
629 // FIXME: What about load types other than Standard and Reload?
631 [oldDocumentLoader setTriggeringAction:action];
632 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
633 [self checkNavigationPolicyForRequest:request
634 documentLoader:oldDocumentLoader formState:formState
635 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
637 // must grab this now, since this load may stop the previous load and clear this flag
638 BOOL isRedirect = quickRedirectComing;
639 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
641 quickRedirectComing = NO;
642 [provisionalDocumentLoader setIsClientRedirect:YES];
643 } else if (sameURL) {
644 // Example of this case are sites that reload the same URL with a different cookie
645 // driving the generated content, or a master frame with links that drive a target
646 // frame, where the user has clicked on the same link repeatedly.
647 [self setLoadType:FrameLoadTypeSame];
652 [oldDocumentLoader release];
656 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
661 NSURL *URL = [request URL];
663 BOOL isRedirect = quickRedirectComing;
664 quickRedirectComing = NO;
666 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
667 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
668 // NB: must happen after _setURL, since we add based on the current request.
669 // Must also happen before we openURL and displace the scroll position, since
670 // adding the BF item will save away scroll state.
672 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
673 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
674 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
675 // though its load is not yet done. I think this all works out OK, for one because
676 // we have already saved away the scroll and doc state for the long slow load,
677 // but it's not an obvious case.
679 [client _addHistoryItemForFragmentScroll];
682 [frameBridge scrollToAnchorWithURL:URL];
685 // This will clear previousItem from the rest of the frame tree tree that didn't
686 // doing any loading. We need to make a pass on this now, since for anchor nav
687 // we'll not go through a real load and reach Completed state
688 [self checkLoadComplete];
691 [client _dispatchDidChangeLocationWithinPageForFrame];
692 [client _didFinishLoad];
695 - (void)closeOldDataSources
697 // FIXME: is it important for this traversal to be postorder instead of preorder?
698 // FIXME: add helpers for postorder traversal?
699 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
700 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
703 [client _dispatchWillCloseFrame];
705 [client _setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
708 // Called after we send an openURL:... down to WebCore.
711 if ([self loadType] == FrameLoadTypeStandard && [documentLoader isClientRedirect])
712 [client _updateHistoryAfterClientRedirect];
714 if ([client _isDocumentLoaderLoadingFromPageCache:documentLoader]) {
715 // Force a layout to update view size and thereby update scrollbars.
716 [client _forceLayout];
718 NSArray *responses = [[self documentLoader] responses];
719 NSURLResponse *response;
720 int i, count = [responses count];
721 for (i = 0; i < count; i++) {
722 response = [responses objectAtIndex: i];
723 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
726 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
727 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
728 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
732 [client _loadedFromPageCache];
734 [[self documentLoader] setPrimaryLoadComplete:YES];
736 // FIXME: Why only this frame and not parent frames?
737 [self checkLoadCompleteForThisFrame];
741 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
743 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
745 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
747 NSURLResponse *response = [pdl response];
749 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
750 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
752 if (loadType != FrameLoadTypeReplace)
753 [self closeOldDataSources];
756 [client _makeRepresentationForDocumentLoader:pdl];
758 [self transitionToCommitted:pageCache];
760 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
761 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
762 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
763 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
764 if (sentRedirectNotification)
765 [self clientRedirectCancelledOrFinished:NO];
767 NSURL *baseURL = [[provisionalDocumentLoader request] _webDataRequestBaseURL];
768 NSURL *URL = baseURL ? baseURL : [response URL];
770 if (!URL || [URL _web_isEmpty])
771 URL = [NSURL URLWithString:@"about:blank"];
773 [frameBridge openURL:URL
775 contentType:[response MIMEType]
776 refresh:[headers objectForKey:@"Refresh"]
777 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
778 pageCache:pageCache];
785 - (NSURLRequest *)initialRequest
787 return [[self activeDocumentLoader] initialRequest];
790 - (void)_receivedData:(NSData *)data
792 [[self activeDocumentLoader] receivedData:data];
795 - (void)_setRequest:(NSURLRequest *)request
797 [[self activeDocumentLoader] setRequest:request];
800 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
801 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
803 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
806 - (WebCoreFrameBridge *)bridge
811 - (void)_handleFallbackContent
813 [frameBridge handleFallbackContent];
818 return [[self activeDocumentLoader] isStopping];
821 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
823 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
826 - (void)_setResponse:(NSURLResponse *)response
828 [[self activeDocumentLoader] setResponse:response];
831 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
833 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
836 - (void)_finishedLoading
838 WebDocumentLoader *dl = [self activeDocumentLoader];
840 WebCoreFrameBridge *bridge = frameBridge;
843 [dl finishedLoading];
845 if ([dl mainDocumentError] || ![dl frameLoader]) {
850 [dl setPrimaryLoadComplete:YES];
851 [client _dispatchDidLoadMainResourceForDocumentLoader:dl];
852 [self checkLoadComplete];
857 - (void)_notifyIconChanged:(NSURL *)iconURL
859 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
860 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDocumentLoader] URL] _web_originalDataAsString] withSize:WebIconSmallSize];
861 [client _dispatchDidReceiveIcon:icon];
866 return [[self activeDocumentLoader] URL];
869 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
871 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
874 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
876 return [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist URL:[response URL]];
879 - (void)clearArchivedResources
881 [pendingArchivedResources removeAllObjects];
882 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
885 - (void)deliverArchivedResources
887 if (![pendingArchivedResources count] || [self defersCallbacks])
890 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
892 while ((loader = [keyEnum nextObject])) {
893 WebResource *resource = [pendingArchivedResources objectForKey:loader];
894 [loader didReceiveResponse:[resource _response]];
895 NSData *data = [resource data];
896 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
897 [loader didFinishLoading];
900 [pendingArchivedResources removeAllObjects];
903 - (void)deliverArchivedResourcesAfterDelay
905 if (![pendingArchivedResources count] || [self defersCallbacks])
908 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
911 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
912 // FIXME: It would be nice to eventually to share this code somehow.
913 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
915 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
917 if (policy == NSURLRequestReturnCacheDataElseLoad) {
919 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
921 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
923 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
925 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
927 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
929 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
931 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
938 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
940 if (wkGetNSURLResponseMustRevalidate(response))
942 if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
947 - (NSMutableDictionary *)pendingArchivedResources
949 if (!pendingArchivedResources)
950 pendingArchivedResources = [[NSMutableDictionary alloc] init];
952 return pendingArchivedResources;
955 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
957 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
958 WebResource *resource = [client _archivedSubresourceForURL:originalURL fromDocumentLoader:[self activeDocumentLoader]];
959 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
960 CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
961 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
962 [self deliverArchivedResourcesAfterDelay];
969 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
971 return [pendingArchivedResources objectForKey:loader] != nil;
974 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
976 [pendingArchivedResources removeObjectForKey:loader];
978 if (![pendingArchivedResources count])
979 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
982 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
984 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
987 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
989 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
992 - (BOOL)isHostedByObjectElement
994 // Handle <object> fallback for error cases.
995 DOMHTMLElement *hostElement = [client frameElement];
996 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
999 - (BOOL)isLoadingMainFrame
1001 return [client _isMainFrame];
1004 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1006 return [WebView canShowMIMEType:MIMEType];
1009 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1011 return [WebView _representationExistsForURLScheme:URLScheme];
1014 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1016 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1019 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1021 [self checkNavigationPolicyForRequest:newRequest
1022 documentLoader:[self activeDocumentLoader]
1028 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1030 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1035 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1040 - (void)cancelContentPolicy
1042 [listener _invalidate];
1047 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1049 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1050 if (unreachableURL == nil)
1053 if (!isBackForwardLoadType(policyLoadType))
1056 // We only treat unreachableURLs specially during the delegate callbacks
1057 // for provisional load errors and navigation policy decisions. The former
1058 // case handles well-formed URLs that can't be loaded, and the latter
1059 // case handles malformed URLs and unknown schemes. Loading alternate content
1060 // at other times behaves like a standard load.
1061 WebDocumentLoader *compareDocumentLoader = nil;
1062 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1063 compareDocumentLoader = policyDocumentLoader;
1064 else if (delegateIsHandlingProvisionalLoadError)
1065 compareDocumentLoader = [self provisionalDocumentLoader];
1067 return compareDocumentLoader != nil && [unreachableURL isEqual:[[compareDocumentLoader request] URL]];
1070 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1074 ASSERT(!policyDocumentLoader);
1075 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1076 WebDataSource *newDataSource = [client _dataSourceForDocumentLoader:policyDocumentLoader];
1078 NSMutableURLRequest *r = [newDataSource request];
1079 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1080 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1081 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1082 type = FrameLoadTypeSame;
1084 type = FrameLoadTypeStandard;
1086 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1087 [newDataSource _addToUnarchiveState:archive];
1089 // When we loading alternate content for an unreachable URL that we're
1090 // visiting in the b/f list, we treat it as a reload so the b/f list
1091 // is appropriately maintained.
1092 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1093 ASSERT(type == FrameLoadTypeStandard);
1094 type = FrameLoadTypeReload;
1097 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:nil];
1100 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1102 ASSERT(!policyDocumentLoader);
1103 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1105 [policyDocumentLoader setTriggeringAction:action];
1106 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1108 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:formState];
1111 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1113 if (documentLoader == nil)
1116 NSMutableURLRequest *request = [[documentLoader request] mutableCopy];
1117 NSURL *unreachableURL = [documentLoader unreachableURL];
1118 if (unreachableURL != nil)
1119 [request setURL:unreachableURL];
1121 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1122 ASSERT(!policyDocumentLoader);
1123 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1126 [policyDocumentLoader setOverrideEncoding:encoding];
1128 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1133 if (documentLoader == nil)
1136 NSMutableURLRequest *initialRequest = [documentLoader request];
1138 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1139 // Reloading in this case will lose the current contents (see 4151001).
1140 if ([[[[documentLoader request] URL] absoluteString] length] == 0)
1143 // Replace error-page URL with the URL we were trying to reach.
1144 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1145 if (unreachableURL != nil)
1146 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1148 ASSERT(!policyDocumentLoader);
1149 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1150 NSMutableURLRequest *request = [policyDocumentLoader request];
1152 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1154 // If we're about to rePOST, set up action so the app can warn the user
1155 if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1156 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeFormResubmitted
1157 event:nil originalURL:[request URL]];
1158 [policyDocumentLoader setTriggeringAction:action];
1161 [policyDocumentLoader setOverrideEncoding:[documentLoader overrideEncoding]];
1163 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReload formState:nil];
1166 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1168 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1171 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1173 [[client _dataSourceForDocumentLoader:loader] _finishedLoading];
1176 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1178 [[client _dataSourceForDocumentLoader:loader] _receivedData:data];
1183 return loadType == FrameLoadTypeReplace;
1186 - (void)setReplacing
1188 loadType = FrameLoadTypeReplace;
1191 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1193 [[client _dataSourceForDocumentLoader:loader] _revertToProvisionalState];
1196 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1198 [[client _dataSourceForDocumentLoader:loader] _setMainDocumentError:error];
1201 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1203 [loader setPrimaryLoadComplete:YES];
1204 [client _dispatchDidLoadMainResourceForDocumentLoader:[self activeDocumentLoader]];
1205 [self checkLoadComplete];
1208 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1210 [[client _dataSourceForDocumentLoader:loader] _clearUnarchivingState];
1213 - (void)prepareForLoadStart
1215 [client _progressStarted];
1216 [client _dispatchDidStartProvisionalLoadForFrame];
1219 - (BOOL)subframeIsLoading
1221 // It's most likely that the last added frame is the last to load so we walk backwards.
1222 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1223 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1228 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1230 [client _willChangeTitleForDocument:loader];
1233 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1235 [client _didChangeTitleForDocument:loader];
1237 // The title doesn't get communicated to the WebView until we are committed.
1238 if ([loader isCommitted]) {
1239 NSURL *URLForHistory = [[client _dataSourceForDocumentLoader:loader] _URLForHistory];
1240 if (URLForHistory != nil) {
1241 // Must update the entries in the back-forward list too.
1242 // This must go through the WebFrame because it has the right notion of the current b/f item.
1243 [client _setTitle:[loader title] forURL:URLForHistory];
1244 [client _setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1245 [client _dispatchDidReceiveTitle:[loader title]];
1250 - (FrameLoadType)loadType
1255 - (void)setLoadType:(FrameLoadType)type
1260 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1262 [listener _invalidate];
1266 NSURLRequest *request = policyRequest;
1267 NSString *frameName = policyFrameName;
1268 id target = policyTarget;
1269 SEL selector = policySelector;
1270 WebFormState *formState = policyFormState;
1272 policyRequest = nil;
1273 policyFrameName = nil;
1275 policySelector = nil;
1276 policyFormState = nil;
1280 objc_msgSend(target, selector, nil, nil, nil);
1282 objc_msgSend(target, selector, nil, nil);
1286 [frameName release];
1288 [formState release];
1291 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1293 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1294 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1296 policyRequest = [request retain];
1297 policyTarget = [target retain];
1298 policyFrameName = [frameName retain];
1299 policySelector = selector;
1300 listener = [decisionListener retain];
1301 policyFormState = [formState retain];
1303 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1305 [decisionListener release];
1308 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1310 NSURLRequest *request = [[policyRequest retain] autorelease];
1311 NSString *frameName = [[policyFrameName retain] autorelease];
1312 id target = [[policyTarget retain] autorelease];
1313 SEL selector = policySelector;
1314 WebFormState *formState = [[policyFormState retain] autorelease];
1316 // will release policy* objects, hence the above retains
1317 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1320 case WebPolicyIgnore:
1323 case WebPolicyDownload:
1324 [client _startDownloadWithRequest:request];
1331 objc_msgSend(target, selector, request, frameName, formState);
1334 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1335 documentLoader:(WebDocumentLoader *)loader
1336 formState:(WebFormState *)formState
1338 withSelector:(SEL)selector
1340 NSDictionary *action = [loader triggeringAction];
1341 if (action == nil) {
1342 action = [self actionInformationForNavigationType:NavigationTypeOther
1343 event:nil originalURL:[request URL]];
1344 [loader setTriggeringAction:action];
1347 // Don't ask more than once for the same request or if we are loading an empty URL.
1348 // This avoids confusion on the part of the client.
1349 if ([request isEqual:[loader lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1350 [target performSelector:selector withObject:request withObject:nil];
1354 // We are always willing to show alternate content for unreachable URLs;
1355 // treat it like a reload so it maintains the right state for b/f list.
1356 if ([request _webDataRequestUnreachableURL] != nil) {
1357 if (isBackForwardLoadType(policyLoadType))
1358 policyLoadType = FrameLoadTypeReload;
1359 [target performSelector:selector withObject:request withObject:nil];
1363 [loader setLastCheckedRequest:request];
1365 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1367 ASSERT(policyRequest == nil);
1368 policyRequest = [request retain];
1369 ASSERT(policyTarget == nil);
1370 policyTarget = [target retain];
1371 policySelector = selector;
1372 ASSERT(listener == nil);
1373 listener = [decisionListener retain];
1374 ASSERT(policyFormState == nil);
1375 policyFormState = [formState retain];
1377 delegateIsDecidingNavigationPolicy = YES;
1378 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1379 delegateIsDecidingNavigationPolicy = NO;
1381 [decisionListener release];
1384 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1386 NSURLRequest *request = [[policyRequest retain] autorelease];
1387 id target = [[policyTarget retain] autorelease];
1388 SEL selector = policySelector;
1389 WebFormState *formState = [[policyFormState retain] autorelease];
1391 // will release policy* objects, hence the above retains
1392 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1395 case WebPolicyIgnore:
1398 case WebPolicyDownload:
1399 [client _startDownloadWithRequest:request];
1403 if (![WebView _canHandleRequest:request]) {
1404 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1410 [target performSelector:selector withObject:request withObject:formState];
1413 // Called after the FormsDelegate is done processing willSubmitForm:
1414 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1417 [listener _invalidate];
1421 [self startLoading];
1424 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1426 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1427 // nil policyDataSource because loading the alternate page will have passed
1428 // through this method already, nested; otherwise, policyDataSource should still be set.
1429 ASSERT(policyDocumentLoader || [provisionalDocumentLoader unreachableURL] != nil);
1431 BOOL isTargetItem = [client _provisionalItemIsTarget];
1433 // Two reasons we can't continue:
1434 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1435 // is the user responding Cancel to the form repost nag sheet.
1436 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1437 // The "before unload" event handler runs only for the main frame.
1438 BOOL canContinue = request && (![self isLoadingMainFrame] || [frameBridge shouldClose]);
1441 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1442 // need to report that the client redirect was cancelled.
1443 if (quickRedirectComing)
1444 [self clientRedirectCancelledOrFinished:NO];
1446 [self setPolicyDocumentLoader:nil];
1448 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1449 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1450 // we only do this when punting a navigation for the target frame or top-level frame.
1451 if ((isTargetItem || [self isLoadingMainFrame]) && isBackForwardLoadType(policyLoadType))
1452 [client _resetBackForwardList];
1457 FrameLoadType type = policyLoadType;
1458 WebDocumentLoader *dl = [policyDocumentLoader retain];
1463 [self startProvisionalLoad:dl];
1466 [self setPolicyDocumentLoader:nil];
1468 if (isBackForwardLoadType(type)) {
1469 if ([client _loadProvisionalItemFromPageCache])
1474 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1475 // mechanism across the willSubmitForm callout.
1476 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1477 [[[client webView] _formDelegate] frame:client sourceFrame:[(WebFrameBridge *)[formState sourceFrame] webFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1479 [self continueAfterWillSubmitForm:WebPolicyUse];
1482 - (void)loadDocumentLoader:(WebDocumentLoader *)loader withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1484 ASSERT([client webView] != nil);
1486 // Unfortunately the view must be non-nil, this is ultimately due
1487 // to parser requiring a FrameView. We should fix this dependency.
1489 ASSERT([client frameView] != nil);
1491 policyLoadType = type;
1493 WebFrame *parentFrame = [client parentFrame];
1495 [loader setOverrideEncoding:[[[parentFrame dataSource] _documentLoader] overrideEncoding]];
1497 [loader setFrameLoader:self];
1499 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1501 [self setPolicyDocumentLoader:loader];
1503 [self checkNavigationPolicyForRequest:[loader request]
1504 documentLoader:loader
1507 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1510 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1512 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1513 delegateIsHandlingUnimplementablePolicy = YES;
1514 [client _dispatchUnableToImplementPolicyWithError:error];
1515 delegateIsHandlingUnimplementablePolicy = NO;
1518 - (void)didFirstLayout
1520 if (isBackForwardLoadType(loadType) && [client _hasBackForwardList])
1521 [client _restoreScrollPositionAndViewState];
1523 firstLayoutDone = YES;
1524 [client _dispatchDidFirstLayoutInFrame];
1527 - (void)frameLoadCompleted
1529 [client _frameLoadCompleted];
1531 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1533 firstLayoutDone = YES;
1536 - (BOOL)firstLayoutDone
1538 return firstLayoutDone;
1541 - (BOOL)isQuickRedirectComing
1543 return quickRedirectComing;
1546 - (void)transitionToCommitted:(NSDictionary *)pageCache
1548 ASSERT([client webView] != nil);
1549 ASSERT([self state] == WebFrameStateProvisional);
1551 if ([self state] != WebFrameStateProvisional)
1554 [client _setCopiesOnScroll];
1555 [client _updateHistoryForCommit];
1557 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1558 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1559 // or the two will stomp each other.
1560 WebDocumentLoader *pdl = provisionalDocumentLoader;
1561 [frameBridge closeURL];
1562 if (pdl != provisionalDocumentLoader)
1565 [self commitProvisionalLoad];
1567 // Handle adding the URL to the back/forward list.
1568 WebDocumentLoader *dl = documentLoader;
1569 NSString *ptitle = [dl title];
1572 case WebFrameLoadTypeForward:
1573 case WebFrameLoadTypeBack:
1574 case WebFrameLoadTypeIndexedBackForward:
1575 if ([client _hasBackForwardList]) {
1576 [client _updateHistoryForBackForwardNavigation];
1578 // Create a document view for this document, or used the cached view.
1580 [client _setDocumentViewFromPageCache:pageCache];
1582 [client _makeDocumentView];
1586 case WebFrameLoadTypeReload:
1587 case WebFrameLoadTypeSame:
1588 case WebFrameLoadTypeReplace:
1589 [client _updateHistoryForReload];
1590 [client _makeDocumentView];
1593 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1594 case WebFrameLoadTypeReloadAllowingStaleData:
1595 [client _makeDocumentView];
1598 case WebFrameLoadTypeStandard:
1599 [client _updateHistoryForStandardLoad];
1600 [client _makeDocumentView];
1603 case WebFrameLoadTypeInternal:
1604 [client _updateHistoryForInternalLoad];
1605 [client _makeDocumentView];
1608 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1609 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1611 ASSERT_NOT_REACHED();
1614 // Tell the client we've committed this URL.
1615 ASSERT([[client frameView] documentView] != nil);
1616 [client _dispatchDidCommitLoadForFrame];
1618 // If we have a title let the WebView know about it.
1620 [client _dispatchDidReceiveTitle:ptitle];
1623 - (void)checkLoadCompleteForThisFrame
1625 ASSERT([client webView] != nil);
1627 switch ([self state]) {
1628 case WebFrameStateProvisional: {
1629 if (delegateIsHandlingProvisionalLoadError)
1632 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
1634 // If we've received any errors we may be stuck in the provisional state and actually complete.
1635 NSError *error = [pdl mainDocumentError];
1637 // Check all children first.
1638 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1639 BOOL shouldReset = YES;
1640 if (![pdl isLoadingInAPISense]) {
1641 delegateIsHandlingProvisionalLoadError = YES;
1642 [client _dispatchDidFailProvisionalLoadWithError:error];
1643 delegateIsHandlingProvisionalLoadError = NO;
1645 // FIXME: can stopping loading here possibly have
1646 // any effect, if isLoading is false, which it
1647 // must be, to be in this branch of the if? And is it ok to just do
1648 // a full-on stopLoading?
1649 [self stopLoadingSubframes];
1652 // Finish resetting the load state, but only if another load hasn't been started by the
1653 // delegate callback.
1654 if (pdl == provisionalDocumentLoader)
1655 [self clearProvisionalLoad];
1657 NSURL *unreachableURL = [provisionalDocumentLoader unreachableURL];
1658 if (unreachableURL != nil && [unreachableURL isEqual:[[pdl request] URL]])
1663 [client _resetAfterLoadError:resetToken];
1665 [client _doNotResetAfterLoadError:resetToken];
1671 case WebFrameStateCommittedPage: {
1672 WebDocumentLoader *dl = documentLoader;
1674 if (![dl isLoadingInAPISense]) {
1675 [self markLoadComplete];
1677 // FIXME: Is this subsequent work important if we already navigated away?
1678 // Maybe there are bugs because of that, or extra work we can skip because
1679 // the new page is ready.
1681 [client _forceLayoutForNonHTML];
1683 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
1684 if ((isBackForwardLoadType([self loadType]) || [self loadType] == WebFrameLoadTypeReload)
1685 && [client _hasBackForwardList])
1686 [client _restoreScrollPositionAndViewState];
1688 NSError *error = [dl mainDocumentError];
1690 [client _dispatchDidFailLoadWithError:error];
1692 [client _dispatchDidFinishLoadForFrame];
1694 [client _progressCompleted];
1701 case WebFrameStateComplete:
1702 // Even if already complete, we might have set a previous item on a frame that
1703 // didn't do any data loading on the past transaction. Make sure to clear these out.
1704 [client _frameLoadCompleted];
1708 ASSERT_NOT_REACHED();
1711 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1716 WebCoreFrameBridge <WebCoreFrameBridge> *bridge = frameBridge;
1719 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1723 WebCoreFrameBridge *mainBridge = [mainFrame _frameLoader]->frameBridge;
1724 [mainBridge retain];
1726 [mainBridge setName:frameName];
1728 [mainFrame _dispatchShow];
1730 [mainBridge setOpener:bridge];
1731 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1733 [mainBridge release];
1739 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1741 if (response != nil)
1742 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1745 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1748 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1750 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1753 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1755 ASSERT(request != nil);
1757 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1758 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1760 if (newRequest == nil)
1761 *error = [NSError _webKitErrorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled URL:[request URL]];
1768 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1770 if (frameName == nil) {
1771 [client loadRequest:request];
1775 WebFrame *frame = [client findFrameNamed:frameName];
1777 [frame loadRequest:request];
1781 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeOther
1782 event:nil originalURL:[request URL]];
1783 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1784 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1787 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1788 data:(NSArray *)postData contentType:(NSString *)contentType
1789 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1791 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1792 // This prevents a potential bug which may cause a page with a form that uses itself
1793 // as an action to be returned from the cache without submitting.
1795 // FIXME: Where's the code that implements what the comment above says?
1797 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1798 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1799 [request setValue:referrer forHTTPHeaderField:@"Referer"];
1800 [request setHTTPMethod:@"POST"];
1801 webSetHTTPBody(request, postData);
1802 [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
1804 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1805 WebFormState *formState = nil;
1807 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
1809 if (target != nil) {
1810 WebFrame *targetFrame = [client findFrameNamed:target];
1811 if (targetFrame != nil)
1812 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1814 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1815 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1817 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1820 [formState release];
1823 - (void)detachChildren
1825 // FIXME: is it really necessary to do this in reverse order any more?
1826 WebFrame *child = [client _lastChildFrame];
1827 WebFrame *prev = [child _previousSiblingFrame];
1828 for (; child; child = prev, prev = [child _previousSiblingFrame])
1829 [[child _frameLoader] detachFromParent];
1832 - (void)detachFromParent
1834 WebCoreFrameBridge *bridge = [frameBridge retain];
1838 [client _detachedFromParent1];
1839 [self detachChildren];
1840 [client _detachedFromParent2];
1841 [self setDocumentLoader:nil];
1842 [client _detachedFromParent3];
1843 [[frameBridge parent] removeChild:bridge];
1845 NSObject <WebFrameLoaderClient>* c = [client retain];
1847 [c _detachedFromParent4];
1853 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1855 [request setValue:[frameBridge userAgentForURL:[request URL]] forHTTPHeaderField:@"User-Agent"];
1857 if ([self loadType] == FrameLoadTypeReload)
1858 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1860 // Don't set the cookie policy URL if it's already been set.
1861 if ([request mainDocumentURL] == nil) {
1862 if (mainResource && ([self isLoadingMainFrame] || f))
1863 [request setMainDocumentURL:[request URL]];
1865 [request setMainDocumentURL:[[[[client webView] mainFrame] dataSource] _URL]];
1869 [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"];
1872 - (void)safeLoadURL:(NSURL *)URL
1874 // Call the bridge because this is where our security checks are made.
1875 [frameBridge loadURL:URL
1876 referrer:[[[documentLoader request] URL] _web_originalDataAsString]
1880 triggeringEvent:[NSApp currentEvent]
1885 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1887 NavigationType navType;
1888 if (isFormSubmission) {
1889 navType = NavigationTypeFormSubmitted;
1890 } else if (event == nil) {
1891 if (type == FrameLoadTypeReload)
1892 navType = NavigationTypeReload;
1893 else if (isBackForwardLoadType(type))
1894 navType = NavigationTypeBackForward;
1896 navType = NavigationTypeOther;
1898 navType = NavigationTypeLinkClicked;
1900 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
1903 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1905 switch ([event type]) {
1906 case NSLeftMouseDown:
1907 case NSRightMouseDown:
1908 case NSOtherMouseDown:
1910 case NSRightMouseUp:
1911 case NSOtherMouseUp: {
1912 NSView *topViewInEventWindow = [[event window] contentView];
1913 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1914 while (viewContainingPoint != nil) {
1915 if ([viewContainingPoint isKindOfClass:[WebView class]])
1917 viewContainingPoint = [viewContainingPoint superview];
1919 if (viewContainingPoint != nil) {
1920 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1921 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
1922 return [NSDictionary dictionaryWithObjectsAndKeys:
1923 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1924 elementInfo, WebActionElementKey,
1925 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1926 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1927 URL, WebActionOriginalURLKey,
1935 return [NSDictionary dictionaryWithObjectsAndKeys:
1936 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1937 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1938 URL, WebActionOriginalURLKey,
1943 // Called every time a resource is completely loaded, or an error is received.
1944 - (void)checkLoadComplete
1946 ASSERT([client webView] != nil);
1949 for (WebFrame *frame = client; frame; frame = parent) {
1951 [[frame _frameLoader] checkLoadCompleteForThisFrame];
1952 parent = [frame parentFrame];