summaryrefslogtreecommitdiffstats
path: root/WebCore/loader
diff options
context:
space:
mode:
authorRussell Brenner <russellbrenner@google.com>2010-11-18 17:33:13 -0800
committerRussell Brenner <russellbrenner@google.com>2010-12-02 13:47:21 -0800
commit6b70adc33054f8aee8c54d0f460458a9df11b8a5 (patch)
tree103a13998c33944d6ab3b8318c509a037e639460 /WebCore/loader
parentbdf4ebc8e70b2d221b6ee7a65660918ecb1d33aa (diff)
downloadexternal_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.zip
external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.gz
external_webkit-6b70adc33054f8aee8c54d0f460458a9df11b8a5.tar.bz2
Merge WebKit at r72274: Initial merge by git.
Change-Id: Ie51f0b4a16da82942bd516dce59cfb79ebbe25fb
Diffstat (limited to 'WebCore/loader')
-rw-r--r--WebCore/loader/DocumentLoader.cpp15
-rw-r--r--WebCore/loader/DocumentThreadableLoader.cpp3
-rw-r--r--WebCore/loader/FormSubmission.cpp46
-rw-r--r--WebCore/loader/FormSubmission.h2
-rw-r--r--WebCore/loader/FrameLoader.cpp35
-rw-r--r--WebCore/loader/FrameLoader.h19
-rw-r--r--WebCore/loader/MainResourceLoader.cpp2
-rw-r--r--WebCore/loader/NetscapePlugInStreamLoader.cpp8
-rw-r--r--WebCore/loader/NetscapePlugInStreamLoader.h2
-rw-r--r--WebCore/loader/ProgressTracker.cpp2
-rw-r--r--WebCore/loader/ResourceLoadNotifier.cpp8
-rw-r--r--WebCore/loader/ResourceLoadNotifier.h2
-rw-r--r--WebCore/loader/ResourceLoadScheduler.cpp282
-rw-r--r--WebCore/loader/ResourceLoadScheduler.h113
-rw-r--r--WebCore/loader/ResourceLoader.cpp53
-rw-r--r--WebCore/loader/ResourceLoader.h12
-rw-r--r--WebCore/loader/SubresourceLoader.cpp3
-rw-r--r--WebCore/loader/cache/CachedCSSStyleSheet.cpp5
-rw-r--r--WebCore/loader/cache/CachedCSSStyleSheet.h2
-rw-r--r--WebCore/loader/cache/CachedFont.cpp7
-rw-r--r--WebCore/loader/cache/CachedFont.h2
-rw-r--r--WebCore/loader/cache/CachedImage.cpp7
-rw-r--r--WebCore/loader/cache/CachedImage.h4
-rw-r--r--WebCore/loader/cache/CachedResource.cpp5
-rw-r--r--WebCore/loader/cache/CachedResource.h14
-rw-r--r--WebCore/loader/cache/CachedScript.cpp5
-rw-r--r--WebCore/loader/cache/CachedScript.h2
-rw-r--r--WebCore/loader/cache/CachedXSLStyleSheet.cpp5
-rw-r--r--WebCore/loader/cache/CachedXSLStyleSheet.h2
-rw-r--r--WebCore/loader/icon/IconLoader.cpp3
-rw-r--r--WebCore/loader/loader.cpp421
-rw-r--r--WebCore/loader/loader.h82
32 files changed, 653 insertions, 520 deletions
diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp
index 0836805..07bae46 100644
--- a/WebCore/loader/DocumentLoader.cpp
+++ b/WebCore/loader/DocumentLoader.cpp
@@ -38,6 +38,7 @@
#endif
#include "CachedPage.h"
#include "CachedResourceLoader.h"
+#include "DOMWindow.h"
#include "Document.h"
#include "DocumentParser.h"
#include "Event.h"
@@ -364,7 +365,13 @@ void DocumentLoader::updateLoading()
return;
}
ASSERT(this == frameLoader()->activeDocumentLoader());
+ bool wasLoading = m_loading;
setLoading(frameLoader()->isLoading());
+
+ if (wasLoading && !m_loading) {
+ if (DOMWindow* window = m_frame->existingDOMWindow())
+ window->finishedLoading();
+ }
}
void DocumentLoader::setFrame(Frame* frame)
@@ -803,10 +810,12 @@ void DocumentLoader::transferLoadingResourcesFromPage(Page* oldPage)
{
ASSERT(oldPage != m_frame->page());
- FrameLoaderClient* frameLoaderClient = frameLoader()->client();
+ FrameLoader* loader = frameLoader();
+ ASSERT(loader);
+
const ResourceRequest& request = originalRequest();
if (isLoadingMainResource()) {
- frameLoaderClient->transferLoadingResourceFromPage(
+ loader->dispatchTransferLoadingResourceFromPage(
m_mainResourceLoader->identifier(), this, request, oldPage);
}
@@ -814,7 +823,7 @@ void DocumentLoader::transferLoadingResourcesFromPage(Page* oldPage)
ResourceLoaderSet::const_iterator it = m_subresourceLoaders.begin();
ResourceLoaderSet::const_iterator end = m_subresourceLoaders.end();
for (; it != end; ++it) {
- frameLoaderClient->transferLoadingResourceFromPage(
+ loader->dispatchTransferLoadingResourceFromPage(
(*it)->identifier(), this, request, oldPage);
}
}
diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp
index a792144..03cea73 100644
--- a/WebCore/loader/DocumentThreadableLoader.cpp
+++ b/WebCore/loader/DocumentThreadableLoader.cpp
@@ -38,6 +38,7 @@
#include "Frame.h"
#include "FrameLoader.h"
#include "ResourceHandle.h"
+#include "ResourceLoadScheduler.h"
#include "ResourceRequest.h"
#include "SecurityOrigin.h"
#include "SubresourceLoader.h"
@@ -319,7 +320,7 @@ void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Secur
// Clear the loader so that any callbacks from SubresourceLoader::create will not have the old loader.
m_loader = 0;
- m_loader = SubresourceLoader::create(m_document->frame(), this, request, securityCheck, sendLoadCallbacks, sniffContent);
+ m_loader = resourceLoadScheduler()->scheduleSubresourceLoad(m_document->frame(), this, request, ResourceLoadScheduler::Medium, securityCheck, sendLoadCallbacks, sniffContent);
return;
}
diff --git a/WebCore/loader/FormSubmission.cpp b/WebCore/loader/FormSubmission.cpp
index f3f19d2..a9f2680 100644
--- a/WebCore/loader/FormSubmission.cpp
+++ b/WebCore/loader/FormSubmission.cpp
@@ -110,6 +110,17 @@ void FormSubmission::Attributes::parseMethodType(const String& type)
m_method = FormSubmission::GetMethod;
}
+void FormSubmission::Attributes::copyFrom(const Attributes& other)
+{
+ m_method = other.m_method;
+ m_isMultiPartForm = other.m_isMultiPartForm;
+
+ m_action = other.m_action;
+ m_target = other.m_target;
+ m_encodingType = other.m_encodingType;
+ m_acceptCharset = other.m_acceptCharset;
+}
+
inline FormSubmission::FormSubmission(Method method, const KURL& action, const String& target, const String& contentType, PassRefPtr<FormState> state, PassRefPtr<FormData> data, const String& boundary, bool lockHistory, PassRefPtr<Event> event)
: m_method(method)
, m_action(action)
@@ -126,21 +137,40 @@ inline FormSubmission::FormSubmission(Method method, const KURL& action, const S
PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const Attributes& attributes, PassRefPtr<Event> event, bool lockHistory, FormSubmissionTrigger trigger)
{
ASSERT(form);
+
+ HTMLFormControlElement* submitButton = 0;
+ if (event && event->target() && event->target()->toNode())
+ submitButton = static_cast<HTMLFormControlElement*>(event->target()->toNode());
+
+ FormSubmission::Attributes copiedAttributes;
+ copiedAttributes.copyFrom(attributes);
+ if (submitButton) {
+ String attributeValue;
+ if (!(attributeValue = submitButton->getAttribute(formactionAttr)).isNull())
+ copiedAttributes.parseAction(attributeValue);
+ if (!(attributeValue = submitButton->getAttribute(formenctypeAttr)).isNull())
+ copiedAttributes.parseEncodingType(attributeValue);
+ if (!(attributeValue = submitButton->getAttribute(formmethodAttr)).isNull())
+ copiedAttributes.parseMethodType(attributeValue);
+ if (!(attributeValue = submitButton->getAttribute(formtargetAttr)).isNull())
+ copiedAttributes.setTarget(attributeValue);
+ }
+
Document* document = form->document();
- KURL actionURL = document->completeURL(attributes.action().isEmpty() ? document->url().string() : attributes.action());
+ KURL actionURL = document->completeURL(copiedAttributes.action().isEmpty() ? document->url().string() : copiedAttributes.action());
bool isMailtoForm = actionURL.protocolIs("mailto");
bool isMultiPartForm = false;
- String encodingType = attributes.encodingType();
+ String encodingType = copiedAttributes.encodingType();
- if (attributes.method() == PostMethod) {
- isMultiPartForm = attributes.isMultiPartForm();
+ if (copiedAttributes.method() == PostMethod) {
+ isMultiPartForm = copiedAttributes.isMultiPartForm();
if (isMultiPartForm && isMailtoForm) {
encodingType = "application/x-www-form-urlencoded";
isMultiPartForm = false;
}
}
- TextEncoding dataEncoding = isMailtoForm ? UTF8Encoding() : FormDataBuilder::encodingFromAcceptCharset(attributes.acceptCharset(), document);
+ TextEncoding dataEncoding = isMailtoForm ? UTF8Encoding() : FormDataBuilder::encodingFromAcceptCharset(copiedAttributes.acceptCharset(), document);
RefPtr<DOMFormData> domFormData = DOMFormData::create(dataEncoding.encodingForFormSubmission());
Vector<pair<String, String> > formValues;
@@ -166,7 +196,7 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
boundary = formData->boundary().data();
} else {
formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding());
- if (attributes.method() == PostMethod && isMailtoForm) {
+ if (copiedAttributes.method() == PostMethod && isMailtoForm) {
// Convert the form data into a string that we put into the URL.
appendMailtoPostFormDataToURL(actionURL, *formData, encodingType);
formData = FormData::create();
@@ -174,9 +204,9 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
}
formData->setIdentifier(generateFormDataIdentifier());
- String targetOrBaseTarget = attributes.target().isEmpty() ? document->baseTarget() : attributes.target();
+ String targetOrBaseTarget = copiedAttributes.target().isEmpty() ? document->baseTarget() : copiedAttributes.target();
RefPtr<FormState> formState = FormState::create(form, formValues, document->frame(), trigger);
- return adoptRef(new FormSubmission(attributes.method(), actionURL, targetOrBaseTarget, encodingType, formState.release(), formData.release(), boundary, lockHistory, event));
+ return adoptRef(new FormSubmission(copiedAttributes.method(), actionURL, targetOrBaseTarget, encodingType, formState.release(), formData.release(), boundary, lockHistory, event));
}
KURL FormSubmission::requestURL() const
diff --git a/WebCore/loader/FormSubmission.h b/WebCore/loader/FormSubmission.h
index b935882..d724835 100644
--- a/WebCore/loader/FormSubmission.h
+++ b/WebCore/loader/FormSubmission.h
@@ -72,6 +72,8 @@ public:
const String& acceptCharset() const { return m_acceptCharset; }
void setAcceptCharset(const String& value) { m_acceptCharset = value; }
+ void copyFrom(const Attributes&);
+
private:
Method m_method;
bool m_isMultiPartForm;
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index 8277338..6eb9830 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -209,9 +209,6 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
, m_suppressOpenerInNewFrame(false)
, m_sandboxFlags(SandboxAll)
, m_forcedSandboxFlags(SandboxNone)
-#ifndef NDEBUG
- , m_didDispatchDidCommitLoad(false)
-#endif
{
}
@@ -1529,11 +1526,6 @@ bool FrameLoader::willLoadMediaElementURL(KURL& url)
return error.isNull();
}
-ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
-{
- return m_client->interruptForPolicyChangeError(request);
-}
-
bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
{
KURL unreachableURL = docLoader->unreachableURL();
@@ -1767,8 +1759,17 @@ bool FrameLoader::frameHasLoaded() const
void FrameLoader::transferLoadingResourcesFromPage(Page* oldPage)
{
ASSERT(oldPage != m_frame->page());
- if (isLoading())
+ if (isLoading()) {
activeDocumentLoader()->transferLoadingResourcesFromPage(oldPage);
+ oldPage->progress()->progressCompleted(m_frame);
+ if (m_frame->page())
+ m_frame->page()->progress()->progressStarted(m_frame);
+ }
+}
+
+void FrameLoader::dispatchTransferLoadingResourceFromPage(unsigned long identifier, DocumentLoader* docLoader, const ResourceRequest& request, Page* oldPage)
+{
+ notifier()->dispatchTransferLoadingResourceFromPage(identifier, docLoader, request, oldPage);
}
void FrameLoader::setDocumentLoader(DocumentLoader* loader)
@@ -2187,10 +2188,6 @@ void FrameLoader::finishedLoading()
dl->setPrimaryLoadComplete(true);
m_client->dispatchDidLoadMainResource(dl.get());
checkLoadComplete();
-
- DOMWindow* window = m_frame->existingDOMWindow();
- if (window && window->printDeferred())
- window->print();
}
bool FrameLoader::isHostedByObjectElement() const
@@ -2433,9 +2430,6 @@ void FrameLoader::checkLoadCompleteForThisFrame()
return;
const ResourceError& error = dl->mainDocumentError();
-#ifndef NDEBUG
- m_didDispatchDidCommitLoad = false;
-#endif
if (!error.isNull())
m_client->dispatchDidFailLoad(error);
else
@@ -3325,6 +3319,11 @@ ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) co
return m_client->cannotShowURLError(request);
}
+ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request) const
+{
+ return m_client->interruptForPolicyChangeError(request);
+}
+
ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& response) const
{
return m_client->fileDoesNotExistError(response);
@@ -3439,10 +3438,6 @@ void FrameLoader::dispatchDidCommitLoad()
if (m_stateMachine.creatingInitialEmptyDocument())
return;
-#ifndef NDEBUG
- m_didDispatchDidCommitLoad = true;
-#endif
-
m_client->dispatchDidCommitLoad();
#if ENABLE(INSPECTOR)
diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h
index b07ed27..009b179 100644
--- a/WebCore/loader/FrameLoader.h
+++ b/WebCore/loader/FrameLoader.h
@@ -138,6 +138,7 @@ public:
bool isLoading() const;
bool frameHasLoaded() const;
void transferLoadingResourcesFromPage(Page*);
+ void dispatchTransferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*);
int numPendingOrLoadingRequests(bool recurse) const;
String referrer() const;
@@ -170,7 +171,7 @@ public:
ResourceError fileDoesNotExistError(const ResourceResponse&) const;
ResourceError blockedError(const ResourceRequest&) const;
ResourceError cannotShowURLError(const ResourceRequest&) const;
- ResourceError interruptionForPolicyChangeError(const ResourceRequest&);
+ ResourceError interruptionForPolicyChangeError(const ResourceRequest&) const;
bool isHostedByObjectElement() const;
bool isLoadingMainFrame() const;
@@ -337,12 +338,6 @@ public:
NetworkingContext* networkingContext() const;
private:
- bool canCachePageContainingThisFrame();
-#ifndef NDEBUG
- void logCanCachePageDecision();
- bool logCanCacheFrameDecision(int indentLevel);
-#endif
-
void checkTimerFired(Timer<FrameLoader>*);
void navigateWithinDocument(HistoryItem*);
@@ -367,8 +362,6 @@ private:
void mainReceivedError(const ResourceError&, bool isComplete);
- void setLoadType(FrameLoadType);
-
static void callContinueLoadAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
static void callContinueLoadAfterNewWindowPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue);
static void callContinueFragmentScrollAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
@@ -390,8 +383,6 @@ private:
void closeOldDataSources();
void prepareForCachedPageRestore();
- void updateHistoryAfterClientRedirect();
-
bool shouldReloadToHandleUnreachableURL(DocumentLoader*);
void dispatchDidCommitLoad();
@@ -422,8 +413,6 @@ private:
void provisionalLoadStarted();
- bool canCachePage();
-
bool didOpenURL(const KURL&);
void scheduleCheckCompleted();
@@ -499,10 +488,6 @@ private:
SandboxFlags m_sandboxFlags;
SandboxFlags m_forcedSandboxFlags;
-#ifndef NDEBUG
- bool m_didDispatchDidCommitLoad;
-#endif
-
RefPtr<FrameNetworkingContext> m_networkingContext;
};
diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp
index 7e5eb90..85ceb19 100644
--- a/WebCore/loader/MainResourceLoader.cpp
+++ b/WebCore/loader/MainResourceLoader.cpp
@@ -44,6 +44,7 @@
#endif
#include "ResourceError.h"
#include "ResourceHandle.h"
+#include "ResourceLoadScheduler.h"
#include "SchemeRegistry.h"
#include "Settings.h"
#include <wtf/CurrentTime.h>
@@ -548,6 +549,7 @@ bool MainResourceLoader::loadNow(ResourceRequest& r)
if (shouldLoadEmptyBeforeRedirect && !shouldLoadEmpty && defersLoading())
return true;
+ resourceLoadScheduler()->addMainResourceLoad(this);
if (m_substituteData.isValid())
handleDataLoadSoon(r);
else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
diff --git a/WebCore/loader/NetscapePlugInStreamLoader.cpp b/WebCore/loader/NetscapePlugInStreamLoader.cpp
index 1225652..8c2a426 100644
--- a/WebCore/loader/NetscapePlugInStreamLoader.cpp
+++ b/WebCore/loader/NetscapePlugInStreamLoader.cpp
@@ -44,9 +44,13 @@ NetscapePlugInStreamLoader::~NetscapePlugInStreamLoader()
{
}
-PassRefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame* frame, NetscapePlugInStreamLoaderClient* client)
+PassRefPtr<NetscapePlugInStreamLoader> NetscapePlugInStreamLoader::create(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
{
- return adoptRef(new NetscapePlugInStreamLoader(frame, client));
+ RefPtr<NetscapePlugInStreamLoader> loader(adoptRef(new NetscapePlugInStreamLoader(frame, client)));
+ loader->setShouldBufferData(false);
+ loader->documentLoader()->addPlugInStreamLoader(loader.get());
+ loader->init(request);
+ return loader.release();
}
bool NetscapePlugInStreamLoader::isDone() const
diff --git a/WebCore/loader/NetscapePlugInStreamLoader.h b/WebCore/loader/NetscapePlugInStreamLoader.h
index c8c4cb6..4d7d03b 100644
--- a/WebCore/loader/NetscapePlugInStreamLoader.h
+++ b/WebCore/loader/NetscapePlugInStreamLoader.h
@@ -47,7 +47,7 @@ namespace WebCore {
class NetscapePlugInStreamLoader : public ResourceLoader {
public:
- static PassRefPtr<NetscapePlugInStreamLoader> create(Frame*, NetscapePlugInStreamLoaderClient*);
+ static PassRefPtr<NetscapePlugInStreamLoader> create(Frame*, NetscapePlugInStreamLoaderClient*, const ResourceRequest&);
virtual ~NetscapePlugInStreamLoader();
bool isDone() const;
diff --git a/WebCore/loader/ProgressTracker.cpp b/WebCore/loader/ProgressTracker.cpp
index 6bc2055..cd15433 100644
--- a/WebCore/loader/ProgressTracker.cpp
+++ b/WebCore/loader/ProgressTracker.cpp
@@ -241,7 +241,7 @@ void ProgressTracker::completeProgress(unsigned long identifier)
{
ProgressItem* item = m_progressItems.get(identifier);
- // FIXME: Can this happen?
+ // This can happen if a load fails without receiving any response data.
if (!item)
return;
diff --git a/WebCore/loader/ResourceLoadNotifier.cpp b/WebCore/loader/ResourceLoadNotifier.cpp
index b32b737..d002ef3 100644
--- a/WebCore/loader/ResourceLoadNotifier.cpp
+++ b/WebCore/loader/ResourceLoadNotifier.cpp
@@ -160,6 +160,14 @@ void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsi
#endif
}
+void ResourceLoadNotifier::dispatchTransferLoadingResourceFromPage(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request, Page* oldPage)
+{
+ ASSERT(oldPage != m_frame->page());
+ m_frame->loader()->client()->transferLoadingResourceFromPage(identifier, loader, request, oldPage);
+
+ oldPage->progress()->completeProgress(identifier);
+}
+
void ResourceLoadNotifier::sendRemainingDelegateMessages(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
{
if (!response.isNull())
diff --git a/WebCore/loader/ResourceLoadNotifier.h b/WebCore/loader/ResourceLoadNotifier.h
index 93fcccc..2f10856 100644
--- a/WebCore/loader/ResourceLoadNotifier.h
+++ b/WebCore/loader/ResourceLoadNotifier.h
@@ -37,6 +37,7 @@ namespace WebCore {
class AuthenticationChallenge;
class DocumentLoader;
class Frame;
+class Page;
class ResourceError;
class ResourceLoader;
class ResourceResponse;
@@ -60,6 +61,7 @@ public:
void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&);
void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int length);
void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier, double finishTime);
+ void dispatchTransferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*);
void sendRemainingDelegateMessages(DocumentLoader*, unsigned long identifier, const ResourceResponse&, int length, const ResourceError&);
diff --git a/WebCore/loader/ResourceLoadScheduler.cpp b/WebCore/loader/ResourceLoadScheduler.cpp
new file mode 100644
index 0000000..80bea97
--- /dev/null
+++ b/WebCore/loader/ResourceLoadScheduler.cpp
@@ -0,0 +1,282 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
+ Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
+ Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2010 Google Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ResourceLoadScheduler.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "InspectorInstrumentation.h"
+#include "KURL.h"
+#include "Logging.h"
+#include "NetscapePlugInStreamLoader.h"
+#include "ResourceLoader.h"
+#include "ResourceRequest.h"
+#include "SubresourceLoader.h"
+
+#define REQUEST_MANAGEMENT_ENABLED 1
+
+namespace WebCore {
+
+#if REQUEST_MANAGEMENT_ENABLED
+static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
+// Match the parallel connection count used by the networking layer.
+static unsigned maxRequestsInFlightPerHost;
+#else
+static const unsigned maxRequestsInFlightForNonHTTPProtocols = 10000;
+static const unsigned maxRequestsInFlightPerHost = 10000;
+#endif
+
+ResourceLoadScheduler::HostInformation* ResourceLoadScheduler::hostForURL(const KURL& url, CreateHostPolicy createHostPolicy)
+{
+ if (!url.protocolInHTTPFamily())
+ return m_nonHTTPProtocolHost;
+
+ m_hosts.checkConsistency();
+ String hostName = url.host();
+ HostInformation* host = m_hosts.get(hostName);
+ if (!host && createHostPolicy == CreateIfNotFound) {
+ host = new HostInformation(hostName, maxRequestsInFlightPerHost);
+ m_hosts.add(hostName, host);
+ }
+ return host;
+}
+
+ResourceLoadScheduler* resourceLoadScheduler()
+{
+ ASSERT(isMainThread());
+ DEFINE_STATIC_LOCAL(ResourceLoadScheduler, resourceLoadScheduler, ());
+ return &resourceLoadScheduler;
+}
+
+ResourceLoadScheduler::ResourceLoadScheduler()
+ : m_nonHTTPProtocolHost(new HostInformation(String(), maxRequestsInFlightForNonHTTPProtocols))
+ , m_requestTimer(this, &ResourceLoadScheduler::requestTimerFired)
+ , m_isSuspendingPendingRequests(false)
+{
+#if REQUEST_MANAGEMENT_ENABLED
+ maxRequestsInFlightPerHost = initializeMaximumHTTPConnectionCountPerHost();
+#endif
+}
+
+PassRefPtr<SubresourceLoader> ResourceLoadScheduler::scheduleSubresourceLoad(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, Priority priority, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff)
+{
+ PassRefPtr<SubresourceLoader> loader = SubresourceLoader::create(frame, client, request, securityCheck, sendResourceLoadCallbacks, shouldContentSniff);
+ if (loader)
+ scheduleLoad(loader.get(), priority);
+ return loader;
+}
+
+PassRefPtr<NetscapePlugInStreamLoader> ResourceLoadScheduler::schedulePluginStreamLoad(Frame* frame, NetscapePlugInStreamLoaderClient* client, const ResourceRequest& request)
+{
+ PassRefPtr<NetscapePlugInStreamLoader> loader = NetscapePlugInStreamLoader::create(frame, client, request);
+ if (loader)
+ scheduleLoad(loader.get(), Low);
+ return loader;
+}
+
+void ResourceLoadScheduler::addMainResourceLoad(ResourceLoader* resourceLoader)
+{
+ hostForURL(resourceLoader->url(), CreateIfNotFound)->addLoadInProgress(resourceLoader);
+}
+
+void ResourceLoadScheduler::scheduleLoad(ResourceLoader* resourceLoader, Priority priority)
+{
+ ASSERT(resourceLoader);
+#if !REQUEST_MANAGEMENT_ENABLED
+ priority = HighestPriority;
+#endif
+
+ LOG(ResourceLoading, "ResourceLoadScheduler::load resource %p '%s'", resourceLoader, resourceLoader->url().string().latin1().data());
+ HostInformation* host = hostForURL(resourceLoader->url(), CreateIfNotFound);
+ bool hadRequests = host->hasRequests();
+ host->schedule(resourceLoader, priority);
+
+ if (priority > Low || !resourceLoader->url().protocolInHTTPFamily() || (priority == Low && !hadRequests)) {
+ // Try to request important resources immediately.
+ servePendingRequests(host, priority);
+ } else {
+ // Handle asynchronously so early low priority requests don't get scheduled before later high priority ones.
+ InspectorInstrumentation::didScheduleResourceRequest(resourceLoader->frameLoader() ? resourceLoader->frameLoader()->frame()->document() : 0, resourceLoader->url());
+ scheduleServePendingRequests();
+ }
+}
+
+void ResourceLoadScheduler::remove(ResourceLoader* resourceLoader)
+{
+ ASSERT(resourceLoader);
+
+ HostInformation* host = hostForURL(resourceLoader->url());
+ if (host)
+ host->remove(resourceLoader);
+ scheduleServePendingRequests();
+}
+
+void ResourceLoadScheduler::crossOriginRedirectReceived(ResourceLoader* resourceLoader, const KURL& redirectURL)
+{
+ HostInformation* oldHost = hostForURL(resourceLoader->url());
+ ASSERT(oldHost);
+ HostInformation* newHost = hostForURL(redirectURL, CreateIfNotFound);
+
+ if (oldHost->name() == newHost->name())
+ return;
+
+ newHost->addLoadInProgress(resourceLoader);
+ oldHost->remove(resourceLoader);
+}
+
+void ResourceLoadScheduler::servePendingRequests(Priority minimumPriority)
+{
+ LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests. m_isSuspendingPendingRequests=%d", m_isSuspendingPendingRequests);
+ if (m_isSuspendingPendingRequests)
+ return;
+
+ m_requestTimer.stop();
+
+ servePendingRequests(m_nonHTTPProtocolHost, minimumPriority);
+
+ Vector<HostInformation*> hostsToServe;
+ m_hosts.checkConsistency();
+ HostMap::iterator end = m_hosts.end();
+ for (HostMap::iterator iter = m_hosts.begin(); iter != end; ++iter)
+ hostsToServe.append(iter->second);
+
+ int size = hostsToServe.size();
+ for (int i = 0; i < size; ++i) {
+ HostInformation* host = hostsToServe[i];
+ if (host->hasRequests())
+ servePendingRequests(host, minimumPriority);
+ else
+ delete m_hosts.take(host->name());
+ }
+}
+
+void ResourceLoadScheduler::servePendingRequests(HostInformation* host, Priority minimumPriority)
+{
+ LOG(ResourceLoading, "ResourceLoadScheduler::servePendingRequests HostInformation.m_name='%s'", host->name().latin1().data());
+
+ for (int priority = HighestPriority; priority >= minimumPriority; --priority) {
+ HostInformation::RequestQueue& requestsPending = host->requestsPending((Priority) priority);
+
+ while (!requestsPending.isEmpty()) {
+ RefPtr<ResourceLoader> resourceLoader = requestsPending.first();
+
+ // For named hosts - which are only http(s) hosts - we should always enforce the connection limit.
+ // For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing
+ // and we don't know all stylesheets yet.
+ Document* document = resourceLoader->frameLoader() ? resourceLoader->frameLoader()->frame()->document() : 0;
+ bool shouldLimitRequests = !host->name().isNull() || (document && (document->parsing() || !document->haveStylesheetsLoaded()));
+ if (shouldLimitRequests && host->limitRequests())
+ return;
+
+ resourceLoader->start();
+ if (!resourceLoader->reachedTerminalState())
+ host->addLoadInProgress(resourceLoader.get());
+ requestsPending.removeFirst();
+ }
+ }
+}
+
+void ResourceLoadScheduler::suspendPendingRequests()
+{
+ ASSERT(!m_isSuspendingPendingRequests);
+ m_isSuspendingPendingRequests = true;
+}
+
+void ResourceLoadScheduler::resumePendingRequests()
+{
+ ASSERT(m_isSuspendingPendingRequests);
+ m_isSuspendingPendingRequests = false;
+ if (!m_hosts.isEmpty() || m_nonHTTPProtocolHost->hasRequests())
+ scheduleServePendingRequests();
+}
+
+void ResourceLoadScheduler::scheduleServePendingRequests()
+{
+ LOG(ResourceLoading, "ResourceLoadScheduler::scheduleServePendingRequests, m_requestTimer.isActive()=%u", m_requestTimer.isActive());
+ if (!m_requestTimer.isActive())
+ m_requestTimer.startOneShot(0);
+}
+
+void ResourceLoadScheduler::requestTimerFired(Timer<ResourceLoadScheduler>*)
+{
+ LOG(ResourceLoading, "ResourceLoadScheduler::requestTimerFired\n");
+ servePendingRequests();
+}
+
+ResourceLoadScheduler::HostInformation::HostInformation(const String& name, unsigned maxRequestsInFlight)
+ : m_name(name)
+ , m_maxRequestsInFlight(maxRequestsInFlight)
+{
+}
+
+ResourceLoadScheduler::HostInformation::~HostInformation()
+{
+ ASSERT(m_requestsLoading.isEmpty());
+ for (unsigned p = 0; p <= HighestPriority; p++)
+ ASSERT(m_requestsPending[p].isEmpty());
+}
+
+void ResourceLoadScheduler::HostInformation::schedule(ResourceLoader* resourceLoader, Priority priority)
+{
+ m_requestsPending[priority].append(resourceLoader);
+}
+
+void ResourceLoadScheduler::HostInformation::addLoadInProgress(ResourceLoader* resourceLoader)
+{
+ LOG(ResourceLoading, "HostInformation '%s' loading '%s'. Current count %d", m_name.latin1().data(), resourceLoader->url().string().latin1().data(), m_requestsLoading.size());
+ m_requestsLoading.add(resourceLoader);
+}
+
+void ResourceLoadScheduler::HostInformation::remove(ResourceLoader* resourceLoader)
+{
+ if (m_requestsLoading.contains(resourceLoader)) {
+ m_requestsLoading.remove(resourceLoader);
+ return;
+ }
+
+ for (int priority = HighestPriority; priority >= LowestPriority; --priority) {
+ RequestQueue::iterator end = m_requestsPending[priority].end();
+ for (RequestQueue::iterator it = m_requestsPending[priority].begin(); it != end; ++it) {
+ if (*it == resourceLoader) {
+ m_requestsPending[priority].remove(it);
+ return;
+ }
+ }
+ }
+}
+
+bool ResourceLoadScheduler::HostInformation::hasRequests() const
+{
+ if (!m_requestsLoading.isEmpty())
+ return true;
+ for (unsigned p = 0; p <= HighestPriority; p++) {
+ if (!m_requestsPending[p].isEmpty())
+ return true;
+ }
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/ResourceLoadScheduler.h b/WebCore/loader/ResourceLoadScheduler.h
new file mode 100644
index 0000000..84f8845
--- /dev/null
+++ b/WebCore/loader/ResourceLoadScheduler.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
+ Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
+ Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2010 Google Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ResourceLoadScheduler_h
+#define ResourceLoadScheduler_h
+
+#include "FrameLoaderTypes.h"
+#include "PlatformString.h"
+#include "Timer.h"
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class Frame;
+class KURL;
+class NetscapePlugInStreamLoader;
+class NetscapePlugInStreamLoaderClient;
+class ResourceLoader;
+class ResourceRequest;
+class SubresourceLoader;
+class SubresourceLoaderClient;
+
+class ResourceLoadScheduler : public Noncopyable {
+public:
+ friend ResourceLoadScheduler* resourceLoadScheduler();
+
+ enum Priority { VeryLow, Low, Medium, High, LowestPriority = VeryLow, HighestPriority = High };
+ PassRefPtr<SubresourceLoader> scheduleSubresourceLoad(Frame*, SubresourceLoaderClient*, const ResourceRequest&, Priority = Low, SecurityCheckPolicy = DoSecurityCheck, bool sendResourceLoadCallbacks = true, bool shouldContentSniff = true);
+ PassRefPtr<NetscapePlugInStreamLoader> schedulePluginStreamLoad(Frame*, NetscapePlugInStreamLoaderClient*, const ResourceRequest&);
+ void addMainResourceLoad(ResourceLoader*);
+ void remove(ResourceLoader*);
+ void crossOriginRedirectReceived(ResourceLoader*, const KURL& redirectURL);
+
+ void servePendingRequests(Priority minimumPriority = VeryLow);
+ void suspendPendingRequests();
+ void resumePendingRequests();
+
+private:
+ ResourceLoadScheduler();
+ ~ResourceLoadScheduler();
+
+ void scheduleLoad(ResourceLoader*, Priority);
+ void scheduleServePendingRequests();
+ void requestTimerFired(Timer<ResourceLoadScheduler>*);
+
+ class HostInformation : public Noncopyable {
+ public:
+ HostInformation(const String&, unsigned);
+ ~HostInformation();
+
+ const String& name() const { return m_name; }
+ void schedule(ResourceLoader*, Priority = VeryLow);
+ void addLoadInProgress(ResourceLoader*);
+ void remove(ResourceLoader*);
+ bool hasRequests() const;
+ bool limitRequests() const { return m_requestsLoading.size() >= m_maxRequestsInFlight; }
+
+ typedef Deque<RefPtr<ResourceLoader> > RequestQueue;
+ RequestQueue& requestsPending(Priority priority) { return m_requestsPending[priority]; }
+
+ private:
+ RequestQueue m_requestsPending[HighestPriority + 1];
+ typedef HashSet<RefPtr<ResourceLoader> > RequestMap;
+ RequestMap m_requestsLoading;
+ const String m_name;
+ const int m_maxRequestsInFlight;
+ };
+
+ enum CreateHostPolicy {
+ CreateIfNotFound,
+ FindOnly
+ };
+
+ HostInformation* hostForURL(const KURL&, CreateHostPolicy = FindOnly);
+ void servePendingRequests(HostInformation*, Priority);
+
+ typedef HashMap<String, HostInformation*, StringHash> HostMap;
+ HostMap m_hosts;
+ HostInformation* m_nonHTTPProtocolHost;
+
+ Timer<ResourceLoadScheduler> m_requestTimer;
+
+ bool m_isSuspendingPendingRequests;
+};
+
+ResourceLoadScheduler* resourceLoadScheduler();
+
+}
+
+#endif
diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp
index eab5acd..42b6092 100644
--- a/WebCore/loader/ResourceLoader.cpp
+++ b/WebCore/loader/ResourceLoader.cpp
@@ -39,8 +39,9 @@
#include "InspectorInstrumentation.h"
#include "Page.h"
#include "ProgressTracker.h"
-#include "ResourceHandle.h"
#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceLoadScheduler.h"
#include "Settings.h"
#include "SharedBuffer.h"
@@ -95,6 +96,8 @@ void ResourceLoader::releaseResources()
m_identifier = 0;
+ resourceLoadScheduler()->remove(this);
+
if (m_handle) {
// Clear out the ResourceHandle's client so that it doesn't try to call
// us back after we release it, unless it has been replaced by someone else.
@@ -107,9 +110,10 @@ void ResourceLoader::releaseResources()
m_deferredRequest = ResourceRequest();
}
-bool ResourceLoader::load(const ResourceRequest& r)
+void ResourceLoader::init(const ResourceRequest& r)
{
ASSERT(!m_handle);
+ ASSERT(m_request.isNull());
ASSERT(m_deferredRequest.isNull());
ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
@@ -125,30 +129,43 @@ bool ResourceLoader::load(const ResourceRequest& r)
clientRequest.setFirstPartyForCookies(document->firstPartyForCookies());
}
- willSendRequest(clientRequest, ResourceResponse());
- if (clientRequest.isNull()) {
- didFail(frameLoader()->cancelledError(r));
- return false;
- }
+ m_request = clientRequest;
+}
+
+void ResourceLoader::start()
+{
+ ASSERT(!m_handle);
+ ASSERT(!m_request.isNull());
+ ASSERT(m_deferredRequest.isNull());
+
+ willSendRequest(m_request, ResourceResponse());
+ if (m_request.isNull()) {
+ didFail(frameLoader()->cancelledError(m_request));
+ return;
+ }
+<<<<<<< HEAD
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
if (m_documentLoader->scheduleArchiveLoad(this, clientRequest, r.url()))
return true;
#endif
+=======
+ if (m_documentLoader->scheduleArchiveLoad(this, m_request, m_request.url()))
+ return;
+>>>>>>> webkit.org at r72274
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, clientRequest, r.url()))
- return true;
+ if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, m_request, m_request.url()))
+ return;
#endif
if (m_defersLoading) {
- m_deferredRequest = clientRequest;
- return true;
+ m_deferredRequest = m_request;
+ return;
}
-
- m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), clientRequest, this, m_defersLoading, m_shouldContentSniff);
- return true;
+ if (!m_reachedTerminalState)
+ m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), m_request, this, m_defersLoading, m_shouldContentSniff);
}
void ResourceLoader::setDefersLoading(bool defers)
@@ -157,9 +174,9 @@ void ResourceLoader::setDefersLoading(bool defers)
if (m_handle)
m_handle->setDefersLoading(defers);
if (!defers && !m_deferredRequest.isNull()) {
- ResourceRequest request(m_deferredRequest);
+ m_request = m_deferredRequest;
m_deferredRequest = ResourceRequest();
- load(request);
+ start();
}
}
@@ -234,6 +251,8 @@ void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceRes
frameLoader()->notifier()->willSendRequest(this, request, redirectResponse);
}
+ if (!redirectResponse.isNull())
+ resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url());
m_request = request;
}
@@ -354,7 +373,7 @@ void ResourceLoader::didCancel(const ResourceError& error)
m_handle->cancel();
m_handle = 0;
}
- if (m_sendResourceLoadCallbacks && !m_calledDidFinishLoad)
+ if (m_sendResourceLoadCallbacks && m_identifier && !m_calledDidFinishLoad)
frameLoader()->notifier()->didFailToLoad(this, error);
releaseResources();
diff --git a/WebCore/loader/ResourceLoader.h b/WebCore/loader/ResourceLoader.h
index 29afbc1..0da76fb 100644
--- a/WebCore/loader/ResourceLoader.h
+++ b/WebCore/loader/ResourceLoader.h
@@ -54,7 +54,7 @@ namespace WebCore {
void cancel();
- virtual bool load(const ResourceRequest&);
+ virtual void init(const ResourceRequest&);
FrameLoader* frameLoader() const;
DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
@@ -126,9 +126,12 @@ namespace WebCore {
virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*);
#endif
+ const KURL& url() const { return m_request.url(); }
ResourceHandle* handle() const { return m_handle.get(); }
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
+ bool reachedTerminalState() const { return m_reachedTerminalState; }
+
void setShouldBufferData(bool shouldBufferData);
protected:
@@ -137,12 +140,15 @@ namespace WebCore {
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
friend class ApplicationCacheHost; // for access to request()
#endif
-
+ friend class ResourceLoadScheduler; // for access to start()
+ // start() actually sends the load to the network (unless the load is being
+ // deferred) and should only be called by ResourceLoadScheduler or setDefersLoading().
+ void start();
+
virtual void didCancel(const ResourceError&);
void didFinishLoadingOnePart(double finishTime);
const ResourceRequest& request() const { return m_request; }
- bool reachedTerminalState() const { return m_reachedTerminalState; }
bool cancelled() const { return m_cancelled; }
bool defersLoading() const { return m_defersLoading; }
diff --git a/WebCore/loader/SubresourceLoader.cpp b/WebCore/loader/SubresourceLoader.cpp
index 5377382..3ae4d6f 100644
--- a/WebCore/loader/SubresourceLoader.cpp
+++ b/WebCore/loader/SubresourceLoader.cpp
@@ -86,8 +86,7 @@ PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, Subresourc
RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
subloader->documentLoader()->addSubresourceLoader(subloader.get());
- if (!subloader->load(newRequest))
- return 0;
+ subloader->init(newRequest);
return subloader.release();
}
diff --git a/WebCore/loader/cache/CachedCSSStyleSheet.cpp b/WebCore/loader/cache/CachedCSSStyleSheet.cpp
index f0016d1..9ec979b 100644
--- a/WebCore/loader/cache/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/cache/CachedCSSStyleSheet.cpp
@@ -117,10 +117,11 @@ void CachedCSSStyleSheet::checkNotify()
c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
}
-void CachedCSSStyleSheet::error()
+void CachedCSSStyleSheet::error(CachedResource::Status status)
{
+ setStatus(status);
+ ASSERT(errorOccurred());
setLoading(false);
- setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/cache/CachedCSSStyleSheet.h b/WebCore/loader/cache/CachedCSSStyleSheet.h
index abcdb85..a982e03 100644
--- a/WebCore/loader/cache/CachedCSSStyleSheet.h
+++ b/WebCore/loader/cache/CachedCSSStyleSheet.h
@@ -49,7 +49,7 @@ namespace WebCore {
virtual void setEncoding(const String&);
virtual String encoding() const;
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error();
+ virtual void error(CachedResource::Status);
void checkNotify();
diff --git a/WebCore/loader/cache/CachedFont.cpp b/WebCore/loader/cache/CachedFont.cpp
index 6297ad1..96654a5 100644
--- a/WebCore/loader/cache/CachedFont.cpp
+++ b/WebCore/loader/cache/CachedFont.cpp
@@ -111,7 +111,7 @@ bool CachedFont::ensureCustomFontData()
if (!m_fontData && !errorOccurred() && !isLoading() && m_data) {
m_fontData = createFontCustomPlatformData(m_data.get());
if (!m_fontData)
- setErrorOccurred(true);
+ setStatus(DecodeError);
}
#endif
return m_fontData;
@@ -206,10 +206,11 @@ void CachedFont::checkNotify()
}
-void CachedFont::error()
+void CachedFont::error(CachedResource::Status status)
{
+ setStatus(status);
+ ASSERT(errorOccurred());
setLoading(false);
- setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/cache/CachedFont.h b/WebCore/loader/cache/CachedFont.h
index e1a34e8..5814087 100644
--- a/WebCore/loader/cache/CachedFont.h
+++ b/WebCore/loader/cache/CachedFont.h
@@ -54,7 +54,7 @@ public:
virtual void didAddClient(CachedResourceClient*);
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error();
+ virtual void error(CachedResource::Status);
virtual void allClientsRemoved();
diff --git a/WebCore/loader/cache/CachedImage.cpp b/WebCore/loader/cache/CachedImage.cpp
index ce1c9a3..c610b0b 100644
--- a/WebCore/loader/cache/CachedImage.cpp
+++ b/WebCore/loader/cache/CachedImage.cpp
@@ -290,7 +290,7 @@ void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
IntSize s = imageSize(1.0f);
size_t estimatedDecodedImageSize = s.width() * s.height() * 4; // no overflow check
if (m_image->isNull() || (maxDecodedImageSize > 0 && estimatedDecodedImageSize > maxDecodedImageSize)) {
- error();
+ error(errorOccurred() ? status() : DecodeError);
if (inCache())
cache()->remove(this);
return;
@@ -310,10 +310,11 @@ void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
}
}
-void CachedImage::error()
+void CachedImage::error(CachedResource::Status status)
{
clear();
- setErrorOccurred(true);
+ setStatus(status);
+ ASSERT(errorOccurred() || httpStatusCodeErrorOccurred());
m_data.clear();
notifyObservers();
setLoading(false);
diff --git a/WebCore/loader/cache/CachedImage.h b/WebCore/loader/cache/CachedImage.h
index 313f3f3..af36534 100644
--- a/WebCore/loader/cache/CachedImage.h
+++ b/WebCore/loader/cache/CachedImage.h
@@ -65,11 +65,11 @@ public:
virtual void destroyDecodedData();
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error();
+ virtual void error(CachedResource::Status);
virtual void httpStatusCodeError() { m_httpStatusCodeErrorOccurred = true; }
bool httpStatusCodeErrorOccurred() const { return m_httpStatusCodeErrorOccurred; }
-
+
void checkNotify();
virtual bool isImage() const { return true; }
diff --git a/WebCore/loader/cache/CachedResource.cpp b/WebCore/loader/cache/CachedResource.cpp
index c440ec9..d4eac2e 100644
--- a/WebCore/loader/cache/CachedResource.cpp
+++ b/WebCore/loader/cache/CachedResource.cpp
@@ -66,7 +66,6 @@ CachedResource::CachedResource(const String& url, Type type)
, m_inLiveDecodedResourcesList(false)
, m_requestedFromNetworkingLayer(false)
, m_sendResourceLoadCallbacks(true)
- , m_errorOccurred(false)
, m_inCache(false)
, m_loading(false)
, m_type(type)
@@ -454,7 +453,7 @@ void CachedResource::unregisterHandle(CachedResourceHandleBase* h)
bool CachedResource::canUseCacheValidator() const
{
- if (m_loading || m_errorOccurred)
+ if (m_loading || errorOccurred())
return false;
if (m_response.cacheControlContainsNoStore())
@@ -467,7 +466,7 @@ bool CachedResource::canUseCacheValidator() const
bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const
{
- if (m_errorOccurred) {
+ if (errorOccurred()) {
LOG(ResourceLoading, "CachedResource %p mustRevalidate because of m_errorOccurred\n", this);
return true;
}
diff --git a/WebCore/loader/cache/CachedResource.h b/WebCore/loader/cache/CachedResource.h
index ba02459..ed60f84 100644
--- a/WebCore/loader/cache/CachedResource.h
+++ b/WebCore/loader/cache/CachedResource.h
@@ -70,7 +70,9 @@ public:
enum Status {
Unknown, // let cache decide what to do with it
Pending, // only partially loaded
- Cached // regular case
+ Cached, // regular case
+ LoadError,
+ DecodeError
};
CachedResource(const String& url, Type);
@@ -82,8 +84,8 @@ public:
virtual void setEncoding(const String&) { }
virtual String encoding() const { return String(); }
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error() { }
- virtual void httpStatusCodeError() { error(); } // Images keep loading in spite of HTTP errors (for legacy compat with <img>, etc.).
+ virtual void error(CachedResource::Status) { }
+ virtual void httpStatusCodeError() { error(LoadError); } // Images keep loading in spite of HTTP errors (for legacy compat with <img>, etc.).
const String &url() const { return m_url; }
Type type() const { return static_cast<Type>(m_type); }
@@ -174,8 +176,7 @@ public:
String accept() const { return m_accept; }
void setAccept(const String& accept) { m_accept = accept; }
- bool errorOccurred() const { return m_errorOccurred; }
- void setErrorOccurred(bool b) { m_errorOccurred = b; }
+ bool errorOccurred() const { return (status() == LoadError || status() == DecodeError); }
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
@@ -251,12 +252,11 @@ private:
bool m_requestedFromNetworkingLayer : 1;
bool m_sendResourceLoadCallbacks : 1;
- bool m_errorOccurred : 1;
bool m_inCache : 1;
bool m_loading : 1;
unsigned m_type : 3; // Type
- unsigned m_status : 2; // Status
+ unsigned m_status : 3; // Status
#ifndef NDEBUG
bool m_deleted;
diff --git a/WebCore/loader/cache/CachedScript.cpp b/WebCore/loader/cache/CachedScript.cpp
index 50a8c17..54b4503 100644
--- a/WebCore/loader/cache/CachedScript.cpp
+++ b/WebCore/loader/cache/CachedScript.cpp
@@ -100,10 +100,11 @@ void CachedScript::checkNotify()
c->notifyFinished(this);
}
-void CachedScript::error()
+void CachedScript::error(CachedResource::Status status)
{
+ setStatus(status);
+ ASSERT(errorOccurred());
setLoading(false);
- setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/cache/CachedScript.h b/WebCore/loader/cache/CachedScript.h
index 7311f9b..30fcb1e 100644
--- a/WebCore/loader/cache/CachedScript.h
+++ b/WebCore/loader/cache/CachedScript.h
@@ -46,7 +46,7 @@ namespace WebCore {
virtual void setEncoding(const String&);
virtual String encoding() const;
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error();
+ virtual void error(CachedResource::Status);
void checkNotify();
diff --git a/WebCore/loader/cache/CachedXSLStyleSheet.cpp b/WebCore/loader/cache/CachedXSLStyleSheet.cpp
index 5b30e30..ca7bf13 100644
--- a/WebCore/loader/cache/CachedXSLStyleSheet.cpp
+++ b/WebCore/loader/cache/CachedXSLStyleSheet.cpp
@@ -87,10 +87,11 @@ void CachedXSLStyleSheet::checkNotify()
c->setXSLStyleSheet(m_url, m_response.url(), m_sheet);
}
-void CachedXSLStyleSheet::error()
+void CachedXSLStyleSheet::error(CachedResource::Status status)
{
+ setStatus(status);
+ ASSERT(errorOccurred());
setLoading(false);
- setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/cache/CachedXSLStyleSheet.h b/WebCore/loader/cache/CachedXSLStyleSheet.h
index 8587b0b..8b29792 100644
--- a/WebCore/loader/cache/CachedXSLStyleSheet.h
+++ b/WebCore/loader/cache/CachedXSLStyleSheet.h
@@ -46,7 +46,7 @@ namespace WebCore {
virtual void setEncoding(const String&);
virtual String encoding() const;
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual void error();
+ virtual void error(CachedResource::Status);
void checkNotify();
diff --git a/WebCore/loader/icon/IconLoader.cpp b/WebCore/loader/icon/IconLoader.cpp
index adfa04b..24562d0 100644
--- a/WebCore/loader/icon/IconLoader.cpp
+++ b/WebCore/loader/icon/IconLoader.cpp
@@ -33,6 +33,7 @@
#include "IconDatabase.h"
#include "Logging.h"
#include "ResourceHandle.h"
+#include "ResourceLoadScheduler.h"
#include "ResourceResponse.h"
#include "ResourceRequest.h"
#include "SharedBuffer.h"
@@ -68,7 +69,7 @@ void IconLoader::startLoading()
// SubresourceLoader::create returns.
m_loadIsInProgress = true;
- RefPtr<SubresourceLoader> loader = SubresourceLoader::create(m_frame, this, m_frame->loader()->iconURL());
+ RefPtr<SubresourceLoader> loader = resourceLoadScheduler()->scheduleSubresourceLoad(m_frame, this, m_frame->loader()->iconURL());
if (!loader)
LOG_ERROR("Failed to start load for icon at url %s", m_frame->loader()->iconURL().string().ascii().data());
diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp
index bd27312..1d32f82 100644
--- a/WebCore/loader/loader.cpp
+++ b/WebCore/loader/loader.cpp
@@ -28,45 +28,20 @@
#include "CachedImage.h"
#include "CachedResource.h"
#include "CachedResourceLoader.h"
-#include "InspectorInstrumentation.h"
#include "Frame.h"
#include "FrameLoader.h"
-#include "HTMLDocument.h"
#include "Logging.h"
#include "Request.h"
#include "ResourceHandle.h"
+#include "ResourceLoadScheduler.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
-#include "SecurityOrigin.h"
#include "SharedBuffer.h"
-#include "SubresourceLoader.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
-#define REQUEST_MANAGEMENT_ENABLED 1
-
namespace WebCore {
-#if REQUEST_MANAGEMENT_ENABLED
-// Match the parallel connection count used by the networking layer
-static unsigned maxRequestsInFlightPerHost;
-// Having a limit might still help getting more important resources first
-static const unsigned maxRequestsInFlightForNonHTTPProtocols = 20;
-#else
-static const unsigned maxRequestsInFlightPerHost = 10000;
-static const unsigned maxRequestsInFlightForNonHTTPProtocols = 10000;
-#endif
-
-Loader::Loader()
- : m_requestTimer(this, &Loader::requestTimerFired)
- , m_isSuspendingPendingRequests(false)
-{
- m_nonHTTPProtocolHost = Host::create(AtomicString(), maxRequestsInFlightForNonHTTPProtocols);
-#if REQUEST_MANAGEMENT_ENABLED
- maxRequestsInFlightPerHost = initializeMaximumHTTPConnectionCountPerHost();
-#endif
-}
-
Loader::~Loader()
{
ASSERT_NOT_REACHED();
@@ -95,307 +70,111 @@ static ResourceRequest::TargetType cachedResourceTypeToTargetType(CachedResource
return ResourceRequest::TargetIsSubresource;
}
-Loader::Priority Loader::determinePriority(const CachedResource* resource) const
+static ResourceLoadScheduler::Priority determinePriority(const CachedResource* resource)
{
-#if REQUEST_MANAGEMENT_ENABLED
switch (resource->type()) {
case CachedResource::CSSStyleSheet:
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
#endif
- return High;
- case CachedResource::Script:
+ return ResourceLoadScheduler::High;
+ case CachedResource::Script:
case CachedResource::FontResource:
- return Medium;
+ return ResourceLoadScheduler::Medium;
case CachedResource::ImageResource:
- return Low;
+ return ResourceLoadScheduler::Low;
#if ENABLE(LINK_PREFETCH)
case CachedResource::LinkPrefetch:
- return VeryLow;
+ return ResourceLoadScheduler::VeryLow;
#endif
}
ASSERT_NOT_REACHED();
- return Low;
-#else
- return High;
-#endif
+ return ResourceLoadScheduler::Low;
}
void Loader::load(CachedResourceLoader* cachedResourceLoader, CachedResource* resource, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
{
- LOG(ResourceLoading, "Loader::load resource %p '%s'", resource, resource->url().latin1().data());
ASSERT(cachedResourceLoader);
Request* request = new Request(cachedResourceLoader, resource, incremental, securityCheck, sendResourceLoadCallbacks);
- RefPtr<Host> host;
- KURL url(ParsedURLString, resource->url());
- if (url.protocolInHTTPFamily()) {
- m_hosts.checkConsistency();
- AtomicString hostName = url.host();
- host = m_hosts.get(hostName.impl());
- if (!host) {
- host = Host::create(hostName, maxRequestsInFlightPerHost);
- m_hosts.add(hostName.impl(), host);
- }
- } else
- host = m_nonHTTPProtocolHost;
-
- bool hadRequests = host->hasRequests();
- Priority priority = determinePriority(resource);
- host->addRequest(request, priority);
cachedResourceLoader->incrementRequestCount(request->cachedResource());
- if (priority > Low || !url.protocolInHTTPFamily() || (priority == Low && !hadRequests)) {
- // Try to request important resources immediately
- host->servePendingRequests(priority);
- } else {
- // Handle asynchronously so early low priority requests don't get scheduled before later high priority ones
- InspectorInstrumentation::didScheduleResourceRequest(cachedResourceLoader->document(), resource->url());
- scheduleServePendingRequests();
- }
-}
-
-void Loader::scheduleServePendingRequests()
-{
- LOG(ResourceLoading, "Loader::scheduleServePendingRequests, m_requestTimer.isActive()=%u", m_requestTimer.isActive());
- if (!m_requestTimer.isActive())
- m_requestTimer.startOneShot(0);
-}
-
-void Loader::requestTimerFired(Timer<Loader>*)
-{
- LOG(ResourceLoading, "Loader::requestTimerFired\n");
- servePendingRequests();
-}
-
-void Loader::servePendingRequests(Priority minimumPriority)
-{
- LOG(ResourceLoading, "Loader::servePendingRequests. m_isSuspendingPendingRequests=%d", m_isSuspendingPendingRequests);
- if (m_isSuspendingPendingRequests)
- return;
-
- m_requestTimer.stop();
-
- m_nonHTTPProtocolHost->servePendingRequests(minimumPriority);
-
- Vector<Host*> hostsToServe;
- m_hosts.checkConsistency();
- HostMap::iterator i = m_hosts.begin();
- HostMap::iterator end = m_hosts.end();
- for (;i != end; ++i)
- hostsToServe.append(i->second.get());
-
- for (unsigned n = 0; n < hostsToServe.size(); ++n) {
- Host* host = hostsToServe[n];
- if (host->hasRequests())
- host->servePendingRequests(minimumPriority);
- else if (!host->processingResource()){
- AtomicString name = host->name();
- m_hosts.remove(name.impl());
+ ResourceRequest resourceRequest(request->cachedResource()->url());
+ resourceRequest.setTargetType(cachedResourceTypeToTargetType(request->cachedResource()->type()));
+
+ if (!request->cachedResource()->accept().isEmpty())
+ resourceRequest.setHTTPAccept(request->cachedResource()->accept());
+
+ if (request->cachedResource()->isCacheValidator()) {
+ CachedResource* resourceToRevalidate = request->cachedResource()->resourceToRevalidate();
+ ASSERT(resourceToRevalidate->canUseCacheValidator());
+ ASSERT(resourceToRevalidate->isLoaded());
+ const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
+ const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
+ if (!lastModified.isEmpty() || !eTag.isEmpty()) {
+ ASSERT(cachedResourceLoader->cachePolicy() != CachePolicyReload);
+ if (cachedResourceLoader->cachePolicy() == CachePolicyRevalidate)
+ resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
+ if (!lastModified.isEmpty())
+ resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
+ if (!eTag.isEmpty())
+ resourceRequest.setHTTPHeaderField("If-None-Match", eTag);
}
}
-}
-
-void Loader::suspendPendingRequests()
-{
- ASSERT(!m_isSuspendingPendingRequests);
- m_isSuspendingPendingRequests = true;
-}
-
-void Loader::resumePendingRequests()
-{
- ASSERT(m_isSuspendingPendingRequests);
- m_isSuspendingPendingRequests = false;
- if (!m_hosts.isEmpty() || m_nonHTTPProtocolHost->hasRequests())
- scheduleServePendingRequests();
-}
-
-void Loader::nonCacheRequestInFlight(const KURL& url)
-{
- if (!url.protocolInHTTPFamily())
- return;
- AtomicString hostName = url.host();
- m_hosts.checkConsistency();
- RefPtr<Host> host = m_hosts.get(hostName.impl());
- if (!host) {
- host = Host::create(hostName, maxRequestsInFlightPerHost);
- m_hosts.add(hostName.impl(), host);
- }
-
- host->nonCacheRequestInFlight();
-}
-
-void Loader::nonCacheRequestComplete(const KURL& url)
-{
- if (!url.protocolInHTTPFamily())
- return;
-
- AtomicString hostName = url.host();
- m_hosts.checkConsistency();
- RefPtr<Host> host = m_hosts.get(hostName.impl());
- ASSERT(host);
- if (!host)
- return;
+#if ENABLE(LINK_PREFETCH)
+ if (request->cachedResource()->type() == CachedResource::LinkPrefetch)
+ resourceRequest.setHTTPHeaderField("X-Purpose", "prefetch");
+#endif
- host->nonCacheRequestComplete();
+ RefPtr<SubresourceLoader> loader = resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->document()->frame(),
+ this, resourceRequest, determinePriority(resource), request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks());
+ if (loader && !loader->reachedTerminalState())
+ m_requestsLoading.add(loader.release(), request);
+ else {
+ // FIXME: What if resources in other frames were waiting for this revalidation?
+ LOG(ResourceLoading, "Cannot start loading '%s'", request->cachedResource()->url().latin1().data());
+ cachedResourceLoader->decrementRequestCount(request->cachedResource());
+ cachedResourceLoader->setLoadInProgress(true);
+ if (resource->resourceToRevalidate())
+ cache()->revalidationFailed(resource);
+ resource->error(CachedResource::LoadError);
+ cachedResourceLoader->setLoadInProgress(false);
+ delete request;
+ }
}
void Loader::cancelRequests(CachedResourceLoader* cachedResourceLoader)
{
cachedResourceLoader->clearPendingPreloads();
- if (m_nonHTTPProtocolHost->hasRequests())
- m_nonHTTPProtocolHost->cancelRequests(cachedResourceLoader);
-
- Vector<Host*> hostsToCancel;
- m_hosts.checkConsistency();
- HostMap::iterator i = m_hosts.begin();
- HostMap::iterator end = m_hosts.end();
- for (;i != end; ++i)
- hostsToCancel.append(i->second.get());
-
- for (unsigned n = 0; n < hostsToCancel.size(); ++n) {
- Host* host = hostsToCancel[n];
- if (host->hasRequests())
- host->cancelRequests(cachedResourceLoader);
+ Vector<SubresourceLoader*, 256> loadersToCancel;
+ RequestMap::iterator end = m_requestsLoading.end();
+ for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
+ Request* r = i->second;
+ if (r->cachedResourceLoader() == cachedResourceLoader)
+ loadersToCancel.append(i->first.get());
}
- scheduleServePendingRequests();
-
- ASSERT(cachedResourceLoader->requestCount() == (cachedResourceLoader->loadInProgress() ? 1 : 0));
-}
-
-Loader::Host::Host(const AtomicString& name, unsigned maxRequestsInFlight)
- : m_name(name)
- , m_maxRequestsInFlight(maxRequestsInFlight)
- , m_numResourcesProcessing(0)
- , m_nonCachedRequestsInFlight(0)
-{
-}
-
-Loader::Host::~Host()
-{
- ASSERT(m_requestsLoading.isEmpty());
- for (unsigned p = 0; p <= High; p++)
- ASSERT(m_requestsPending[p].isEmpty());
-}
-
-void Loader::Host::addRequest(Request* request, Priority priority)
-{
- m_requestsPending[priority].append(request);
-}
-
-void Loader::Host::nonCacheRequestInFlight()
-{
- ++m_nonCachedRequestsInFlight;
-}
-
-void Loader::Host::nonCacheRequestComplete()
-{
- --m_nonCachedRequestsInFlight;
- ASSERT(m_nonCachedRequestsInFlight >= 0);
-
- cache()->loader()->scheduleServePendingRequests();
-}
-
-bool Loader::Host::hasRequests() const
-{
- if (!m_requestsLoading.isEmpty())
- return true;
- for (unsigned p = 0; p <= High; p++) {
- if (!m_requestsPending[p].isEmpty())
- return true;
+ for (unsigned i = 0; i < loadersToCancel.size(); ++i) {
+ SubresourceLoader* loader = loadersToCancel[i];
+ didFail(loader, true);
}
- return false;
}
-void Loader::Host::servePendingRequests(Loader::Priority minimumPriority)
+void Loader::willSendRequest(SubresourceLoader* loader, ResourceRequest&, const ResourceResponse&)
{
- LOG(ResourceLoading, "Host::servePendingRequests '%s'", m_name.string().latin1().data());
- if (cache()->loader()->isSuspendingPendingRequests()) {
- LOG(ResourceLoading, "...isSuspendingPendingRequests");
+ RequestMap::iterator i = m_requestsLoading.find(loader);
+ if (i == m_requestsLoading.end())
return;
- }
-
- bool serveMore = true;
- for (int priority = High; priority >= minimumPriority && serveMore; --priority)
- servePendingRequests(m_requestsPending[priority], serveMore);
-}
-
-void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& serveLowerPriority)
-{
- while (!requestsPending.isEmpty()) {
- Request* request = requestsPending.first();
- CachedResourceLoader* cachedResourceLoader = request->cachedResourceLoader();
- bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator();
-
- // For named hosts - which are only http(s) hosts - we should always enforce the connection limit.
- // For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing
- // and we don't know all stylesheets yet.
- bool shouldLimitRequests = !m_name.isNull() || cachedResourceLoader->document()->parsing() || !cachedResourceLoader->document()->haveStylesheetsLoaded();
- if (shouldLimitRequests && m_requestsLoading.size() + m_nonCachedRequestsInFlight >= m_maxRequestsInFlight) {
- serveLowerPriority = false;
- return;
- }
- requestsPending.removeFirst();
-
- ResourceRequest resourceRequest(request->cachedResource()->url());
- resourceRequest.setTargetType(cachedResourceTypeToTargetType(request->cachedResource()->type()));
-
- if (!request->cachedResource()->accept().isEmpty())
- resourceRequest.setHTTPAccept(request->cachedResource()->accept());
-
- // Do not set the referrer or HTTP origin here. That's handled by SubresourceLoader::create.
-
- if (resourceIsCacheValidator) {
- CachedResource* resourceToRevalidate = request->cachedResource()->resourceToRevalidate();
- ASSERT(resourceToRevalidate->canUseCacheValidator());
- ASSERT(resourceToRevalidate->isLoaded());
- const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
- const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
- if (!lastModified.isEmpty() || !eTag.isEmpty()) {
- ASSERT(cachedResourceLoader->cachePolicy() != CachePolicyReload);
- if (cachedResourceLoader->cachePolicy() == CachePolicyRevalidate)
- resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
- if (!lastModified.isEmpty())
- resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
- if (!eTag.isEmpty())
- resourceRequest.setHTTPHeaderField("If-None-Match", eTag);
- }
- }
-
-#if ENABLE(LINK_PREFETCH)
- if (request->cachedResource()->type() == CachedResource::LinkPrefetch)
- resourceRequest.setHTTPHeaderField("Purpose", "prefetch");
-#endif
-
- RefPtr<SubresourceLoader> loader = SubresourceLoader::create(cachedResourceLoader->document()->frame(),
- this, resourceRequest, request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks());
- if (loader) {
- m_requestsLoading.add(loader.release(), request);
- request->cachedResource()->setRequestedFromNetworkingLayer();
- LOG(ResourceLoading, "Host '%s' loading '%s'. Current count %d", m_name.string().latin1().data(), request->cachedResource()->url().latin1().data(), m_requestsLoading.size());
- } else {
- // FIXME: What if resources in other frames were waiting for this revalidation?
- LOG(ResourceLoading, "Host '%s' cannot start loading '%s'", m_name.string().latin1().data(), request->cachedResource()->url().latin1().data());
- CachedResource* resource = request->cachedResource();
- cachedResourceLoader->decrementRequestCount(resource);
- cachedResourceLoader->setLoadInProgress(true);
- if (resource->resourceToRevalidate())
- cache()->revalidationFailed(resource);
- resource->error();
- cachedResourceLoader->setLoadInProgress(false);
- delete request;
- }
- }
+
+ Request* request = i->second;
+ request->cachedResource()->setRequestedFromNetworkingLayer();
}
-void Loader::Host::didFinishLoading(SubresourceLoader* loader)
+void Loader::didFinishLoading(SubresourceLoader* loader)
{
- RefPtr<Host> myProtector(this);
-
RequestMap::iterator i = m_requestsLoading.find(loader);
if (i == m_requestsLoading.end())
return;
@@ -412,34 +191,29 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
CachedResource* resource = request->cachedResource();
ASSERT(!resource->resourceToRevalidate());
- LOG(ResourceLoading, "Host '%s' received %s. Current count %d\n", m_name.string().latin1().data(), resource->url().latin1().data(), m_requestsLoading.size());
+ LOG(ResourceLoading, "Received '%s'.", resource->url().latin1().data());
// If we got a 4xx response, we're pretending to have received a network
// error, so we can't send the successful data() and finish() callbacks.
if (!resource->errorOccurred()) {
cachedResourceLoader->setLoadInProgress(true);
resource->data(loader->resourceData(), true);
- resource->finish();
+ if (!resource->errorOccurred())
+ resource->finish();
}
delete request;
-
- cachedResourceLoader->setLoadInProgress(false);
-
+ cachedResourceLoader->setLoadInProgress(false);
cachedResourceLoader->checkForPendingPreloads();
-
- servePendingRequests();
}
-void Loader::Host::didFail(SubresourceLoader* loader, const ResourceError&)
+void Loader::didFail(SubresourceLoader* loader, const ResourceError&)
{
didFail(loader);
}
-void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
+void Loader::didFail(SubresourceLoader* loader, bool cancelled)
{
- RefPtr<Host> myProtector(this);
-
loader->clearClient();
RequestMap::iterator i = m_requestsLoading.find(loader);
@@ -457,14 +231,14 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
CachedResource* resource = request->cachedResource();
- LOG(ResourceLoading, "Host '%s' failed to load %s (cancelled=%d). Current count %d\n", m_name.string().latin1().data(), resource->url().latin1().data(), cancelled, m_requestsLoading.size());
+ LOG(ResourceLoading, "Failed to load '%s' (cancelled=%d).\n", resource->url().latin1().data(), cancelled);
if (resource->resourceToRevalidate())
cache()->revalidationFailed(resource);
if (!cancelled) {
cachedResourceLoader->setLoadInProgress(true);
- resource->error();
+ resource->error(CachedResource::LoadError);
}
cachedResourceLoader->setLoadInProgress(false);
@@ -474,14 +248,10 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
delete request;
cachedResourceLoader->checkForPendingPreloads();
-
- servePendingRequests();
}
-void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
+void Loader::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
{
- RefPtr<Host> protector(this);
-
Request* request = m_requestsLoading.get(loader);
// FIXME: This is a workaround for <rdar://problem/5236843>
@@ -510,7 +280,6 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
delete request;
- servePendingRequests();
return;
}
// Did not get 304 response, continue as a regular resource load.
@@ -541,10 +310,8 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
}
}
-void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, int size)
+void Loader::didReceiveData(SubresourceLoader* loader, const char* data, int size)
{
- RefPtr<Host> protector(this);
-
Request* request = m_requestsLoading.get(loader);
if (!request)
return;
@@ -554,7 +321,7 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
if (resource->errorOccurred())
return;
-
+
if (resource->response().httpStatusCode() >= 400) {
resource->httpStatusCodeError();
return;
@@ -570,10 +337,8 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
resource->data(loader->resourceData(), false);
}
-void Loader::Host::didReceiveCachedMetadata(SubresourceLoader* loader, const char* data, int size)
+void Loader::didReceiveCachedMetadata(SubresourceLoader* loader, const char* data, int size)
{
- RefPtr<Host> protector(this);
-
Request* request = m_requestsLoading.get(loader);
if (!request)
return;
@@ -583,41 +348,5 @@ void Loader::Host::didReceiveCachedMetadata(SubresourceLoader* loader, const cha
resource->setSerializedCachedMetadata(data, size);
}
-
-void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, CachedResourceLoader* cachedResourceLoader)
-{
- RequestQueue remaining;
- RequestQueue::iterator end = requestsPending.end();
- for (RequestQueue::iterator it = requestsPending.begin(); it != end; ++it) {
- Request* request = *it;
- if (request->cachedResourceLoader() == cachedResourceLoader) {
- cache()->remove(request->cachedResource());
- cachedResourceLoader->decrementRequestCount(request->cachedResource());
- delete request;
- } else
- remaining.append(request);
- }
- requestsPending.swap(remaining);
-}
-
-void Loader::Host::cancelRequests(CachedResourceLoader* cachedResourceLoader)
-{
- for (unsigned p = 0; p <= High; p++)
- cancelPendingRequests(m_requestsPending[p], cachedResourceLoader);
-
- Vector<SubresourceLoader*, 256> loadersToCancel;
-
- RequestMap::iterator end = m_requestsLoading.end();
- for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
- Request* r = i->second;
- if (r->cachedResourceLoader() == cachedResourceLoader)
- loadersToCancel.append(i->first.get());
- }
-
- for (unsigned i = 0; i < loadersToCancel.size(); ++i) {
- SubresourceLoader* loader = loadersToCancel[i];
- didFail(loader, true);
- }
-}
} //namespace WebCore
diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h
index 4d353e0..818f56f 100644
--- a/WebCore/loader/loader.h
+++ b/WebCore/loader/loader.h
@@ -23,94 +23,36 @@
#define loader_h
#include "FrameLoaderTypes.h"
-#include "PlatformString.h"
+#include "SubresourceLoader.h"
#include "SubresourceLoaderClient.h"
-#include "Timer.h"
-#include <wtf/Deque.h>
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
-#include <wtf/text/AtomicString.h>
-#include <wtf/text/AtomicStringImpl.h>
+#include <wtf/RefPtr.h>
namespace WebCore {
class CachedResource;
class CachedResourceLoader;
- class KURL;
class Request;
- class Loader : public Noncopyable {
+ class Loader : public Noncopyable, private SubresourceLoaderClient {
public:
- Loader();
~Loader();
void load(CachedResourceLoader*, CachedResource*, bool incremental = true, SecurityCheckPolicy = DoSecurityCheck, bool sendResourceLoadCallbacks = true);
-
void cancelRequests(CachedResourceLoader*);
-
- enum Priority { VeryLow, Low, Medium, High };
- void servePendingRequests(Priority minimumPriority = VeryLow);
-
- bool isSuspendingPendingRequests() { return m_isSuspendingPendingRequests; }
- void suspendPendingRequests();
- void resumePendingRequests();
-
- void nonCacheRequestInFlight(const KURL&);
- void nonCacheRequestComplete(const KURL&);
private:
- Priority determinePriority(const CachedResource*) const;
- void scheduleServePendingRequests();
-
- void requestTimerFired(Timer<Loader>*);
-
- class Host : public RefCounted<Host>, private SubresourceLoaderClient {
- public:
- static PassRefPtr<Host> create(const AtomicString& name, unsigned maxRequestsInFlight)
- {
- return adoptRef(new Host(name, maxRequestsInFlight));
- }
- ~Host();
-
- const AtomicString& name() const { return m_name; }
- void addRequest(Request*, Priority);
- void nonCacheRequestInFlight();
- void nonCacheRequestComplete();
- void servePendingRequests(Priority minimumPriority = VeryLow);
- void cancelRequests(CachedResourceLoader*);
- bool hasRequests() const;
-
- bool processingResource() const { return m_numResourcesProcessing != 0 || m_nonCachedRequestsInFlight !=0; }
-
- private:
- Host(const AtomicString&, unsigned);
-
- virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
- virtual void didReceiveData(SubresourceLoader*, const char*, int);
- virtual void didReceiveCachedMetadata(SubresourceLoader*, const char*, int);
- virtual void didFinishLoading(SubresourceLoader*);
- virtual void didFail(SubresourceLoader*, const ResourceError&);
-
- typedef Deque<Request*> RequestQueue;
- void servePendingRequests(RequestQueue& requestsPending, bool& serveLowerPriority);
- void didFail(SubresourceLoader*, bool cancelled = false);
- void cancelPendingRequests(RequestQueue& requestsPending, CachedResourceLoader*);
-
- RequestQueue m_requestsPending[High + 1];
- typedef HashMap<RefPtr<SubresourceLoader>, Request*> RequestMap;
- RequestMap m_requestsLoading;
- const AtomicString m_name;
- const int m_maxRequestsInFlight;
- int m_numResourcesProcessing;
- int m_nonCachedRequestsInFlight;
- };
- typedef HashMap<AtomicStringImpl*, RefPtr<Host> > HostMap;
- HostMap m_hosts;
- RefPtr<Host> m_nonHTTPProtocolHost;
+ virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse&);
+ virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
+ virtual void didReceiveData(SubresourceLoader*, const char*, int);
+ virtual void didReceiveCachedMetadata(SubresourceLoader*, const char*, int);
+ virtual void didFinishLoading(SubresourceLoader*);
+ virtual void didFail(SubresourceLoader*, const ResourceError&);
+ void didFail(SubresourceLoader*, bool cancelled = false);
- Timer<Loader> m_requestTimer;
-
- bool m_isSuspendingPendingRequests;
+ typedef HashMap<RefPtr<SubresourceLoader>, Request*> RequestMap;
+ RequestMap m_requestsLoading;
};
}