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 "WebIconDatabaseBridge.h"
41 //#import <WebCore/WebCoreIconDatabaseBridge.h>
42 #import <WebCore/WebCoreSystemInterface.h>
44 #import "WebFrameInternal.h"
45 #import "WebNSURLExtras.h"
46 #import "WebResourcePrivate.h"
47 #import "WebViewInternal.h"
49 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
51 return [a caseInsensitiveCompare:b] == NSOrderedSame;
54 BOOL isBackForwardLoadType(FrameLoadType type)
57 case FrameLoadTypeStandard:
58 case FrameLoadTypeReload:
59 case FrameLoadTypeReloadAllowingStaleData:
60 case FrameLoadTypeSame:
61 case FrameLoadTypeInternal:
62 case FrameLoadTypeReplace:
64 case FrameLoadTypeBack:
65 case FrameLoadTypeForward:
66 case FrameLoadTypeIndexedBackForward:
73 @implementation WebFrameLoader
75 - (id)initWithFrame:(WebCoreFrameBridge *)bridge client:(WebFrame <WebFrameLoaderClient> *)c
81 state = WebFrameStateCommittedPage;
88 // FIXME: should these even exist?
89 [mainResourceLoader release];
90 [subresourceLoaders release];
91 [plugInStreamLoaders release];
92 [documentLoader release];
93 [provisionalDocumentLoader release];
95 ASSERT(!policyDocumentLoader);
100 - (WebDocumentLoader *)activeDocumentLoader
102 if (state == WebFrameStateProvisional)
103 return provisionalDocumentLoader;
105 return documentLoader;
108 - (void)addPlugInStreamLoader:(WebLoader *)loader
110 if (!plugInStreamLoaders)
111 plugInStreamLoaders = [[NSMutableArray alloc] init];
112 [plugInStreamLoaders addObject:loader];
113 [[self activeDocumentLoader] setLoading:YES];
116 - (void)removePlugInStreamLoader:(WebLoader *)loader
118 [plugInStreamLoaders removeObject:loader];
119 [[self activeDocumentLoader] updateLoading];
122 - (void)defersCallbacksChanged
124 BOOL defers = [frameBridge defersLoading];
125 for (WebFrame *frame = client; frame; frame = [frame _traverseNextFrameStayWithin:client])
126 [[frame _frameLoader] setDefersCallbacks:defers];
129 - (BOOL)defersCallbacks
131 return [frameBridge defersLoading];
134 - (void)setDefersCallbacks:(BOOL)defers
136 [mainResourceLoader setDefersCallbacks:defers];
138 NSEnumerator *e = [subresourceLoaders objectEnumerator];
140 while ((loader = [e nextObject]))
141 [loader setDefersCallbacks:defers];
143 e = [plugInStreamLoaders objectEnumerator];
144 while ((loader = [e nextObject]))
145 [loader setDefersCallbacks:defers];
147 [self deliverArchivedResourcesAfterDelay];
150 - (void)stopLoadingPlugIns
152 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
153 [plugInStreamLoaders removeAllObjects];
156 - (BOOL)isLoadingMainResource
158 return mainResourceLoader != nil;
161 - (BOOL)isLoadingSubresources
163 return [subresourceLoaders count];
166 - (BOOL)isLoadingPlugIns
168 return [plugInStreamLoaders count];
173 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
176 - (void)stopLoadingSubresources
178 NSArray *loaders = [subresourceLoaders copy];
179 [loaders makeObjectsPerformSelector:@selector(cancel)];
181 [subresourceLoaders removeAllObjects];
184 - (void)addSubresourceLoader:(WebLoader *)loader
186 ASSERT(!provisionalDocumentLoader);
187 if (subresourceLoaders == nil)
188 subresourceLoaders = [[NSMutableArray alloc] init];
189 [subresourceLoaders addObject:loader];
190 [[self activeDocumentLoader] setLoading:YES];
193 - (void)removeSubresourceLoader:(WebLoader *)loader
195 [subresourceLoaders removeObject:loader];
196 [[self activeDocumentLoader] updateLoading];
199 - (NSData *)mainResourceData
201 return [mainResourceLoader resourceData];
204 - (void)releaseMainResourceLoader
206 [mainResourceLoader release];
207 mainResourceLoader = nil;
210 - (void)cancelMainResourceLoad
212 [mainResourceLoader cancel];
215 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
217 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
219 [mainResourceLoader setIdentifier:identifier];
220 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
221 if (![mainResourceLoader loadWithRequest:request]) {
222 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
223 // should it be caught by other parts of WebKit or other parts of the app?
224 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
225 [mainResourceLoader release];
226 mainResourceLoader = nil;
233 - (void)stopLoadingWithError:(NSError *)error
235 [mainResourceLoader cancelWithError:error];
238 - (void)setDocumentLoader:(WebDocumentLoader *)loader
240 if (loader == nil && documentLoader == nil)
243 ASSERT(loader != documentLoader);
245 [client _prepareForDataSourceReplacement];
246 [documentLoader detachFromFrameLoader];
249 [documentLoader release];
250 documentLoader = loader;
253 - (WebDocumentLoader *)documentLoader
255 return documentLoader;
258 - (void)setPolicyDocumentLoader:(WebDocumentLoader *)loader
260 if (policyDocumentLoader == loader)
263 if (policyDocumentLoader != provisionalDocumentLoader && policyDocumentLoader != documentLoader)
264 [policyDocumentLoader detachFromFrameLoader];
266 [policyDocumentLoader release];
268 policyDocumentLoader = loader;
271 - (WebDocumentLoader *)provisionalDocumentLoader
273 return provisionalDocumentLoader;
276 - (void)setProvisionalDocumentLoader:(WebDocumentLoader *)loader
278 ASSERT(!loader || !provisionalDocumentLoader);
280 if (provisionalDocumentLoader != documentLoader)
281 [provisionalDocumentLoader detachFromFrameLoader];
284 [provisionalDocumentLoader release];
285 provisionalDocumentLoader = loader;
288 - (WebFrameState)state
294 static const char * const stateNames[] = {
295 "WebFrameStateProvisional",
296 "WebFrameStateCommittedPage",
297 "WebFrameStateComplete"
301 static CFAbsoluteTime _timeOfLastCompletedLoad;
303 + (CFAbsoluteTime)timeOfLastCompletedLoad
305 return _timeOfLastCompletedLoad;
308 - (void)provisionalLoadStarted
310 firstLayoutDone = NO;
311 [frameBridge provisionalLoadStarted];
313 [client _provisionalLoadStarted];
316 - (void)setState:(WebFrameState)newState
320 if (state == WebFrameStateProvisional)
321 [self provisionalLoadStarted];
322 else if (state == WebFrameStateComplete) {
323 [self frameLoadCompleted];
324 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
325 [[self documentLoader] stopRecordingResponses];
329 - (void)clearProvisionalLoad
331 [self setProvisionalDocumentLoader:nil];
332 [client _progressCompleted];
333 [self setState:WebFrameStateComplete];
336 - (void)markLoadComplete
338 [self setState:WebFrameStateComplete];
341 - (void)commitProvisionalLoad
343 [self stopLoadingSubresources];
344 [self stopLoadingPlugIns];
346 [self setDocumentLoader:provisionalDocumentLoader];
347 [self setProvisionalDocumentLoader:nil];
348 [self setState:WebFrameStateCommittedPage];
351 - (void)stopLoadingSubframes
353 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
354 [[(WebFrameBridge *)child frameLoader] stopLoading];
359 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
363 isStoppingLoad = YES;
365 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
367 [self stopLoadingSubframes];
368 [provisionalDocumentLoader stopLoading];
369 [documentLoader stopLoading];
370 [self setProvisionalDocumentLoader:nil];
371 [self clearArchivedResources];
376 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
379 [provisionalDocumentLoader prepareForLoadStart];
381 if ([self isLoadingMainResource])
384 [client _clearLoadingFromPageCacheForDocumentLoader:provisionalDocumentLoader];
386 id identifier = [client _dispatchIdentifierForInitialRequest:[provisionalDocumentLoader originalRequest] fromDocumentLoader:provisionalDocumentLoader];
388 if (![self startLoadingMainResourceWithRequest:[provisionalDocumentLoader actualRequest] identifier:identifier])
389 [provisionalDocumentLoader updateLoading];
392 - (void)startProvisionalLoad:(WebDocumentLoader *)loader
394 [self setProvisionalDocumentLoader:loader];
395 [self setState:WebFrameStateProvisional];
398 - (void)setupForReplace
400 [self setState:WebFrameStateProvisional];
401 WebDocumentLoader *old = provisionalDocumentLoader;
402 provisionalDocumentLoader = documentLoader;
403 documentLoader = nil;
406 [self detachChildren];
409 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
411 // FIXME: why retain here, but not in the other place this happens?
413 // The identifier is released after the last callback, rather than in dealloc,
414 // to avoid potential cycles.
415 return [[client _dispatchIdentifierForInitialRequest:clientRequest fromDocumentLoader:[self activeDocumentLoader]] retain];
418 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
420 [clientRequest setValue:[frameBridge userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
421 return [client _dispatchResource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDocumentLoader:[self activeDocumentLoader]];
424 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
426 [client _dispatchDidReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
429 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
431 [client _dispatchDidCancelAuthenticationChallenge:currentWebChallenge forResource:identifier fromDocumentLoader:[self activeDocumentLoader]];
434 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
436 [[self activeDocumentLoader] addResponse:r];
438 [client _incrementProgressForIdentifier:identifier response:r];
439 [client _dispatchResource:identifier didReceiveResponse:r fromDocumentLoader:[self activeDocumentLoader]];
442 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
444 [client _incrementProgressForIdentifier:identifier data:data];
445 [client _dispatchResource:identifier didReceiveContentLength:lengthReceived fromDocumentLoader:[self activeDocumentLoader]];
448 - (void)_didFinishLoadingForResource:(id)identifier
450 [client _completeProgressForIdentifier:identifier];
451 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:[self activeDocumentLoader]];
454 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
456 [client _completeProgressForIdentifier:identifier];
458 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:[self activeDocumentLoader]];
461 - (BOOL)_privateBrowsingEnabled
463 return [client _privateBrowsingEnabled];
466 - (void)_finishedLoadingResource
468 [self checkLoadComplete];
471 - (void)_receivedError:(NSError *)error
473 [self checkLoadComplete];
476 - (NSURLRequest *)_originalRequest
478 return [[self activeDocumentLoader] originalRequestCopy];
481 - (WebFrame *)webFrame
486 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
488 WebDocumentLoader *loader = [self activeDocumentLoader];
491 WebCoreFrameBridge *bridge = frameBridge;
493 // Retain the bridge because the stop may release the last reference to it.
496 WebFrame *cli = [client retain];
499 // FIXME: Don't want to do this if an entirely new load is going, so should check
500 // that both data sources on the frame are either self or nil.
501 // Can't call _bridge because we might not have commited yet
503 if ([cli _shouldFallBackForError:error])
504 [bridge handleFallbackContent];
507 if ([self state] == WebFrameStateProvisional) {
508 NSURL *failedURL = [[provisionalDocumentLoader originalRequestCopy] URL];
509 [bridge didNotOpenURL:failedURL];
510 [client _invalidateCurrentItemPageCache];
512 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
513 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
514 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
515 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
517 if (sentRedirectNotification)
518 [self clientRedirectCancelledOrFinished:NO];
522 [loader mainReceivedError:error complete:isComplete];
529 - (void)clientRedirectCancelledOrFinished:(BOOL)cancelWithLoadInProgress
531 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
532 // the redirect succeeded. We should either rename this API, or add a new method, like
533 // -webView:didFinishClientRedirectForFrame:
534 [client _dispatchDidCancelClientRedirectForFrame];
536 if (!cancelWithLoadInProgress)
537 quickRedirectComing = NO;
539 sentRedirectNotification = NO;
542 - (void)clientRedirectedTo:(NSURL *)URL delay:(NSTimeInterval)seconds fireDate:(NSDate *)date lockHistory:(BOOL)lockHistory isJavaScriptFormAction:(BOOL)isJavaScriptFormAction
544 [client _dispatchWillPerformClientRedirectToURL:URL delay:seconds fireDate:date];
546 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
547 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
548 sentRedirectNotification = YES;
550 // If a "quick" redirect comes in an, we set a special mode so we treat the next
551 // load as part of the same navigation.
553 if (!documentLoader || isJavaScriptFormAction) {
554 // If we don't have a dataSource, we have no "original" load on which to base a redirect,
555 // so we better just treat the redirect as a normal load.
556 quickRedirectComing = NO;
558 quickRedirectComing = lockHistory;
562 - (BOOL)shouldReloadForCurrent:(NSURL *)currentURL andDestination:(NSURL *)destinationURL
564 return !(([currentURL fragment] || [destinationURL fragment]) &&
565 [[currentURL _webkit_URLByRemovingFragment] isEqual:[destinationURL _webkit_URLByRemovingFragment]]);
568 // main funnel for navigating via callback from WebCore (e.g., clicking a link, redirect)
569 - (void)loadURL:(NSURL *)URL referrer:(NSString *)referrer loadType:(FrameLoadType)_loadType target:(NSString *)target triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
571 BOOL isFormSubmission = (values != nil);
573 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
574 [request setValue:referrer forHTTPHeaderField:@"Referer"];
575 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:(event != nil || isFormSubmission)];
576 if (_loadType == FrameLoadTypeReload)
577 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
579 // I believe this is never called with LoadSame. If it is, we probably want to set the cache
580 // policy of LoadFromOrigin, but I didn't test that.
581 ASSERT(_loadType != FrameLoadTypeSame);
583 NSDictionary *action = [self actionInformationForLoadType:_loadType isFormSubmission:isFormSubmission event:event originalURL:URL];
584 WebFormState *formState = nil;
586 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
589 WebFrame *targetFrame = [client findFrameNamed:target];
590 if (targetFrame != nil) {
591 [[targetFrame _frameLoader] loadURL:URL referrer:referrer loadType:_loadType target:nil triggeringEvent:event form:form formValues:values];
593 [self checkNewWindowPolicyForRequest:request
598 withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
605 WebDocumentLoader *oldDocumentLoader = [documentLoader retain];
607 BOOL sameURL = [client _shouldTreatURLAsSameAsCurrent:URL];
609 // Make sure to do scroll to anchor processing even if the URL is
610 // exactly the same so pages with '#' links and DHTML side effects
612 if (!isFormSubmission
613 && _loadType != FrameLoadTypeReload
614 && _loadType != FrameLoadTypeSame
615 && ![self shouldReloadForCurrent:URL andDestination:[frameBridge URL]]
617 // We don't want to just scroll if a link from within a
618 // frameset is trying to reload the frameset into _top.
619 && ![frameBridge isFrameSet]) {
621 // Just do anchor navigation within the existing content.
623 // We don't do this if we are submitting a form, explicitly reloading,
624 // currently displaying a frameset, or if the new URL does not have a fragment.
625 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
627 // FIXME: What about load types other than Standard and Reload?
629 [oldDocumentLoader setTriggeringAction:action];
630 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
631 [self checkNavigationPolicyForRequest:request
632 documentLoader:oldDocumentLoader formState:formState
633 andCall:self withSelector:@selector(continueFragmentScrollAfterNavigationPolicy:formState:)];
635 // must grab this now, since this load may stop the previous load and clear this flag
636 BOOL isRedirect = quickRedirectComing;
637 [self _loadRequest:request triggeringAction:action loadType:_loadType formState:formState];
639 quickRedirectComing = NO;
640 [provisionalDocumentLoader setIsClientRedirect:YES];
641 } else if (sameURL) {
642 // Example of this case are sites that reload the same URL with a different cookie
643 // driving the generated content, or a master frame with links that drive a target
644 // frame, where the user has clicked on the same link repeatedly.
645 [self setLoadType:FrameLoadTypeSame];
650 [oldDocumentLoader release];
654 -(void)continueFragmentScrollAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
659 NSURL *URL = [request URL];
661 BOOL isRedirect = quickRedirectComing;
662 quickRedirectComing = NO;
664 [documentLoader replaceRequestURLForAnchorScrollWithURL:URL];
665 if (!isRedirect && ![client _shouldTreatURLAsSameAsCurrent:URL]) {
666 // NB: must happen after _setURL, since we add based on the current request.
667 // Must also happen before we openURL and displace the scroll position, since
668 // adding the BF item will save away scroll state.
670 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
671 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
672 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
673 // though its load is not yet done. I think this all works out OK, for one because
674 // we have already saved away the scroll and doc state for the long slow load,
675 // but it's not an obvious case.
677 [client _addHistoryItemForFragmentScroll];
680 [frameBridge scrollToAnchorWithURL:URL];
683 // This will clear previousItem from the rest of the frame tree tree that didn't
684 // doing any loading. We need to make a pass on this now, since for anchor nav
685 // we'll not go through a real load and reach Completed state
686 [self checkLoadComplete];
689 [client _dispatchDidChangeLocationWithinPageForFrame];
690 [client _didFinishLoad];
693 - (void)closeOldDataSources
695 // FIXME: is it important for this traversal to be postorder instead of preorder?
696 // FIXME: add helpers for postorder traversal?
697 for (WebCoreFrameBridge *child = [frameBridge firstChild]; child; child = [child nextSibling])
698 [[(WebFrameBridge *)child frameLoader] closeOldDataSources];
701 [client _dispatchWillCloseFrame];
703 [client _setMainFrameDocumentReady:NO]; // stop giving out the actual DOMDocument to observers
706 // Called after we send an openURL:... down to WebCore.
709 if ([self loadType] == FrameLoadTypeStandard && [documentLoader isClientRedirect])
710 [client _updateHistoryAfterClientRedirect];
712 if ([client _isDocumentLoaderLoadingFromPageCache:documentLoader]) {
713 // Force a layout to update view size and thereby update scrollbars.
714 [client _forceLayout];
716 NSArray *responses = [[self documentLoader] responses];
717 NSURLResponse *response;
718 int i, count = [responses count];
719 for (i = 0; i < count; i++) {
720 response = [responses objectAtIndex: i];
721 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
724 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[response URL]];
725 [self requestFromDelegateForRequest:request identifier:&identifier error:&error];
726 [self sendRemainingDelegateMessagesWithIdentifier:identifier response:response length:(unsigned)[response expectedContentLength] error:error];
730 [client _loadedFromPageCache];
732 [[self documentLoader] setPrimaryLoadComplete:YES];
734 // FIXME: Why only this frame and not parent frames?
735 [self checkLoadCompleteForThisFrame];
739 - (void)commitProvisionalLoad:(NSDictionary *)pageCache
741 bool reload = loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData;
743 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
745 NSURLResponse *response = [pdl response];
747 NSDictionary *headers = [response isKindOfClass:[NSHTTPURLResponse class]]
748 ? [(NSHTTPURLResponse *)response allHeaderFields] : nil;
750 if (loadType != FrameLoadTypeReplace)
751 [self closeOldDataSources];
754 [client _makeRepresentationForDocumentLoader:pdl];
756 [self transitionToCommitted:pageCache];
758 // Call -_clientRedirectCancelledOrFinished: here so that the frame load delegate is notified that the redirect's
759 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
760 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
761 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
762 if (sentRedirectNotification)
763 [self clientRedirectCancelledOrFinished:NO];
765 NSURL *baseURL = [[provisionalDocumentLoader request] _webDataRequestBaseURL];
766 NSURL *URL = baseURL ? baseURL : [response URL];
768 if (!URL || [URL _web_isEmpty])
769 URL = [NSURL URLWithString:@"about:blank"];
771 [frameBridge openURL:URL
773 contentType:[response MIMEType]
774 refresh:[headers objectForKey:@"Refresh"]
775 lastModified:(pageCache ? nil : wkGetNSURLResponseLastModifiedDate(response))
776 pageCache:pageCache];
783 - (NSURLRequest *)initialRequest
785 return [[self activeDocumentLoader] initialRequest];
788 - (void)_receivedData:(NSData *)data
790 [[self activeDocumentLoader] receivedData:data];
793 - (void)_setRequest:(NSURLRequest *)request
795 [[self activeDocumentLoader] setRequest:request];
798 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection
799 request:(NSURLRequest *)request response:(NSURLResponse *)response proxy:(id)proxy
801 [client _downloadWithLoadingConnection:connection request:request response:response proxy:proxy];
804 - (WebCoreFrameBridge *)bridge
809 - (void)_handleFallbackContent
811 [frameBridge handleFallbackContent];
816 return [[self activeDocumentLoader] isStopping];
819 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
821 [[self activeDocumentLoader] setupForReplaceByMIMEType:newMIMEType];
824 - (void)_setResponse:(NSURLResponse *)response
826 [[self activeDocumentLoader] setResponse:response];
829 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
831 [[self activeDocumentLoader] mainReceivedError:error complete:isComplete];
834 - (void)_finishedLoading
836 WebDocumentLoader *dl = [self activeDocumentLoader];
838 WebCoreFrameBridge *bridge = frameBridge;
841 [dl finishedLoading];
843 if ([dl mainDocumentError] || ![dl frameLoader]) {
848 [dl setPrimaryLoadComplete:YES];
849 [client _dispatchDidLoadMainResourceForDocumentLoader:dl];
850 [self checkLoadComplete];
855 - (void)_notifyIconChanged:(NSURL *)iconURL
857 ASSERT([[WebIconDatabaseBridge sharedInstance] _isEnabled]);
858 NSImage *icon = [[WebIconDatabaseBridge sharedInstance]
859 iconForPageURL:[[[self activeDocumentLoader] URL] _web_originalDataAsString]
860 withSize:NSMakeSize(16, 16)];
861 [client _dispatchDidReceiveIcon:icon];
866 return [[self activeDocumentLoader] URL];
869 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
871 return [client _cancelledErrorWithRequest:request];
874 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
876 return [client _fileDoesNotExistErrorWithResponse:response];
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)handleUnimplementablePolicyWithError:(NSError *)error
984 delegateIsHandlingUnimplementablePolicy = YES;
985 [client _dispatchUnableToImplementPolicyWithError:error];
986 delegateIsHandlingUnimplementablePolicy = NO;
989 - (void)cannotShowMIMETypeWithResponse:(NSURLResponse *)response
991 [self handleUnimplementablePolicyWithError:[client _cannotShowMIMETypeErrorWithResponse:response]];
994 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
996 return [client _interruptForPolicyChangeErrorWithRequest:request];
999 - (BOOL)isHostedByObjectElement
1001 // Handle <object> fallback for error cases.
1002 DOMHTMLElement *hostElement = [client frameElement];
1003 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
1006 - (BOOL)isLoadingMainFrame
1008 return [client _isMainFrame];
1011 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
1013 return [WebView canShowMIMEType:MIMEType];
1016 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
1018 return [WebView _representationExistsForURLScheme:URLScheme];
1021 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
1023 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
1026 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
1028 [self checkNavigationPolicyForRequest:newRequest
1029 documentLoader:[self activeDocumentLoader]
1035 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
1037 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
1042 [client _dispatchDecidePolicyForMIMEType:MIMEType request:[[self activeDocumentLoader] request] decisionListener:listener];
1047 - (void)cancelContentPolicy
1049 [listener _invalidate];
1054 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
1056 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
1057 if (unreachableURL == nil)
1060 if (!isBackForwardLoadType(policyLoadType))
1063 // We only treat unreachableURLs specially during the delegate callbacks
1064 // for provisional load errors and navigation policy decisions. The former
1065 // case handles well-formed URLs that can't be loaded, and the latter
1066 // case handles malformed URLs and unknown schemes. Loading alternate content
1067 // at other times behaves like a standard load.
1068 WebDocumentLoader *compareDocumentLoader = nil;
1069 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
1070 compareDocumentLoader = policyDocumentLoader;
1071 else if (delegateIsHandlingProvisionalLoadError)
1072 compareDocumentLoader = [self provisionalDocumentLoader];
1074 return compareDocumentLoader != nil && [unreachableURL isEqual:[[compareDocumentLoader request] URL]];
1077 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
1081 ASSERT(!policyDocumentLoader);
1082 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1084 NSMutableURLRequest *r = [policyDocumentLoader request];
1085 [self addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
1086 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
1087 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1088 type = FrameLoadTypeSame;
1090 type = FrameLoadTypeStandard;
1092 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1093 [client _addDocumentLoader:policyDocumentLoader toUnarchiveState:archive];
1095 // When we loading alternate content for an unreachable URL that we're
1096 // visiting in the b/f list, we treat it as a reload so the b/f list
1097 // is appropriately maintained.
1098 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
1099 ASSERT(type == FrameLoadTypeStandard);
1100 type = FrameLoadTypeReload;
1103 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:nil];
1106 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(FrameLoadType)type formState:(WebFormState *)formState
1108 ASSERT(!policyDocumentLoader);
1109 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1111 [policyDocumentLoader setTriggeringAction:action];
1112 [policyDocumentLoader setOverrideEncoding:[[self documentLoader] overrideEncoding]];
1114 [self loadDocumentLoader:policyDocumentLoader withLoadType:type formState:formState];
1117 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
1119 if (documentLoader == nil)
1122 NSMutableURLRequest *request = [[documentLoader request] mutableCopy];
1123 NSURL *unreachableURL = [documentLoader unreachableURL];
1124 if (unreachableURL != nil)
1125 [request setURL:unreachableURL];
1127 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
1128 ASSERT(!policyDocumentLoader);
1129 policyDocumentLoader = [client _createDocumentLoaderWithRequest:request];
1132 [policyDocumentLoader setOverrideEncoding:encoding];
1134 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReloadAllowingStaleData formState:nil];
1139 if (documentLoader == nil)
1142 NSMutableURLRequest *initialRequest = [documentLoader request];
1144 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
1145 // Reloading in this case will lose the current contents (see 4151001).
1146 if ([[[[documentLoader request] URL] absoluteString] length] == 0)
1149 // Replace error-page URL with the URL we were trying to reach.
1150 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
1151 if (unreachableURL != nil)
1152 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
1154 ASSERT(!policyDocumentLoader);
1155 policyDocumentLoader = [client _createDocumentLoaderWithRequest:initialRequest];
1156 NSMutableURLRequest *request = [policyDocumentLoader request];
1158 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
1160 // If we're about to rePOST, set up action so the app can warn the user
1161 if (isCaseInsensitiveEqual([request HTTPMethod], @"POST")) {
1162 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeFormResubmitted
1163 event:nil originalURL:[request URL]];
1164 [policyDocumentLoader setTriggeringAction:action];
1167 [policyDocumentLoader setOverrideEncoding:[documentLoader overrideEncoding]];
1169 [self loadDocumentLoader:policyDocumentLoader withLoadType:FrameLoadTypeReload formState:nil];
1172 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
1174 [client _dispatchDidReceiveServerRedirectForProvisionalLoadForFrame];
1177 - (void)finishedLoadingDocument:(WebDocumentLoader *)loader
1179 [client _finishedLoadingDocument:loader];
1182 - (void)committedLoadWithDocumentLoader:(WebDocumentLoader *)loader data:(NSData *)data
1184 [client _committedLoadWithDocumentLoader:loader data:data];
1189 return loadType == FrameLoadTypeReplace;
1192 - (void)setReplacing
1194 loadType = FrameLoadTypeReplace;
1197 - (void)revertToProvisionalWithDocumentLoader:(WebDocumentLoader *)loader
1199 [client _revertToProvisionalStateForDocumentLoader:loader];
1202 - (void)documentLoader:(WebDocumentLoader *)loader setMainDocumentError:(NSError *)error
1204 [client _setMainDocumentError:error forDocumentLoader:loader];
1207 - (void)documentLoader:(WebDocumentLoader *)loader mainReceivedCompleteError:(NSError *)error
1209 [loader setPrimaryLoadComplete:YES];
1210 [client _dispatchDidLoadMainResourceForDocumentLoader:[self activeDocumentLoader]];
1211 [self checkLoadComplete];
1214 - (void)finalSetupForReplaceWithDocumentLoader:(WebDocumentLoader *)loader
1216 [client _clearUnarchivingStateForLoader:loader];
1219 - (void)prepareForLoadStart
1221 [client _progressStarted];
1222 [client _dispatchDidStartProvisionalLoadForFrame];
1225 - (BOOL)subframeIsLoading
1227 // It's most likely that the last added frame is the last to load so we walk backwards.
1228 for (WebFrame *frame = [client _lastChildFrame]; frame; frame = [frame _previousSiblingFrame])
1229 if ([[frame dataSource] isLoading] || [[frame provisionalDataSource] isLoading])
1234 - (void)willChangeTitleForDocument:(WebDocumentLoader *)loader
1236 [client _willChangeTitleForDocument:loader];
1239 - (void)didChangeTitleForDocument:(WebDocumentLoader *)loader
1241 [client _didChangeTitleForDocument:loader];
1243 // The title doesn't get communicated to the WebView until we are committed.
1244 if ([loader isCommitted]) {
1245 NSURL *URLForHistory = [[loader URLForHistory] _webkit_canonicalize];
1246 if (URLForHistory != nil) {
1247 // Must update the entries in the back-forward list too.
1248 // This must go through the WebFrame because it has the right notion of the current b/f item.
1249 [client _setTitle:[loader title] forURL:URLForHistory];
1250 [client _setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1251 [client _dispatchDidReceiveTitle:[loader title]];
1256 - (FrameLoadType)loadType
1261 - (void)setLoadType:(FrameLoadType)type
1266 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1268 [listener _invalidate];
1272 NSURLRequest *request = policyRequest;
1273 NSString *frameName = policyFrameName;
1274 id target = policyTarget;
1275 SEL selector = policySelector;
1276 WebFormState *formState = policyFormState;
1278 policyRequest = nil;
1279 policyFrameName = nil;
1281 policySelector = nil;
1282 policyFormState = nil;
1286 objc_msgSend(target, selector, nil, nil, nil);
1288 objc_msgSend(target, selector, nil, nil);
1292 [frameName release];
1294 [formState release];
1297 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1299 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1300 _initWithTarget:self action:@selector(continueAfterNewWindowPolicy:)];
1302 policyRequest = [request retain];
1303 policyTarget = [target retain];
1304 policyFrameName = [frameName retain];
1305 policySelector = selector;
1306 listener = [decisionListener retain];
1307 policyFormState = [formState retain];
1309 [client _dispatchDecidePolicyForNewWindowAction:action request:request newFrameName:frameName decisionListener:decisionListener];
1311 [decisionListener release];
1314 - (void)continueAfterNewWindowPolicy:(WebPolicyAction)policy
1316 NSURLRequest *request = [[policyRequest retain] autorelease];
1317 NSString *frameName = [[policyFrameName retain] autorelease];
1318 id target = [[policyTarget retain] autorelease];
1319 SEL selector = policySelector;
1320 WebFormState *formState = [[policyFormState retain] autorelease];
1322 // will release policy* objects, hence the above retains
1323 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1326 case WebPolicyIgnore:
1329 case WebPolicyDownload:
1330 [client _startDownloadWithRequest:request];
1337 objc_msgSend(target, selector, request, frameName, formState);
1340 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1341 documentLoader:(WebDocumentLoader *)loader
1342 formState:(WebFormState *)formState
1344 withSelector:(SEL)selector
1346 NSDictionary *action = [loader triggeringAction];
1347 if (action == nil) {
1348 action = [self actionInformationForNavigationType:NavigationTypeOther
1349 event:nil originalURL:[request URL]];
1350 [loader setTriggeringAction:action];
1353 // Don't ask more than once for the same request or if we are loading an empty URL.
1354 // This avoids confusion on the part of the client.
1355 if ([request isEqual:[loader lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1356 [target performSelector:selector withObject:request withObject:nil];
1360 // We are always willing to show alternate content for unreachable URLs;
1361 // treat it like a reload so it maintains the right state for b/f list.
1362 if ([request _webDataRequestUnreachableURL] != nil) {
1363 if (isBackForwardLoadType(policyLoadType))
1364 policyLoadType = FrameLoadTypeReload;
1365 [target performSelector:selector withObject:request withObject:nil];
1369 [loader setLastCheckedRequest:request];
1371 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1373 ASSERT(policyRequest == nil);
1374 policyRequest = [request retain];
1375 ASSERT(policyTarget == nil);
1376 policyTarget = [target retain];
1377 policySelector = selector;
1378 ASSERT(listener == nil);
1379 listener = [decisionListener retain];
1380 ASSERT(policyFormState == nil);
1381 policyFormState = [formState retain];
1383 delegateIsDecidingNavigationPolicy = YES;
1384 [client _dispatchDecidePolicyForNavigationAction:action request:request decisionListener:decisionListener];
1385 delegateIsDecidingNavigationPolicy = NO;
1387 [decisionListener release];
1390 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1392 NSURLRequest *request = [[policyRequest retain] autorelease];
1393 id target = [[policyTarget retain] autorelease];
1394 SEL selector = policySelector;
1395 WebFormState *formState = [[policyFormState retain] autorelease];
1397 // will release policy* objects, hence the above retains
1398 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1401 case WebPolicyIgnore:
1404 case WebPolicyDownload:
1405 [client _startDownloadWithRequest:request];
1409 if (![WebView _canHandleRequest:request]) {
1410 [self handleUnimplementablePolicyWithError:[client _cannotShowURLErrorWithRequest:request]];
1416 [target performSelector:selector withObject:request withObject:formState];
1419 // Called after the FormsDelegate is done processing willSubmitForm:
1420 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1423 [listener _invalidate];
1427 [self startLoading];
1430 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1432 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1433 // nil policyDataSource because loading the alternate page will have passed
1434 // through this method already, nested; otherwise, policyDataSource should still be set.
1435 ASSERT(policyDocumentLoader || [provisionalDocumentLoader unreachableURL] != nil);
1437 BOOL isTargetItem = [client _provisionalItemIsTarget];
1439 // Two reasons we can't continue:
1440 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1441 // is the user responding Cancel to the form repost nag sheet.
1442 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1443 // The "before unload" event handler runs only for the main frame.
1444 BOOL canContinue = request && (![self isLoadingMainFrame] || [frameBridge shouldClose]);
1447 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1448 // need to report that the client redirect was cancelled.
1449 if (quickRedirectComing)
1450 [self clientRedirectCancelledOrFinished:NO];
1452 [self setPolicyDocumentLoader:nil];
1454 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1455 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1456 // we only do this when punting a navigation for the target frame or top-level frame.
1457 if ((isTargetItem || [self isLoadingMainFrame]) && isBackForwardLoadType(policyLoadType))
1458 [client _resetBackForwardList];
1463 FrameLoadType type = policyLoadType;
1464 WebDocumentLoader *dl = [policyDocumentLoader retain];
1469 [self startProvisionalLoad:dl];
1472 [self setPolicyDocumentLoader:nil];
1474 if (isBackForwardLoadType(type) && [client _loadProvisionalItemFromPageCache])
1478 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1479 // mechanism across the willSubmitForm callout.
1480 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1481 [[client _formDelegate] frame:client sourceFrame:[(WebFrameBridge *)[formState sourceFrame] webFrame]
1482 willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1484 [self continueAfterWillSubmitForm:WebPolicyUse];
1487 - (void)loadDocumentLoader:(WebDocumentLoader *)loader withLoadType:(FrameLoadType)type formState:(WebFormState *)formState
1489 ASSERT([client _hasWebView]);
1491 // Unfortunately the view must be non-nil, this is ultimately due
1492 // to parser requiring a FrameView. We should fix this dependency.
1494 ASSERT([client frameView] != nil);
1496 policyLoadType = type;
1498 WebCoreFrameBridge *parentFrame = [[self bridge] parent];
1500 [loader setOverrideEncoding:[[[(WebFrameBridge *)parentFrame frameLoader] documentLoader] overrideEncoding]];
1502 [loader setFrameLoader:self];
1504 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1506 [self setPolicyDocumentLoader:loader];
1508 [self checkNavigationPolicyForRequest:[loader request]
1509 documentLoader:loader
1512 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1515 - (void)didFirstLayout
1517 if (isBackForwardLoadType(loadType) && [client _hasBackForwardList])
1518 [client _restoreScrollPositionAndViewState];
1520 firstLayoutDone = YES;
1521 [client _dispatchDidFirstLayoutInFrame];
1524 - (void)frameLoadCompleted
1526 [client _frameLoadCompleted];
1528 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1530 firstLayoutDone = YES;
1533 - (BOOL)firstLayoutDone
1535 return firstLayoutDone;
1538 - (BOOL)isQuickRedirectComing
1540 return quickRedirectComing;
1543 - (void)transitionToCommitted:(NSDictionary *)pageCache
1545 ASSERT([client _hasWebView]);
1546 ASSERT([self state] == WebFrameStateProvisional);
1548 if ([self state] != WebFrameStateProvisional)
1551 [client _setCopiesOnScroll];
1552 [client _updateHistoryForCommit];
1554 // The call to closeURL invokes the unload event handler, which can execute arbitrary
1555 // JavaScript. If the script initiates a new load, we need to abandon the current load,
1556 // or the two will stomp each other.
1557 WebDocumentLoader *pdl = provisionalDocumentLoader;
1558 [frameBridge closeURL];
1559 if (pdl != provisionalDocumentLoader)
1562 [self commitProvisionalLoad];
1564 // Handle adding the URL to the back/forward list.
1565 WebDocumentLoader *dl = documentLoader;
1566 NSString *ptitle = [dl title];
1569 case WebFrameLoadTypeForward:
1570 case WebFrameLoadTypeBack:
1571 case WebFrameLoadTypeIndexedBackForward:
1572 if ([client _hasBackForwardList]) {
1573 [client _updateHistoryForBackForwardNavigation];
1575 // Create a document view for this document, or used the cached view.
1577 [client _setDocumentViewFromPageCache:pageCache];
1579 [client _makeDocumentView];
1583 case WebFrameLoadTypeReload:
1584 case WebFrameLoadTypeSame:
1585 case WebFrameLoadTypeReplace:
1586 [client _updateHistoryForReload];
1587 [client _makeDocumentView];
1590 // FIXME - just get rid of this case, and merge WebFrameLoadTypeReloadAllowingStaleData with the above case
1591 case WebFrameLoadTypeReloadAllowingStaleData:
1592 [client _makeDocumentView];
1595 case WebFrameLoadTypeStandard:
1596 [client _updateHistoryForStandardLoad];
1597 [client _makeDocumentView];
1600 case WebFrameLoadTypeInternal:
1601 [client _updateHistoryForInternalLoad];
1602 [client _makeDocumentView];
1605 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
1606 // An exception should be thrown if we're in the WebFrameLoadTypeUninitialized state.
1608 ASSERT_NOT_REACHED();
1611 // Tell the client we've committed this URL.
1612 ASSERT([[client frameView] documentView] != nil);
1613 [client _dispatchDidCommitLoadForFrame];
1615 // If we have a title let the WebView know about it.
1617 [client _dispatchDidReceiveTitle:ptitle];
1620 - (void)checkLoadCompleteForThisFrame
1622 ASSERT([client _hasWebView]);
1624 switch ([self state]) {
1625 case WebFrameStateProvisional: {
1626 if (delegateIsHandlingProvisionalLoadError)
1629 WebDocumentLoader *pdl = [provisionalDocumentLoader retain];
1631 // If we've received any errors we may be stuck in the provisional state and actually complete.
1632 NSError *error = [pdl mainDocumentError];
1634 // Check all children first.
1635 LoadErrorResetToken *resetToken = [client _tokenForLoadErrorReset];
1636 BOOL shouldReset = YES;
1637 if (![pdl isLoadingInAPISense]) {
1638 delegateIsHandlingProvisionalLoadError = YES;
1639 [client _dispatchDidFailProvisionalLoadWithError:error];
1640 delegateIsHandlingProvisionalLoadError = NO;
1642 // FIXME: can stopping loading here possibly have
1643 // any effect, if isLoading is false, which it
1644 // must be, to be in this branch of the if? And is it ok to just do
1645 // a full-on stopLoading?
1646 [self stopLoadingSubframes];
1649 // Finish resetting the load state, but only if another load hasn't been started by the
1650 // delegate callback.
1651 if (pdl == provisionalDocumentLoader)
1652 [self clearProvisionalLoad];
1654 NSURL *unreachableURL = [provisionalDocumentLoader unreachableURL];
1655 if (unreachableURL != nil && [unreachableURL isEqual:[[pdl request] URL]])
1660 [client _resetAfterLoadError:resetToken];
1662 [client _doNotResetAfterLoadError:resetToken];
1668 case WebFrameStateCommittedPage: {
1669 WebDocumentLoader *dl = documentLoader;
1671 if (![dl isLoadingInAPISense]) {
1672 [self markLoadComplete];
1674 // FIXME: Is this subsequent work important if we already navigated away?
1675 // Maybe there are bugs because of that, or extra work we can skip because
1676 // the new page is ready.
1678 [client _forceLayoutForNonHTML];
1680 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
1681 if ((isBackForwardLoadType([self loadType]) || [self loadType] == WebFrameLoadTypeReload)
1682 && [client _hasBackForwardList])
1683 [client _restoreScrollPositionAndViewState];
1685 NSError *error = [dl mainDocumentError];
1687 [client _dispatchDidFailLoadWithError:error];
1689 [client _dispatchDidFinishLoadForFrame];
1691 [client _progressCompleted];
1698 case WebFrameStateComplete:
1699 // Even if already complete, we might have set a previous item on a frame that
1700 // didn't do any data loading on the past transaction. Make sure to clear these out.
1701 [client _frameLoadCompleted];
1705 ASSERT_NOT_REACHED();
1708 - (void)continueLoadRequestAfterNewWindowPolicy:(NSURLRequest *)request frameName:(NSString *)frameName formState:(WebFormState *)formState
1713 WebCoreFrameBridge <WebCoreFrameBridge> *bridge = frameBridge;
1716 WebFrame *mainFrame = [client _dispatchCreateWebViewWithRequest:nil];
1720 WebCoreFrameBridge *mainBridge = [mainFrame _frameLoader]->frameBridge;
1721 [mainBridge retain];
1723 [mainBridge setName:frameName];
1725 [mainFrame _dispatchShow];
1727 [mainBridge setOpener:bridge];
1728 [[mainFrame _frameLoader] _loadRequest:request triggeringAction:nil loadType:WebFrameLoadTypeStandard formState:formState];
1730 [mainBridge release];
1736 - (void)sendRemainingDelegateMessagesWithIdentifier:(id)identifier response:(NSURLResponse *)response length:(unsigned)length error:(NSError *)error
1738 if (response != nil)
1739 [client _dispatchResource:identifier didReceiveResponse:response fromDocumentLoader:documentLoader];
1742 [client _dispatchResource:identifier didReceiveContentLength:(WebNSUInteger)length fromDocumentLoader:documentLoader];
1745 [client _dispatchResource:identifier didFinishLoadingFromDocumentLoader:documentLoader];
1747 [client _dispatchResource:identifier didFailLoadingWithError:error fromDocumentLoader:documentLoader];
1750 - (NSURLRequest *)requestFromDelegateForRequest:(NSURLRequest *)request identifier:(id *)identifier error:(NSError **)error
1752 ASSERT(request != nil);
1754 *identifier = [client _dispatchIdentifierForInitialRequest:request fromDocumentLoader:documentLoader];
1755 NSURLRequest *newRequest = [client _dispatchResource:*identifier willSendRequest:request redirectResponse:nil fromDocumentLoader:documentLoader];
1757 if (newRequest == nil)
1758 *error = [client _cancelledErrorWithRequest:request];
1765 - (void)loadRequest:(NSURLRequest *)request inFrameNamed:(NSString *)frameName
1767 if (frameName == nil) {
1768 [client loadRequest:request];
1772 WebFrame *frame = [client findFrameNamed:frameName];
1774 [frame loadRequest:request];
1778 NSDictionary *action = [self actionInformationForNavigationType:NavigationTypeOther
1779 event:nil originalURL:[request URL]];
1780 [self checkNewWindowPolicyForRequest:request action:action frameName:frameName formState:nil
1781 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1784 - (void)postWithURL:(NSURL *)URL referrer:(NSString *)referrer target:(NSString *)target
1785 data:(NSArray *)postData contentType:(NSString *)contentType
1786 triggeringEvent:(NSEvent *)event form:(DOMElement *)form formValues:(NSDictionary *)values
1788 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
1789 // This prevents a potential bug which may cause a page with a form that uses itself
1790 // as an action to be returned from the cache without submitting.
1792 // FIXME: Where's the code that implements what the comment above says?
1794 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
1795 [self addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:YES];
1796 [request setValue:referrer forHTTPHeaderField:@"Referer"];
1797 [request setHTTPMethod:@"POST"];
1798 webSetHTTPBody(request, postData);
1799 [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
1801 NSDictionary *action = [self actionInformationForLoadType:FrameLoadTypeStandard isFormSubmission:YES event:event originalURL:URL];
1802 WebFormState *formState = nil;
1804 formState = [[WebFormState alloc] initWithForm:form values:values sourceFrame:frameBridge];
1806 if (target != nil) {
1807 WebFrame *targetFrame = [client findFrameNamed:target];
1808 if (targetFrame != nil)
1809 [[targetFrame _frameLoader] _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1811 [self checkNewWindowPolicyForRequest:request action:action frameName:target formState:formState
1812 andCall:self withSelector:@selector(continueLoadRequestAfterNewWindowPolicy:frameName:formState:)];
1814 [self _loadRequest:request triggeringAction:action loadType:FrameLoadTypeStandard formState:formState];
1817 [formState release];
1820 - (void)detachChildren
1822 // FIXME: is it really necessary to do this in reverse order any more?
1823 WebFrame *child = [client _lastChildFrame];
1824 WebFrame *prev = [child _previousSiblingFrame];
1825 for (; child; child = prev, prev = [child _previousSiblingFrame])
1826 [[child _frameLoader] detachFromParent];
1829 - (void)detachFromParent
1831 WebCoreFrameBridge *bridge = [frameBridge retain];
1835 [client _detachedFromParent1];
1836 [self detachChildren];
1837 [client _detachedFromParent2];
1838 [self setDocumentLoader:nil];
1839 [client _detachedFromParent3];
1840 [[frameBridge parent] removeChild:bridge];
1842 NSObject <WebFrameLoaderClient>* c = [client retain];
1844 [c _detachedFromParent4];
1850 - (void)addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
1852 [request setValue:[frameBridge userAgentForURL:[request URL]] forHTTPHeaderField:@"User-Agent"];
1854 if ([self loadType] == FrameLoadTypeReload)
1855 [request setValue:@"max-age=0" forHTTPHeaderField:@"Cache-Control"];
1857 // Don't set the cookie policy URL if it's already been set.
1858 if ([request mainDocumentURL] == nil) {
1859 if (mainResource && ([self isLoadingMainFrame] || f))
1860 [request setMainDocumentURL:[request URL]];
1862 [request setMainDocumentURL:[client _mainFrameURL]];
1866 [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"];
1869 - (void)safeLoadURL:(NSURL *)URL
1871 // Call the bridge because this is where our security checks are made.
1872 [frameBridge loadURL:URL
1873 referrer:[[[documentLoader request] URL] _web_originalDataAsString]
1877 triggeringEvent:[NSApp currentEvent]
1882 - (NSDictionary *)actionInformationForLoadType:(FrameLoadType)type isFormSubmission:(BOOL)isFormSubmission event:(NSEvent *)event originalURL:(NSURL *)URL
1884 NavigationType navType;
1885 if (isFormSubmission) {
1886 navType = NavigationTypeFormSubmitted;
1887 } else if (event == nil) {
1888 if (type == FrameLoadTypeReload)
1889 navType = NavigationTypeReload;
1890 else if (isBackForwardLoadType(type))
1891 navType = NavigationTypeBackForward;
1893 navType = NavigationTypeOther;
1895 navType = NavigationTypeLinkClicked;
1897 return [self actionInformationForNavigationType:navType event:event originalURL:URL];
1900 - (NSDictionary *)actionInformationForNavigationType:(NavigationType)navigationType event:(NSEvent *)event originalURL:(NSURL *)URL
1902 switch ([event type]) {
1903 case NSLeftMouseDown:
1904 case NSRightMouseDown:
1905 case NSOtherMouseDown:
1907 case NSRightMouseUp:
1908 case NSOtherMouseUp: {
1909 NSView *topViewInEventWindow = [[event window] contentView];
1910 NSView *viewContainingPoint = [topViewInEventWindow hitTest:[topViewInEventWindow convertPoint:[event locationInWindow] fromView:nil]];
1911 while (viewContainingPoint != nil) {
1912 if ([viewContainingPoint isKindOfClass:[WebView class]])
1914 viewContainingPoint = [viewContainingPoint superview];
1916 if (viewContainingPoint != nil) {
1917 NSPoint point = [viewContainingPoint convertPoint:[event locationInWindow] fromView:nil];
1918 NSDictionary *elementInfo = [(WebView *)viewContainingPoint elementAtPoint:point];
1919 return [NSDictionary dictionaryWithObjectsAndKeys:
1920 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1921 elementInfo, WebActionElementKey,
1922 [NSNumber numberWithInt:[event buttonNumber]], WebActionButtonKey,
1923 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1924 URL, WebActionOriginalURLKey,
1932 return [NSDictionary dictionaryWithObjectsAndKeys:
1933 [NSNumber numberWithInt:navigationType], WebActionNavigationTypeKey,
1934 [NSNumber numberWithInt:[event modifierFlags]], WebActionModifierFlagsKey,
1935 URL, WebActionOriginalURLKey,
1940 // Called every time a resource is completely loaded, or an error is received.
1941 - (void)checkLoadComplete
1943 ASSERT([client _hasWebView]);
1946 for (WebFrame *frame = client; frame; frame = parent) {
1948 [[frame _frameLoader] checkLoadCompleteForThisFrame];
1949 parent = [frame parentFrame];