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 "WebDataSourceInternal.h"
33 #import "WebDocumentLoadStateMac.h"
34 #import "WebDownloadInternal.h"
35 #import "WebFrameBridge.h"
36 #import "WebFrameInternal.h"
37 #import "WebFrameLoadDelegate.h"
38 #import "WebHistory.h"
39 #import "WebIconDatabasePrivate.h"
40 #import "WebKitErrorsPrivate.h"
41 #import "WebKitLogging.h"
42 #import "WebKitNSStringExtras.h"
43 #import "WebMainResourceLoader.h"
44 #import "WebNSDictionaryExtras.h"
45 #import "WebNSURLExtras.h"
46 #import "WebPreferences.h"
47 #import "WebResourcePrivate.h"
48 #import "WebResourceLoadDelegate.h"
49 #import "WebDefaultResourceLoadDelegate.h"
50 #import "WebScriptDebugServerPrivate.h"
51 #import "WebViewInternal.h"
52 #import <JavaScriptCore/Assertions.h>
53 #import <WebKit/DOMHTML.h>
55 @implementation WebFrameLoader
57 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
62 state = WebFrameStateCommittedPage;
69 // FIXME: should these even exist?
70 [mainResourceLoader release];
71 [subresourceLoaders release];
72 [plugInStreamLoaders release];
73 [documentLoadState release];
74 [provisionalDocumentLoadState release];
76 ASSERT(!policyDocumentLoadState);
81 - (WebDocumentLoadState *)activeDocumentLoadState
83 if (state == WebFrameStateProvisional)
84 return provisionalDocumentLoadState;
86 return documentLoadState;
89 - (WebDataSource *)activeDataSource
91 return [client _dataSourceForDocumentLoadState:[self activeDocumentLoadState]];
94 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
96 return [[self activeDataSource] _archivedSubresourceForURL:URL];
99 - (void)addPlugInStreamLoader:(WebLoader *)loader
101 if (!plugInStreamLoaders)
102 plugInStreamLoaders = [[NSMutableArray alloc] init];
103 [plugInStreamLoaders addObject:loader];
104 [[self activeDocumentLoadState] setLoading:YES];
107 - (void)removePlugInStreamLoader:(WebLoader *)loader
109 [plugInStreamLoaders removeObject:loader];
110 [[self activeDocumentLoadState] updateLoading];
113 - (void)defersCallbacksChanged
115 [self setDefersCallbacks:[[client webView] defersCallbacks]];
118 - (BOOL)defersCallbacks
120 return [[client webView] defersCallbacks];
123 - (void)setDefersCallbacks:(BOOL)defers
125 [mainResourceLoader setDefersCallbacks:defers];
127 NSEnumerator *e = [subresourceLoaders objectEnumerator];
129 while ((loader = [e nextObject]))
130 [loader setDefersCallbacks:defers];
132 e = [plugInStreamLoaders objectEnumerator];
133 while ((loader = [e nextObject]))
134 [loader setDefersCallbacks:defers];
136 [self deliverArchivedResourcesAfterDelay];
139 - (void)stopLoadingPlugIns
141 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
142 [plugInStreamLoaders removeAllObjects];
145 - (BOOL)isLoadingMainResource
147 return mainResourceLoader != nil;
150 - (BOOL)isLoadingSubresources
152 return [subresourceLoaders count];
155 - (BOOL)isLoadingPlugIns
157 return [plugInStreamLoaders count];
162 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
165 - (void)stopLoadingSubresources
167 NSArray *loaders = [subresourceLoaders copy];
168 [loaders makeObjectsPerformSelector:@selector(cancel)];
170 [subresourceLoaders removeAllObjects];
173 - (void)addSubresourceLoader:(WebLoader *)loader
175 ASSERT(!provisionalDocumentLoadState);
176 if (subresourceLoaders == nil)
177 subresourceLoaders = [[NSMutableArray alloc] init];
178 [subresourceLoaders addObject:loader];
179 [[self activeDocumentLoadState] setLoading:YES];
182 - (void)removeSubresourceLoader:(WebLoader *)loader
184 [subresourceLoaders removeObject:loader];
185 [[self activeDocumentLoadState] updateLoading];
188 - (NSData *)mainResourceData
190 return [mainResourceLoader resourceData];
193 - (void)releaseMainResourceLoader
195 [mainResourceLoader release];
196 mainResourceLoader = nil;
199 - (void)cancelMainResourceLoad
201 [mainResourceLoader cancel];
204 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
206 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
208 [mainResourceLoader setIdentifier:identifier];
209 [client _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
210 if (![mainResourceLoader loadWithRequest:request]) {
211 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
212 // should it be caught by other parts of WebKit or other parts of the app?
213 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
214 [mainResourceLoader release];
215 mainResourceLoader = nil;
222 - (void)stopLoadingWithError:(NSError *)error
224 [mainResourceLoader cancelWithError:error];
227 - (WebDataSource *)dataSource
229 return [client _dataSourceForDocumentLoadState:documentLoadState];
232 - (void)_setDocumentLoadState:(WebDocumentLoadState *)loadState
234 if (loadState == nil && documentLoadState == nil)
237 ASSERT(loadState != documentLoadState);
239 [client _prepareForDataSourceReplacement];
240 [documentLoadState detachFromFrameLoader];
243 [documentLoadState release];
244 documentLoadState = loadState;
247 - (WebDocumentLoadState *)documentLoadState
249 return documentLoadState;
252 - (WebDataSource *)policyDataSource
254 return [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
257 - (void)_setPolicyDocumentLoadState:(WebDocumentLoadState *)loadState
259 if (policyDocumentLoadState == loadState)
262 if (policyDocumentLoadState != provisionalDocumentLoadState && policyDocumentLoadState != documentLoadState)
263 [policyDocumentLoadState detachFromFrameLoader];
265 [policyDocumentLoadState release];
267 policyDocumentLoadState = loadState;
270 - (void)clearDataSource
272 [self _setDocumentLoadState:nil];
275 - (WebDataSource *)provisionalDataSource
277 return [client _dataSourceForDocumentLoadState:provisionalDocumentLoadState];
280 - (WebDocumentLoadState *)provisionalDocumentLoadState
282 return provisionalDocumentLoadState;
285 - (void)_setProvisionalDocumentLoadState:(WebDocumentLoadState *)loadState
287 ASSERT(!loadState || !provisionalDocumentLoadState);
289 if (provisionalDocumentLoadState != documentLoadState)
290 [provisionalDocumentLoadState detachFromFrameLoader];
293 [provisionalDocumentLoadState release];
294 provisionalDocumentLoadState = loadState;
297 - (void)_clearProvisionalDataSource
299 [self _setProvisionalDocumentLoadState:nil];
302 - (WebFrameState)state
308 static const char * const stateNames[] = {
309 "WebFrameStateProvisional",
310 "WebFrameStateCommittedPage",
311 "WebFrameStateComplete"
315 static CFAbsoluteTime _timeOfLastCompletedLoad;
317 + (CFAbsoluteTime)timeOfLastCompletedLoad
319 return _timeOfLastCompletedLoad;
322 - (void)_setState:(WebFrameState)newState
324 LOG(Loading, "%@: transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
325 if ([client webView])
326 LOG(Timing, "%@: transition from %s to %s, %f seconds since start of document load", [client name], stateNames[state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[[client webView] mainFrame] dataSource] _documentLoadState] loadingStartedTime]);
328 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
329 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoadState] loadingStartedTime]);
333 if (state == WebFrameStateProvisional)
334 [client _provisionalLoadStarted];
335 else if (state == WebFrameStateComplete) {
336 [client _frameLoadCompleted];
337 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
338 [[self documentLoadState] stopRecordingResponses];
342 - (void)clearProvisionalLoad
344 [self _setProvisionalDocumentLoadState:nil];
345 [[client webView] _progressCompleted:client];
346 [self _setState:WebFrameStateComplete];
349 - (void)markLoadComplete
351 [self _setState:WebFrameStateComplete];
354 - (void)commitProvisionalLoad
356 [self stopLoadingSubresources];
357 [self stopLoadingPlugIns];
359 [self _setDocumentLoadState:provisionalDocumentLoadState];
360 [self _setProvisionalDocumentLoadState:nil];
361 [self _setState:WebFrameStateCommittedPage];
366 [[self provisionalDocumentLoadState] stopLoading];
367 [[self documentLoadState] stopLoading];
368 [self _clearProvisionalDataSource];
369 [self clearArchivedResources];
372 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
375 [provisionalDocumentLoadState prepareForLoadStart];
377 if ([self isLoadingMainResource])
380 [[self provisionalDataSource] _setLoadingFromPageCache:NO];
383 id resourceLoadDelegate = [[client webView] resourceLoadDelegate];
384 if ([resourceLoadDelegate respondsToSelector:@selector(webView:identifierForInitialRequest:fromDataSource:)])
385 identifier = [resourceLoadDelegate webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoadState originalRequest] fromDataSource:[self provisionalDataSource]];
387 identifier = [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:[client webView] identifierForInitialRequest:[provisionalDocumentLoadState originalRequest] fromDataSource:[self provisionalDataSource]];
389 if (![[provisionalDocumentLoadState frameLoader] startLoadingMainResourceWithRequest:[provisionalDocumentLoadState actualRequest] identifier:identifier])
390 [provisionalDocumentLoadState updateLoading];
393 - (void)startProvisionalLoad:(WebDataSource *)ds
395 [self _setProvisionalDocumentLoadState:[ds _documentLoadState]];
396 [self _setState:WebFrameStateProvisional];
399 - (void)setupForReplace
401 [self _setState:WebFrameStateProvisional];
402 WebDocumentLoadState *old = provisionalDocumentLoadState;
403 provisionalDocumentLoadState = documentLoadState;
404 documentLoadState = nil;
407 [client _detachChildren];
410 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
412 WebView *webView = [client webView];
414 // The identifier is released after the last callback, rather than in dealloc
415 // to avoid potential cycles.
416 if ([webView _resourceLoadDelegateImplementations].delegateImplementsIdentifierForRequest)
417 return [[[webView resourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
419 return [[[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView identifierForInitialRequest:clientRequest fromDataSource:[self activeDataSource]] retain];
422 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
424 WebView *webView = [client webView];
426 [clientRequest setValue:[webView userAgentForURL:[clientRequest URL]] forHTTPHeaderField:@"User-Agent"];
428 if ([webView _resourceLoadDelegateImplementations].delegateImplementsWillSendRequest)
429 return [[webView resourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
431 return [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier willSendRequest:clientRequest redirectResponse:redirectResponse fromDataSource:[self activeDataSource]];
434 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
436 WebView *webView = [client webView];
438 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveAuthenticationChallenge)
439 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
441 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
444 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
446 WebView *webView = [client webView];
448 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidCancelAuthenticationChallenge)
449 [[webView resourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
451 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didCancelAuthenticationChallenge:currentWebChallenge fromDataSource:[self activeDataSource]];
455 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
457 WebView *webView = [client webView];
459 [[self activeDocumentLoadState] addResponse:r];
461 [webView _incrementProgressForIdentifier:identifier response:r];
463 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveResponse)
464 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
466 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveResponse:r fromDataSource:[self activeDataSource]];
469 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
471 WebView *webView = [client webView];
473 [webView _incrementProgressForIdentifier:identifier data:data];
475 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidReceiveContentLength)
476 [[webView resourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
478 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didReceiveContentLength:(WebNSUInteger)lengthReceived fromDataSource:[self activeDataSource]];
481 - (void)_didFinishLoadingForResource:(id)identifier
483 WebView *webView = [client webView];
485 [webView _completeProgressForIdentifier:identifier];
487 if ([webView _resourceLoadDelegateImplementations].delegateImplementsDidFinishLoadingFromDataSource)
488 [[webView resourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
490 [[WebDefaultResourceLoadDelegate sharedResourceLoadDelegate] webView:webView resource:identifier didFinishLoadingFromDataSource:[self activeDataSource]];
493 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
495 WebView *webView = [client webView];
497 [webView _completeProgressForIdentifier:identifier];
500 [[webView _resourceLoadDelegateForwarder] webView:webView resource:identifier didFailLoadingWithError:error fromDataSource:[self activeDataSource]];
503 - (BOOL)_privateBrowsingEnabled
505 return [[[client webView] preferences] privateBrowsingEnabled];
508 - (void)_finishedLoadingResource
510 [client _checkLoadComplete];
513 - (void)_receivedError:(NSError *)error
515 [client _checkLoadComplete];
518 - (NSURLRequest *)_originalRequest
520 return [[self activeDocumentLoadState] originalRequestCopy];
523 - (WebFrame *)webFrame
528 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
530 WebDocumentLoadState *loadState = [self activeDocumentLoadState];
533 WebFrameBridge *bridge = [client _bridge];
535 // Retain the bridge because the stop may release the last reference to it.
538 WebFrame *cli = [client retain];
541 // FIXME: Don't want to do this if an entirely new load is going, so should check
542 // that both data sources on the frame are either self or nil.
543 // Can't call [self _bridge] because we might not have commited yet
545 // FIXME: WebKitErrorPlugInWillHandleLoad is a workaround for the cancel we do to prevent loading plugin content twice. See <rdar://problem/4258008>
546 if ([error code] != NSURLErrorCancelled && [error code] != WebKitErrorPlugInWillHandleLoad)
547 [bridge handleFallbackContent];
552 [cli _receivedMainResourceError:error];
553 [loadState mainReceivedError:error complete:isComplete];
560 - (NSURLRequest *)initialRequest
562 return [[self activeDataSource] initialRequest];
565 - (void)_receivedData:(NSData *)data
567 [[self activeDocumentLoadState] receivedData:data];
570 - (void)_setRequest:(NSURLRequest *)request
572 [[self activeDocumentLoadState] setRequest:request];
575 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
577 [WebDownload _downloadWithLoadingConnection:connection
580 delegate:[[client webView] downloadDelegate]
584 - (WebFrameBridge *)bridge
586 return [client _bridge];
589 - (void)_handleFallbackContent
591 [[self bridge] handleFallbackContent];
596 return [[self activeDocumentLoadState] isStopping];
599 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
601 [[self activeDocumentLoadState] setupForReplaceByMIMEType:newMIMEType];
604 - (void)_setResponse:(NSURLResponse *)response
606 [[self activeDocumentLoadState] setResponse:response];
609 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
611 [[self activeDocumentLoadState] mainReceivedError:error complete:isComplete];
614 - (void)_finishedLoading
616 WebDataSource *ds = [self activeDataSource];
619 [[self activeDocumentLoadState] finishedLoading];
621 if ([ds _mainDocumentError] || ![ds webFrame]) {
626 [[self activeDocumentLoadState] setPrimaryLoadComplete:YES];
627 if ([WebScriptDebugServer listenerCount])
628 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
629 [client _checkLoadComplete];
634 - (void)_notifyIconChanged:(NSURL *)iconURL
636 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
637 ASSERT(client == [[client webView] mainFrame]);
639 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
641 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
643 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
647 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
652 return [[self activeDataSource] _URL];
655 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
657 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
658 code:NSURLErrorCancelled
662 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
664 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
665 code:NSURLErrorFileDoesNotExist
669 - (void)clearArchivedResources
671 [pendingArchivedResources removeAllObjects];
672 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
675 - (void)deliverArchivedResources
677 if (![pendingArchivedResources count] || [self defersCallbacks])
680 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
682 while ((loader = [keyEnum nextObject])) {
683 WebResource *resource = [pendingArchivedResources objectForKey:loader];
684 [loader didReceiveResponse:[resource _response]];
685 NSData *data = [resource data];
686 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
687 [loader didFinishLoading];
690 [pendingArchivedResources removeAllObjects];
693 - (void)deliverArchivedResourcesAfterDelay
695 if (![pendingArchivedResources count] || [self defersCallbacks])
698 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
701 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
703 return [a caseInsensitiveCompare:b] == NSOrderedSame;
706 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
707 // FIXME: It would be nice to eventually to share this code somehow.
708 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
710 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
712 if (policy == NSURLRequestReturnCacheDataElseLoad) {
714 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
716 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
718 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
720 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
722 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
724 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
726 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
733 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
735 if (WKGetNSURLResponseMustRevalidate(theResponse)) {
737 } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
744 - (NSMutableDictionary *)pendingArchivedResources
746 if (!pendingArchivedResources)
747 pendingArchivedResources = [[NSMutableDictionary alloc] init];
749 return pendingArchivedResources;
752 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
754 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
755 WebResource *resource = [self _archivedSubresourceForURL:originalURL];
756 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
757 [[self pendingArchivedResources] _webkit_setObject:resource forUncopiedKey:loader];
758 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
759 [self deliverArchivedResourcesAfterDelay];
766 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
768 return [pendingArchivedResources objectForKey:loader] != nil;
771 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
773 [pendingArchivedResources removeObjectForKey:loader];
775 if (![pendingArchivedResources count])
776 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
779 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
781 [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
784 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
786 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
789 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
791 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
794 - (BOOL)isHostedByObjectElement
796 // Handle <object> fallback for error cases.
797 DOMHTMLElement *hostElement = [client frameElement];
798 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
801 - (BOOL)isLoadingMainFrame
803 return [client _isMainFrame];
806 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
808 return [WebView canShowMIMEType:MIMEType];
811 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
813 return [WebView _representationExistsForURLScheme:URLScheme];
816 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
818 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
821 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
823 [self checkNavigationPolicyForRequest:newRequest
824 dataSource:[self activeDataSource]
830 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
832 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
837 [[[client webView] _policyDelegateForwarder] webView:[client webView] decidePolicyForMIMEType:MIMEType
838 request:[[self activeDocumentLoadState] request]
840 decisionListener:listener];
844 - (void)cancelContentPolicy
846 [listener _invalidate];
851 static inline BOOL isBackForwardLoadType(WebFrameLoadType type)
854 case WebFrameLoadTypeStandard:
855 case WebFrameLoadTypeReload:
856 case WebFrameLoadTypeReloadAllowingStaleData:
857 case WebFrameLoadTypeSame:
858 case WebFrameLoadTypeInternal:
859 case WebFrameLoadTypeReplace:
861 case WebFrameLoadTypeBack:
862 case WebFrameLoadTypeForward:
863 case WebFrameLoadTypeIndexedBackForward:
866 ASSERT_NOT_REACHED();
870 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
872 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
873 if (unreachableURL == nil)
876 if (!isBackForwardLoadType(policyLoadType))
879 // We only treat unreachableURLs specially during the delegate callbacks
880 // for provisional load errors and navigation policy decisions. The former
881 // case handles well-formed URLs that can't be loaded, and the latter
882 // case handles malformed URLs and unknown schemes. Loading alternate content
883 // at other times behaves like a standard load.
884 WebDataSource *compareDataSource = nil;
885 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy)
886 compareDataSource = [self policyDataSource];
887 else if (delegateIsHandlingProvisionalLoadError)
888 compareDataSource = [self provisionalDataSource];
890 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
893 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
895 WebFrameLoadType type;
897 ASSERT(!policyDocumentLoadState);
898 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
899 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
901 NSMutableURLRequest *r = [newDataSource request];
902 [client _addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
903 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
904 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
905 type = WebFrameLoadTypeSame;
907 type = WebFrameLoadTypeStandard;
909 [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
910 [newDataSource _addToUnarchiveState:archive];
912 // When we loading alternate content for an unreachable URL that we're
913 // visiting in the b/f list, we treat it as a reload so the b/f list
914 // is appropriately maintained.
915 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
916 ASSERT(type == WebFrameLoadTypeStandard);
917 type = WebFrameLoadTypeReload;
920 [self loadDataSource:newDataSource withLoadType:type formState:nil];
923 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)type formState:(WebFormState *)formState
925 ASSERT(!policyDocumentLoadState);
926 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
927 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
929 [policyDocumentLoadState setTriggeringAction:action];
930 [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
932 [self loadDataSource:newDataSource withLoadType:type formState:formState];
935 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
937 WebDataSource *ds = [self dataSource];
941 NSMutableURLRequest *request = [[ds request] mutableCopy];
942 NSURL *unreachableURL = [ds unreachableURL];
943 if (unreachableURL != nil)
944 [request setURL:unreachableURL];
946 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
947 ASSERT(!policyDocumentLoadState);
948 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
949 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
952 [policyDocumentLoadState setOverrideEncoding:encoding];
954 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
959 WebDataSource *ds = [self dataSource];
963 NSMutableURLRequest *initialRequest = [ds request];
965 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
966 // Reloading in this case will lose the current contents (see 4151001).
967 if ([[[[ds request] URL] absoluteString] length] == 0)
970 // Replace error-page URL with the URL we were trying to reach.
971 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
972 if (unreachableURL != nil)
973 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
975 ASSERT(!policyDocumentLoadState);
976 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:initialRequest];
977 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
978 NSMutableURLRequest *request = [newDataSource request];
980 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
982 // If we're about to rePOST, set up action so the app can warn the user
983 if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
984 NSDictionary *action = [client _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
985 [policyDocumentLoadState setTriggeringAction:action];
988 [policyDocumentLoadState setOverrideEncoding:[[ds _documentLoadState] overrideEncoding]];
990 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
993 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
995 [client _didReceiveServerRedirectForProvisionalLoadForFrame];
998 - (void)finishedLoadingDocumentLoadState:(WebDocumentLoadState *)loadState
1000 [[client _dataSourceForDocumentLoadState:loadState] _finishedLoading];
1003 - (void)commitProvisitionalLoad
1005 [client _commitProvisionalLoad:nil];
1008 - (void)committedLoadWithDocumentLoadState:(WebDocumentLoadState *)loadState data:(NSData *)data
1010 [[client _dataSourceForDocumentLoadState:loadState] _receivedData:data];
1015 return loadType == WebFrameLoadTypeReplace;
1018 - (void)setReplacing
1020 loadType = WebFrameLoadTypeReplace;
1023 - (void)revertToProvisionalWithDocumentLoadState:(WebDocumentLoadState *)loadState
1025 [[client _dataSourceForDocumentLoadState:loadState] _revertToProvisionalState];
1028 - (void)documentLoadState:(WebDocumentLoadState *)loadState setMainDocumentError:(NSError *)error
1030 [[client _dataSourceForDocumentLoadState:loadState] _setMainDocumentError:error];
1033 - (void)documentLoadState:(WebDocumentLoadState *)loadState mainReceivedCompleteError:(NSError *)error
1035 [loadState setPrimaryLoadComplete:YES];
1036 if ([WebScriptDebugServer listenerCount])
1037 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
1038 [client _checkLoadComplete];
1041 - (void)finalSetupForReplaceWithDocumentLoadState:(WebDocumentLoadState *)loadState
1043 [[client _dataSourceForDocumentLoadState:loadState] _clearUnarchivingState];
1046 - (void)prepareForLoadStart
1048 [[client webView] _progressStarted:client];
1049 [[client webView] _didStartProvisionalLoadForFrame:client];
1050 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1051 didStartProvisionalLoadForFrame:client];
1054 - (BOOL)subframeIsLoading
1056 return [client _subframeIsLoading];
1059 - (void)willChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
1061 // FIXME: should do this only in main frame case, right?
1062 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
1065 - (void)didChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
1067 // FIXME: should do this only in main frame case, right?
1068 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
1070 // The title doesn't get communicated to the WebView until we are committed.
1071 if ([loadState isCommitted]) {
1072 NSURL *URLForHistory = [[client _dataSourceForDocumentLoadState:loadState] _URLForHistory];
1073 if (URLForHistory != nil) {
1074 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
1075 [entry setTitle:[loadState title]];
1077 // Must update the entries in the back-forward list too. This must go through the WebFrame because
1078 // it has the right notion of the current b/f item.
1079 [client _setTitle:[loadState title]];
1081 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
1082 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
1083 didReceiveTitle:[loadState title]
1089 - (WebFrameLoadType)loadType
1094 - (void)setLoadType:(WebFrameLoadType)type
1099 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
1101 [listener _invalidate];
1105 NSURLRequest *request = policyRequest;
1106 NSString *frameName = policyFrameName;
1107 id target = policyTarget;
1108 SEL selector = policySelector;
1109 WebFormState *formState = policyFormState;
1111 policyRequest = nil;
1112 policyFrameName = nil;
1114 policySelector = nil;
1115 policyFormState = nil;
1119 objc_msgSend(target, selector, nil, nil, nil);
1121 objc_msgSend(target, selector, nil, nil);
1125 [frameName release];
1127 [formState release];
1130 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1132 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1133 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1135 policyRequest = [request retain];
1136 policyTarget = [target retain];
1137 policyFrameName = [frameName retain];
1138 policySelector = selector;
1139 listener = [decisionListener retain];
1140 policyFormState = [formState retain];
1142 WebView *wv = [client webView];
1143 [[wv _policyDelegateForwarder] webView:wv
1144 decidePolicyForNewWindowAction:action
1146 newFrameName:frameName
1147 decisionListener:decisionListener];
1149 [decisionListener release];
1152 - (void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1154 NSURLRequest *request = [[policyRequest retain] autorelease];
1155 NSString *frameName = [[policyFrameName retain] autorelease];
1156 id target = [[policyTarget retain] autorelease];
1157 SEL selector = policySelector;
1158 WebFormState *formState = [[policyFormState retain] autorelease];
1160 // will release policy* objects, hence the above retains
1161 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1163 BOOL shouldContinue = NO;
1166 case WebPolicyIgnore:
1168 case WebPolicyDownload:
1169 // FIXME: should download full request
1170 [[client webView] _downloadURL:[request URL]];
1173 shouldContinue = YES;
1176 ASSERT_NOT_REACHED();
1179 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1182 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1183 dataSource:(WebDataSource *)dataSource
1184 formState:(WebFormState *)formState
1186 withSelector:(SEL)selector
1188 NSDictionary *action = [[dataSource _documentLoadState] triggeringAction];
1189 if (action == nil) {
1190 action = [client _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1191 [[dataSource _documentLoadState] setTriggeringAction:action];
1194 // Don't ask more than once for the same request or if we are loading an empty URL.
1195 // This avoids confusion on the part of the client.
1196 if ([request isEqual:[[dataSource _documentLoadState] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1197 [target performSelector:selector withObject:request withObject:nil];
1201 // We are always willing to show alternate content for unreachable URLs;
1202 // treat it like a reload so it maintains the right state for b/f list.
1203 if ([request _webDataRequestUnreachableURL] != nil) {
1204 if (isBackForwardLoadType(policyLoadType))
1205 policyLoadType = WebFrameLoadTypeReload;
1206 [target performSelector:selector withObject:request withObject:nil];
1210 [[dataSource _documentLoadState] setLastCheckedRequest:request];
1212 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1214 ASSERT(policyRequest == nil);
1215 policyRequest = [request retain];
1216 ASSERT(policyTarget == nil);
1217 policyTarget = [target retain];
1218 policySelector = selector;
1219 ASSERT(listener == nil);
1220 listener = [decisionListener retain];
1221 ASSERT(policyFormState == nil);
1222 policyFormState = [formState retain];
1224 WebView *wv = [client webView];
1225 delegateIsDecidingNavigationPolicy = YES;
1226 [[wv _policyDelegateForwarder] webView:wv
1227 decidePolicyForNavigationAction:action
1230 decisionListener:decisionListener];
1231 delegateIsDecidingNavigationPolicy = NO;
1233 [decisionListener release];
1236 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1238 NSURLRequest *request = [[policyRequest retain] autorelease];
1239 id target = [[policyTarget retain] autorelease];
1240 SEL selector = policySelector;
1241 WebFormState *formState = [[policyFormState retain] autorelease];
1243 // will release policy* objects, hence the above retains
1244 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1246 BOOL shouldContinue = NO;
1249 case WebPolicyIgnore:
1251 case WebPolicyDownload:
1252 // FIXME: should download full request
1253 [[client webView] _downloadURL:[request URL]];
1256 if (![WebView _canHandleRequest:request]) {
1257 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1259 shouldContinue = YES;
1263 ASSERT_NOT_REACHED();
1266 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1269 // Called after the FormsDelegate is done processing willSubmitForm:
1270 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1273 [listener _invalidate];
1277 [self startLoading];
1280 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1282 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1283 // nil policyDataSource because loading the alternate page will have passed
1284 // through this method already, nested; otherwise, policyDataSource should still be set.
1285 ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1287 BOOL isTargetItem = [client _provisionalItemIsTarget];
1289 // Two reasons we can't continue:
1290 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1291 // is the user responding Cancel to the form repost nag sheet.
1292 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1293 // The "before unload" event handler runs only for the main frame.
1294 BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1297 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1298 // need to report that the client redirect was cancelled.
1299 if ([client _quickRedirectComing])
1300 [client _clientRedirectCancelledOrFinished:NO];
1302 [self _setPolicyDocumentLoadState:nil];
1304 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1305 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1306 // we only do this when punting a navigation for the target frame or top-level frame.
1307 if ((isTargetItem || [[client webView] mainFrame] == client) && isBackForwardLoadType(policyLoadType))
1308 [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1313 WebFrameLoadType type = policyLoadType;
1314 WebDataSource *dataSource = [[self policyDataSource] retain];
1319 [self startProvisionalLoad:dataSource];
1321 [dataSource release];
1322 [self _setPolicyDocumentLoadState:nil];
1324 if (client == [[client webView] mainFrame])
1325 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1327 if (type == WebFrameLoadTypeForward || type == WebFrameLoadTypeBack || type == WebFrameLoadTypeIndexedBackForward) {
1328 if ([client _loadProvisionalItemFromPageCache])
1333 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1334 // mechanism across the willSubmitForm callout.
1335 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1336 [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1339 [self continueAfterWillSubmitForm:WebPolicyUse];
1343 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1345 ASSERT([client webView] != nil);
1347 // Unfortunately the view must be non-nil, this is ultimately due
1348 // to parser requiring a FrameView. We should fix this dependency.
1350 ASSERT([client frameView] != nil);
1352 policyLoadType = type;
1354 WebDocumentLoadStateMac *loadState = (WebDocumentLoadStateMac *)[newDataSource _documentLoadState];
1356 WebFrame *parentFrame = [client parentFrame];
1358 [loadState setOverrideEncoding:[[[parentFrame dataSource] _documentLoadState] overrideEncoding]];
1360 [loadState setFrameLoader:self];
1361 [loadState setDataSource:newDataSource];
1363 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1365 [self _setPolicyDocumentLoadState:loadState];
1367 [self checkNavigationPolicyForRequest:[newDataSource request]
1368 dataSource:newDataSource
1371 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1374 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1376 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1377 WebView *wv = [client webView];
1378 delegateIsHandlingUnimplementablePolicy = YES;
1379 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:client];
1380 delegateIsHandlingUnimplementablePolicy = NO;
1383 - (BOOL)delegateIsHandlingProvisionalLoadError
1385 return delegateIsHandlingProvisionalLoadError;
1388 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1390 delegateIsHandlingProvisionalLoadError = is;
1393 - (void)didFirstLayout
1395 if ([[client webView] backForwardList]) {
1396 if (loadType == WebFrameLoadTypeForward || loadType == WebFrameLoadTypeBack || loadType == WebFrameLoadTypeIndexedBackForward)
1397 [client _restoreScrollPositionAndViewState];
1400 firstLayoutDone = YES;
1402 WebView *wv = [client webView];
1403 [[wv _frameLoadDelegateForwarder] webView:wv didFirstLayoutInFrame:client];
1406 - (void)provisionalLoadStarted
1408 firstLayoutDone = NO;
1411 - (void)frameLoadCompleted
1413 // After a canceled provisional load, firstLayoutDone is NO. Reset it to YES if we're displaying a page.
1414 if ([self dataSource])
1415 firstLayoutDone = YES;
1418 - (BOOL)firstLayoutDone
1420 return firstLayoutDone;