Route main resource loads through the memory cache.
authorjaphet@chromium.org <japhet@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Dec 2012 18:28:26 +0000 (18:28 +0000)
committerjaphet@chromium.org <japhet@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Dec 2012 18:28:26 +0000 (18:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=49246

Reviewed by Antti Koivisto.

Source/WebCore:

Note that this patch doesn't actually enable caching of main resources. That will be done in a later patch.
The MainResourceLoader actually has an underlying SubresourceLoader (with the cache layer between them).
In several places, the MainResourceLoader's SubresourceLoader is treated as special.

No new tests, as this is primarily a refactor. A couple of expected results changed slightly.

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::setRequest):
(WebCore::DocumentLoader::subresource):
(WebCore::DocumentLoader::addSubresourceLoader): Because the SubresourceLoader underlying the main resource
    needs special handling in certain cases, track it separately from the real SubresourceLoaders.
(WebCore::DocumentLoader::removeSubresourceLoader):
(WebCore::DocumentLoader::startLoadingMainResource):
* loader/MainResourceLoader.cpp:
(WebCore::MainResourceLoader::MainResourceLoader):
(WebCore::MainResourceLoader::receivedError):
(WebCore::MainResourceLoader::cancel):
(WebCore::MainResourceLoader::clearResource):
(WebCore):
(WebCore::MainResourceLoader::frameLoader):
(WebCore::MainResourceLoader::request):
(WebCore::MainResourceLoader::continueAfterNavigationPolicy):
(WebCore::MainResourceLoader::resourceData):
(WebCore::MainResourceLoader::redirectReceived):
(WebCore::MainResourceLoader::willSendRequest):
(WebCore::MainResourceLoader::continueAfterContentPolicy):
(WebCore::MainResourceLoader::responseReceived):
(WebCore::MainResourceLoader::dataReceived):
(WebCore::MainResourceLoader::didFinishLoading):
(WebCore::MainResourceLoader::notifyFinished):
(WebCore::MainResourceLoader::reportMemoryUsage):
(WebCore::MainResourceLoader::handleSubstituteDataLoadNow):
(WebCore::MainResourceLoader::load):
(WebCore::MainResourceLoader::setDefersLoading):
(WebCore::MainResourceLoader::defersLoading):
(WebCore::MainResourceLoader::setShouldBufferData):
(WebCore::MainResourceLoader::loader):
(WebCore::MainResourceLoader::identifier):
* loader/MainResourceLoader.h:
(MainResourceLoader):
(WebCore::MainResourceLoader::documentLoader):
* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::willSendRequest):
* loader/ResourceLoader.h:
(WebCore::ResourceLoader::defersLoading):
(WebCore::ResourceLoader::cancelled):
* loader/appcache/ApplicationCacheHost.cpp:
(WebCore::ApplicationCacheHost::maybeLoadFallbackForMainResponse):
(WebCore::ApplicationCacheHost::maybeLoadFallbackForMainError):
* loader/mac/DocumentLoaderMac.cpp:
(WebCore::DocumentLoader::schedule):
(WebCore::DocumentLoader::unschedule):

LayoutTests:

* http/tests/inspector/resource-parameters.html: The main resource's url will exclude the fragment identifier here.
* http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt: The error code for loads cancelled
    by an embedder's willSendRequest() will show as standard load cancellations rather than as a content policy
    failure. This was an odd quirk of how MainResourceLoader::willSendRequest() was implemented (namely, doing a
    content policy check on ResourceRequests with empty urls).
* platform/chromium/http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt: See previous.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/inspector/resource-parameters.html
LayoutTests/http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt
LayoutTests/platform/chromium-linux/fast/replaced/border-radius-clip-content-edge-expected.png
LayoutTests/platform/chromium/http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/loader/DocumentLoader.cpp
Source/WebCore/loader/MainResourceLoader.cpp
Source/WebCore/loader/MainResourceLoader.h
Source/WebCore/loader/ResourceLoader.cpp
Source/WebCore/loader/ResourceLoader.h
Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
Source/WebCore/loader/cache/CachedRawResource.cpp
Source/WebCore/loader/cache/CachedResourceLoader.cpp
Source/WebCore/loader/mac/DocumentLoaderMac.cpp

index 7cbf88d..70f084d 100644 (file)
@@ -1,3 +1,17 @@
+2012-12-11  Nate Chapin  <japhet@chromium.org>
+
+        Route main resource loads through the memory cache.
+        https://bugs.webkit.org/show_bug.cgi?id=49246
+
+        Reviewed by Antti Koivisto.
+
+        * http/tests/inspector/resource-parameters.html: The main resource's url will exclude the fragment identifier here.
+        * http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt: The error code for loads cancelled
+            by an embedder's willSendRequest() will show as standard load cancellations rather than as a content policy
+            failure. This was an odd quirk of how MainResourceLoader::willSendRequest() was implemented (namely, doing a
+            content policy check on ResourceRequests with empty urls).
+        * platform/chromium/http/tests/misc/will-send-request-returns-null-on-redirect-expected.txt: See previous.
+
 2012-12-11  Aaron Colwell  <acolwell@chromium.org>
 
         Update MediaSource to allow append() calls in "ended" state.
index 53d87a2..9e09966 100644 (file)
@@ -17,7 +17,7 @@ function test()
     function onRequestFinished(event)
     {
         var request = event.data;
-        if (request.url !== "http://localhost:8000/inspector/resources/post-target.cgi?queryParam1=queryValue1&queryParam2=#fragmentParam1=fragmentValue1&fragmentParam2=")
+        if (request.url !== "http://localhost:8000/inspector/resources/post-target.cgi?queryParam1=queryValue1&queryParam2=")
             return;
         InspectorTest.addObject(new WebInspector.HAREntry(request).build(), InspectorTest.HARPropertyFormatters);
         InspectorTest.completeTest();
index 5cf7c7d..3d6c16f 100644 (file)
@@ -2,7 +2,7 @@ http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - willSendRequest
 <unknown> - didFinishLoading
 http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - willSendRequest <NSURLRequest URL http://www.example.com/, main document URL http://127.0.0.1:8000/misc/will-send-request-returns-null-on-redirect.html, http method GET> redirectResponse <NSURLResponse http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php, http status code 302>
 Returning null for this redirect
-http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - didFailLoadingWithError: <NSError domain WebKitErrorDomain, code 102>
+http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - didFailLoadingWithError: <NSError domain NSURLErrorDomain, code -999>
 https://bugs.webkit.org/show_bug.cgi?id=27595
 This test checks to make sure that things behave as expected when the resource load delegate returns null in response to willSendRequest.
 
index 5950d5d..84ce154 100644 (file)
Binary files a/LayoutTests/platform/chromium-linux/fast/replaced/border-radius-clip-content-edge-expected.png and b/LayoutTests/platform/chromium-linux/fast/replaced/border-radius-clip-content-edge-expected.png differ
index 2fbf822..91d25f6 100644 (file)
@@ -2,7 +2,7 @@ http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - willSendRequest
 <unknown> - didFinishLoading
 http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - willSendRequest <NSURLRequest URL http://www.example.com/, main document URL http://127.0.0.1:8000/misc/will-send-request-returns-null-on-redirect.html, http method GET> redirectResponse <NSURLResponse http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php, http status code 302>
 Returning null for this redirect
-http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - didFailLoadingWithError: <NSError domain WebKit, code -10000, failing URL "(null)">
+http://127.0.0.1:8000/misc/resources/redirect-to-http-url.php - didFailLoadingWithError: <NSError domain NSURLErrorDomain, code -999, failing URL "(null)">
 https://bugs.webkit.org/show_bug.cgi?id=27595
 This test checks to make sure that things behave as expected when the resource load delegate returns null in response to willSendRequest.
 
index a734897..bf18c40 100644 (file)
@@ -1,3 +1,63 @@
+2012-12-11  Nate Chapin  <japhet@chromium.org>
+
+        Route main resource loads through the memory cache.
+        https://bugs.webkit.org/show_bug.cgi?id=49246
+
+        Reviewed by Antti Koivisto.
+
+        Note that this patch doesn't actually enable caching of main resources. That will be done in a later patch.
+        The MainResourceLoader actually has an underlying SubresourceLoader (with the cache layer between them).
+        In several places, the MainResourceLoader's SubresourceLoader is treated as special.
+
+        No new tests, as this is primarily a refactor. A couple of expected results changed slightly.
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::setRequest):
+        (WebCore::DocumentLoader::subresource):
+        (WebCore::DocumentLoader::addSubresourceLoader): Because the SubresourceLoader underlying the main resource
+            needs special handling in certain cases, track it separately from the real SubresourceLoaders.
+        (WebCore::DocumentLoader::removeSubresourceLoader):
+        (WebCore::DocumentLoader::startLoadingMainResource):
+        * loader/MainResourceLoader.cpp:
+        (WebCore::MainResourceLoader::MainResourceLoader):
+        (WebCore::MainResourceLoader::receivedError):
+        (WebCore::MainResourceLoader::cancel):
+        (WebCore::MainResourceLoader::clearResource):
+        (WebCore):
+        (WebCore::MainResourceLoader::frameLoader):
+        (WebCore::MainResourceLoader::request):
+        (WebCore::MainResourceLoader::continueAfterNavigationPolicy):
+        (WebCore::MainResourceLoader::resourceData):
+        (WebCore::MainResourceLoader::redirectReceived):
+        (WebCore::MainResourceLoader::willSendRequest):
+        (WebCore::MainResourceLoader::continueAfterContentPolicy):
+        (WebCore::MainResourceLoader::responseReceived):
+        (WebCore::MainResourceLoader::dataReceived):
+        (WebCore::MainResourceLoader::didFinishLoading):
+        (WebCore::MainResourceLoader::notifyFinished):
+        (WebCore::MainResourceLoader::reportMemoryUsage):
+        (WebCore::MainResourceLoader::handleSubstituteDataLoadNow):
+        (WebCore::MainResourceLoader::load):
+        (WebCore::MainResourceLoader::setDefersLoading):
+        (WebCore::MainResourceLoader::defersLoading):
+        (WebCore::MainResourceLoader::setShouldBufferData):
+        (WebCore::MainResourceLoader::loader):
+        (WebCore::MainResourceLoader::identifier):
+        * loader/MainResourceLoader.h:
+        (MainResourceLoader):
+        (WebCore::MainResourceLoader::documentLoader):
+        * loader/ResourceLoader.cpp:
+        (WebCore::ResourceLoader::willSendRequest):
+        * loader/ResourceLoader.h:
+        (WebCore::ResourceLoader::defersLoading):
+        (WebCore::ResourceLoader::cancelled):
+        * loader/appcache/ApplicationCacheHost.cpp:
+        (WebCore::ApplicationCacheHost::maybeLoadFallbackForMainResponse):
+        (WebCore::ApplicationCacheHost::maybeLoadFallbackForMainError):
+        * loader/mac/DocumentLoaderMac.cpp:
+        (WebCore::DocumentLoader::schedule):
+        (WebCore::DocumentLoader::unschedule):
+
 2012-12-11  Aaron Colwell  <acolwell@chromium.org>
 
         Update MediaSource to allow append() calls in "ended" state.
index 3218c12..291f156 100644 (file)
@@ -180,13 +180,7 @@ void DocumentLoader::setRequest(const ResourceRequest& req)
     // would be a WebFoundation bug if it sent a redirect callback after commit.
     ASSERT(!m_committed);
 
-    KURL oldURL = m_request.url();
     m_request = req;
-
-    // Only dispatchDidReceiveServerRedirectForProvisionalLoad() if URL changed (and is non-null).
-    // Also, don't send it when replacing unreachable URLs with alternate content.
-    if (!handlingUnreachableURL && !req.url().isNull() && oldURL != req.url())
-        frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad();
 }
 
 void DocumentLoader::setMainDocumentError(const ResourceError& error)
@@ -585,6 +579,9 @@ PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
     if (!resource || !resource->isLoaded())
         return archiveResourceForURL(url);
 
+    if (resource->type() == CachedResource::MainResource)
+        return 0;
+
     // FIXME: This has the side effect of making the resource non-purgeable.
     // It would be better if it didn't have this permanent effect.
     if (!resource->makePurgeable(false))
@@ -811,11 +808,22 @@ void DocumentLoader::stopLoadingSubresources()
 
 void DocumentLoader::addSubresourceLoader(ResourceLoader* loader)
 {
+    // The main resource's underlying ResourceLoader will ask to be added here.
+    // It is much simpler to handle special casing of main resource loads if we don't
+    // let it be added. In the main resource load case, m_mainResourceLoader->loader()
+    // will still be null at this point, but m_gotFirstByte should be false here if and only
+    // if we are just starting the main resource load.
+    if (!m_gotFirstByte)
+        return;
+    ASSERT(!m_subresourceLoaders.contains(loader));
+    ASSERT(!m_mainResourceLoader || m_mainResourceLoader->loader() != loader);
     m_subresourceLoaders.add(loader);
 }
 
 void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
 {
+    if (!m_subresourceLoaders.contains(loader))
+        return;
     m_subresourceLoaders.remove(loader);
     checkLoadComplete();
     if (Frame* frame = m_frame)
@@ -881,6 +889,10 @@ void DocumentLoader::startLoadingMainResource()
 
     if (m_request.isNull()) {
         m_mainResourceLoader = 0;
+        // If the load was aborted by clearing m_request, it's possible the ApplicationCacheHost
+        // is now in a state where starting an empty load will be inconsistent. Replace it with
+        // a new ApplicationCacheHost.
+        m_applicationCacheHost = adoptPtr(new ApplicationCacheHost(this));
         maybeLoadEmpty();
     }
 }
index f074189..4398786 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "ApplicationCacheHost.h"
 #include "BackForwardController.h"
+#include "CachedResourceLoader.h"
+#include "CachedResourceRequest.h"
 #include "Console.h"
 #include "DOMWindow.h"
 #include "Document.h"
 #include "HTMLFormElement.h"
 #include "HistoryItem.h"
 #include "InspectorInstrumentation.h"
-#include "LoaderStrategy.h"
 #include "Page.h"
-#include "PlatformStrategies.h"
+#include "ProgressTracker.h"
+#include "ResourceBuffer.h"
 #include "ResourceError.h"
 #include "ResourceHandle.h"
-#include "ResourceLoadScheduler.h"
 #include "SchemeRegistry.h"
 #include "SecurityOrigin.h"
 #include "Settings.h"
+#include "SubresourceLoader.h"
 #include <wtf/CurrentTime.h>
 
 #if PLATFORM(QT)
 #include "WebCoreSystemInterface.h"
 #endif
 
-// FIXME: More that is in common with SubresourceLoader should move up into ResourceLoader.
-
 namespace WebCore {
 
 MainResourceLoader::MainResourceLoader(DocumentLoader* documentLoader)
-    : ResourceLoader(documentLoader->frame(), ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck))
-    , m_dataLoadTimer(this, &MainResourceLoader::handleSubstituteDataLoadNow)
+    : m_dataLoadTimer(this, &MainResourceLoader::handleSubstituteDataLoadNow)
+    , m_documentLoader(documentLoader)
     , m_loadingMultipartContent(false)
     , m_waitingForContentPolicy(false)
     , m_timeOfLastDataReceived(0.0)
@@ -102,34 +102,32 @@ void MainResourceLoader::receivedError(const ResourceError& error)
     // document loaders. Also, mainReceivedError ends up calling a FrameLoadDelegate method
     // and didFailToLoad calls a ResourceLoadDelegate method and they need to be in the correct order.
     documentLoader()->mainReceivedError(error);
+}
 
-    if (!cancelled()) {
-        ASSERT(!reachedTerminalState());
-        frameLoader()->notifier()->didFailToLoad(this, error);
-        
-        releaseResources();
-    }
-
-    ASSERT(reachedTerminalState());
+void MainResourceLoader::cancel()
+{
+    cancel(ResourceError());
 }
 
-void MainResourceLoader::willCancel(const ResourceError&)
+void MainResourceLoader::cancel(const ResourceError& error)
 {
+    RefPtr<MainResourceLoader> protect(this);
+    ResourceError resourceError = error.isNull() ? frameLoader()->cancelledError(request()) : error;
+
     m_dataLoadTimer.stop();
 
     if (m_waitingForContentPolicy) {
         frameLoader()->policyChecker()->cancelCheck();
         ASSERT(m_waitingForContentPolicy);
         m_waitingForContentPolicy = false;
-        deref(); // balances ref in didReceiveResponse
+        deref(); // balances ref in responseReceived
     }
-}
 
-void MainResourceLoader::didCancel(const ResourceError& error)
-{
-    // We should notify the frame loader after fully canceling the load, because it can do complicated work
-    // like calling DOMWindow::print(), during which a half-canceled load could try to finish.
-    documentLoader()->mainReceivedError(error);
+    if (loader())
+        loader()->cancel(resourceError);
+
+    clearResource();
+    receivedError(resourceError);
 
 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
     if (m_filter) {
@@ -139,6 +137,24 @@ void MainResourceLoader::didCancel(const ResourceError& error)
 #endif
 }
 
+void MainResourceLoader::clearResource()
+{
+    if (m_resource) {
+        m_resource->removeClient(this);
+        m_resource = 0;
+    }
+}
+
+FrameLoader* MainResourceLoader::frameLoader() const
+{
+    return m_documentLoader->frameLoader();
+}
+
+const ResourceRequest& MainResourceLoader::request() const
+{
+    return m_resource ? m_resource->resourceRequest() : m_initialRequest;
+}
+
 ResourceError MainResourceLoader::interruptedForPolicyChangeError() const
 {
     return frameLoader()->client()->interruptedForPolicyChangeError(request());
@@ -163,7 +179,7 @@ void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& re
     else if (m_substituteData.isValid()) {
         // A redirect resulted in loading substitute data.
         ASSERT(documentLoader()->timing()->redirectCount());
-        handle()->cancel();
+        clearResource();
         handleSubstituteDataLoadSoon(request);
     }
 
@@ -183,10 +199,15 @@ bool MainResourceLoader::isPostOrRedirectAfterPost(const ResourceRequest& newReq
     return false;
 }
 
-void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
+PassRefPtr<ResourceBuffer> MainResourceLoader::resourceData()
 {
-    ResourceLoader::addData(data, length, allAtOnce);
-    documentLoader()->receivedData(data, length);
+    return m_resource ? m_resource->resourceBuffer() : 0;
+}
+
+void MainResourceLoader::redirectReceived(CachedResource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+    ASSERT_UNUSED(resource, resource == m_resource);
+    willSendRequest(request, redirectResponse);
 }
 
 void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
@@ -239,8 +260,6 @@ void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const Reso
         }
     }
 
-    ResourceLoader::willSendRequest(newRequest, redirectResponse);
-
     // Don't set this on the first request. It is set when the main load was started.
     m_documentLoader->setRequest(newRequest);
 
@@ -277,17 +296,16 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
         if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) {
             frameLoader()->policyChecker()->cannotShowMIMEType(r);
             // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::.
-            if (!reachedTerminalState())
-                stopLoadingForPolicyChange();
+            stopLoadingForPolicyChange();
             return;
         }
         break;
     }
 
     case PolicyDownload: {
-        // m_handle can be null, e.g. when loading a substitute resource from application cache.
-        if (!m_handle) {
-            receivedError(cannotShowURLError());
+        // m_resource can be null, e.g. when loading a substitute resource from application cache.
+        if (!m_resource) {
+            receivedError(frameLoader()->client()->cannotShowURLError(request()));
             return;
         }
         InspectorInstrumentation::continueWithPolicyDownload(m_documentLoader->frame(), documentLoader(), identifier(), r);
@@ -297,7 +315,7 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
         ResourceRequest request = this->request();
         frameLoader()->setOriginalURLForDownloadRequest(request);
 
-        frameLoader()->client()->download(m_handle.get(), request, r);
+        frameLoader()->client()->download(loader()->handle(), request, r);
 
         // It might have gone missing
         if (frameLoader())
@@ -329,13 +347,9 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
         }
     }
 
-    // we may have cancelled this load as part of switching to fallback content
-    if (!reachedTerminalState())
-        ResourceLoader::didReceiveResponse(r);
-
-    if (m_documentLoader && !m_documentLoader->isStopping() && m_substituteData.isValid()) {
+    if (!m_documentLoader->isStopping() && m_substituteData.isValid()) {
         if (m_substituteData.content()->size())
-            didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true);
+            dataReceived(0, m_substituteData.content()->data(), m_substituteData.content()->size());
         if (!m_documentLoader->isStopping())
             didFinishLoading(0);
     }
@@ -352,11 +366,12 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction policy)
     m_waitingForContentPolicy = false;
     if (!m_documentLoader->isStopping())
         continueAfterContentPolicy(policy, m_response);
-    deref(); // balances ref in didReceiveResponse
+    deref(); // balances ref in responseReceived
 }
 
-void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
+void MainResourceLoader::responseReceived(CachedResource* resource, const ResourceResponse& r)
 {
+    ASSERT_UNUSED(resource, m_resource == resource);
     if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainResponse(request(), r))
         return;
 
@@ -382,7 +397,7 @@ void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
 
     if (m_loadingMultipartContent) {
         m_documentLoader->setupForReplace();
-        clearResourceData();
+        m_resource->clear();
     }
     
     if (r.isMultipart())
@@ -398,7 +413,7 @@ void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
 
     ASSERT(!m_waitingForContentPolicy);
     m_waitingForContentPolicy = true;
-    ref(); // balanced by deref in continueAfterContentPolicy and didCancel
+    ref(); // balanced by deref in continueAfterContentPolicy and cancel
 
     // Always show content with valid substitute data.
     if (m_documentLoader->substituteData().isValid()) {
@@ -423,11 +438,11 @@ void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
     frameLoader()->policyChecker()->checkContentPolicy(m_response, callContinueAfterContentPolicy, this);
 }
 
-void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
+void MainResourceLoader::dataReceived(CachedResource* resource, const char* data, int length)
 {
     ASSERT(data);
     ASSERT(length != 0);
-
+    ASSERT_UNUSED(resource, resource == m_resource);
     ASSERT(!m_response.isNull());
 
 #if USE(CFNETWORK) || PLATFORM(MAC)
@@ -452,16 +467,15 @@ void MainResourceLoader::didReceiveData(const char* data, int length, long long
         // If we don't have blockedData, that means we're still accumulating data
         if (!blockedData) {
             // Transition to committed state.
-            ResourceLoader::didReceiveData("", 0, 0, false);
+            documentLoader()->receivedData(0, 0);
             return;
         }
 
         data = blockedData;
-        encodedDataLength = -1;
     }
 #endif
 
-    documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce);
+    documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, -1, false);
 
     // The additional processing can do anything including possibly removing the last
     // reference to this object; one example of this is 3266216.
@@ -469,7 +483,7 @@ void MainResourceLoader::didReceiveData(const char* data, int length, long long
 
     m_timeOfLastDataReceived = monotonicallyIncreasingTime();
 
-    ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
+    documentLoader()->receivedData(data, length);
 
 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
     if (WebFilterEvaluator *filter = m_filter) {
@@ -490,7 +504,7 @@ void MainResourceLoader::didFinishLoading(double finishTime)
     // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
     // See <rdar://problem/6304600> for more details.
 #if !USE(CF)
-    ASSERT(!defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame.get()));
+    ASSERT(!defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_documentLoader->frame()));
 #endif
 
     // The additional processing can do anything including possibly removing the last
@@ -506,7 +520,7 @@ void MainResourceLoader::didFinishLoading(double finishTime)
         // Remove this->m_filter early so didReceiveData doesn't see it.
         m_filter = 0;
         if (data)
-            didReceiveData(data, length, -1, false);
+            dataReceived(m_resource.get(), data, length);
         wkFilterRelease(filter);
     }
 #endif
@@ -516,13 +530,18 @@ void MainResourceLoader::didFinishLoading(double finishTime)
 
     documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime()));
     documentLoader()->finishedLoading();
-    ResourceLoader::didFinishLoading(finishTime);
 
     dl->applicationCacheHost()->finishedLoadingMainResource();
 }
 
-void MainResourceLoader::didFail(const ResourceError& error)
+void MainResourceLoader::notifyFinished(CachedResource* resource)
 {
+    ASSERT_UNUSED(resource, m_resource == resource);
+    if (!m_resource || (!m_resource->errorOccurred() && !m_resource->wasCanceled())) {
+        didFinishLoading(m_resource->loadFinishTime());
+        return;
+    }
+
 #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
     if (m_filter) {
         wkFilterRelease(m_filter);
@@ -530,6 +549,7 @@ void MainResourceLoader::didFail(const ResourceError& error)
     }
 #endif
 
+    const ResourceError& error = m_resource->resourceError();
     if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error))
         return;
 
@@ -545,7 +565,6 @@ void MainResourceLoader::didFail(const ResourceError& error)
 void MainResourceLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
-    ResourceLoader::reportMemoryUsage(memoryObjectInfo);
     info.addMember(m_initialRequest);
     info.addMember(m_substituteData);
     info.addMember(m_dataLoadTimer);
@@ -564,7 +583,7 @@ void MainResourceLoader::handleSubstituteDataLoadNow(MainResourceLoaderTimer*)
     m_initialRequest = ResourceRequest();
         
     ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
-    didReceiveResponse(response);
+    responseReceived(0, response);
 }
 
 void MainResourceLoader::startDataLoadTimer()
@@ -587,29 +606,8 @@ void MainResourceLoader::handleSubstituteDataLoadSoon(const ResourceRequest& r)
         handleSubstituteDataLoadNow(0);
 }
 
-void MainResourceLoader::loadNow(ResourceRequest& r)
-{
-    ASSERT(!m_handle);
-    ASSERT(!defersLoading());
-
-#if USE(PLATFORM_STRATEGIES)
-    platformStrategies()->loaderStrategy()->resourceLoadScheduler()->addMainResourceLoad(this);
-#else
-    resourceLoadScheduler()->addMainResourceLoad(this);
-#endif
-
-    if (m_substituteData.isValid())
-        handleSubstituteDataLoadSoon(r);
-    else
-        m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), r, this, false, true);
-
-    return;
-}
-
-void MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData)
+void MainResourceLoader::load(const ResourceRequest& initialRequest, const SubstituteData& substituteData)
 {
-    ASSERT(!m_handle);
-
     // It appears that it is possible for this load to be cancelled and derefenced by the DocumentLoader
     // in willSendRequest() if loadNow() is called.
     RefPtr<MainResourceLoader> protect(this);
@@ -619,7 +617,7 @@ void MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& su
     ASSERT(documentLoader()->timing()->navigationStart());
     ASSERT(!documentLoader()->timing()->fetchStart());
     documentLoader()->timing()->markFetchStart();
-    ResourceRequest request(r);
+    ResourceRequest request(initialRequest);
 
     // Send this synthetic delegate callback since clients expect it, and
     // we no longer send the callback from within NSURLConnection for
@@ -627,37 +625,66 @@ void MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& su
     willSendRequest(request, ResourceResponse());
     ASSERT(!deletionHasBegun());
 
-    // <rdar://problem/4801066>
-    // willSendRequest() is liable to make the call to frameLoader() return null, so we need to check that here
-    if (!frameLoader() || request.isNull()) {
-        if (!reachedTerminalState())
-            releaseResources();
+    // willSendRequest() may lead to our DocumentLoader being detached or cancelling the load via nulling the ResourceRequest.
+    if (!documentLoader()->frame() || request.isNull())
         return;
-    }
 
     documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData);
 
-    if (defersLoading())
-        m_initialRequest = request;
-    else
-        loadNow(request);
+    if (m_substituteData.isValid()) {
+        handleSubstituteDataLoadSoon(request);
+        return;
+    }
+
+    DEFINE_STATIC_LOCAL(ResourceLoaderOptions, mainResourceLoadOptions,
+        (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck));
+    CachedResourceRequest cachedResourceRequest(request, mainResourceLoadOptions);
+    m_resource = documentLoader()->cachedResourceLoader()->requestMainResource(cachedResourceRequest);
+    if (!m_resource) {
+        documentLoader()->setRequest(ResourceRequest());
+        return;
+    }
+    m_resource->addClient(this);
+
+    // We need to wait until after requestMainResource() is called to setRequest(), because there are a bunch of headers set when
+    // the underlying ResourceLoader is created, and DocumentLoader::m_request needs to include those. However, the cache will
+    // strip the fragment identifier (which DocumentLoader::m_request should also include), so add that back in.
+    if (loader())
+        request = loader()->originalRequest();
+    if (initialRequest.url() != request.url()) {
+        ASSERT(equalIgnoringFragmentIdentifier(initialRequest.url(), request.url()));
+        request.setURL(initialRequest.url());
+    }
+    documentLoader()->setRequest(request);
 }
 
 void MainResourceLoader::setDefersLoading(bool defers)
 {
-    ResourceLoader::setDefersLoading(defers);
+    if (loader())
+        loader()->setDefersLoading(defers);
+}
 
-    if (defers) {
-        if (m_dataLoadTimer.isActive())
-            m_dataLoadTimer.stop();
-    } else {
-        if (m_initialRequest.isNull())
-            return;
+bool MainResourceLoader::defersLoading() const
+{
+    return loader() ? loader()->defersLoading() : false;
+}
 
-        ResourceRequest initialRequest(m_initialRequest);
-        m_initialRequest = ResourceRequest();
-        loadNow(initialRequest);
-    }
+void MainResourceLoader::setShouldBufferData(DataBufferingPolicy shouldBufferData)
+{
+    ASSERT(m_resource);
+    m_resource->setShouldBufferData(shouldBufferData);
+}
+
+ResourceLoader* MainResourceLoader::loader() const
+{ 
+    return m_resource ? m_resource->loader() : 0;
+}
+
+unsigned long MainResourceLoader::identifier() const
+{
+    if (ResourceLoader* resourceLoader = loader())
+        return resourceLoader->identifier();
+    return 0;
 }
 
 }
index 5943721..9123c0a 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef MainResourceLoader_h
 #define MainResourceLoader_h
 
+#include "CachedRawResource.h"
+#include "CachedResourceHandle.h"
 #include "FrameLoaderTypes.h"
 #include "ResourceLoader.h"
 #include "SubstituteData.h"
@@ -49,21 +51,20 @@ namespace WebCore {
 class FormState;
 class ResourceRequest;
 
-class MainResourceLoader : public ResourceLoader {
+class MainResourceLoader : public RefCounted<MainResourceLoader>, public CachedRawResourceClient {
+    WTF_MAKE_FAST_ALLOCATED;
 public:
     static PassRefPtr<MainResourceLoader> create(DocumentLoader*);
     virtual ~MainResourceLoader();
 
     void load(const ResourceRequest&, const SubstituteData&);
-    virtual void addData(const char*, int, bool allAtOnce) OVERRIDE;
+    void cancel();
+    void cancel(const ResourceError&);
+    ResourceLoader* loader() const;
+    PassRefPtr<ResourceBuffer> resourceData();
 
-    virtual void setDefersLoading(bool) OVERRIDE;
-
-    virtual void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse) OVERRIDE;
-    virtual void didReceiveResponse(const ResourceResponse&) OVERRIDE;
-    virtual void didReceiveData(const char*, int, long long encodedDataLength, bool allAtOnce) OVERRIDE;
-    virtual void didFinishLoading(double finishTime) OVERRIDE;
-    virtual void didFail(const ResourceError&) OVERRIDE;
+    void setDefersLoading(bool);
+    void setShouldBufferData(DataBufferingPolicy);
 
 #if HAVE(RUNLOOP_TIMER)
     typedef RunLoopTimer<MainResourceLoader> MainResourceLoaderTimer;
@@ -71,18 +72,21 @@ public:
     typedef Timer<MainResourceLoader> MainResourceLoaderTimer;
 #endif
 
+    unsigned long identifier() const;
     bool isLoadingMultipartContent() const { return m_loadingMultipartContent; }
 
-    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
+    void reportMemoryUsage(MemoryObjectInfo*) const;
 
 private:
     explicit MainResourceLoader(DocumentLoader*);
 
-    virtual void willCancel(const ResourceError&) OVERRIDE;
-    virtual void didCancel(const ResourceError&) OVERRIDE;
-
-    void loadNow(ResourceRequest&);
+    virtual void redirectReceived(CachedResource*, ResourceRequest&, const ResourceResponse&) OVERRIDE;
+    virtual void responseReceived(CachedResource*, const ResourceResponse&) OVERRIDE;
+    virtual void dataReceived(CachedResource*, const char* data, int dataLength) OVERRIDE;
+    virtual void notifyFinished(CachedResource*) OVERRIDE;
 
+    void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
+    void didFinishLoading(double finishTime);
     void handleSubstituteDataLoadSoon(const ResourceRequest&);
     void handleSubstituteDataLoadNow(MainResourceLoaderTimer*);
 
@@ -104,10 +108,22 @@ private:
     void substituteMIMETypeFromPluginDatabase(const ResourceResponse&);
 #endif
 
+    FrameLoader* frameLoader() const;
+    DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
+
+    const ResourceRequest& request() const;
+    void clearResource();
+
+    bool defersLoading() const;
+
+    CachedResourceHandle<CachedRawResource> m_resource;
+
     ResourceRequest m_initialRequest;
     SubstituteData m_substituteData;
+    ResourceResponse m_response;
 
     MainResourceLoaderTimer m_dataLoadTimer;
+    RefPtr<DocumentLoader> m_documentLoader;
 
     bool m_loadingMultipartContent;
     bool m_waitingForContentPolicy;
index 56d282e..4afe300 100644 (file)
@@ -251,6 +251,9 @@ void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceRes
 #endif
     }
     m_request = request;
+
+    if (!redirectResponse.isNull() && !m_documentLoader->isCommitted())
+        frameLoader()->client()->dispatchDidReceiveServerRedirectForProvisionalLoad();
 }
 
 void ResourceLoader::didSendData(unsigned long long, unsigned long long)
index 2e4a61b..e29d6a7 100644 (file)
@@ -65,6 +65,7 @@ public:
     ResourceError cannotShowURLError();
     
     virtual void setDefersLoading(bool);
+    bool defersLoading() const { return m_defersLoading; }
 
     unsigned long identifier() const { return m_identifier; }
 
@@ -167,7 +168,6 @@ protected:
     void didFinishLoadingOnePart(double finishTime);
 
     bool cancelled() const { return m_cancelled; }
-    bool defersLoading() const { return m_defersLoading; }
 
     RefPtr<ResourceHandle> m_handle;
     RefPtr<Frame> m_frame;
index fe9f010..513f066 100644 (file)
@@ -103,7 +103,7 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceReques
         if (isApplicationCacheEnabled()) {
             m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader());
 
-            if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get()))
+            if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader()->loader(), m_mainResourceApplicationCache.get()))
                 return true;
         }
     }
@@ -117,7 +117,7 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest&
         if (isApplicationCacheEnabled()) {
             m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader);
 
-            if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get()))
+            if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader()->loader(), m_mainResourceApplicationCache.get()))
                 return true;
         }
     }
index b0d8c96..a3a445f 100644 (file)
@@ -98,6 +98,7 @@ void CachedRawResource::allClientsRemoved()
 
 void CachedRawResource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
 {
+    CachedResourceHandle<CachedRawResource> protect(this);
     if (!response.isNull()) {
         CachedResourceClientWalker<CachedRawResourceClient> w(m_clients);
         while (CachedRawResourceClient* c = w.next())
index e937b7b..023ac46 100644 (file)
@@ -706,7 +706,8 @@ void CachedResourceLoader::loadDone(CachedResource* resource)
     RefPtr<Document> protectDocument(m_document);
 
 #if ENABLE(RESOURCE_TIMING)
-    if (resource) {
+    // FIXME: Add resource timing support for main resources.
+    if (resource && resource->type() != CachedResource::MainResource) {
         HashMap<CachedResource*, InitiatorInfo>::iterator initiatorIt = m_initiatorMap.find(resource);
         if (initiatorIt != m_initiatorMap.end()) {
             ASSERT(document());
index 0288b0d..0b53b36 100644 (file)
@@ -55,8 +55,8 @@ static void unscheduleAll(const ResourceLoaderSet& loaders, SchedulePair* pair)
 
 void DocumentLoader::schedule(SchedulePair* pair)
 {
-    if (m_mainResourceLoader && m_mainResourceLoader->handle())
-        m_mainResourceLoader->handle()->schedule(pair);
+    if (m_mainResourceLoader && m_mainResourceLoader->loader() && m_mainResourceLoader->loader()->handle())
+        m_mainResourceLoader->loader()->handle()->schedule(pair);
     scheduleAll(m_subresourceLoaders, pair);
     scheduleAll(m_plugInStreamLoaders, pair);
     scheduleAll(m_multipartSubresourceLoaders, pair);
@@ -64,8 +64,8 @@ void DocumentLoader::schedule(SchedulePair* pair)
 
 void DocumentLoader::unschedule(SchedulePair* pair)
 {
-    if (m_mainResourceLoader && m_mainResourceLoader->handle())
-        m_mainResourceLoader->handle()->unschedule(pair);
+    if (m_mainResourceLoader && m_mainResourceLoader->loader() && m_mainResourceLoader->loader()->handle())
+        m_mainResourceLoader->loader()->handle()->unschedule(pair);
     unscheduleAll(m_subresourceLoaders, pair);
     unscheduleAll(m_plugInStreamLoaders, pair);
     unscheduleAll(m_multipartSubresourceLoaders, pair);