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 "WebFrameBridge.h"
34 #import "WebFrameInternal.h"
35 #import "WebFrameLoadDelegate.h"
36 #import "WebHistory.h"
37 #import "WebIconDatabasePrivate.h"
38 #import "WebKitErrorsPrivate.h"
39 #import "WebKitLogging.h"
40 #import "WebKitNSStringExtras.h"
41 #import "WebMainResourceLoader.h"
42 #import "WebNSDictionaryExtras.h"
43 #import "WebNSURLExtras.h"
44 #import "WebPreferences.h"
45 #import "WebResourcePrivate.h"
46 #import "WebScriptDebugServerPrivate.h"
47 #import "WebViewInternal.h"
48 #import <JavaScriptCore/Assertions.h>
49 #import <WebKit/DOMHTML.h>
51 @implementation WebFrameLoader
53 - (id)initWithClient:(WebFrame <WebFrameLoaderClient> *)c
58 state = WebFrameStateCommittedPage;
65 // FIXME: should these even exist?
66 [mainResourceLoader release];
67 [subresourceLoaders release];
68 [plugInStreamLoaders release];
69 [documentLoadState release];
70 [provisionalDocumentLoadState release];
72 ASSERT(!policyDocumentLoadState);
77 - (WebDocumentLoadState *)activeDocumentLoadState
79 if (state == WebFrameStateProvisional)
80 return provisionalDocumentLoadState;
82 return documentLoadState;
85 - (WebDataSource *)activeDataSource
87 return [client _dataSourceForDocumentLoadState:[self activeDocumentLoadState]];
90 - (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
92 return [[self activeDataSource] _archivedSubresourceForURL:URL];
95 - (void)addPlugInStreamLoader:(WebLoader *)loader
97 if (!plugInStreamLoaders)
98 plugInStreamLoaders = [[NSMutableArray alloc] init];
99 [plugInStreamLoaders addObject:loader];
100 [[self activeDocumentLoadState] setLoading:YES];
103 - (void)removePlugInStreamLoader:(WebLoader *)loader
105 [plugInStreamLoaders removeObject:loader];
106 [[self activeDocumentLoadState] updateLoading];
109 - (void)defersCallbacksChanged
111 [self setDefersCallbacks:[[client webView] defersCallbacks]];
114 - (BOOL)defersCallbacks
116 return [[client webView] defersCallbacks];
119 - (void)setDefersCallbacks:(BOOL)defers
121 [mainResourceLoader setDefersCallbacks:defers];
123 NSEnumerator *e = [subresourceLoaders objectEnumerator];
125 while ((loader = [e nextObject]))
126 [loader setDefersCallbacks:defers];
128 e = [plugInStreamLoaders objectEnumerator];
129 while ((loader = [e nextObject]))
130 [loader setDefersCallbacks:defers];
132 [self deliverArchivedResourcesAfterDelay];
135 - (void)stopLoadingPlugIns
137 [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
138 [plugInStreamLoaders removeAllObjects];
141 - (BOOL)isLoadingMainResource
143 return mainResourceLoader != nil;
146 - (BOOL)isLoadingSubresources
148 return [subresourceLoaders count];
151 - (BOOL)isLoadingPlugIns
153 return [plugInStreamLoaders count];
158 return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
161 - (void)stopLoadingSubresources
163 NSArray *loaders = [subresourceLoaders copy];
164 [loaders makeObjectsPerformSelector:@selector(cancel)];
166 [subresourceLoaders removeAllObjects];
169 - (void)addSubresourceLoader:(WebLoader *)loader
171 ASSERT(!provisionalDocumentLoadState);
172 if (subresourceLoaders == nil)
173 subresourceLoaders = [[NSMutableArray alloc] init];
174 [subresourceLoaders addObject:loader];
175 [[self activeDocumentLoadState] setLoading:YES];
178 - (void)removeSubresourceLoader:(WebLoader *)loader
180 [subresourceLoaders removeObject:loader];
181 [[self activeDocumentLoadState] updateLoading];
184 - (NSData *)mainResourceData
186 return [mainResourceLoader resourceData];
189 - (void)releaseMainResourceLoader
191 [mainResourceLoader release];
192 mainResourceLoader = nil;
195 - (void)cancelMainResourceLoad
197 [mainResourceLoader cancel];
200 - (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
202 mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
204 [mainResourceLoader setIdentifier:identifier];
205 [client _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
206 if (![mainResourceLoader loadWithRequest:request]) {
207 // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
208 // should it be caught by other parts of WebKit or other parts of the app?
209 LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
210 [mainResourceLoader release];
211 mainResourceLoader = nil;
218 - (void)stopLoadingWithError:(NSError *)error
220 [mainResourceLoader cancelWithError:error];
223 - (WebDataSource *)dataSource
225 return [client _dataSourceForDocumentLoadState:documentLoadState];
228 - (void)_setDocumentLoadState:(WebDocumentLoadState *)loadState
230 if (loadState == nil && documentLoadState == nil)
233 ASSERT(loadState != documentLoadState);
235 [client _prepareForDataSourceReplacement];
236 [documentLoadState detachFromFrameLoader];
239 [documentLoadState release];
240 documentLoadState = loadState;
243 - (WebDocumentLoadState *)documentLoadState
245 return documentLoadState;
248 - (WebDataSource *)policyDataSource
250 return [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
253 - (void)_setPolicyDocumentLoadState:(WebDocumentLoadState *)loadState
256 [policyDocumentLoadState release];
257 policyDocumentLoadState = loadState;
260 - (void)clearDataSource
262 [self _setDocumentLoadState:nil];
265 - (WebDataSource *)provisionalDataSource
267 return [client _dataSourceForDocumentLoadState:provisionalDocumentLoadState];
270 - (WebDocumentLoadState *)provisionalDocumentLoadState
272 return provisionalDocumentLoadState;
275 - (void)_setProvisionalDocumentLoadState:(WebDocumentLoadState *)loadState
277 ASSERT(!loadState || !provisionalDocumentLoadState);
279 if (provisionalDocumentLoadState != documentLoadState)
280 [provisionalDocumentLoadState detachFromFrameLoader];
283 [provisionalDocumentLoadState release];
284 provisionalDocumentLoadState = loadState;
287 - (void)_clearProvisionalDataSource
289 [self _setProvisionalDocumentLoadState:nil];
292 - (WebFrameState)state
298 static const char * const stateNames[] = {
299 "WebFrameStateProvisional",
300 "WebFrameStateCommittedPage",
301 "WebFrameStateComplete"
305 static CFAbsoluteTime _timeOfLastCompletedLoad;
307 + (CFAbsoluteTime)timeOfLastCompletedLoad
309 return _timeOfLastCompletedLoad;
312 - (void)_setState:(WebFrameState)newState
314 LOG(Loading, "%@: transition from %s to %s", [client name], stateNames[state], stateNames[newState]);
315 if ([client webView])
316 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]);
318 if (newState == WebFrameStateComplete && client == [[client webView] mainFrame])
319 LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[[self dataSource] _documentLoadState] loadingStartedTime]);
323 if (state == WebFrameStateProvisional)
324 [client _provisionalLoadStarted];
325 else if (state == WebFrameStateComplete) {
326 [client _frameLoadCompleted];
327 _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
328 [[self documentLoadState] stopRecordingResponses];
332 - (void)clearProvisionalLoad
334 [self _setProvisionalDocumentLoadState:nil];
335 [[client webView] _progressCompleted:client];
336 [self _setState:WebFrameStateComplete];
339 - (void)markLoadComplete
341 [self _setState:WebFrameStateComplete];
344 - (void)commitProvisionalLoad
346 [self stopLoadingSubresources];
347 [self stopLoadingPlugIns];
349 [self _setDocumentLoadState:provisionalDocumentLoadState];
350 [self _setProvisionalDocumentLoadState:nil];
351 [self _setState:WebFrameStateCommittedPage];
356 [[self provisionalDocumentLoadState] stopLoading];
357 [[self documentLoadState] stopLoading];
358 [self _clearProvisionalDataSource];
359 [self clearArchivedResources];
362 // FIXME: poor method name; also why is this not part of startProvisionalLoad:?
365 [[self provisionalDataSource] _startLoading];
368 - (void)startProvisionalLoad:(WebDataSource *)ds
370 [self _setProvisionalDocumentLoadState:[ds _documentLoadState]];
371 [self _setState:WebFrameStateProvisional];
374 - (void)setupForReplace
376 [self _setState:WebFrameStateProvisional];
377 WebDocumentLoadState *old = provisionalDocumentLoadState;
378 provisionalDocumentLoadState = documentLoadState;
379 documentLoadState = nil;
382 [client _detachChildren];
385 - (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
387 return [[self activeDataSource] _identifierForInitialRequest:clientRequest];
390 - (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
392 return [[self activeDataSource] _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
395 - (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
397 [[self activeDataSource] _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
400 - (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
402 [[self activeDataSource] _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
405 - (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
407 [[self activeDataSource] _didReceiveResponse:r forResource:identifier];
410 - (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
412 [[self activeDataSource] _didReceiveData:data contentLength:lengthReceived forResource:identifier];
415 - (void)_didFinishLoadingForResource:(id)identifier
417 [[self activeDataSource] _didFinishLoadingForResource:identifier];
420 - (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
422 [[self activeDataSource] _didFailLoadingWithError:error forResource:identifier];
425 - (BOOL)_privateBrowsingEnabled
427 return [[[client webView] preferences] privateBrowsingEnabled];
430 - (void)_finishedLoadingResource
432 [client _checkLoadComplete];
435 - (void)_receivedError:(NSError *)error
437 [client _checkLoadComplete];
440 - (NSURLRequest *)_originalRequest
442 return [[self activeDocumentLoadState] originalRequestCopy];
445 - (WebFrame *)webFrame
450 - (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
452 WebDataSource *ds = [self activeDataSource];
454 [ds _receivedMainResourceError:error complete:isComplete];
458 - (NSURLRequest *)initialRequest
460 return [[self activeDataSource] initialRequest];
463 - (void)_receivedData:(NSData *)data
465 [[self activeDocumentLoadState] receivedData:data];
468 - (void)_setRequest:(NSURLRequest *)request
470 [[self activeDocumentLoadState] setRequest:request];
473 - (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(id)proxy
475 [[self activeDataSource] _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
478 - (WebFrameBridge *)bridge
480 return [client _bridge];
483 - (void)_handleFallbackContent
485 [[self bridge] handleFallbackContent];
490 return [[self activeDocumentLoadState] isStopping];
493 - (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
495 [[self activeDocumentLoadState] setupForReplaceByMIMEType:newMIMEType];
498 - (void)_setResponse:(NSURLResponse *)response
500 [[self activeDocumentLoadState] setResponse:response];
503 - (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
505 [[self activeDocumentLoadState] mainReceivedError:error complete:isComplete];
508 - (void)_finishedLoading
510 WebDataSource *ds = [self activeDataSource];
513 [[self activeDocumentLoadState] finishedLoading];
515 if ([ds _mainDocumentError] || ![ds webFrame]) {
520 [[self activeDocumentLoadState] setPrimaryLoadComplete:YES];
521 if ([WebScriptDebugServer listenerCount])
522 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
523 [client _checkLoadComplete];
528 - (void)_notifyIconChanged:(NSURL *)iconURL
530 ASSERT([[WebIconDatabase sharedIconDatabase] _isEnabled]);
531 ASSERT(client == [[client webView] mainFrame]);
533 [[client webView] _willChangeValueForKey:_WebMainFrameIconKey];
535 NSImage *icon = [[WebIconDatabase sharedIconDatabase] iconForURL:[[[self activeDataSource] _URL] _web_originalDataAsString] withSize:WebIconSmallSize];
537 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
541 [[client webView] _didChangeValueForKey:_WebMainFrameIconKey];
546 return [[self activeDataSource] _URL];
549 - (NSError *)cancelledErrorWithRequest:(NSURLRequest *)request
551 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
552 code:NSURLErrorCancelled
556 - (NSError *)fileDoesNotExistErrorWithResponse:(NSURLResponse *)response
558 return [NSError _webKitErrorWithDomain:NSURLErrorDomain
559 code:NSURLErrorFileDoesNotExist
563 - (void)clearArchivedResources
565 [pendingArchivedResources removeAllObjects];
566 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
569 - (void)deliverArchivedResources
571 if (![pendingArchivedResources count] || [self defersCallbacks])
574 NSEnumerator *keyEnum = [pendingArchivedResources keyEnumerator];
576 while ((loader = [keyEnum nextObject])) {
577 WebResource *resource = [pendingArchivedResources objectForKey:loader];
578 [loader didReceiveResponse:[resource _response]];
579 NSData *data = [resource data];
580 [loader didReceiveData:data lengthReceived:[data length] allAtOnce:YES];
581 [loader didFinishLoading];
584 [pendingArchivedResources removeAllObjects];
587 - (void)deliverArchivedResourcesAfterDelay
589 if (![pendingArchivedResources count] || [self defersCallbacks])
592 [self performSelector:@selector(deliverArchivedResources) withObject:nil afterDelay:0];
595 static BOOL isCaseInsensitiveEqual(NSString *a, NSString *b)
597 return [a caseInsensitiveCompare:b] == NSOrderedSame;
600 // The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
601 // FIXME: It would be nice to eventually to share this code somehow.
602 - (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
604 NSURLRequestCachePolicy policy = [theRequest cachePolicy];
606 if (policy == NSURLRequestReturnCacheDataElseLoad) {
608 } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
610 } else if (policy == NSURLRequestReloadIgnoringCacheData) {
612 } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
614 } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
616 } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
618 } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
620 } else if (isCaseInsensitiveEqual(@"POST", [theRequest HTTPMethod])) {
627 - (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
629 if (WKGetNSURLResponseMustRevalidate(theResponse)) {
631 } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
638 - (NSMutableDictionary *)pendingArchivedResources
640 if (!pendingArchivedResources)
641 pendingArchivedResources = [[NSMutableDictionary alloc] init];
643 return pendingArchivedResources;
646 - (BOOL)willUseArchiveForRequest:(NSURLRequest *)r originalURL:(NSURL *)originalURL loader:(WebLoader *)loader
648 if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
649 WebResource *resource = [self _archivedSubresourceForURL:originalURL];
650 if (resource && [self _canUseResourceWithResponse:[resource _response]]) {
651 [[self pendingArchivedResources] _webkit_setObject:resource forUncopiedKey:loader];
652 // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
653 [self deliverArchivedResourcesAfterDelay];
660 - (BOOL)archiveLoadPendingForLoader:(WebLoader *)loader
662 return [pendingArchivedResources objectForKey:loader] != nil;
665 - (void)cancelPendingArchiveLoadForLoader:(WebLoader *)loader
667 [pendingArchivedResources removeObjectForKey:loader];
669 if (![pendingArchivedResources count])
670 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverArchivedResources) object:nil];
673 - (void)_addExtraFieldsToRequest:(NSMutableURLRequest *)request mainResource:(BOOL)mainResource alwaysFromRequest:(BOOL)f
675 [client _addExtraFieldsToRequest:request mainResource:mainResource alwaysFromRequest:f];
678 - (void)cannotShowMIMETypeForURL:(NSURL *)URL
680 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
683 - (NSError *)interruptForPolicyChangeErrorWithRequest:(NSURLRequest *)request
685 return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
688 - (BOOL)isHostedByObjectElement
690 // Handle <object> fallback for error cases.
691 DOMHTMLElement *hostElement = [client frameElement];
692 return hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]];
695 - (BOOL)isLoadingMainFrame
697 return [client _isMainFrame];
700 + (BOOL)_canShowMIMEType:(NSString *)MIMEType
702 return [WebView canShowMIMEType:MIMEType];
705 + (BOOL)_representationExistsForURLScheme:(NSString *)URLScheme
707 return [WebView _representationExistsForURLScheme:URLScheme];
710 + (NSString *)_generatedMIMETypeForURLScheme:(NSString *)URLScheme
712 return [WebView _generatedMIMETypeForURLScheme:URLScheme];
715 - (void)_checkNavigationPolicyForRequest:(NSURLRequest *)newRequest andCall:(id)obj withSelector:(SEL)sel
717 [self checkNavigationPolicyForRequest:newRequest
718 dataSource:[self activeDataSource]
724 - (void)_checkContentPolicyForMIMEType:(NSString *)MIMEType andCall:(id)obj withSelector:(SEL)sel
726 WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc] _initWithTarget:obj action:sel];
730 [[self activeDataSource] _decidePolicyForMIMEType:MIMEType decisionListener:l];
734 - (void)cancelContentPolicy
736 [listener _invalidate];
741 - (BOOL)shouldReloadToHandleUnreachableURLFromRequest:(NSURLRequest *)request
743 NSURL *unreachableURL = [request _webDataRequestUnreachableURL];
744 if (unreachableURL == nil) {
748 if (policyLoadType != WebFrameLoadTypeForward
749 && policyLoadType != WebFrameLoadTypeBack
750 && policyLoadType != WebFrameLoadTypeIndexedBackForward) {
754 // We only treat unreachableURLs specially during the delegate callbacks
755 // for provisional load errors and navigation policy decisions. The former
756 // case handles well-formed URLs that can't be loaded, and the latter
757 // case handles malformed URLs and unknown schemes. Loading alternate content
758 // at other times behaves like a standard load.
759 WebDataSource *compareDataSource = nil;
760 if (delegateIsDecidingNavigationPolicy || delegateIsHandlingUnimplementablePolicy) {
761 compareDataSource = [self policyDataSource];
762 } else if (delegateIsHandlingProvisionalLoadError) {
763 compareDataSource = [self provisionalDataSource];
766 return compareDataSource != nil && [unreachableURL isEqual:[[compareDataSource request] URL]];
769 - (void)_loadRequest:(NSURLRequest *)request archive:(WebArchive *)archive
771 WebFrameLoadType type;
773 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
774 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
776 NSMutableURLRequest *r = [newDataSource request];
777 [client _addExtraFieldsToRequest:r mainResource:YES alwaysFromRequest:NO];
778 if ([client _shouldTreatURLAsSameAsCurrent:[request URL]]) {
779 [r setCachePolicy:NSURLRequestReloadIgnoringCacheData];
780 type = WebFrameLoadTypeSame;
782 type = WebFrameLoadTypeStandard;
784 [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
785 [newDataSource _addToUnarchiveState:archive];
787 // When we loading alternate content for an unreachable URL that we're
788 // visiting in the b/f list, we treat it as a reload so the b/f list
789 // is appropriately maintained.
790 if ([self shouldReloadToHandleUnreachableURLFromRequest:request]) {
791 ASSERT(type == WebFrameLoadTypeStandard);
792 type = WebFrameLoadTypeReload;
795 [self loadDataSource:newDataSource withLoadType:type formState:nil];
798 - (void)_loadRequest:(NSURLRequest *)request triggeringAction:(NSDictionary *)action loadType:(WebFrameLoadType)type formState:(WebFormState *)formState
800 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
801 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
803 [policyDocumentLoadState setTriggeringAction:action];
805 [policyDocumentLoadState setOverrideEncoding:[[self documentLoadState] overrideEncoding]];
807 [self loadDataSource:newDataSource withLoadType:type formState:formState];
810 - (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
812 WebDataSource *ds = [self dataSource];
816 NSMutableURLRequest *request = [[ds request] mutableCopy];
817 NSURL *unreachableURL = [ds unreachableURL];
818 if (unreachableURL != nil)
819 [request setURL:unreachableURL];
821 [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
822 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:request];
823 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
826 [policyDocumentLoadState setOverrideEncoding:encoding];
828 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReloadAllowingStaleData formState:nil];
833 WebDataSource *ds = [self dataSource];
837 NSMutableURLRequest *initialRequest = [ds request];
839 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
840 // Reloading in this case will lose the current contents (see 4151001).
841 if ([[[[ds request] URL] absoluteString] length] == 0)
844 // Replace error-page URL with the URL we were trying to reach.
845 NSURL *unreachableURL = [initialRequest _webDataRequestUnreachableURL];
846 if (unreachableURL != nil)
847 initialRequest = [NSURLRequest requestWithURL:unreachableURL];
849 policyDocumentLoadState = [client _createDocumentLoadStateWithRequest:initialRequest];
850 WebDataSource *newDataSource = [client _dataSourceForDocumentLoadState:policyDocumentLoadState];
851 NSMutableURLRequest *request = [newDataSource request];
853 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
855 // If we're about to rePOST, set up action so the app can warn the user
856 if ([[request HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
857 NSDictionary *action = [client _actionInformationForNavigationType:WebNavigationTypeFormResubmitted event:nil originalURL:[request URL]];
858 [policyDocumentLoadState setTriggeringAction:action];
861 [policyDocumentLoadState setOverrideEncoding:[[ds _documentLoadState] overrideEncoding]];
863 [self loadDataSource:newDataSource withLoadType:WebFrameLoadTypeReload formState:nil];
866 - (void)didReceiveServerRedirectForProvisionalLoadForFrame
868 [client _didReceiveServerRedirectForProvisionalLoadForFrame];
871 - (void)finishedLoadingDocumentLoadState:(WebDocumentLoadState *)loadState
873 [[client _dataSourceForDocumentLoadState:loadState] _finishedLoading];
876 - (void)commitProvisitionalLoad
878 [client _commitProvisionalLoad:nil];
881 - (void)committedLoadWithDocumentLoadState:(WebDocumentLoadState *)loadState data:(NSData *)data
883 [[client _dataSourceForDocumentLoadState:loadState] _receivedData:data];
888 return loadType == WebFrameLoadTypeReplace;
893 loadType = WebFrameLoadTypeReplace;
896 - (void)revertToProvisionalWithDocumentLoadState:(WebDocumentLoadState *)loadState
898 [[client _dataSourceForDocumentLoadState:loadState] _revertToProvisionalState];
901 - (void)documentLoadState:(WebDocumentLoadState *)loadState setMainDocumentError:(NSError *)error
903 [[client _dataSourceForDocumentLoadState:loadState] _setMainDocumentError:error];
906 - (void)documentLoadState:(WebDocumentLoadState *)loadState mainReceivedCompleteError:(NSError *)error
908 [loadState setPrimaryLoadComplete:YES];
909 if ([WebScriptDebugServer listenerCount])
910 [[WebScriptDebugServer sharedScriptDebugServer] webView:[client webView] didLoadMainResourceForDataSource:[self activeDataSource]];
911 [client _checkLoadComplete];
914 - (void)finalSetupForReplaceWithDocumentLoadState:(WebDocumentLoadState *)loadState
916 [[client _dataSourceForDocumentLoadState:loadState] _clearUnarchivingState];
919 - (void)prepareForLoadStart
921 [[client webView] _progressStarted:client];
922 [[client webView] _didStartProvisionalLoadForFrame:client];
923 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
924 didStartProvisionalLoadForFrame:client];
927 - (BOOL)subframeIsLoading
929 return [client _subframeIsLoading];
932 - (void)willChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
934 // FIXME: should do this only in main frame case, right?
935 [[client webView] _willChangeValueForKey:_WebMainFrameTitleKey];
938 - (void)didChangeTitleForDocumentLoadState:(WebDocumentLoadState *)loadState
940 // FIXME: should do this only in main frame case, right?
941 [[client webView] _didChangeValueForKey:_WebMainFrameTitleKey];
943 // The title doesn't get communicated to the WebView until we are committed.
944 if ([loadState isCommitted]) {
945 NSURL *URLForHistory = [[client _dataSourceForDocumentLoadState:loadState] _URLForHistory];
946 if (URLForHistory != nil) {
947 WebHistoryItem *entry = [[WebHistory optionalSharedHistory] itemForURL:URLForHistory];
948 [entry setTitle:[loadState title]];
950 // Must update the entries in the back-forward list too. This must go through the WebFrame because
951 // it has the right notion of the current b/f item.
952 [client _setTitle:[loadState title]];
954 [[client webView] setMainFrameDocumentReady:YES]; // update observers with new DOMDocument
955 [[[client webView] _frameLoadDelegateForwarder] webView:[client webView]
956 didReceiveTitle:[loadState title]
962 - (WebFrameLoadType)loadType
967 - (void)setLoadType:(WebFrameLoadType)type
972 - (void)invalidatePendingPolicyDecisionCallingDefaultAction:(BOOL)call
974 [listener _invalidate];
978 NSURLRequest *request = policyRequest;
979 NSString *frameName = policyFrameName;
980 id target = policyTarget;
981 SEL selector = policySelector;
982 WebFormState *formState = policyFormState;
985 policyFrameName = nil;
987 policySelector = nil;
988 policyFormState = nil;
992 objc_msgSend(target, selector, nil, nil, nil);
994 objc_msgSend(target, selector, nil, nil);
1000 [formState release];
1003 - (void)checkNewWindowPolicyForRequest:(NSURLRequest *)request action:(NSDictionary *)action frameName:(NSString *)frameName formState:(WebFormState *)formState andCall:(id)target withSelector:(SEL)selector
1005 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc]
1006 _initWithTarget:self action:@selector(_continueAfterNewWindowPolicy:)];
1008 policyRequest = [request retain];
1009 policyTarget = [target retain];
1010 policyFrameName = [frameName retain];
1011 policySelector = selector;
1012 listener = [decisionListener retain];
1013 policyFormState = [formState retain];
1015 WebView *wv = [client webView];
1016 [[wv _policyDelegateForwarder] webView:wv
1017 decidePolicyForNewWindowAction:action
1019 newFrameName:frameName
1020 decisionListener:decisionListener];
1022 [decisionListener release];
1025 -(void)_continueAfterNewWindowPolicy:(WebPolicyAction)policy
1027 NSURLRequest *request = [[policyRequest retain] autorelease];
1028 NSString *frameName = [[policyFrameName retain] autorelease];
1029 id target = [[policyTarget retain] autorelease];
1030 SEL selector = policySelector;
1031 WebFormState *formState = [[policyFormState retain] autorelease];
1033 // will release policy* objects, hence the above retains
1034 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1036 BOOL shouldContinue = NO;
1039 case WebPolicyIgnore:
1041 case WebPolicyDownload:
1042 // FIXME: should download full request
1043 [[client webView] _downloadURL:[request URL]];
1046 shouldContinue = YES;
1049 ASSERT_NOT_REACHED();
1052 objc_msgSend(target, selector, shouldContinue ? request : nil, frameName, formState);
1055 - (void)checkNavigationPolicyForRequest:(NSURLRequest *)request
1056 dataSource:(WebDataSource *)dataSource
1057 formState:(WebFormState *)formState
1059 withSelector:(SEL)selector
1061 NSDictionary *action = [[dataSource _documentLoadState] triggeringAction];
1062 if (action == nil) {
1063 action = [client _actionInformationForNavigationType:WebNavigationTypeOther event:nil originalURL:[request URL]];
1064 [[dataSource _documentLoadState] setTriggeringAction:action];
1067 // Don't ask more than once for the same request or if we are loading an empty URL.
1068 // This avoids confusion on the part of the client.
1069 if ([request isEqual:[[dataSource _documentLoadState] lastCheckedRequest]] || [[request URL] _web_isEmpty]) {
1070 [target performSelector:selector withObject:request withObject:nil];
1074 // We are always willing to show alternate content for unreachable URLs;
1075 // treat it like a reload so it maintains the right state for b/f list.
1076 if ([request _webDataRequestUnreachableURL] != nil) {
1077 if (policyLoadType == WebFrameLoadTypeForward
1078 || policyLoadType == WebFrameLoadTypeBack
1079 || policyLoadType == WebFrameLoadTypeIndexedBackForward) {
1080 policyLoadType = WebFrameLoadTypeReload;
1082 [target performSelector:selector withObject:request withObject:nil];
1086 [[dataSource _documentLoadState] setLastCheckedRequest:request];
1088 WebPolicyDecisionListener *decisionListener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterNavigationPolicy:)];
1090 ASSERT(policyRequest == nil);
1091 policyRequest = [request retain];
1092 ASSERT(policyTarget == nil);
1093 policyTarget = [target retain];
1094 policySelector = selector;
1095 ASSERT(listener == nil);
1096 listener = [decisionListener retain];
1097 ASSERT(policyFormState == nil);
1098 policyFormState = [formState retain];
1100 WebView *wv = [client webView];
1101 delegateIsDecidingNavigationPolicy = YES;
1102 [[wv _policyDelegateForwarder] webView:wv
1103 decidePolicyForNavigationAction:action
1106 decisionListener:decisionListener];
1107 delegateIsDecidingNavigationPolicy = NO;
1109 [decisionListener release];
1112 - (void)continueAfterNavigationPolicy:(WebPolicyAction)policy
1114 NSURLRequest *request = [[policyRequest retain] autorelease];
1115 id target = [[policyTarget retain] autorelease];
1116 SEL selector = policySelector;
1117 WebFormState *formState = [[policyFormState retain] autorelease];
1119 // will release policy* objects, hence the above retains
1120 [self invalidatePendingPolicyDecisionCallingDefaultAction:NO];
1122 BOOL shouldContinue = NO;
1125 case WebPolicyIgnore:
1127 case WebPolicyDownload:
1128 // FIXME: should download full request
1129 [[client webView] _downloadURL:[request URL]];
1132 if (![WebView _canHandleRequest:request]) {
1133 [self handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowURL forURL:[request URL]];
1135 shouldContinue = YES;
1139 ASSERT_NOT_REACHED();
1142 [target performSelector:selector withObject:(shouldContinue ? request : nil) withObject:formState];
1145 // Called after the FormsDelegate is done processing willSubmitForm:
1146 - (void)continueAfterWillSubmitForm:(WebPolicyAction)policy
1149 [listener _invalidate];
1153 [self startLoading];
1156 - (void)continueLoadRequestAfterNavigationPolicy:(NSURLRequest *)request formState:(WebFormState *)formState
1158 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
1159 // nil policyDataSource because loading the alternate page will have passed
1160 // through this method already, nested; otherwise, policyDataSource should still be set.
1161 ASSERT([self policyDataSource] || [[self provisionalDataSource] unreachableURL] != nil);
1163 BOOL isTargetItem = [client _provisionalItemIsTarget];
1165 // Two reasons we can't continue:
1166 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
1167 // is the user responding Cancel to the form repost nag sheet.
1168 // 2) User responded Cancel to an alert popped up by the before unload event handler.
1169 // The "before unload" event handler runs only for the main frame.
1170 BOOL canContinue = request && ([[client webView] mainFrame] != client || [[self bridge] shouldClose]);
1173 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
1174 // need to report that the client redirect was cancelled.
1175 if ([client _quickRedirectComing])
1176 [client _clientRedirectCancelledOrFinished:NO];
1178 [self _setPolicyDocumentLoadState:nil];
1179 // If the navigation request came from the back/forward menu, and we punt on it, we have the
1180 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
1181 // we only do this when punting a navigation for the target frame or top-level frame.
1182 if ((isTargetItem || [[client webView] mainFrame] == client)
1183 && (policyLoadType == WebFrameLoadTypeForward
1184 || policyLoadType == WebFrameLoadTypeBack
1185 || policyLoadType == WebFrameLoadTypeIndexedBackForward))
1186 [(WebFrame <WebFrameLoaderClient> *)[[client webView] mainFrame] _resetBackForwardList];
1190 WebFrameLoadType type = policyLoadType;
1191 WebDataSource *dataSource = [[self policyDataSource] retain];
1196 [self startProvisionalLoad:dataSource];
1198 [dataSource release];
1199 [self _setPolicyDocumentLoadState:nil];
1201 if (client == [[client webView] mainFrame])
1202 LOG(DocumentLoad, "loading %@", [[[self provisionalDataSource] request] URL]);
1204 if (type == WebFrameLoadTypeForward || type == WebFrameLoadTypeBack || type == WebFrameLoadTypeIndexedBackForward) {
1205 if ([client _loadProvisionalItemFromPageCache])
1210 // It's a bit of a hack to reuse the WebPolicyDecisionListener for the continuation
1211 // mechanism across the willSubmitForm callout.
1212 listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(continueAfterWillSubmitForm:)];
1213 [[[client webView] _formDelegate] frame:client sourceFrame:[formState sourceFrame] willSubmitForm:[formState form] withValues:[formState values] submissionListener:listener];
1216 [self continueAfterWillSubmitForm:WebPolicyUse];
1220 - (void)loadDataSource:(WebDataSource *)newDataSource withLoadType:(WebFrameLoadType)type formState:(WebFormState *)formState
1222 ASSERT([client webView] != nil);
1224 // Unfortunately the view must be non-nil, this is ultimately due
1225 // to parser requiring a FrameView. We should fix this dependency.
1227 ASSERT([client frameView] != nil);
1229 policyLoadType = type;
1231 WebFrame *parentFrame = [client parentFrame];
1233 [[newDataSource _documentLoadState] setOverrideEncoding:[[[parentFrame dataSource] _documentLoadState] overrideEncoding]];
1235 WebDocumentLoadStateMac *loadState = (WebDocumentLoadStateMac *)[newDataSource _documentLoadState];
1236 [loadState setFrameLoader:self];
1237 [loadState setDataSource:newDataSource];
1239 [self invalidatePendingPolicyDecisionCallingDefaultAction:YES];
1241 [self _setPolicyDocumentLoadState:[newDataSource _documentLoadState]];
1243 [self checkNavigationPolicyForRequest:[newDataSource request]
1244 dataSource:newDataSource
1247 withSelector:@selector(continueLoadRequestAfterNavigationPolicy:formState:)];
1250 - (void)handleUnimplementablePolicyWithErrorCode:(int)code forURL:(NSURL *)URL
1252 NSError *error = [NSError _webKitErrorWithDomain:WebKitErrorDomain code:code URL:URL];
1253 WebView *wv = [client webView];
1254 delegateIsHandlingUnimplementablePolicy = YES;
1255 [[wv _policyDelegateForwarder] webView:wv unableToImplementPolicyWithError:error frame:client];
1256 delegateIsHandlingUnimplementablePolicy = NO;
1259 - (BOOL)delegateIsHandlingProvisionalLoadError
1261 return delegateIsHandlingProvisionalLoadError;
1264 - (void)setDelegateIsHandlingProvisionalLoadError:(BOOL)is
1266 delegateIsHandlingProvisionalLoadError = is;