summaryrefslogtreecommitdiffstats
path: root/WebCore/loader/loader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader/loader.cpp')
-rw-r--r--WebCore/loader/loader.cpp495
1 files changed, 0 insertions, 495 deletions
diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp
deleted file mode 100644
index 6221a6a..0000000
--- a/WebCore/loader/loader.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- 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.
-
- 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 "loader.h"
-
-#include "Cache.h"
-#include "CachedImage.h"
-#include "CachedResource.h"
-#include "CString.h"
-#include "DocLoader.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "HTMLDocument.h"
-#include "Request.h"
-#include "ResourceHandle.h"
-#include "ResourceRequest.h"
-#include "ResourceResponse.h"
-#include "SecurityOrigin.h"
-#include "SubresourceLoader.h"
-#include <wtf/Assertions.h>
-#include <wtf/Vector.h>
-
-#define REQUEST_MANAGEMENT_ENABLED 0
-#define REQUEST_DEBUG 0
-
-namespace WebCore {
-
-#if REQUEST_MANAGEMENT_ENABLED
-// Match the parallel connection count used by the networking layer
-// FIXME should not hardcode something like this
-static const unsigned maxRequestsInFlightPerHost = 4;
-// 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_nonHTTPProtocolHost(AtomicString(), maxRequestsInFlightForNonHTTPProtocols)
- , m_requestTimer(this, &Loader::requestTimerFired)
-{
-}
-
-Loader::~Loader()
-{
- ASSERT_NOT_REACHED();
-}
-
-Loader::Priority Loader::determinePriority(const CachedResource* resource) const
-{
-#if REQUEST_MANAGEMENT_ENABLED
- switch (resource->type()) {
- case CachedResource::CSSStyleSheet:
-#if ENABLE(XSLT)
- case CachedResource::XSLStyleSheet:
-#endif
-#if ENABLE(XBL)
- case CachedResource::XBL:
-#endif
- return High;
- case CachedResource::Script:
- case CachedResource::FontResource:
- return Medium;
- case CachedResource::ImageResource:
- return Low;
- }
- ASSERT_NOT_REACHED();
- return Low;
-#else
- return High;
-#endif
-}
-
-void Loader::load(DocLoader* docLoader, CachedResource* resource, bool incremental, bool skipCanLoadCheck, bool sendResourceLoadCallbacks)
-{
- ASSERT(docLoader);
- Request* request = new Request(docLoader, resource, incremental, skipCanLoadCheck, sendResourceLoadCallbacks);
-
- Host* host;
- KURL url(resource->url());
- bool isHTTP = url.protocolIs("http") || url.protocolIs("https");
- if (isHTTP) {
- AtomicString hostName = url.host();
- host = m_hosts.get(hostName.impl());
- if (!host) {
- host = new Host(hostName, maxRequestsInFlightPerHost);
- m_hosts.add(hostName.impl(), host);
- }
- } else
- host = &m_nonHTTPProtocolHost;
-
- bool hadRequests = host->hasRequests();
- Priority priority = determinePriority(resource);
- host->addRequest(request, priority);
- docLoader->incrementRequestCount();
-
- if (priority > Low || !isHTTP || !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
- scheduleServePendingRequests();
- }
-}
-
-void Loader::scheduleServePendingRequests()
-{
- if (!m_requestTimer.isActive())
- m_requestTimer.startOneShot(0);
-}
-
-void Loader::requestTimerFired(Timer<Loader>*)
-{
- servePendingRequests();
-}
-
-void Loader::servePendingRequests(Priority minimumPriority)
-{
- m_requestTimer.stop();
-
- m_nonHTTPProtocolHost.servePendingRequests(minimumPriority);
-
- Vector<Host*> hostsToServe;
- copyValuesToVector(m_hosts, hostsToServe);
- 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();
- delete host;
- m_hosts.remove(name.impl());
- }
- }
-}
-
-void Loader::cancelRequests(DocLoader* docLoader)
-{
- if (m_nonHTTPProtocolHost.hasRequests())
- m_nonHTTPProtocolHost.cancelRequests(docLoader);
-
- Vector<Host*> hostsToCancel;
- copyValuesToVector(m_hosts, hostsToCancel);
- for (unsigned n = 0; n < hostsToCancel.size(); ++n) {
- Host* host = hostsToCancel[n];
- if (host->hasRequests())
- host->cancelRequests(docLoader);
- }
-
- scheduleServePendingRequests();
-
- if (docLoader->loadInProgress())
- ASSERT(docLoader->requestCount() == 1);
- else
- ASSERT(docLoader->requestCount() == 0);
-}
-
-Loader::Host::Host(const AtomicString& name, unsigned maxRequestsInFlight)
- : m_name(name)
- , m_maxRequestsInFlight(maxRequestsInFlight)
- , m_processingResource(false)
-{
-}
-
-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);
-}
-
-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;
- }
- return false;
-}
-
-void Loader::Host::servePendingRequests(Loader::Priority minimumPriority)
-{
- 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();
- DocLoader* docLoader = request->docLoader();
- bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator();
- // If the document is fully parsed and there are no pending stylesheets there won't be any more
- // resources that we would want to push to the front of the queue. Just hand off the remaining resources
- // to the networking layer.
- bool parsedAndStylesheetsKnown = !docLoader->doc()->parsing() && docLoader->doc()->haveStylesheetsLoaded();
- if (!parsedAndStylesheetsKnown && !resourceIsCacheValidator && m_requestsLoading.size() >= m_maxRequestsInFlight) {
- serveLowerPriority = false;
- return;
- }
- requestsPending.removeFirst();
-
- ResourceRequest resourceRequest(request->cachedResource()->url());
-#ifdef ANDROID
- resourceRequest.setCachedResource(request->cachedResource());
-#endif
-
- if (!request->cachedResource()->accept().isEmpty())
- resourceRequest.setHTTPAccept(request->cachedResource()->accept());
-
- KURL referrer = docLoader->doc()->url();
- if ((referrer.protocolIs("http") || referrer.protocolIs("https")) && referrer.path().isEmpty())
- referrer.setPath("/");
- resourceRequest.setHTTPReferrer(referrer.string());
- FrameLoader::addHTTPOriginIfNeeded(resourceRequest, docLoader->doc()->securityOrigin()->toString());
-
- 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()) {
- if (docLoader->cachePolicy() == CachePolicyReload || docLoader->cachePolicy() == CachePolicyRefresh)
- 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);
- }
- }
-
- RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(),
- this, resourceRequest, request->shouldSkipCanLoadCheck(), request->sendResourceLoadCallbacks());
- if (loader) {
- m_requestsLoading.add(loader.release(), request);
- request->cachedResource()->setRequestedFromNetworkingLayer();
-#if REQUEST_DEBUG
- printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), request->cachedResource()->url().latin1().data());
-#endif
- } else {
- docLoader->decrementRequestCount();
- docLoader->setLoadInProgress(true);
- request->cachedResource()->error();
- docLoader->setLoadInProgress(false);
- delete request;
- }
- }
-}
-
-void Loader::Host::didFinishLoading(SubresourceLoader* loader)
-{
- RequestMap::iterator i = m_requestsLoading.find(loader);
- if (i == m_requestsLoading.end())
- return;
-
- m_processingResource = true;
-
- Request* request = i->second;
- m_requestsLoading.remove(i);
- DocLoader* docLoader = request->docLoader();
- if (!request->isMultipart())
- docLoader->decrementRequestCount();
-
- CachedResource* resource = request->cachedResource();
- ASSERT(!resource->resourceToRevalidate());
-
- // 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()) {
- docLoader->setLoadInProgress(true);
- resource->data(loader->resourceData(), true);
- resource->finish();
- }
-
- delete request;
-
- docLoader->setLoadInProgress(false);
-
- docLoader->checkForPendingPreloads();
-
-#if REQUEST_DEBUG
- KURL u(resource->url());
- printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data());
-#endif
- servePendingRequests();
-
- m_processingResource = false;
-}
-
-void Loader::Host::didFail(SubresourceLoader* loader, const ResourceError&)
-{
- didFail(loader);
-}
-
-void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
-{
- loader->clearClient();
-
- RequestMap::iterator i = m_requestsLoading.find(loader);
- if (i == m_requestsLoading.end())
- return;
-
- m_processingResource = true;
-
- Request* request = i->second;
- m_requestsLoading.remove(i);
- DocLoader* docLoader = request->docLoader();
- if (!request->isMultipart())
- docLoader->decrementRequestCount();
-
- CachedResource* resource = request->cachedResource();
-
- if (resource->resourceToRevalidate())
- cache()->revalidationFailed(resource);
-
- if (!cancelled) {
- docLoader->setLoadInProgress(true);
- resource->error();
- }
-
- docLoader->setLoadInProgress(false);
- if (cancelled || !resource->isPreloaded())
- cache()->remove(resource);
-
- delete request;
-
- docLoader->checkForPendingPreloads();
-
- servePendingRequests();
-
- m_processingResource = false;
-}
-
-void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
-{
- Request* request = m_requestsLoading.get(loader);
-
- // FIXME: This is a workaround for <rdar://problem/5236843>
- // If a load starts while the frame is still in the provisional state
- // (this can be the case when loading the user style sheet), committing the load then causes all
- // requests to be removed from the m_requestsLoading map. This means that request might be null here.
- // In that case we just return early.
- // ASSERT(request);
- if (!request)
- return;
-
- CachedResource* resource = request->cachedResource();
-
- if (resource->isCacheValidator()) {
- if (response.httpStatusCode() == 304) {
- // 304 Not modified / Use local copy
- m_requestsLoading.remove(loader);
- request->docLoader()->decrementRequestCount();
-
- // Existing resource is ok, just use it updating the expiration time.
- cache()->revalidationSucceeded(resource, response);
-
- if (request->docLoader()->frame())
- request->docLoader()->frame()->loader()->checkCompleted();
-
- delete request;
-
- servePendingRequests();
- return;
- }
- // Did not get 304 response, continue as a regular resource load.
- cache()->revalidationFailed(resource);
- }
-
- resource->setResponse(response);
-
- String encoding = response.textEncodingName();
- if (!encoding.isNull())
- request->cachedResource()->setEncoding(encoding);
-
- if (request->isMultipart()) {
- ASSERT(request->cachedResource()->isImage());
- static_cast<CachedImage*>(request->cachedResource())->clear();
- if (request->docLoader()->frame())
- request->docLoader()->frame()->loader()->checkCompleted();
- } else if (response.isMultipart()) {
- request->setIsMultipart(true);
-
- // We don't count multiParts in a DocLoader's request count
- request->docLoader()->decrementRequestCount();
-
- // If we get a multipart response, we must have a handle
- ASSERT(loader->handle());
- if (!request->cachedResource()->isImage())
- loader->handle()->cancel();
- }
-}
-
-void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, int size)
-{
- Request* request = m_requestsLoading.get(loader);
- if (!request)
- return;
-
- CachedResource* resource = request->cachedResource();
- ASSERT(!resource->isCacheValidator());
-
- if (resource->errorOccurred())
- return;
-
- m_processingResource = true;
-
- if (resource->response().httpStatusCode() / 100 == 4) {
- // Treat a 4xx response like a network error.
- resource->error();
- m_processingResource = false;
- return;
- }
-
- // Set the data.
- if (request->isMultipart()) {
- // The loader delivers the data in a multipart section all at once, send eof.
- // The resource data will change as the next part is loaded, so we need to make a copy.
- RefPtr<SharedBuffer> copiedData = SharedBuffer::create(data, size);
- resource->data(copiedData.release(), true);
- } else if (request->isIncremental())
- resource->data(loader->resourceData(), false);
-
- m_processingResource = false;
-}
-
-void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoader* docLoader)
-{
- RequestQueue remaining;
- RequestQueue::iterator end = requestsPending.end();
- for (RequestQueue::iterator it = requestsPending.begin(); it != end; ++it) {
- Request* request = *it;
- if (request->docLoader() == docLoader) {
- cache()->remove(request->cachedResource());
- delete request;
- docLoader->decrementRequestCount();
- } else
- remaining.append(request);
- }
- requestsPending.swap(remaining);
-}
-
-void Loader::Host::cancelRequests(DocLoader* docLoader)
-{
- for (unsigned p = 0; p <= High; p++)
- cancelPendingRequests(m_requestsPending[p], docLoader);
-
- 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->docLoader() == docLoader)
- loadersToCancel.append(i->first.get());
- }
-
- for (unsigned i = 0; i < loadersToCancel.size(); ++i) {
- SubresourceLoader* loader = loadersToCancel[i];
- didFail(loader, true);
- }
-}
-
-} //namespace WebCore