WebKit:
authorddkilzer <ddkilzer@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Aug 2006 11:23:37 +0000 (11:23 +0000)
committerddkilzer <ddkilzer@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Aug 2006 11:23:37 +0000 (11:23 +0000)
        Reviewed by NOBODY (build fix).

        * WebCoreSupport/WebSubresourceLoader.m: REALLY moved to Loader/
        * WebView/WebFrameLoader.h: REALLY moved to Loader/
        * WebView/WebFrameLoader.m: REALLY moved to Loader/
        * WebView/WebLoader.h: REALLY moved to Loader/
        * WebView/WebLoader.m: REALLY moved to Loader/
        * WebView/WebMainResourceLoader.m: REALLY moved to Loader/

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15796 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/ChangeLog
WebKit/Loader/WebFrameLoader.h [new file with mode: 0644]
WebKit/Loader/WebFrameLoader.m [new file with mode: 0644]
WebKit/Loader/WebLoader.h [new file with mode: 0644]
WebKit/Loader/WebLoader.m [new file with mode: 0644]
WebKit/Loader/WebMainResourceLoader.m [new file with mode: 0644]
WebKit/Loader/WebSubresourceLoader.m [new file with mode: 0644]

index c2a1b8bd9994ec32c8a953d88dbb2366d4b13511..27db8f2b523afbd3d847dd98ec86340322c57341 100644 (file)
@@ -1,3 +1,14 @@
+2006-08-04  David Kilzer  <ddkilzer@kilzer.net>
+
+        Reviewed by NOBODY (build fix).
+
+        * WebCoreSupport/WebSubresourceLoader.m: REALLY moved to Loader/
+        * WebView/WebFrameLoader.h: REALLY moved to Loader/
+        * WebView/WebFrameLoader.m: REALLY moved to Loader/
+        * WebView/WebLoader.h: REALLY moved to Loader/
+        * WebView/WebLoader.m: REALLY moved to Loader/
+        * WebView/WebMainResourceLoader.m: REALLY moved to Loader/
+
 2006-08-03  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Darin.
diff --git a/WebKit/Loader/WebFrameLoader.h b/WebKit/Loader/WebFrameLoader.h
new file mode 100644 (file)
index 0000000..8ed40a1
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKitSystemInterface.h>
+
+@class WebDataSource;
+@class WebMainResourceLoader;
+@class WebIconLoader;
+@class WebLoader;
+@class WebResource;
+
+@interface WebFrameLoader : NSObject
+{
+@public
+    // Client for main resource.
+    WebMainResourceLoader *mainResourceLoader;
+    
+    // Clients for other resources.
+    NSMutableArray *subresourceLoaders;
+    NSMutableArray *plugInStreamLoaders;
+    WebIconLoader *iconLoader;
+    
+    WebFrame *webFrame;
+    WebDataSource *dataSource;
+    WebDataSource *provisionalDataSource;
+    WebFrameState state;
+}
+
+- (id)initWithWebFrame:(WebFrame *)wf;
+// FIXME: should really split isLoadingIcon from hasLoadedIcon, no?
+- (BOOL)hasIconLoader;
+- (void)loadIconWithRequest:(NSURLRequest *)request;
+- (void)stopLoadingIcon;
+- (void)addPlugInStreamLoader:(WebLoader *)loader;
+- (void)removePlugInStreamLoader:(WebLoader *)loader;
+- (void)setDefersCallbacks:(BOOL)defers;
+- (void)stopLoadingPlugIns;
+- (BOOL)isLoadingMainResource;
+- (BOOL)isLoadingSubresources;
+- (BOOL)isLoading;
+- (void)stopLoadingSubresources;
+- (void)addSubresourceLoader:(WebLoader *)loader;
+- (void)removeSubresourceLoader:(WebLoader *)loader;
+- (NSData *)mainResourceData;
+- (void)releaseMainResourceLoader;
+- (void)cancelMainResourceLoad;
+- (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier;
+- (void)stopLoadingWithError:(NSError *)error;
+- (void)clearProvisionalLoad;
+- (void)stopLoading;
+- (void)markLoadComplete;
+- (void)commitProvisionalLoad;
+- (void)startLoading;
+- (void)startProvisionalLoad:(WebDataSource *)dataSource;
+- (WebDataSource *)dataSource;
+- (WebDataSource *)provisionalDataSource;
+- (WebDataSource *)activeDataSource;
+- (WebFrameState)state;
+- (void)clearDataSource;
+- (void)setupForReplace;
++ (CFAbsoluteTime)timeOfLastCompletedLoad;
+
+- (WebResource *)_archivedSubresourceForURL:(NSURL *)URL;
+- (BOOL)_defersCallbacks;
+- (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest;
+- (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse;
+- (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier;
+- (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier;
+- (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier;
+- (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier;
+- (void)_didFinishLoadingForResource:(id)identifier;
+- (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier;
+- (BOOL)_privateBrowsingEnabled;
+- (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier;
+- (void)_addPlugInStreamLoader:(WebLoader *)loader;
+- (void)_removePlugInStreamLoader:(WebLoader *)loader;
+- (void)_finishedLoadingResource;
+- (void)_receivedError:(NSError *)error;
+- (void)_addSubresourceLoader:(WebLoader *)loader;
+- (void)_removeSubresourceLoader:(WebLoader *)loader;
+- (NSURLRequest *)_originalRequest;
+- (WebFrame *)webFrame;
+- (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete;
+- (NSURLRequest *)initialRequest;
+- (void)_receivedData:(NSData *)data;
+- (void)_setRequest:(NSURLRequest *)request;
+- (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr)proxy;
+- (void)_handleFallbackContent;
+- (BOOL)_isStopping;
+- (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener;
+- (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType;
+- (void)_setResponse:(NSURLResponse *)response;
+- (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete;
+- (void)_finishedLoading;
+- (void)_mainReceivedBytesSoFar:(unsigned)bytesSoFar complete:(BOOL)isComplete;
+- (void)_iconLoaderReceivedPageIcon:(WebIconLoader *)iconLoader;
+- (NSURL *)_URL;
+
+@end
diff --git a/WebKit/Loader/WebFrameLoader.m b/WebKit/Loader/WebFrameLoader.m
new file mode 100644 (file)
index 0000000..66ac749
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WebFrameLoader.h>
+
+#import <JavaScriptCore/Assertions.h>
+#import <WebKit/WebDataSourceInternal.h>
+#import <WebKit/WebFrameInternal.h>
+#import <WebKit/WebIconLoader.h>
+#import <WebKit/WebMainResourceLoader.h>
+#import <WebKit/WebKitLogging.h>
+#import <WebKit/WebViewInternal.h>
+
+@implementation WebFrameLoader
+
+- (id)initWithWebFrame:(WebFrame *)wf
+{
+    self = [super init];
+    if (self) {
+        webFrame = wf;
+        state = WebFrameStateCommittedPage;
+    }
+    return self;    
+}
+
+- (void)dealloc
+{
+    // FIXME: should these even exist?
+    [mainResourceLoader release];
+    [subresourceLoaders release];
+    [plugInStreamLoaders release];
+    [iconLoader release];
+    [dataSource release];
+    [provisionalDataSource release];
+    
+    [super dealloc];
+}
+
+- (BOOL)hasIconLoader
+{
+    return iconLoader != nil;
+}
+
+- (void)loadIconWithRequest:(NSURLRequest *)request
+{
+    ASSERT(!iconLoader);
+    iconLoader = [[WebIconLoader alloc] initWithRequest:request];
+    [iconLoader setFrameLoader:self];
+    [iconLoader loadWithRequest:request];
+}
+
+- (void)stopLoadingIcon
+{
+    [iconLoader stopLoading];
+}
+
+- (void)addPlugInStreamLoader:(WebLoader *)loader
+{
+    if (!plugInStreamLoaders)
+        plugInStreamLoaders = [[NSMutableArray alloc] init];
+    [plugInStreamLoaders addObject:loader];
+}
+
+- (void)removePlugInStreamLoader:(WebLoader *)loader
+{
+    [plugInStreamLoaders removeObject:loader];
+}    
+
+- (void)setDefersCallbacks:(BOOL)defers
+{
+    [mainResourceLoader setDefersCallbacks:defers];
+    
+    NSEnumerator *e = [subresourceLoaders objectEnumerator];
+    WebLoader *loader;
+    while ((loader = [e nextObject]))
+        [loader setDefersCallbacks:defers];
+    
+    e = [plugInStreamLoaders objectEnumerator];
+    while ((loader = [e nextObject]))
+        [loader setDefersCallbacks:defers];
+}
+
+- (void)stopLoadingPlugIns
+{
+    [plugInStreamLoaders makeObjectsPerformSelector:@selector(cancel)];
+    [plugInStreamLoaders removeAllObjects];   
+}
+
+- (BOOL)isLoadingMainResource
+{
+    return mainResourceLoader != nil;
+}
+
+- (BOOL)isLoadingSubresources
+{
+    return [subresourceLoaders count];
+}
+
+- (BOOL)isLoadingPlugIns
+{
+    return [plugInStreamLoaders count];
+}
+
+- (BOOL)isLoading
+{
+    return [self isLoadingMainResource] || [self isLoadingSubresources] || [self isLoadingPlugIns];
+}
+
+- (void)stopLoadingSubresources
+{
+    NSArray *loaders = [subresourceLoaders copy];
+    [loaders makeObjectsPerformSelector:@selector(cancel)];
+    [loaders release];
+    [subresourceLoaders removeAllObjects];
+}
+
+- (void)addSubresourceLoader:(WebLoader *)loader
+{
+    if (subresourceLoaders == nil)
+        subresourceLoaders = [[NSMutableArray alloc] init];
+    [subresourceLoaders addObject:loader];
+}
+
+- (void)removeSubresourceLoader:(WebLoader *)loader
+{
+    [subresourceLoaders removeObject:loader];
+}
+
+- (NSData *)mainResourceData
+{
+    return [mainResourceLoader resourceData];
+}
+
+- (void)releaseMainResourceLoader
+{
+    [mainResourceLoader release];
+    mainResourceLoader = nil;
+}
+
+- (void)cancelMainResourceLoad
+{
+    [mainResourceLoader cancel];
+}
+
+- (BOOL)startLoadingMainResourceWithRequest:(NSMutableURLRequest *)request identifier:(id)identifier
+{
+    mainResourceLoader = [[WebMainResourceLoader alloc] initWithFrameLoader:self];
+    
+    [mainResourceLoader setIdentifier:identifier];
+    [[provisionalDataSource webFrame] _addExtraFieldsToRequest:request mainResource:YES alwaysFromRequest:NO];
+    if (![mainResourceLoader loadWithRequest:request]) {
+        // FIXME: if this should really be caught, we should just ASSERT this doesn't happen;
+        // should it be caught by other parts of WebKit or other parts of the app?
+        LOG_ERROR("could not create WebResourceHandle for URL %@ -- should be caught by policy handler level", [request URL]);
+        [mainResourceLoader release];
+        mainResourceLoader = nil;
+        return NO;
+    }
+    
+    return YES;
+}
+
+- (void)stopLoadingWithError:(NSError *)error
+{
+    [mainResourceLoader cancelWithError:error];
+}
+
+- (WebDataSource *)dataSource
+{
+    return dataSource; 
+}
+
+- (void)_setDataSource:(WebDataSource *)ds
+{
+    if (ds == nil && dataSource == nil)
+        return;
+    
+    ASSERT(ds != dataSource);
+    
+    [webFrame _prepareForDataSourceReplacement];
+    [dataSource _setWebFrame:nil];
+    
+    [ds retain];
+    [dataSource release];
+    dataSource = ds;
+
+    [ds _setWebFrame:webFrame];
+}
+
+- (void)clearDataSource
+{
+    [self _setDataSource:nil];
+}
+
+- (WebDataSource *)provisionalDataSource 
+{
+    return provisionalDataSource; 
+}
+
+- (void)_setProvisionalDataSource: (WebDataSource *)d
+{
+    ASSERT(!d || !provisionalDataSource);
+
+    if (provisionalDataSource != dataSource)
+        [provisionalDataSource _setWebFrame:nil];
+
+    [d retain];
+    [provisionalDataSource release];
+    provisionalDataSource = d;
+
+    [d _setWebFrame:webFrame];
+}
+
+- (void)_clearProvisionalDataSource
+{
+    [self _setProvisionalDataSource:nil];
+}
+
+- (WebFrameState)state
+{
+    return state;
+}
+
+#ifndef NDEBUG
+static const char * const stateNames[] = {
+    "WebFrameStateProvisional",
+    "WebFrameStateCommittedPage",
+    "WebFrameStateComplete"
+};
+#endif
+
+static CFAbsoluteTime _timeOfLastCompletedLoad;
+
++ (CFAbsoluteTime)timeOfLastCompletedLoad
+{
+    return _timeOfLastCompletedLoad;
+}
+
+- (void)_setState:(WebFrameState)newState
+{
+    LOG(Loading, "%@:  transition from %s to %s", [webFrame name], stateNames[state], stateNames[newState]);
+    if ([webFrame webView])
+        LOG(Timing, "%@:  transition from %s to %s, %f seconds since start of document load", [webFrame name], stateNames[state], stateNames[newState], CFAbsoluteTimeGetCurrent() - [[[[webFrame webView] mainFrame] dataSource] _loadingStartedTime]);
+    
+    if (newState == WebFrameStateComplete && webFrame == [[webFrame webView] mainFrame])
+        LOG(DocumentLoad, "completed %@ (%f seconds)", [[[self dataSource] request] URL], CFAbsoluteTimeGetCurrent() - [[self dataSource] _loadingStartedTime]);
+    
+    state = newState;
+    
+    if (state == WebFrameStateProvisional)
+        [webFrame _provisionalLoadStarted];
+    else if (state == WebFrameStateComplete) {
+        [webFrame _frameLoadCompleted];
+        _timeOfLastCompletedLoad = CFAbsoluteTimeGetCurrent();
+        [dataSource _stopRecordingResponses];
+    }
+}
+
+- (void)clearProvisionalLoad
+{
+    [self _setProvisionalDataSource:nil];
+    [[webFrame webView] _progressCompleted:webFrame];
+    [self _setState:WebFrameStateComplete];
+}
+
+- (void)markLoadComplete
+{
+    [self _setState:WebFrameStateComplete];
+}
+
+- (void)clearIconLoader
+{
+    [iconLoader release];
+    iconLoader = nil;
+}
+
+- (void)commitProvisionalLoad
+{
+    [self stopLoadingSubresources];
+    [self stopLoadingPlugIns];
+    [self clearIconLoader];
+
+    [self _setDataSource:provisionalDataSource];
+    [self _setProvisionalDataSource:nil];
+    [self _setState:WebFrameStateCommittedPage];
+}
+
+- (void)stopLoading
+{
+    [provisionalDataSource _stopLoading];
+    [dataSource _stopLoading];
+    [self _clearProvisionalDataSource];
+}
+
+// FIXME: poor method name; also why is this not part of startProvisionalLoad:?
+- (void)startLoading
+{
+    [provisionalDataSource _startLoading];
+}
+
+- (void)startProvisionalLoad:(WebDataSource *)ds
+{
+    [self _setProvisionalDataSource:ds];
+    [self _setState:WebFrameStateProvisional];
+}
+
+- (void)setupForReplace
+{
+    [self _setState:WebFrameStateProvisional];
+    WebDataSource *old = provisionalDataSource;
+    provisionalDataSource = dataSource;
+    dataSource = nil;
+    [old release];
+    
+    [webFrame _detachChildren];
+}
+
+- (WebDataSource *)activeDataSource
+{
+    if (state == WebFrameStateProvisional)
+        return provisionalDataSource;
+
+    return dataSource;
+}
+
+- (WebResource *)_archivedSubresourceForURL:(NSURL *)URL
+{
+    return [[self activeDataSource] _archivedSubresourceForURL:URL];
+}
+
+- (BOOL)_defersCallbacks
+{
+    return [[self activeDataSource] _defersCallbacks];
+}
+
+- (id)_identifierForInitialRequest:(NSURLRequest *)clientRequest
+{
+    return [[self activeDataSource] _identifierForInitialRequest:clientRequest];
+}
+
+- (NSURLRequest *)_willSendRequest:(NSMutableURLRequest *)clientRequest forResource:(id)identifier redirectResponse:(NSURLResponse *)redirectResponse
+{
+    return [[self activeDataSource] _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
+}
+
+- (void)_didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
+{
+    return [[self activeDataSource] _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
+}
+
+- (void)_didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)currentWebChallenge forResource:(id)identifier
+{
+    return [[self activeDataSource] _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
+}
+
+- (void)_didReceiveResponse:(NSURLResponse *)r forResource:(id)identifier
+{
+    return [[self activeDataSource] _didReceiveResponse:r forResource:identifier];
+}
+
+- (void)_didReceiveData:(NSData *)data contentLength:(int)lengthReceived forResource:(id)identifier
+{
+    return [[self activeDataSource] _didReceiveData:data contentLength:lengthReceived forResource:identifier];
+}
+
+- (void)_didFinishLoadingForResource:(id)identifier
+{
+    return [[self activeDataSource] _didFinishLoadingForResource:identifier];
+}
+
+- (void)_didFailLoadingWithError:(NSError *)error forResource:(id)identifier
+{
+    return [[self activeDataSource] _didFailLoadingWithError:error forResource:identifier];
+}
+
+- (BOOL)_privateBrowsingEnabled
+{
+    return [[self activeDataSource] _privateBrowsingEnabled];
+}
+
+- (void)_addPlugInStreamLoader:(WebLoader *)loader
+{
+    return [[self activeDataSource] _addPlugInStreamLoader:loader];
+}
+
+- (void)_removePlugInStreamLoader:(WebLoader *)loader
+{
+    return [[self activeDataSource] _removePlugInStreamLoader:loader];
+}
+
+- (void)_finishedLoadingResource
+{
+    return [[self activeDataSource] _finishedLoadingResource];
+}
+
+- (void)_receivedError:(NSError *)error
+{
+    return [[self activeDataSource] _receivedError:error];
+}
+
+- (void)_addSubresourceLoader:(WebLoader *)loader
+{
+    return [[self activeDataSource] _addSubresourceLoader:loader];
+}
+
+- (void)_removeSubresourceLoader:(WebLoader *)loader
+{
+    return [[self activeDataSource] _removeSubresourceLoader:loader];
+}
+
+- (NSURLRequest *)_originalRequest
+{
+    return [[self activeDataSource] _originalRequest];
+}
+
+- (WebFrame *)webFrame
+{
+    return [[self activeDataSource] webFrame];
+}
+
+- (void)_receivedMainResourceError:(NSError *)error complete:(BOOL)isComplete
+{
+    WebDataSource *ds = [self activeDataSource];
+    [ds retain];
+    [ds _receivedMainResourceError:error complete:isComplete];
+    [ds release];
+}
+
+- (NSURLRequest *)initialRequest
+{
+    return [[self activeDataSource] initialRequest];
+}
+
+- (void)_receivedData:(NSData *)data
+{
+    [[self activeDataSource] _receivedData:data];
+}
+
+- (void)_setRequest:(NSURLRequest *)request
+{
+    [[self activeDataSource] _setRequest:request];
+}
+
+- (void)_downloadWithLoadingConnection:(NSURLConnection *)connection request:(NSURLRequest *)request response:(NSURLResponse *)r proxy:(WKNSURLConnectionDelegateProxyPtr)proxy
+{
+    [[self activeDataSource] _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
+}
+
+- (void)_handleFallbackContent
+{
+    [[self activeDataSource] _handleFallbackContent];
+}
+
+- (BOOL)_isStopping
+{
+    return [[self activeDataSource] _isStopping];
+}
+
+- (void)_decidePolicyForMIMEType:(NSString *)MIMEType decisionListener:(WebPolicyDecisionListener *)listener
+{
+    [[self activeDataSource] _decidePolicyForMIMEType:MIMEType decisionListener:listener];
+}
+
+- (void)_setupForReplaceByMIMEType:(NSString *)newMIMEType
+{
+    [[self activeDataSource] _setupForReplaceByMIMEType:newMIMEType];
+}
+
+- (void)_setResponse:(NSURLResponse *)response
+{
+    [[self activeDataSource] _setResponse:response];
+}
+
+- (void)_mainReceivedError:(NSError *)error complete:(BOOL)isComplete
+{
+    [[self activeDataSource] _mainReceivedError:error complete:isComplete];
+}
+
+- (void)_finishedLoading
+{
+    [[self activeDataSource] _finishedLoading];
+}
+
+- (void)_mainReceivedBytesSoFar:(unsigned)bytesSoFar complete:(BOOL)isComplete
+{
+    [[self activeDataSource] _mainReceivedBytesSoFar:bytesSoFar complete:isComplete];
+}
+
+- (void)_iconLoaderReceivedPageIcon:(WebIconLoader *)iLoader
+{
+    ASSERT(iLoader == iconLoader);
+    [[self activeDataSource] _iconLoaderReceivedPageIcon:iLoader];
+}
+
+- (NSURL *)_URL
+{
+    return [[self activeDataSource] _URL];
+}
+
+@end
diff --git a/WebKit/Loader/WebLoader.h b/WebKit/Loader/WebLoader.h
new file mode 100644 (file)
index 0000000..af8d1b5
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class NSError;
+@class NSURLAuthenticationChallenge;
+@class NSURLConnection;
+@class NSURLConnectionAuthenticationChallenge;
+@class NSURLCredential;
+@class NSURLRequest;
+@class NSURLResponse;
+@class WebDataSource;
+@class WebResource;
+@class WebFrameLoader;
+
+@interface WebLoader : NSObject
+{
+@protected
+    WebFrameLoader *frameLoader;
+    NSURLConnection *connection;
+    NSURLRequest *request;
+    BOOL reachedTerminalState;
+    BOOL loadingMultipartContent;
+    BOOL signalledFinish;
+    BOOL cancelledFlag;
+    id identifier;
+@private
+    NSURLResponse *response;
+    NSURLAuthenticationChallenge *currentConnectionChallenge;
+    NSURLAuthenticationChallenge *currentWebChallenge;
+    BOOL defersCallbacks;
+    BOOL waitingToDeliverResource;
+    BOOL deliveredResource;
+    NSURL *originalURL;
+    NSMutableData *resourceData;
+    WebResource *resource;
+#ifndef NDEBUG
+    BOOL isInitializingConnection;
+#endif
+}
+- (void)signalFinish;
+
+- (BOOL)loadWithRequest:(NSURLRequest *)request;
+
+- (void)setFrameLoader:(WebFrameLoader *)fl;
+- (WebFrameLoader *)frameLoader;
+
+- (void)cancel;
+- (void)cancelWithError:(NSError *)error;
+
+- (void)setDefersCallbacks:(BOOL)defers;
+- (BOOL)defersCallbacks;
+
+- (NSError *)cancelledError;
+
+- (void)setIdentifier:(id)ident;
+
+- (void)releaseResources;
+- (NSURLResponse *)response;
+
+- (void)addData:(NSData *)data;
+- (NSData *)resourceData;
+- (void)clearResourceData;
+
+// Connection-less callbacks allow us to send callbacks using data attained from a WebResource instead of an NSURLConnection.
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse;
+- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
+- (void)didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
+- (void)didReceiveResponse:(NSURLResponse *)r;
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived;
+- (void)willStopBufferingData:(NSData *)data;
+- (void)didFinishLoading;
+- (void)didFailWithError:(NSError *)error;
+- (NSCachedURLResponse *)willCacheResponse:(NSCachedURLResponse *)cachedResponse;
+
+// Used to work around the fact that you don't get any more NSURLConnection callbacks until you return from the first one.
++ (BOOL)inConnectionCallback;
+
+@end
+
+// Note: This interface can be removed once this method is declared
+// in Foundation (probably will be in Foundation-485).
+@interface NSObject (WebLoaderExtras)
+- (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived;
+@end
diff --git a/WebKit/Loader/WebLoader.m b/WebKit/Loader/WebLoader.m
new file mode 100644 (file)
index 0000000..a10544d
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WebLoader.h>
+
+#import <Foundation/NSURLAuthenticationChallenge.h>
+#import <Foundation/NSURLConnection.h>
+#import <Foundation/NSURLRequest.h>
+#import <Foundation/NSURLResponse.h>
+
+#import <JavaScriptCore/Assertions.h>
+#import <WebKit/WebDataProtocol.h>
+#import <WebKit/WebKitErrors.h>
+#import <WebKit/WebKitErrorsPrivate.h>
+#import <WebKit/WebFrameLoader.h>
+
+#import <WebKit/WebNSURLRequestExtras.h>
+#import <WebKit/WebKitNSStringExtras.h>
+#import <WebKit/WebResourcePrivate.h>
+#import <WebKitSystemInterface.h>
+
+static unsigned inNSURLConnectionCallback;
+static BOOL NSURLConnectionSupportsBufferedData;
+
+@interface NSURLConnection (NSURLConnectionTigerPrivate)
+- (NSData *)_bufferedData;
+@end
+
+@interface WebLoader (WebNSURLAuthenticationChallengeSender) <NSURLAuthenticationChallengeSender>
+@end
+
+@implementation WebLoader (WebNSURLAuthenticationChallengeSender) 
+
+- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    if (challenge == nil || challenge != currentWebChallenge) {
+        return;
+    }
+
+    [[currentConnectionChallenge sender] useCredential:credential forAuthenticationChallenge:currentConnectionChallenge];
+
+    [currentConnectionChallenge release];
+    currentConnectionChallenge = nil;
+    
+    [currentWebChallenge release];
+    currentWebChallenge = nil;
+}
+
+- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    if (challenge == nil || challenge != currentWebChallenge) {
+        return;
+    }
+
+    [[currentConnectionChallenge sender] continueWithoutCredentialForAuthenticationChallenge:currentConnectionChallenge];
+
+    [currentConnectionChallenge release];
+    currentConnectionChallenge = nil;
+    
+    [currentWebChallenge release];
+    currentWebChallenge = nil;
+}
+
+- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    if (challenge == nil || challenge != currentWebChallenge) {
+        return;
+    }
+
+    [self cancel];
+}
+
+@end
+
+// This declaration is only needed to ease the transition to a new SPI.  It can be removed
+// moving forward beyond Tiger 8A416.
+@interface NSURLProtocol (WebFoundationSecret) 
++ (void)_removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
+@end
+
+@implementation WebLoader
+
++ (void)initialize
+{
+    NSURLConnectionSupportsBufferedData = [NSURLConnection instancesRespondToSelector:@selector(_bufferedData)];
+}
+
+- (void)releaseResources
+{
+    ASSERT(!reachedTerminalState);
+    
+    // It's possible that when we release the handle, it will be
+    // deallocated and release the last reference to this object.
+    // We need to retain to avoid accessing the object after it
+    // has been deallocated and also to avoid reentering this method.
+    
+    [self retain];
+
+    // We need to set reachedTerminalState to YES before we release
+    // the resources to prevent a double dealloc of WebView <rdar://problem/4372628>
+
+    reachedTerminalState = YES;
+
+    [identifier release];
+    identifier = nil;
+
+    [connection release];
+    connection = nil;
+
+    [frameLoader release];
+    frameLoader = nil;
+    
+    [resource release];
+    resource = nil;
+    
+    [resourceData release];
+    resourceData = nil;
+
+    [self release];
+}
+
+- (void)dealloc
+{
+    ASSERT(reachedTerminalState);
+    [request release];
+    [response release];
+    [originalURL release];
+    [super dealloc];
+}
+
+- (void)deliverResource
+{
+    ASSERT(resource);
+    ASSERT(waitingToDeliverResource);
+    
+    if (!defersCallbacks) {
+        [self didReceiveResponse:[resource _response]];
+        NSData *data = [resource data];
+        [self didReceiveData:data lengthReceived:[data length]];
+        [self didFinishLoading];
+        deliveredResource = YES;
+        waitingToDeliverResource = NO;
+    }
+}
+
+- (void)deliverResourceAfterDelay
+{
+    if (resource && !defersCallbacks && !waitingToDeliverResource && !deliveredResource) {
+        [self performSelector:@selector(deliverResource) withObject:nil afterDelay:0];
+        waitingToDeliverResource = YES;
+    }
+}
+
+// The following 2 methods are copied from [NSHTTPURLProtocol _cachedResponsePassesValidityChecks] and modified for our needs.
+// FIXME: It would be nice to eventually to share this code somehow.
+- (BOOL)_canUseResourceForRequest:(NSURLRequest *)theRequest
+{
+    NSURLRequestCachePolicy policy = [theRequest cachePolicy];
+        
+    if (policy == NSURLRequestReturnCacheDataElseLoad) {
+        return YES;
+    } else if (policy == NSURLRequestReturnCacheDataDontLoad) {
+        return YES;
+    } else if (policy == NSURLRequestReloadIgnoringCacheData) {
+        return NO;
+    } else if ([theRequest valueForHTTPHeaderField:@"must-revalidate"] != nil) {
+        return NO;
+    } else if ([theRequest valueForHTTPHeaderField:@"proxy-revalidate"] != nil) {
+        return NO;
+    } else if ([theRequest valueForHTTPHeaderField:@"If-Modified-Since"] != nil) {
+        return NO;
+    } else if ([theRequest valueForHTTPHeaderField:@"Cache-Control"] != nil) {
+        return NO;
+    } else if ([[theRequest HTTPMethod] _webkit_isCaseInsensitiveEqualToString:@"POST"]) {
+        return NO;
+    } else {
+        return YES;
+    }
+}
+
+- (BOOL)_canUseResourceWithResponse:(NSURLResponse *)theResponse
+{
+    if (WKGetNSURLResponseMustRevalidate(theResponse)) {
+        return NO;
+    } else if (WKGetNSURLResponseCalculatedExpiration(theResponse) - CFAbsoluteTimeGetCurrent() < 1) {
+        return NO;
+    } else {
+        return YES;
+    }
+}
+
+- (BOOL)loadWithRequest:(NSURLRequest *)r
+{
+    ASSERT(connection == nil);
+    ASSERT(resource == nil);
+    
+    NSURL *URL = [[r URL] retain];
+    [originalURL release];
+    originalURL = URL;
+    
+    deliveredResource = NO;
+    waitingToDeliverResource = NO;
+
+    NSURLRequest *clientRequest = [self willSendRequest:r redirectResponse:nil];
+    if (clientRequest == nil) {
+        NSError *badURLError = [NSError _webKitErrorWithDomain:NSURLErrorDomain 
+                                                          code:NSURLErrorCancelled
+                                                           URL:[r URL]];
+        [self didFailWithError:badURLError];
+        return NO;
+    }
+    r = clientRequest;
+    
+    if ([[r URL] isEqual:originalURL] && [self _canUseResourceForRequest:r]) {
+        resource = [frameLoader _archivedSubresourceForURL:originalURL];
+        if (resource != nil) {
+            if ([self _canUseResourceWithResponse:[resource _response]]) {
+                [resource retain];
+                // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
+                [self deliverResourceAfterDelay];
+                return YES;
+            } else {
+                resource = nil;
+            }
+        }
+    }
+    
+#ifndef NDEBUG
+    isInitializingConnection = YES;
+#endif
+    connection = [[NSURLConnection alloc] initWithRequest:r delegate:self];
+#ifndef NDEBUG
+    isInitializingConnection = NO;
+#endif
+    if (defersCallbacks) {
+        WKSetNSURLConnectionDefersCallbacks(connection, YES);
+    }
+
+    return YES;
+}
+
+- (void)setDefersCallbacks:(BOOL)defers
+{
+    defersCallbacks = defers;
+    WKSetNSURLConnectionDefersCallbacks(connection, defers);
+    // Deliver the resource after a delay because callers don't expect to receive callbacks while calling this method.
+    [self deliverResourceAfterDelay];
+}
+
+- (BOOL)defersCallbacks
+{
+    return defersCallbacks;
+}
+
+- (void)setFrameLoader:(WebFrameLoader *)fl
+{
+    ASSERT(fl);
+    
+    [fl retain];
+    [frameLoader release];
+    frameLoader = fl;
+
+    [self setDefersCallbacks:[frameLoader _defersCallbacks]];
+}
+
+- (WebFrameLoader *)frameLoader
+{
+    return frameLoader;
+}
+
+- (void)addData:(NSData *)data
+{
+    // Don't buffer data if we're loading it from a WebResource.
+    if (resource == nil) {
+        if (NSURLConnectionSupportsBufferedData) {
+            // Buffer data only if the connection has handed us the data because is has stopped buffering it.
+            if (resourceData != nil) {
+                [resourceData appendData:data];
+            }
+        } else {
+            if (resourceData == nil) {
+                resourceData = [[NSMutableData alloc] init];
+            }
+            [resourceData appendData:data];
+        }
+    }
+}
+
+- (NSData *)resourceData
+{
+    if (resource != nil) {
+        return [resource data];
+    }
+    if (resourceData != nil) {
+        // Retain and autorelease resourceData since releaseResources (which releases resourceData) may be called 
+        // before the caller of this method has an opporuntity to retain the returned data (4070729).
+        return [[resourceData retain] autorelease];
+    }
+    if (NSURLConnectionSupportsBufferedData) {
+        return [connection _bufferedData];
+    }
+    return nil;
+}
+
+- (void)clearResourceData
+{
+    [resourceData setLength:0];
+}
+
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+{
+    ASSERT(!reachedTerminalState);
+    NSMutableURLRequest *mutableRequest = [[newRequest mutableCopy] autorelease];
+    NSMutableURLRequest *clientRequest;
+    NSURLRequest *updatedRequest;
+    BOOL haveDataSchemeRequest = NO;
+    
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+
+    newRequest = mutableRequest;
+
+    // If we have a special "applewebdata" scheme URL we send a fake request to the delegate.
+    clientRequest = [mutableRequest _webDataRequestExternalRequest];
+    if (!clientRequest)
+        clientRequest = mutableRequest;
+    else
+        haveDataSchemeRequest = YES;
+    
+    if (identifier == nil)
+        identifier = [frameLoader _identifierForInitialRequest:clientRequest];
+
+    updatedRequest = [frameLoader _willSendRequest:clientRequest forResource:identifier redirectResponse:redirectResponse];
+
+    if (!haveDataSchemeRequest)
+        newRequest = updatedRequest;
+    else {
+        // If the delegate modified the request use that instead of
+        // our applewebdata request, otherwise use the original
+        // applewebdata request.
+        if (![updatedRequest isEqual:clientRequest]) {
+            newRequest = updatedRequest;
+        
+            // The respondsToSelector: check is only necessary for people building/running prior to Tier 8A416.
+            if ([NSURLProtocol respondsToSelector:@selector(_removePropertyForKey:inRequest:)] &&
+                [newRequest isKindOfClass:[NSMutableURLRequest class]]) {
+                NSMutableURLRequest *mr = (NSMutableURLRequest *)newRequest;
+                [NSURLProtocol _removePropertyForKey:[NSURLRequest _webDataRequestPropertyKey] inRequest:mr];
+            }
+
+        }
+    }
+
+    // Store a copy of the request.
+    [request autorelease];
+
+    request = [newRequest copy];
+
+    [self release];
+    return request;
+}
+
+- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    ASSERT(!reachedTerminalState);
+    ASSERT(!currentConnectionChallenge);
+    ASSERT(!currentWebChallenge);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    currentConnectionChallenge = [challenge retain];;
+    currentWebChallenge = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:self];
+
+    [frameLoader _didReceiveAuthenticationChallenge:currentWebChallenge forResource:identifier];
+
+    [self release];
+}
+
+- (void)didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    ASSERT(!reachedTerminalState);
+    ASSERT(currentConnectionChallenge);
+    ASSERT(currentWebChallenge);
+    ASSERT(currentConnectionChallenge = challenge);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    [frameLoader _didCancelAuthenticationChallenge:currentWebChallenge forResource:identifier];
+    [self release];
+}
+
+- (void)didReceiveResponse:(NSURLResponse *)r
+{
+    ASSERT(!reachedTerminalState);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain]; 
+
+    // If the URL is one of our whacky applewebdata URLs then
+    // fake up a substitute URL to present to the delegate.
+    if([WebDataProtocol _webIsDataProtocolURL:[r URL]]) {
+        r = [[[NSURLResponse alloc] initWithURL:[request _webDataRequestExternalURL] MIMEType:[r MIMEType] expectedContentLength:[r expectedContentLength] textEncodingName:[r textEncodingName]] autorelease];
+    }
+
+    [r retain];
+    [response release];
+    response = r;
+
+    [frameLoader _didReceiveResponse:r forResource:identifier];
+
+    [self release];
+}
+
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+{
+    // The following assertions are not quite valid here, since a subclass
+    // might override didReceiveData: in a way that invalidates them. This
+    // happens with the steps listed in 3266216
+    // ASSERT(con == connection);
+    // ASSERT(!reachedTerminalState);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    
+    [self addData:data];
+    
+    [frameLoader _didReceiveData:data contentLength:lengthReceived forResource:identifier];
+
+    [self release];
+}
+
+- (void)willStopBufferingData:(NSData *)data
+{
+    ASSERT(resourceData == nil);
+    resourceData = [data mutableCopy];
+}
+
+- (void)signalFinish
+{
+    signalledFinish = YES;
+    [frameLoader _didFinishLoadingForResource:identifier];
+}
+
+- (void)didFinishLoading
+{
+    // If load has been cancelled after finishing (which could happen with a 
+    // javascript that changes the window location), do nothing.
+    if (cancelledFlag)
+        return;
+    
+    ASSERT(!reachedTerminalState);
+
+    if (!signalledFinish)
+        [self signalFinish];
+
+    [self releaseResources];
+}
+
+- (void)didFailWithError:(NSError *)error
+{
+    if (cancelledFlag) {
+        return;
+    }
+    
+    ASSERT(!reachedTerminalState);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+
+    [frameLoader _didFailLoadingWithError:error forResource:identifier];
+
+    [self releaseResources];
+    [self release];
+}
+
+- (NSCachedURLResponse *)willCacheResponse:(NSCachedURLResponse *)cachedResponse
+{
+    // When in private browsing mode, prevent caching to disk
+    if ([cachedResponse storagePolicy] == NSURLCacheStorageAllowed && [frameLoader _privateBrowsingEnabled]) {
+        cachedResponse = [[[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
+                                                                   data:[cachedResponse data]
+                                                               userInfo:[cachedResponse userInfo]
+                                                          storagePolicy:NSURLCacheStorageAllowedInMemoryOnly] autorelease];
+    }
+    return cachedResponse;
+}
+
+- (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    NSURLRequest *result = [self willSendRequest:newRequest redirectResponse:redirectResponse];
+    --inNSURLConnectionCallback;
+    return result;
+}
+
+- (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self didReceiveAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self didCancelAuthenticationChallenge:challenge];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self didReceiveResponse:r];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self didReceiveData:data lengthReceived:lengthReceived];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self willStopBufferingData:data];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)con
+{
+    // don't worry about checking connection consistency if this load
+    // got cancelled while finishing.
+    ASSERT(cancelledFlag || con == connection);
+    ++inNSURLConnectionCallback;
+    [self didFinishLoading];
+    --inNSURLConnectionCallback;
+}
+
+- (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error
+{
+    ASSERT(con == connection);
+    ++inNSURLConnectionCallback;
+    [self didFailWithError:error];
+    --inNSURLConnectionCallback;
+}
+
+- (NSCachedURLResponse *)connection:(NSURLConnection *)con willCacheResponse:(NSCachedURLResponse *)cachedResponse
+{
+#ifndef NDEBUG
+    if (connection == nil && isInitializingConnection) {
+        LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (40676250)");
+    }
+#endif
+    ++inNSURLConnectionCallback;
+    NSCachedURLResponse *result = [self willCacheResponse:cachedResponse];
+    --inNSURLConnectionCallback;
+    return result;
+}
+
+- (void)cancelWithError:(NSError *)error
+{
+    ASSERT(!reachedTerminalState);
+
+    // This flag prevents bad behvior when loads that finish cause the
+    // load itself to be cancelled (which could happen with a javascript that 
+    // changes the window location). This is used to prevent both the body
+    // of this method and the body of connectionDidFinishLoading: running
+    // for a single delegate. Cancelling wins.
+    cancelledFlag = YES;
+    
+    [currentConnectionChallenge release];
+    currentConnectionChallenge = nil;
+    
+    [currentWebChallenge release];
+    currentWebChallenge = nil;
+
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(deliverResource) object:nil];
+    [connection cancel];
+
+    [frameLoader _didFailLoadingWithError:error forResource:identifier];
+
+    [self releaseResources];
+}
+
+- (void)cancel
+{
+    if (!reachedTerminalState) {
+        [self cancelWithError:[self cancelledError]];
+    }
+}
+
+- (NSError *)cancelledError
+{
+    return [NSError _webKitErrorWithDomain:NSURLErrorDomain
+                                      code:NSURLErrorCancelled
+                                       URL:[request URL]];
+}
+
+- (void)setIdentifier: ident
+{
+    if (identifier != ident){
+        [identifier release];
+        identifier = [ident retain];
+    }
+}
+
+- (NSURLResponse *)response
+{
+    return response;
+}
+
++ (BOOL)inConnectionCallback
+{
+    return inNSURLConnectionCallback != 0;
+}
+
+@end
diff --git a/WebKit/Loader/WebMainResourceLoader.m b/WebKit/Loader/WebMainResourceLoader.m
new file mode 100644 (file)
index 0000000..0365378
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WebMainResourceLoader.h>
+
+#import <Foundation/NSHTTPCookie.h>
+#import <Foundation/NSURLConnection.h>
+#import <Foundation/NSURLRequest.h>
+#import <Foundation/NSURLResponse.h>
+
+#import <WebKit/DOMHTML.h>
+#import <WebKit/WebDataProtocol.h>
+#import <WebKit/WebDataSourceInternal.h>
+#import <WebKit/WebDocument.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebFrameLoader.h>
+#import <WebKit/WebFrameInternal.h>
+#import <WebKit/WebKitErrors.h>
+#import <WebKit/WebKitErrorsPrivate.h>
+#import <WebKit/WebKitLogging.h>
+#import <WebKit/WebKitNSStringExtras.h>
+#import <WebKit/WebNSObjectExtras.h>
+#import <WebKit/WebNSURLExtras.h>
+#import <WebKit/WebViewInternal.h>
+
+// FIXME: More that is in common with WebSubresourceLoader should move up into WebLoader.
+
+@implementation WebMainResourceLoader
+
+- (id)initWithFrameLoader:(WebFrameLoader *)fl
+{
+    self = [super init];
+    
+    if (self) {
+        [self setFrameLoader:fl];
+        proxy = WKCreateNSURLConnectionDelegateProxy();
+        [proxy setDelegate:self];
+    }
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [_initialRequest release];
+
+    [proxy setDelegate:nil];
+    [proxy release];
+    
+    [super dealloc];
+}
+
+- (void)finalize
+{
+    [proxy setDelegate:nil];
+    [super finalize];
+}
+
+- (void)receivedError:(NSError *)error
+{
+    // Calling _receivedMainResourceError will likely result in a call to release, so we must retain.
+    [self retain];
+    WebFrameLoader *fl = [frameLoader retain]; // super's didFailWithError will release the frameLoader
+
+    if (!cancelledFlag) {
+        ASSERT(!reachedTerminalState);
+        [frameLoader _didFailLoadingWithError:error forResource:identifier];
+    }
+
+    [fl _receivedMainResourceError:error complete:YES];
+
+    if (!cancelledFlag)
+        [self releaseResources];
+
+    ASSERT(reachedTerminalState);
+
+    [fl release];
+    [self release];
+}
+
+- (void)cancelContentPolicy
+{
+    [listener _invalidate];
+    [listener release];
+    listener = nil;
+    [policyResponse release];
+    policyResponse = nil;
+}
+
+-(void)cancelWithError:(NSError *)error
+{
+    // Calling _receivedMainResourceError will likely result in a call to release, so we must retain.
+    [self retain];
+
+    [self cancelContentPolicy];
+    [frameLoader retain];
+    [frameLoader _receivedMainResourceError:error complete:YES];
+    [frameLoader release];
+    [super cancelWithError:error];
+
+    [self release];
+}
+
+- (NSError *)interruptForPolicyChangeError
+{
+    return [NSError _webKitErrorWithDomain:WebKitErrorDomain code:WebKitErrorFrameLoadInterruptedByPolicyChange URL:[request URL]];
+}
+
+-(void)stopLoadingForPolicyChange
+{
+    [self retain];
+    [self cancelWithError:[self interruptForPolicyChangeError]];
+    [self release];
+}
+
+-(void)continueAfterNavigationPolicy:(NSURLRequest *)_request formState:(WebFormState *)state
+{
+    if (!_request) {
+        [self stopLoadingForPolicyChange];
+    }
+}
+
+- (BOOL)_isPostOrRedirectAfterPost:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+{
+    BOOL result = NO;
+    
+    if ([[newRequest HTTPMethod] isEqualToString:@"POST"]) {
+        result = YES;
+    }
+    else if (redirectResponse && [redirectResponse isKindOfClass:[NSHTTPURLResponse class]]) {
+        int status = [(NSHTTPURLResponse *)redirectResponse statusCode];
+        if (((status >= 301 && status <= 303) || status == 307)
+            && [[[frameLoader initialRequest] HTTPMethod] isEqualToString:@"POST"]) {
+            result = YES;
+        }
+    }
+    
+    return result;
+}
+
+- (void)addData:(NSData *)data
+{
+    [super addData:data];
+    [frameLoader _receivedData:data];
+}
+
+- (void)saveResource
+{
+    // Override. We don't want to save the main resource as a subresource of the data source.
+}
+
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse
+{
+    // Note that there are no asserts here as there are for the other callbacks. This is due to the
+    // fact that this "callback" is sent when starting every load, and the state of callback
+    // deferrals plays less of a part in this function in preventing the bad behavior deferring 
+    // callbacks is meant to prevent.
+    ASSERT(newRequest != nil);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+
+    NSURL *URL = [newRequest URL];
+
+    LOG(Redirect, "URL = %@", URL);
+
+    NSMutableURLRequest *mutableRequest = nil;
+    // Update cookie policy base URL as URL changes, except for subframes, which use the
+    // URL of the main frame which doesn't change when we redirect.
+    if ([[frameLoader webFrame] _isMainFrame]) {
+        mutableRequest = [newRequest mutableCopy];
+        [mutableRequest setMainDocumentURL:URL];
+    }
+
+    // If we're fielding a redirect in response to a POST, force a load from origin, since
+    // this is a common site technique to return to a page viewing some data that the POST
+    // just modified.
+    // Also, POST requests always load from origin, but this does not affect subresources.
+    if ([newRequest cachePolicy] == NSURLRequestUseProtocolCachePolicy && 
+        [self _isPostOrRedirectAfterPost:newRequest redirectResponse:redirectResponse]) {
+        if (!mutableRequest) {
+            mutableRequest = [newRequest mutableCopy];
+        }
+        [mutableRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+    }
+    if (mutableRequest) {
+        newRequest = [mutableRequest autorelease];
+    }
+
+    // Note super will make a copy for us, so reassigning newRequest is important. Since we are returning this value, but
+    // it's only guaranteed to be retained by self, and self might be dealloc'ed in this method, we have to autorelease.
+    // See 3777253 for an example.
+    newRequest = [[[super willSendRequest:newRequest redirectResponse:redirectResponse] retain] autorelease];
+
+    // Don't set this on the first request.  It is set
+    // when the main load was started.
+    [frameLoader _setRequest:newRequest];
+    
+    [[frameLoader webFrame] _checkNavigationPolicyForRequest:newRequest
+                                                  dataSource:[frameLoader activeDataSource]
+                                                   formState:nil
+                                                     andCall:self
+                                                withSelector:@selector(continueAfterNavigationPolicy:formState:)];
+
+    [self release];
+    return newRequest;
+}
+
+-(void)continueAfterContentPolicy:(WebPolicyAction)contentPolicy response:(NSURLResponse *)r
+{
+    NSURL *URL = [request URL];
+    NSString *MIMEType = [r MIMEType]; 
+    
+    switch (contentPolicy) {
+    case WebPolicyUse:
+    {
+        // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255).
+        BOOL isRemote = ![URL isFileURL] && ![WebDataProtocol _webIsDataProtocolURL:URL];
+        BOOL isRemoteWebArchive = isRemote && [MIMEType _webkit_isCaseInsensitiveEqualToString:@"application/x-webarchive"];
+        if (![WebDataSource _canShowMIMEType:MIMEType] || isRemoteWebArchive) {
+            [[frameLoader webFrame] _handleUnimplementablePolicyWithErrorCode:WebKitErrorCannotShowMIMEType forURL:URL];
+            // Check reachedTerminalState since the load may have already been cancelled inside of _handleUnimplementablePolicyWithErrorCode::.
+            if (!reachedTerminalState) {
+                [self stopLoadingForPolicyChange];
+            }
+            return;
+        }
+        break;
+    }
+    case WebPolicyDownload:
+        [proxy setDelegate:nil];
+        [frameLoader _downloadWithLoadingConnection:connection request:request response:r proxy:proxy];
+        [proxy release];
+        proxy = nil;
+
+        [self receivedError:[self interruptForPolicyChangeError]];
+        return;
+
+    case WebPolicyIgnore:
+        [self stopLoadingForPolicyChange];
+        return;
+    
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    [self retain];
+
+    if ([r isKindOfClass:[NSHTTPURLResponse class]]) {
+        int status = [(NSHTTPURLResponse *)r statusCode];
+        if (status < 200 || status >= 300) {
+            // Handle <object> fallback for error cases.
+            DOMHTMLElement *hostElement = [[frameLoader webFrame] frameElement];
+            [frameLoader _handleFallbackContent];
+            if (hostElement && [hostElement isKindOfClass:[DOMHTMLObjectElement class]])
+                // object elements are no longer rendered after we fallback, so don't
+                // keep trying to process data from their load
+                [self cancel];
+        }
+    }
+
+    // we may have cancelled this load as part of switching to fallback content
+    if (!reachedTerminalState) {
+        [super didReceiveResponse:r];
+    }
+
+    if (![frameLoader _isStopping] && ([URL _webkit_shouldLoadAsEmptyDocument] || [WebView _representationExistsForURLScheme:[URL scheme]])) {
+        [self didFinishLoading];
+    }
+    
+    [self release];
+}
+
+-(void)continueAfterContentPolicy:(WebPolicyAction)policy
+{
+    NSURLResponse *r = [policyResponse retain];
+    BOOL isStopping = [frameLoader _isStopping];
+
+    [self cancelContentPolicy];
+    if (!isStopping)
+        [self continueAfterContentPolicy:policy response:r];
+
+    [r release];
+}
+
+-(void)checkContentPolicyForResponse:(NSURLResponse *)r
+{
+    WebPolicyDecisionListener *l = [[WebPolicyDecisionListener alloc]
+                                       _initWithTarget:self action:@selector(continueAfterContentPolicy:)];
+    listener = l;
+    policyResponse = [r retain];
+
+    [l retain];
+    [frameLoader _decidePolicyForMIMEType:[r MIMEType] decisionListener:listener];
+    [l release];
+}
+
+
+- (void)didReceiveResponse:(NSURLResponse *)r
+{
+    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
+    ASSERT([[r URL] _webkit_shouldLoadAsEmptyDocument] || ![frameLoader _defersCallbacks]);
+
+    LOG(Loading, "main content type: %@", [r MIMEType]);
+    
+    if (loadingMultipartContent) {
+        [frameLoader _setupForReplaceByMIMEType:[r MIMEType]];
+        [self clearResourceData];
+    }
+    
+    if ([[r MIMEType] isEqualToString:@"multipart/x-mixed-replace"])
+        loadingMultipartContent = YES;
+        
+    // FIXME: This is a workaround to make web archive files work with Foundations that
+    // are too old to know about web archive files. We should remove this before we ship.
+    NSURL *URL = [r URL];
+    if ([[[URL path] pathExtension] _webkit_isCaseInsensitiveEqualToString:@"webarchive"]) {
+        r = [[[NSURLResponse alloc] initWithURL:URL 
+                                       MIMEType:@"application/x-webarchive"
+                          expectedContentLength:[r expectedContentLength] 
+                               textEncodingName:[r textEncodingName]] autorelease];
+    }
+    
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    [frameLoader _setResponse:r];
+    _contentLength = [r expectedContentLength];
+
+    [self checkContentPolicyForResponse:r];
+    [self release];
+}
+
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+{
+    ASSERT(data);
+    ASSERT([data length] != 0);
+    ASSERT(![self defersCallbacks]);
+    ASSERT(![frameLoader _defersCallbacks]);
+    LOG(Loading, "URL = %@, data = %p, length %d", [frameLoader _URL], data, [data length]);
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    [frameLoader _mainReceivedBytesSoFar:_bytesReceived complete:NO];
+    
+    [super didReceiveData:data lengthReceived:lengthReceived];
+    _bytesReceived += [data length];
+
+    LOG(Loading, "%d of %d", _bytesReceived, _contentLength);
+    [self release];
+}
+
+- (void)didFinishLoading
+{
+    ASSERT([[frameLoader _URL] _webkit_shouldLoadAsEmptyDocument] || ![self defersCallbacks]);
+    ASSERT([[frameLoader _URL] _webkit_shouldLoadAsEmptyDocument] || ![frameLoader _defersCallbacks]);
+
+    LOG(Loading, "URL = %@", [frameLoader _URL]);
+        
+    // Calls in this method will most likely result in a call to release, so we must retain.
+    [self retain];
+
+    [frameLoader _finishedLoading];
+    [frameLoader _mainReceivedBytesSoFar:_bytesReceived complete:YES];
+    [super didFinishLoading];
+
+    [self release];
+}
+
+- (void)didFailWithError:(NSError *)error
+{
+    ASSERT(![self defersCallbacks]);
+    ASSERT(![frameLoader _defersCallbacks]);
+
+    [self receivedError:error];
+}
+
+- (NSURLRequest *)loadWithRequestNow:(NSURLRequest *)r
+{
+    BOOL shouldLoadEmptyBeforeRedirect = [[r URL] _webkit_shouldLoadAsEmptyDocument];
+
+    ASSERT(connection == nil);
+    ASSERT(shouldLoadEmptyBeforeRedirect || ![self defersCallbacks]);
+    ASSERT(shouldLoadEmptyBeforeRedirect || ![frameLoader _defersCallbacks]);
+
+    // Send this synthetic delegate callback since clients expect it, and
+    // we no longer send the callback from within NSURLConnection for
+    // initial requests.
+    r = [self willSendRequest:r redirectResponse:nil];
+    NSURL *URL = [r URL];
+    BOOL shouldLoadEmpty = [URL _webkit_shouldLoadAsEmptyDocument];
+
+    if (shouldLoadEmptyBeforeRedirect && !shouldLoadEmpty && [self defersCallbacks]) {
+        return r;
+    }
+
+    if (shouldLoadEmpty || [WebDataSource _representationExistsForURLScheme:[URL scheme]]) {
+        NSString *MIMEType;
+        if (shouldLoadEmpty) {
+            MIMEType = @"text/html";
+        } else {
+            MIMEType = [WebDataSource _generatedMIMETypeForURLScheme:[URL scheme]];
+        }
+
+        NSURLResponse *resp = [[NSURLResponse alloc] initWithURL:URL MIMEType:MIMEType
+            expectedContentLength:0 textEncodingName:nil];
+        [self didReceiveResponse:resp];
+        [resp release];
+    } else {
+        connection = [[NSURLConnection alloc] initWithRequest:r delegate:proxy];
+    }
+
+    return nil;
+}
+
+- (BOOL)loadWithRequest:(NSURLRequest *)r
+{
+    ASSERT(connection == nil);
+
+    BOOL defer = [self defersCallbacks];
+    if (defer) {
+        NSURL *URL = [r URL];
+        BOOL shouldLoadEmpty = [URL _webkit_shouldLoadAsEmptyDocument];
+        if (shouldLoadEmpty) {
+            defer = NO;
+        }
+    }
+    if (!defer) {
+        r = [self loadWithRequestNow:r];
+        if (r != nil) {
+            // Started as an empty document, but was redirected to something non-empty.
+            ASSERT([self defersCallbacks]);
+            defer = YES;
+        }
+    }
+    if (defer) {
+        NSURLRequest *copy = [r copy];
+        [_initialRequest release];
+        _initialRequest = copy;
+    }
+
+    return YES;
+}
+
+- (void)setDefersCallbacks:(BOOL)defers
+{
+    [super setDefersCallbacks:defers];
+    if (!defers) {
+        NSURLRequest *r = _initialRequest;
+        if (r != nil) {
+            _initialRequest = nil;
+            [self loadWithRequestNow:r];
+            [r release];
+        }
+    }
+}
+
+@end
diff --git a/WebKit/Loader/WebSubresourceLoader.m b/WebKit/Loader/WebSubresourceLoader.m
new file mode 100644 (file)
index 0000000..59541e5
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WebSubresourceLoader.h>
+
+#import <JavaScriptCore/Assertions.h>
+#import <WebKit/WebDataSourceInternal.h>
+#import <WebKit/WebFormDataStream.h>
+#import <WebKit/WebFrameInternal.h>
+#import <WebKit/WebFrameLoader.h>
+#import <WebKit/WebKitErrorsPrivate.h>
+#import <WebKit/WebNSURLRequestExtras.h>
+
+#import <Foundation/NSURLResponse.h>
+
+#import <WebCore/WebCoreResourceLoader.h>
+#import <WebKitSystemInterface.h>
+
+@implementation WebSubresourceLoader
+
+- initWithLoader:(id <WebCoreResourceLoader>)l frameLoader:(WebFrameLoader *)fl
+{
+    [super init];
+    
+    coreLoader = [l retain];
+
+    [self setFrameLoader:fl];
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    [coreLoader release];
+    [super dealloc];
+}
+
++ (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
+                                   withRequest:(NSMutableURLRequest *)newRequest
+                                 customHeaders:(NSDictionary *)customHeaders
+                                      referrer:(NSString *)referrer 
+                                forFrameLoader:(WebFrameLoader *)fl
+{
+    WebSubresourceLoader *loader = [[[self alloc] initWithLoader:rLoader frameLoader:fl] autorelease];
+    
+    [fl _addSubresourceLoader:loader];
+
+    NSEnumerator *e = [customHeaders keyEnumerator];
+    NSString *key;
+    while ((key = [e nextObject]))
+        [newRequest addValue:[customHeaders objectForKey:key] forHTTPHeaderField:key];
+
+    // Use the original request's cache policy for two reasons:
+    // 1. For POST requests, we mutate the cache policy for the main resource,
+    //    but we do not want this to apply to subresources
+    // 2. Delegates that modify the cache policy using willSendRequest: should
+    //    not affect any other resources. Such changes need to be done
+    //    per request.
+    if ([newRequest _web_isConditionalRequest])
+        [newRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+    else
+        [newRequest setCachePolicy:[[fl _originalRequest] cachePolicy]];
+    [newRequest _web_setHTTPReferrer:referrer];
+    
+    [[fl webFrame] _addExtraFieldsToRequest:newRequest mainResource:NO alwaysFromRequest:NO];
+            
+    if (![loader loadWithRequest:newRequest])
+        loader = nil;
+    
+    return loader;
+}
+
++ (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
+                                    withMethod:(NSString *)method 
+                                           URL:(NSURL *)URL
+                                 customHeaders:(NSDictionary *)customHeaders
+                                      referrer:(NSString *)referrer
+                                 forFrameLoader:(WebFrameLoader *)fl
+{
+    NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
+
+    // setHTTPMethod is not called for GET requests to work around <rdar://4464032>.
+    if (![method isEqualToString:@"GET"])
+        [newRequest setHTTPMethod:method];
+
+    WebSubresourceLoader *loader = [self startLoadingResource:rLoader withRequest:newRequest customHeaders:customHeaders referrer:referrer forFrameLoader:fl];
+    [newRequest release];
+
+    return loader;
+}
+
++ (WebSubresourceLoader *)startLoadingResource:(id <WebCoreResourceLoader>)rLoader
+                                    withMethod:(NSString *)method 
+                                           URL:(NSURL *)URL
+                                 customHeaders:(NSDictionary *)customHeaders
+                                      postData:(NSArray *)postData
+                                      referrer:(NSString *)referrer
+                                forFrameLoader:(WebFrameLoader *)fl
+{
+    NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] initWithURL:URL];
+
+    // setHTTPMethod is not called for GET requests to work around <rdar://4464032>.
+    if (![method isEqualToString:@"GET"])
+        [newRequest setHTTPMethod:method];
+
+    webSetHTTPBody(newRequest, postData);
+
+    WebSubresourceLoader *loader = [self startLoadingResource:rLoader withRequest:newRequest customHeaders:customHeaders referrer:referrer forFrameLoader:fl];
+    [newRequest release];
+
+    return loader;
+
+}
+
+- (void)receivedError:(NSError *)error
+{
+    [frameLoader _receivedError:error];
+}
+
+- (NSURLRequest *)willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse;
+{
+    NSURL *oldURL = [request URL];
+    NSURLRequest *clientRequest = [super willSendRequest:newRequest redirectResponse:redirectResponse];
+    
+    if (clientRequest != nil && oldURL != [clientRequest URL] && ![oldURL isEqual:[clientRequest URL]])
+        [coreLoader redirectedToURL:[clientRequest URL]];
+
+    return clientRequest;
+}
+
+- (void)didReceiveResponse:(NSURLResponse *)r
+{
+    ASSERT(r);
+
+    if ([[r MIMEType] isEqualToString:@"multipart/x-mixed-replace"])
+        loadingMultipartContent = YES;
+
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    [coreLoader receivedResponse:r];
+    // The coreLoader can cancel a load if it receives a multipart response for a non-image
+    if (reachedTerminalState) {
+        [self release];
+        return;
+    }
+    [super didReceiveResponse:r];
+    [self release];
+    
+    if (loadingMultipartContent && [[self resourceData] length]) {
+        // A subresource loader does not load multipart sections progressively, deliver the previously received data to the coreLoader all at once
+        [coreLoader addData:[self resourceData]];
+        // Clears the data to make way for the next multipart section
+        [self clearResourceData];
+        
+        // After the first multipart section is complete, signal to delegates that this load is "finished" 
+        if (!signalledFinish)
+            [self signalFinish];
+    }
+}
+
+- (void)didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived
+{
+    // retain/release self in this delegate method since the additional processing can do
+    // anything including possibly releasing self; one example of this is 3266216
+    [self retain];
+    // A subresource loader does not load multipart sections progressively, don't deliver any data to the coreLoader yet
+    if (!loadingMultipartContent)
+        [coreLoader addData:data];
+    [super didReceiveData:data lengthReceived:lengthReceived];
+    [self release];
+}
+
+- (void)signalFinish
+{
+    [frameLoader _removeSubresourceLoader:self];
+    [frameLoader _finishedLoadingResource];
+    [super signalFinish];
+}
+
+- (void)didFinishLoading
+{
+    // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
+    [self retain];
+    
+    [coreLoader finishWithData:[self resourceData]];
+    
+    if (!signalledFinish)
+        [self signalFinish];
+        
+    [super didFinishLoading];
+
+    [self release];    
+}
+
+- (void)didFailWithError:(NSError *)error
+{
+    // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
+    [self retain];
+    
+    [coreLoader reportError];
+    [frameLoader _removeSubresourceLoader:self];
+    [self receivedError:error];
+    [super didFailWithError:error];
+
+    [self release];
+}
+
+- (void)cancel
+{
+    // Calling _removeSubresourceLoader will likely result in a call to release, so we must retain.
+    [self retain];
+        
+    [coreLoader cancel];
+    [frameLoader _removeSubresourceLoader:self];
+    [self receivedError:[self cancelledError]];
+    [super cancel];
+
+    [self release];
+}
+
+@end