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/WebCoreIconDatabaseBridge.h>
41 #import <WebCore/WebCoreSystemInterface.h>
43 #import "WebFrameInternal.h"
44 #import "WebNSURLExtras.h"
45 #import "WebResourcePrivate.h"
46 #import "WebViewInternal.h"
48 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
50 return [a caseInsensitiveCompare:b] == NSOrderedSame;
53 BOOL isBackForwardLoadType(FrameLoadType type)
56 case FrameLoadTypeStandard:
57 case FrameLoadTypeReload:
58 case FrameLoadTypeReloadAllowingStaleData:
59 case FrameLoadTypeSame:
60 case FrameLoadTypeInternal:
61 case FrameLoadTypeReplace:
63 case FrameLoadTypeBack:
64 case FrameLoadTypeForward:
65 case FrameLoadTypeIndexedBackForward:
72 @implementation WebFrameLoader
74 - (id)initWithFrame:(WebCoreFrameBridge *)bridge client:(WebFrame <WebFrameLoaderClient> *)c
80 state = WebFrameStateCommittedPage;
87 // FIXME: should these even exist?
88 [mainResourceLoader release];
89 [subresourceLoaders release];
90 [plugInStreamLoaders release];
91 [documentLoader release];
92 [provisionalDocumentLoader release];
94 ASSERT(!policyDocumentLoader);
99 - (WebDocumentLoader *)activeDocumentLoader
101 if (state == WebFrameStateProvisional)
102 return provisionalDocumentLoader;
104 return documentLoader;
107 - (void)addPlugInStreamLoader:(WebLoader *)loader
109 if (!plugInStreamLoaders)
110 plugInStreamLoaders = [[NSMutableArray alloc] init];
111 [plugInStreamLoaders addObject:loader];
112 [[self activeDocumentLoader] setLoading:YES];
115 - (void)removePlugInStreamLoader:(WebLoader *)loader
117 [plugInStreamLoaders removeObject:loader];
118 [[self activeDocumentLoader] updateLoading];
121 - (void)defersCallbacksChanged
123 BOOL defers = [frameBridge defersLoading];
124 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
125 [[frame _frameLoader] setDefersCallbacks:defers];
128 - (BOOL)defersCallbacks
130 return [frameBridge defersLoading];
133 - (void)setDefersCallbacks:(BOOL)defers
135 [mainResourceLoader setDefersCallbacks:defers];
137 NSEnumerator *e = [subresourceLoaders objectEnumerator];
139 while ((loader = [e nextObject]))
140 [loader setDefersCallbacks:defers];
142 e = [plugInStreamLoaders objectEnumerator];
143 while ((loader = [e nextObject]))
144 [loader setDefersCallbacks:defers];
146 [self deliverArchivedResourcesAfterDelay];
149 - (void)stopLoadingPlugIns
151 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
152 [plugInStreamLoaders removeAllObjects];
155 - (BOOL)isLoadingMainResource
157 return mainResourceLoader != nil;
160 - (BOOL)isLoadingSubresources
162 return [subresourceLoaders count];
165 - (BOOL)isLoadingPlugIns
167 return [plugInStreamLoaders count];
172 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
175 - (void)stopLoadingSubresources
177 NSArray *loaders = [subresourceLoaders copy];
178 [loaders makeObjectsPerformSelector:@selector(cancel)];
180 [subresourceLoaders removeAllObjects];
183 - (void)addSubresourceLoader:(WebLoader *)loader
185 ASSERT(!provisionalDocumentLoader);
186 if (subresourceLoaders == nil)
187 subresourceLoaders = [[NSMutableArray alloc] init];
188 [subresourceLoaders addObject:loader];
189 [[self activeDocumentLoader] setLoading:YES];
192 - (void)removeSubresourceLoader:(WebLoader *)loader
194 [subresourceLoaders removeObject:loader];
195 [[self activeDocumentLoader] updateLoading];
198 - (NSData *)mainResourceData
200 return [mainResourceLoader resourceData];
203 - (void)releaseMainResourceLoader
205 [mainResourceLoader release];
206 mainResourceLoader = nil;
209 - (void)cancelMainResourceLoad
211 [mainResourceLoader cancel];
214 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
216 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
218 [mainResourceLoader setIdentifier:identifier];
219 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
220 if (![mainResourceLoader loadWithRequest:request]) {
221 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
222 // should it be caught by other parts of WebKit or other parts of the app?
223 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
224 [mainResourceLoader release];
225 mainResourceLoader = nil;
232 - (void)stopLoadingWithError:(NSError *)error
234 [mainResourceLoader cancelWithError:error];
237 - (void)setDocumentLoader:(WebDocumentLoader *)loader
239 if (loader == nil && documentLoader == nil)
242 ASSERT(loader != documentLoader);
244 [client _prepareForDataSourceReplacement];
245 [documentLoader detachFromFrameLoader];
248 [documentLoader release];
249 documentLoader = loader;
252 - (WebDocumentLoader *)documentLoader
254 return documentLoader;
257 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
259 if (policyDocumentLoader == loader)
262 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
263 [policyDocumentLoader detachFromFrameLoader];
265 [policyDocumentLoader release];
267 policyDocumentLoader = loader;
270 - (WebDocumentLoader *)provisionalDocumentLoader
272 return provisionalDocumentLoader;
275 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
277 ASSERT(!loader || !provisionalDocumentLoader);
279 if (provisionalDocumentLoader != documentLoader)
280 [provisionalDocumentLoader detachFromFrameLoader];
283 [provisionalDocumentLoader release];
284 provisionalDocumentLoader = loader;
287 - (WebFrameState)state
293 static const char * const stateNames[] = {
294 "WebFrameStateProvisional",
295 "WebFrameStateCommittedPage",
296 "WebFrameStateComplete"
300 static CFAbsoluteTime _timeOfLastCompletedLoad;
302 + (CFAbsoluteTime)timeOfLastCompletedLoad
304 return _timeOfLastCompletedLoad;
307 - (void)provisionalLoadStarted
309 firstLayoutDone = NO;
310 [frameBridge provisionalLoadStarted];
312 [client _provisionalLoadStarted];
315 - (void)setState:(WebFrameState)newState
319 if (state == WebFrameStateProvisional)
320 [self provisionalLoadStarted];
321 else if (state == WebFrameStateComplete) {
322 [self frameLoadCompleted];
323 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
324 [[self documentLoader] stopRecordingResponses];
328 - (void)clearProvisionalLoad
330 [self setProvisionalDocumentLoader:nil];
331 [client _progressCompleted];
332 [self setState:WebFrameStateComplete];
335 - (void)markLoadComplete
337 [self setState:WebFrameStateComplete];
340 - (void)commitProvisionalLoad
342 [self stopLoadingSubresources];
343 [self stopLoadingPlugIns];
345 [self setDocumentLoader:provisionalDocumentLoader];
346 [self setProvisionalDocumentLoader:nil];
347 [self setState:WebFrameStateCommittedPage];
350 - (void)stopLoadingSubframes
352 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
353 [[(WebFrameBridge *)child frameLoader] stopLoading];
358 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
362 isStoppingLoad = YES;
364 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
366 [self stopLoadingSubframes];
367 [provisionalDocumentLoader stopLoading];
368 [documentLoader stopLoading];
369 [self setProvisionalDocumentLoader:nil];
370 [self clearArchivedResources];
375 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
378 [provisionalDocumentLoader prepareForLoadStart];
380 if ([self isLoadingMainResource])
383 [client _clearLoadingFromPageCacheForDocumentLoader:provisionalDocumentLoader];
385 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
387 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
388 [provisionalDocumentLoader updateLoading];
391 - (void)startProvisionalLoad:(WebDocumentLoader *)loader
393 [self setProvisionalDocumentLoader:loader];
394 [self setState:WebFrameStateProvisional];
397 - (void)setupForReplace
399 [self setState:WebFrameStateProvisional];
400 WebDocumentLoader *old = provisionalDocumentLoader;
401 provisionalDocumentLoader = documentLoader;
402 documentLoader = nil;
405 [self detachChildren];
408 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
410 // FIXME: why retain here, but not in the other place this happens?
412 // The identifier is released after the last callback, rather than in dealloc,
413 // to avoid potential cycles.
414 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
417 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
419 [clientRequest setValue:[frameBridge userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
420 return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
423 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
425 [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
428 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
430 [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
433 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
435 [[self activeDocumentLoader] addResponse:r];
437 [client _incrementProgressForIdentifier:identifier response:r];
438 [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
441 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
443 [client _incrementProgressForIdentifier:identifier data:data];
444 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
447 - (void)_didFinishLoadingForResource:(id)identifier
449 [client _completeProgressForIdentifier:identifier];
450 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
453 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
455 [client _completeProgressForIdentifier:identifier];
457 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
460 - (BOOL)_privateBrowsingEnabled
462 return [client _privateBrowsingEnabled];
465 - (void)_finishedLoadingResource
467 [self checkLoadComplete];
470 - (void)_receivedError:(NSError *)error
472 [self checkLoadComplete];
475 - (NSURLRequest *)_originalRequest
477 return [[self activeDocumentLoader] originalRequestCopy];
480 - (WebFrame *)webFrame
485 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
487 WebDocumentLoader *loader = [self activeDocumentLoader];
490 WebCoreFrameBridge *bridge = frameBridge;
492 // Retain the bridge because the stop may release the last reference to it.
495 WebFrame *cli = [client retain];
498 // FIXME: Don't want to do this if an entirely new load is going, so should check
499 // that both data sources on the frame are either self or nil.
500 // Can't call _bridge because we might not have commited yet
502 if ([cli _shouldFallBackForError:error])
503 [bridge handleFallbackContent];
506 if ([self state] == WebFrameStateProvisional) {
507 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
508 [bridge didNotOpenURL:failedURL];
509 [client _invalidateCurrentItemPageCache];
511 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
512 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
513 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
514 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
516 if (sentRedirectNotification)
517 [self clientRedirectCancelledOrFinished:NO];
521 [loader mainReceivedError:error complete:isComplete];
528 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
530 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
531 // the redirect succeeded. We should either rename this API, or add a new method, like
532 // -webView:didFinishClientRedirectForFrame:
533 [client _dispatchDidCancelClientRedirectForFrame];
535 if (!cancelWithLoadInProgress)
536 quickRedirectComing = NO;
538 sentRedirectNotification = NO;
541 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
543 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
545 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
546 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
547 sentRedirectNotification = YES;
549 // If a "quick" redirect comes in an, we set a special mode so we treat the next
550 // load as part of the same navigation.
552 if (!documentLoader || isJavaScriptFormAction) {
553 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
554 // so we better just treat the redirect as a normal load.
555 quickRedirectComing = NO;
557 quickRedirectComing = lockHistory;
561 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
563 return !(([currentURL fragment] || [destinationURL fragment]) &&
564 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
567 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
568 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
570 BOOL isFormSubmission = (values != nil);
572 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
573 [request setValue:referrer forHTTPHeaderField:@"Referer"];
574 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
575 if (_loadType == FrameLoadTypeReload)
576 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
578 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
579 // policy of LoadFromOrigin, but I didn't test that.
580 ASSERT(_loadType != FrameLoadTypeSame);
582 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
583 WebFormState *formState = nil;
585 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
588 WebFrame *targetFrame = [client findFrameNamed:target];
589 if (targetFrame != nil) {
590 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
592 [self checkNewWindowPolicyForRequest:request
597 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
604 WebDocumentLoader *oldDocumentLoader = [documentLoader retain];
606 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
608 // Make sure to do scroll to anchor processing even if the URL is
609 // exactly the same so pages with '#' links and DHTML side effects
611 if (!isFormSubmission
612 && _loadType != FrameLoadTypeReload
613 && _loadType != FrameLoadTypeSame
614 && ![self shouldReloadForCurrent:URL andDestination:[frameBridge URL]]
616 // We don't want to just scroll if a link from within a
617 // frameset is trying to reload the frameset into _top.
618 && ![frameBridge isFrameSet]) {
620 // Just do anchor navigation within the existing content.
622 // We don't do this if we are submitting a form, explicitly reloading,
623 // currently displaying a frameset, or if the new URL does not have a fragment.
624 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
626 // FIXME: What about load types other than Standard and Reload?
628 [oldDocumentLoader setTriggeringAction:action];
629 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
630 [self checkNavigationPolicyForRequest:request
631 documentLoader:oldDocumentLoader formState:formState
632 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
634 // must grab this now, since this load may stop the previous load and clear this flag
635 BOOL isRedirect = quickRedirectComing;
636 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
638 quickRedirectComing = NO;
639 [provisionalDocumentLoader setIsClientRedirect:YES];
640 } else if (sameURL) {
641 // Example of this case are sites that reload the same URL with a different cookie
642 // driving the generated content, or a master frame with links that drive a target
643 // frame, where the user has clicked on the same link repeatedly.
644 [self setLoadType:FrameLoadTypeSame];
649 [oldDocumentLoader release];
653 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
658 NSURL *URL = [request URL];
660 BOOL isRedirect = quickRedirectComing;
661 quickRedirectComing = NO;
663 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
664 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
665 // NB: must happen after _setURL, since we add based on the current request.
666 // Must also happen before we openURL and displace the scroll position, since
667 // adding the BF item will save away scroll state.
669 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
670 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
671 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
672 // though its load is not yet done. I think this all works out OK, for one because
673 // we have already saved away the scroll and doc state for the long slow load,
674 // but it's not an obvious case.
676 [client _addHistoryItemForFragmentScroll];
679 [frameBridge scrollToAnchorWithURL:URL];
682 // This will clear previousItem from the rest of the frame tree tree that didn't
683 // doing any loading. We need to make a pass on this now, since for anchor nav
684 // we'll not go through a real load and reach Completed state
685 [self checkLoadComplete];
688 [client _dispatchDidChangeLocationWithinPageForFrame];
689 [client _didFinishLoad];
692 - (void)closeOldDataSources
694 // FIXME: is it important for this traversal to be postorder instead of preorder?
695 // FIXME: add helpers for postorder traversal?
696 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
697 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
700 [client _dispatchWillCloseFrame];
702 [client _setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
705 // Called after we send an openURL:... down to WebCore.
708 if ([self loadType] == FrameLoadTypeStandard && [documentLoader isClientRedirect])
709 [client _updateHistoryAfterClientRedirect];
711 if ([client _isDocumentLoaderLoadingFromPageCache:documentLoader]) {
712 // Force a layout to update view size and thereby update scrollbars.
713 [client _forceLayout];
715 NSArray *responses = [[self documentLoader] responses];
716 NSURLResponse *response;
717 int i, count = [responses count];
718 for (i = 0; i < count; i++) {
719 response = [responses objectAtIndex: i];
720 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
723 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
724 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
725 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
729 [client _loadedFromPageCache];
731 [[self documentLoader] setPrimaryLoadComplete:YES];
733 // FIXME: Why only this frame and not parent frames?
734 [self checkLoadCompleteForThisFrame];
738 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
740 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
742 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
744 NSURLResponse *response = [pdl response];
746 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
747 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
749 if (loadType != FrameLoadTypeReplace)
750 [self closeOldDataSources];
753 [client _makeRepresentationForDocumentLoader:pdl];
755 [self transitionToCommitted:pageCache];
757 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
758 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
759 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
760 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
761 if (sentRedirectNotification)
762 [self clientRedirectCancelledOrFinished:NO];
764 NSURL *baseURL = [[provisionalDocumentLoader request] _webDataRequestBaseURL];
765 NSURL *URL = baseURL ? baseURL : [response URL];
767 if (!URL || [URL _web_isEmpty])
768 URL = [NSURL URLWithString:@"about:blank"];
770 [frameBridge openURL:URL
772 contentType:[response MIMEType]
773 refresh:[headers objectForKey:@"Refresh"]
774 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
775 pageCache:pageCache];
782 - (NSURLRequest *)initialRequest
784 return [[self activeDocumentLoader] initialRequest];
787 - (void)_receivedData:(NSData *)data
789 [[self activeDocumentLoader] receivedData:data];
792 - (void)_setRequest:(NSURLRequest *)request
794 [[self activeDocumentLoader] setRequest:request];
797 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
798 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
800 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
803 - (WebCoreFrameBridge *)bridge
808 - (void)_handleFallbackContent
810 [frameBridge handleFallbackContent];
815 return [[self activeDocumentLoader] isStopping];
818 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
820 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
823 - (void)_setResponse:(NSURLResponse *)response
825 [[self activeDocumentLoader] setResponse:response];
828 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
830 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
833 - (void)_finishedLoading
835 WebDocumentLoader *dl = [self activeDocumentLoader];
837 WebCoreFrameBridge *bridge = frameBridge;
840 [dl finishedLoading];
842 if ([dl mainDocumentError] || ![dl frameLoader]) {
847 [dl setPrimaryLoadComplete:YES];
848 [client _dispatchDidLoadMainResourceForDocumentLoader:dl];
849 [self checkLoadComplete];
854 - (void)_notifyIconChanged:(NSURL *)iconURL
856 ASSERT([[WebCoreIconDatabaseBridge sharedInstance] _isEnabled]);
857 NSImage *icon = [[WebCoreIconDatabaseBridge sharedInstance]
858 iconForPageURL:[[[self activeDocumentLoader] URL] _web_originalDataAsString]
859 withSize:NSMakeSize(16, 16)];
860 [client _dispatchDidReceiveIcon:icon];
865 return [[self activeDocumentLoader] URL];
868 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
870 return [client _cancelledErrorWithRequest:request];
873 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
875 return [client _fileDoesNotExistErrorWithResponse:response];
878 - (void)clearArchivedResources
880 [pendingArchivedResources removeAllObjects];
881 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
884 - (void)deliverArchivedResources
886 if (![pendingArchivedResources count] || [self defersCallbacks])
889 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
891 while ((loader = [keyEnum nextObject])) {
892 WebResource *resource = [pendingArchivedResources objectForKey:loader];
893 [loader didReceiveResponse:[resource _response]];
894 NSData *data = [resource data];
895 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
896 [loader didFinishLoading];
899 [pendingArchivedResources removeAllObjects];
902 - (void)deliverArchivedResourcesAfterDelay
904 if (![pendingArchivedResources count] || [self defersCallbacks])
907 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
910 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
911 // FIXME: It would be nice to eventually to share this code somehow.
912 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
914 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
916 if (policy == NSURLRequestReturnCacheDataElseLoad) {
918 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
920 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
922 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
924 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
926 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
928 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
930 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
937 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)response
939 if (wkGetNSURLResponseMustRevalidate(response))
941 if (wkGetNSURLResponseCalculatedExpiration(response) - CFAbsoluteTimeGetCurrent() < 1)
946 - (NSMutableDictionary *)pendingArchivedResources
948 if (!pendingArchivedResources)
949 pendingArchivedResources = [[NSMutableDictionary alloc] init];
951 return pendingArchivedResources;
954 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
956 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
957 WebResource *resource = [client _archivedSubresourceForURL:originalURL fromDocumentLoader:[self activeDocumentLoader]];
958 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
959 CFDictionarySetValue((CFMutableDictionaryRef)[self pendingArchivedResources], loader, resource);
960 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
961 [self deliverArchivedResourcesAfterDelay];
968 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
970 return [pendingArchivedResources objectForKey:loader] != nil;
973 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
975 [pendingArchivedResources removeObjectForKey:loader];
977 if (![pendingArchivedResources count])
978 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
981 - (void)handleUnimplementablePolicyWithError:(NSError *)error
983 delegateIsHandlingUnimplementablePolicy = YES;
984 [client _dispatchUnableToImplementPolicyWithError:error];
985 delegateIsHandlingUnimplementablePolicy = NO;
988 - (void)cannotShowMIMETypeWithResponse:(NSURLResponse *)response
990 [self handleUnimplementablePolicyWithError:[client _cannotShowMIMETypeErrorWithResponse:response]];
993 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
995 return [client _interruptForPolicyChangeErrorWithRequest:request];
998 - (BOOL)isHostedByObjectElement
1000 // Handle <object> fallback for error cases.
1001 DOMHTMLElement *hostElement = [client frameElement];
1002 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1005 - (BOOL)isLoadingMainFrame
1007 return [client _isMainFrame];
1010 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1012 return [WebView canShowMIMEType:MIMEType];
1015 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1017 return [WebView _representationExistsForURLScheme:URLScheme];
1020 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1022 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1025 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1027 [self checkNavigationPolicyForRequest:newRequest
1028 documentLoader:[self activeDocumentLoader]
1034 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1036 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1041 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1046 - (void)cancelContentPolicy
1048 [listener _invalidate];
1053 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1055 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1056 if (unreachableURL == nil)
1059 if (!isBackForwardLoadType(policyLoadType))
1062 // We only treat unreachableURLs specially during the delegate callbacks
1063 // for provisional load errors and navigation policy decisions. The former
1064 // case handles well-formed URLs that can't be loaded, and the latter
1065 // case handles malformed URLs and unknown schemes. Loading alternate content
1066 // at other times behaves like a standard load.
1067 WebDocumentLoader *compareDocumentLoader = nil;
1068 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1069 compareDocumentLoader = policyDocumentLoader;
1070 else if (delegateIsHandlingProvisionalLoadError)
1071 compareDocumentLoader = [self provisionalDocumentLoader];
1073 return compareDocumentLoader != nil && [unreachableURL isEqual:[[compareDocumentLoader request] URL]];
1076 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1080 ASSERT(!policyDocumentLoader);
1081 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1083 NSMutableURLRequest *r = [policyDocumentLoader request];
1084 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1085 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1086 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1087 type = FrameLoadTypeSame;
1089 type = FrameLoadTypeStandard;
1091 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1092 [client _addDocumentLoader:policyDocumentLoader toUnarchiveState:archive];
1094 // When we loading alternate content for an unreachable URL that we're
1095 // visiting in the b/f list, we treat it as a reload so the b/f list
1096 // is appropriately maintained.
1097 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1098 ASSERT(type == FrameLoadTypeStandard);
1099 type = FrameLoadTypeReload;
1102 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:nil];
1105 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1107 ASSERT(!policyDocumentLoader);
1108 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1110 [policyDocumentLoader setTriggeringAction:action];
1111 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1113 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:formState];
1116 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1118 if (documentLoader == nil)
1121 NSMutableURLRequest *request = [[documentLoader request] mutableCopy];
1122 NSURL *unreachableURL = [documentLoader unreachableURL];
1123 if (unreachableURL != nil)
1124 [request setURL:unreachableURL];
1126 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1127 ASSERT(!policyDocumentLoader);
1128 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1131 [policyDocumentLoader setOverrideEncoding:encoding];
1133 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1138 if (documentLoader == nil)
1141 NSMutableURLRequest *initialRequest = [documentLoader request];
1143 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1144 // Reloading in this case will lose the current contents (see 4151001).
1145 if ([[[[documentLoader request] URL] absoluteString] length] == 0)
1148 // Replace error-page URL with the URL we were trying to reach.
1149 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1150 if (unreachableURL != nil)
1151 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1153 ASSERT(!policyDocumentLoader);
1154 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1155 NSMutableURLRequest *request = [policyDocumentLoader request];
1157 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1159 // If we're about to rePOST, set up action so the app can warn the user
1160 if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1161 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeFormResubmitted
1162 event:nil originalURL:[request URL]];
1163 [policyDocumentLoader setTriggeringAction:action];
1166 [policyDocumentLoader setOverrideEncoding:[documentLoader overrideEncoding]];
1168 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReload formState:nil];
1171 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1173 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1176 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1178 [client _finishedLoadingDocument:loader];
1181 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1183 [client _committedLoadWithDocumentLoader:loader data:data];
1188 return loadType == FrameLoadTypeReplace;
1191 - (void)setReplacing
1193 loadType = FrameLoadTypeReplace;
1196 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1198 [client _revertToProvisionalStateForDocumentLoader:loader];
1201 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1203 [client _setMainDocumentError:error forDocumentLoader:loader];
1206 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1208 [loader setPrimaryLoadComplete:YES];
1209 [client _dispatchDidLoadMainResourceForDocumentLoader:[self activeDocumentLoader]];
1210 [self checkLoadComplete];
1213 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1215 [client _clearUnarchivingStateForLoader:loader];
1218 - (void)prepareForLoadStart
1220 [client _progressStarted];
1221 [client _dispatchDidStartProvisionalLoadForFrame];
1224 - (BOOL)subframeIsLoading
1226 // It's most likely that the last added frame is the last to load so we walk backwards.
1227 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1228 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1233 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1235 [client _willChangeTitleForDocument:loader];
1238 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1240 [client _didChangeTitleForDocument:loader];
1242 // The title doesn't get communicated to the WebView until we are committed.
1243 if ([loader isCommitted]) {
1244 NSURL *URLForHistory = [[loader URLForHistory] _webkit_canonicalize];
1245 if (URLForHistory != nil) {
1246 // Must update the entries in the back-forward list too.
1247 // This must go through the WebFrame because it has the right notion of the current b/f item.
1248 [client _setTitle:[loader title] forURL:URLForHistory];
1249 [client _setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1250 [client _dispatchDidReceiveTitle:[loader title]];
1255 - (FrameLoadType)loadType
1260 - (void)setLoadType:(FrameLoadType)type
1265 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1267 [listener _invalidate];
1271 NSURLRequest *request = policyRequest;
1272 NSString *frameName = policyFrameName;
1273 id target = policyTarget;
1274 SEL selector = policySelector;
1275 WebFormState *formState = policyFormState;
1277 policyRequest = nil;
1278 policyFrameName = nil;
1280 policySelector = nil;
1281 policyFormState = nil;
1285 objc_msgSend(target, selector, nil, nil, nil);
1287 objc_msgSend(target, selector, nil, nil);
1291 [frameName release];
1293 [formState release];
1296 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1298 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1299 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1301 policyRequest = [request retain];
1302 policyTarget = [target retain];
1303 policyFrameName = [frameName retain];
1304 policySelector = selector;
1305 listener = [decisionListener retain];
1306 policyFormState = [formState retain];
1308 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1310 [decisionListener release];
1313 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1315 NSURLRequest *request = [[policyRequest retain] autorelease];
1316 NSString *frameName = [[policyFrameName retain] autorelease];
1317 id target = [[policyTarget retain] autorelease];
1318 SEL selector = policySelector;
1319 WebFormState *formState = [[policyFormState retain] autorelease];
1321 // will release policy* objects, hence the above retains
1322 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1325 case WebPolicyIgnore:
1328 case WebPolicyDownload:
1329 [client _startDownloadWithRequest:request];
1336 objc_msgSend(target, selector, request, frameName, formState);
1339 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1340 documentLoader:(WebDocumentLoader *)loader
1341 formState:(WebFormState *)formState
1343 withSelector:(SEL)selector
1345 NSDictionary *action = [loader triggeringAction];
1346 if (action == nil) {
1347 action = [self actionInformationForNavigationType:NavigationTypeOther
1348 event:nil originalURL:[request URL]];
1349 [loader setTriggeringAction:action];
1352 // Don't ask more than once for the same request or if we are loading an empty URL.
1353 // This avoids confusion on the part of the client.
1354 if ([request isEqual:[loader lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1355 [target performSelector:selector withObject:request withObject:nil];
1359 // We are always willing to show alternate content for unreachable URLs;
1360 // treat it like a reload so it maintains the right state for b/f list.
1361 if ([request _webDataRequestUnreachableURL] != nil) {
1362 if (isBackForwardLoadType(policyLoadType))
1363 policyLoadType = FrameLoadTypeReload;
1364 [target performSelector:selector withObject:request withObject:nil];
1368 [loader setLastCheckedRequest:request];
1370 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1372 ASSERT(policyRequest == nil);
1373 policyRequest = [request retain];
1374 ASSERT(policyTarget == nil);
1375 policyTarget = [target retain];
1376 policySelector = selector;
1377 ASSERT(listener == nil);
1378 listener = [decisionListener retain];
1379 ASSERT(policyFormState == nil);
1380 policyFormState = [formState retain];
1382 delegateIsDecidingNavigationPolicy = YES;
1383 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1384 delegateIsDecidingNavigationPolicy = NO;
1386 [decisionListener release];
1389 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1391 NSURLRequest *request = [[policyRequest retain] autorelease];
1392 id target = [[policyTarget retain] autorelease];
1393 SEL selector = policySelector;
1394 WebFormState *formState = [[policyFormState retain] autorelease];
1396 // will release policy* objects, hence the above retains
1397 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1400 case WebPolicyIgnore:
1403 case WebPolicyDownload:
1404 [client _startDownloadWithRequest:request];
1408 if (![WebView _canHandleRequest:request]) {
1409 [self handleUnimplementablePolicyWithError:[client _cannotShowURLErrorWithRequest:request]];
1415 [target performSelector:selector withObject:request withObject:formState];
1418 // Called after the FormsDelegate is done processing willSubmitForm:
1419 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1422 [listener _invalidate];
1426 [self startLoading];
1429 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1431 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1432 // nil policyDataSource because loading the alternate page will have passed
1433 // through this method already, nested; otherwise, policyDataSource should still be set.
1434 ASSERT(policyDocumentLoader || [provisionalDocumentLoader unreachableURL] != nil);
1436 BOOL isTargetItem = [client _provisionalItemIsTarget];
1438 // Two reasons we can't continue:
1439 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1440 // is the user responding Cancel to the form repost nag sheet.
1441 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1442 // The "before unload" event handler runs only for the main frame.
1443 BOOL canContinue = request && (![self isLoadingMainFrame] || [frameBridge shouldClose]);
1446 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1447 // need to report that the client redirect was cancelled.
1448 if (quickRedirectComing)
1449 [self clientRedirectCancelledOrFinished:NO];
1451 [self setPolicyDocumentLoader:nil];
1453 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1454 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1455 // we only do this when punting a navigation for the target frame or top-level frame.
1456 if ((isTargetItem || [self isLoadingMainFrame]) && isBackForwardLoadType(policyLoadType))
1457 [client _resetBackForwardList];
1462 FrameLoadType type = policyLoadType;
1463 WebDocumentLoader *dl = [policyDocumentLoader retain];
1468 [self startProvisionalLoad:dl];
1471 [self setPolicyDocumentLoader:nil];
1473 if (isBackForwardLoadType(type) && [client _loadProvisionalItemFromPageCache])
1477 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1478 // mechanism across the willSubmitForm callout.
1479 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1480 [[client _formDelegate] frame:client sourceFrame:[(WebFrameBridge *)[formState sourceFrame] webFrame]
1481 willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1483 [self continueAfterWillSubmitForm:WebPolicyUse];
1486 - (void)loadDocumentLoader:(WebDocumentLoader *)loader withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1488 ASSERT([client _hasWebView]);
1490 // Unfortunately the view must be non-nil, this is ultimately due
1491 // to parser requiring a FrameView. We should fix this dependency.
1493 ASSERT([client frameView] != nil);
1495 policyLoadType = type;
1497 WebFrame *parentFrame = [client parentFrame];
1499 [loader setOverrideEncoding:[[[parentFrame _frameLoader] documentLoader] overrideEncoding]];
1501 [loader setFrameLoader:self];
1503 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1505 [self setPolicyDocumentLoader:loader];
1507 [self checkNavigationPolicyForRequest:[loader request]
1508 documentLoader:loader
1511 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1514 - (void)didFirstLayout
1516 if (isBackForwardLoadType(loadType) && [client _hasBackForwardList])
1517 [client _restoreScrollPositionAndViewState];
1519 firstLayoutDone = YES;
1520 [client _dispatchDidFirstLayoutInFrame];
1523 - (void)frameLoadCompleted
1525 [client _frameLoadCompleted];
1527 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1529 firstLayoutDone = YES;
1532 - (BOOL)firstLayoutDone
1534 return firstLayoutDone;
1537 - (BOOL)isQuickRedirectComing
1539 return quickRedirectComing;
1542 - (void)transitionToCommitted:(NSDictionary *)pageCache
1544 ASSERT([client _hasWebView]);
1545 ASSERT([self state] == WebFrameStateProvisional);
1547 if ([self state] != WebFrameStateProvisional)
1550 [client _setCopiesOnScroll];
1551 [client _updateHistoryForCommit];
1553 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1554 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1555 // or the two will stomp each other.
1556 WebDocumentLoader *pdl = provisionalDocumentLoader;
1557 [frameBridge closeURL];
1558 if (pdl != provisionalDocumentLoader)
1561 [self commitProvisionalLoad];
1563 // Handle adding the URL to the back/forward list.
1564 WebDocumentLoader *dl = documentLoader;
1565 NSString *ptitle = [dl title];
1568 case WebFrameLoadTypeForward:
1569 case WebFrameLoadTypeBack:
1570 case WebFrameLoadTypeIndexedBackForward:
1571 if ([client _hasBackForwardList]) {
1572 [client _updateHistoryForBackForwardNavigation];
1574 // Create a document view for this document, or used the cached view.
1576 [client _setDocumentViewFromPageCache:pageCache];
1578 [client _makeDocumentView];
1582 case WebFrameLoadTypeReload:
1583 case WebFrameLoadTypeSame:
1584 case WebFrameLoadTypeReplace:
1585 [client _updateHistoryForReload];
1586 [client _makeDocumentView];
1589 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1590 case WebFrameLoadTypeReloadAllowingStaleData:
1591 [client _makeDocumentView];
1594 case WebFrameLoadTypeStandard:
1595 [client _updateHistoryForStandardLoad];
1596 [client _makeDocumentView];
1599 case WebFrameLoadTypeInternal:
1600 [client _updateHistoryForInternalLoad];
1601 [client _makeDocumentView];
1604 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1605 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1607 ASSERT_NOT_REACHED();
1610 // Tell the client we've committed this URL.
1611 ASSERT([[client frameView] documentView] != nil);
1612 [client _dispatchDidCommitLoadForFrame];
1614 // If we have a title let the WebView know about it.
1616 [client _dispatchDidReceiveTitle:ptitle];
1619 - (void)checkLoadCompleteForThisFrame
1621 ASSERT([client _hasWebView]);
1623 switch ([self state]) {
1624 case WebFrameStateProvisional: {
1625 if (delegateIsHandlingProvisionalLoadError)
1628 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
1630 // If we've received any errors we may be stuck in the provisional state and actually complete.
1631 NSError *error = [pdl mainDocumentError];
1633 // Check all children first.
1634 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1635 BOOL shouldReset = YES;
1636 if (![pdl isLoadingInAPISense]) {
1637 delegateIsHandlingProvisionalLoadError = YES;
1638 [client _dispatchDidFailProvisionalLoadWithError:error];
1639 delegateIsHandlingProvisionalLoadError = NO;
1641 // FIXME: can stopping loading here possibly have
1642 // any effect, if isLoading is false, which it
1643 // must be, to be in this branch of the if? And is it ok to just do
1644 // a full-on stopLoading?
1645 [self stopLoadingSubframes];
1648 // Finish resetting the load state, but only if another load hasn't been started by the
1649 // delegate callback.
1650 if (pdl == provisionalDocumentLoader)
1651 [self clearProvisionalLoad];
1653 NSURL *unreachableURL = [provisionalDocumentLoader unreachableURL];
1654 if (unreachableURL != nil && [unreachableURL isEqual:[[pdl request] URL]])
1659 [client _resetAfterLoadError:resetToken];
1661 [client _doNotResetAfterLoadError:resetToken];
1667 case WebFrameStateCommittedPage: {
1668 WebDocumentLoader *dl = documentLoader;
1670 if (![dl isLoadingInAPISense]) {
1671 [self markLoadComplete];
1673 // FIXME: Is this subsequent work important if we already navigated away?
1674 // Maybe there are bugs because of that, or extra work we can skip because
1675 // the new page is ready.
1677 [client _forceLayoutForNonHTML];
1679 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
1680 if ((isBackForwardLoadType([self loadType]) || [self loadType] == WebFrameLoadTypeReload)
1681 && [client _hasBackForwardList])
1682 [client _restoreScrollPositionAndViewState];
1684 NSError *error = [dl mainDocumentError];
1686 [client _dispatchDidFailLoadWithError:error];
1688 [client _dispatchDidFinishLoadForFrame];
1690 [client _progressCompleted];
1697 case WebFrameStateComplete:
1698 // Even if already complete, we might have set a previous item on a frame that
1699 // didn't do any data loading on the past transaction. Make sure to clear these out.
1700 [client _frameLoadCompleted];
1704 ASSERT_NOT_REACHED();
1707 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1712 WebCoreFrameBridge <WebCoreFrameBridge> *bridge = frameBridge;
1715 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1719 WebCoreFrameBridge *mainBridge = [mainFrame _frameLoader]->frameBridge;
1720 [mainBridge retain];
1722 [mainBridge setName:frameName];
1724 [mainFrame _dispatchShow];
1726 [mainBridge setOpener:bridge];
1727 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1729 [mainBridge release];
1735 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1737 if (response != nil)
1738 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1741 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1744 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1746 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1749 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1751 ASSERT(request != nil);
1753 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1754 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1756 if (newRequest == nil)
1757 *error = [client _cancelledErrorWithRequest:request];
1764 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1766 if (frameName == nil) {
1767 [client loadRequest:request];
1771 WebFrame *frame = [client findFrameNamed:frameName];
1773 [frame loadRequest:request];
1777 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeOther
1778 event:nil originalURL:[request URL]];
1779 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1780 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1783 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1784 data:(NSArray *)postData contentType:(NSString *)contentType
1785 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1787 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1788 // This prevents a potential bug which may cause a page with a form that uses itself
1789 // as an action to be returned from the cache without submitting.
1791 // FIXME: Where's the code that implements what the comment above says?
1793 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1794 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1795 [request setValue:referrer forHTTPHeaderField:@"Referer"];
1796 [request setHTTPMethod:@"POST"];
1797 webSetHTTPBody(request, postData);
1798 [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
1800 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1801 WebFormState *formState = nil;
1803 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
1805 if (target != nil) {
1806 WebFrame *targetFrame = [client findFrameNamed:target];
1807 if (targetFrame != nil)
1808 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1810 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1811 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1813 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1816 [formState release];
1819 - (void)detachChildren
1821 // FIXME: is it really necessary to do this in reverse order any more?
1822 WebFrame *child = [client _lastChildFrame];
1823 WebFrame *prev = [child _previousSiblingFrame];
1824 for (; child; child = prev, prev = [child _previousSiblingFrame])
1825 [[child _frameLoader] detachFromParent];
1828 - (void)detachFromParent
1830 WebCoreFrameBridge *bridge = [frameBridge retain];
1834 [client _detachedFromParent1];
1835 [self detachChildren];
1836 [client _detachedFromParent2];
1837 [self setDocumentLoader:nil];
1838 [client _detachedFromParent3];
1839 [[frameBridge parent] removeChild:bridge];
1841 NSObject <WebFrameLoaderClient>* c = [client retain];
1843 [c _detachedFromParent4];
1849 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1851 [request setValue:[frameBridge userAgentForURL:[request URL]] forHTTPHeaderField:@"User-Agent"];
1853 if ([self loadType] == FrameLoadTypeReload)
1854 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1856 // Don't set the cookie policy URL if it's already been set.
1857 if ([request mainDocumentURL] == nil) {
1858 if (mainResource && ([self isLoadingMainFrame] || f))
1859 [request setMainDocumentURL:[request URL]];
1861 [request setMainDocumentURL:[client _mainFrameURL]];
1865 [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"];
1868 - (void)safeLoadURL:(NSURL *)URL
1870 // Call the bridge because this is where our security checks are made.
1871 [frameBridge loadURL:URL
1872 referrer:[[[documentLoader request] URL] _web_originalDataAsString]
1876 triggeringEvent:[NSApp currentEvent]
1881 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1883 NavigationType navType;
1884 if (isFormSubmission) {
1885 navType = NavigationTypeFormSubmitted;
1886 } else if (event == nil) {
1887 if (type == FrameLoadTypeReload)
1888 navType = NavigationTypeReload;
1889 else if (isBackForwardLoadType(type))
1890 navType = NavigationTypeBackForward;
1892 navType = NavigationTypeOther;
1894 navType = NavigationTypeLinkClicked;
1896 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
1899 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1901 switch ([event type]) {
1902 case NSLeftMouseDown:
1903 case NSRightMouseDown:
1904 case NSOtherMouseDown:
1906 case NSRightMouseUp:
1907 case NSOtherMouseUp: {
1908 NSView *topViewInEventWindow = [[event window] contentView];
1909 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1910 while (viewContainingPoint != nil) {
1911 if ([viewContainingPoint isKindOfClass:[WebView class]])
1913 viewContainingPoint = [viewContainingPoint superview];
1915 if (viewContainingPoint != nil) {
1916 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1917 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
1918 return [NSDictionary dictionaryWithObjectsAndKeys:
1919 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1920 elementInfo, WebActionElementKey,
1921 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1922 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1923 URL, WebActionOriginalURLKey,
1931 return [NSDictionary dictionaryWithObjectsAndKeys:
1932 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1933 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1934 URL, WebActionOriginalURLKey,
1939 // Called every time a resource is completely loaded, or an error is received.
1940 - (void)checkLoadComplete
1942 ASSERT([client _hasWebView]);
1945 for (WebFrame *frame = client; frame; frame = parent) {
1947 [[frame _frameLoader] checkLoadCompleteForThisFrame];
1948 parent = [frame parentFrame];