diff options
author | Russell Brenner <russellbrenner@google.com> | 2010-11-18 17:33:13 -0800 |
---|---|---|
committer | Russell Brenner <russellbrenner@google.com> | 2010-12-02 13:47:21 -0800 |
commit | 6b70adc33054f8aee8c54d0f460458a9df11b8a5 (patch) | |
tree | 103a13998c33944d6ab3b8318c509a037e639460 /WebCore/loader | |
parent | bdf4ebc8e70b2d221b6ee7a65660918ecb1d33aa (diff) | |
download | external_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')
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; }; } |