| Index: Source/WebCore/loader/SubresourceLoader.cpp
|
| diff --git a/Source/WebCore/loader/SubresourceLoader.cpp b/Source/WebCore/loader/SubresourceLoader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..68855a45cf0794e7446f443784669639063c4b85
|
| --- /dev/null
|
| +++ b/Source/WebCore/loader/SubresourceLoader.cpp
|
| @@ -0,0 +1,235 @@
|
| +/*
|
| + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions
|
| + * are met:
|
| + *
|
| + * 1. Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * 2. Redistributions in binary form must reproduce the above copyright
|
| + * notice, this list of conditions and the following disclaimer in the
|
| + * documentation and/or other materials provided with the distribution.
|
| + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
| + * its contributors may be used to endorse or promote products derived
|
| + * from this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
| + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
| + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
| + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
| + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
| + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
| + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
| + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + */
|
| +
|
| +#include "config.h"
|
| +#include "SubresourceLoader.h"
|
| +
|
| +#include "CachedResourceLoader.h"
|
| +#include "Document.h"
|
| +#include "DocumentLoader.h"
|
| +#include "Frame.h"
|
| +#include "FrameLoader.h"
|
| +#include "Logging.h"
|
| +#include "MemoryCache.h"
|
| +#include "ResourceBuffer.h"
|
| +#include "WebCoreMemoryInstrumentation.h"
|
| +#include <wtf/RefCountedLeakCounter.h>
|
| +#include <wtf/StdLibExtras.h>
|
| +#include <wtf/text/CString.h>
|
| +
|
| +namespace WebCore {
|
| +
|
| +DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, subresourceLoaderCounter, ("SubresourceLoader"));
|
| +
|
| +SubresourceLoader::SubresourceLoader(Frame* frame, CachedResource* resource, const ResourceLoaderOptions& options)
|
| + : ResourceLoader(frame, resource, options)
|
| +{
|
| +#ifndef NDEBUG
|
| + subresourceLoaderCounter.increment();
|
| +#endif
|
| +}
|
| +
|
| +SubresourceLoader::~SubresourceLoader()
|
| +{
|
| + ASSERT(m_state != Initialized);
|
| + ASSERT(reachedTerminalState());
|
| +#ifndef NDEBUG
|
| + subresourceLoaderCounter.decrement();
|
| +#endif
|
| +}
|
| +
|
| +PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, CachedResource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
|
| +{
|
| + RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, resource, options)));
|
| + if (!subloader->init(request))
|
| + return 0;
|
| + return subloader.release();
|
| +}
|
| +
|
| +bool SubresourceLoader::init(const ResourceRequest& request)
|
| +{
|
| + if (!ResourceLoader::init(request))
|
| + return false;
|
| +
|
| + ASSERT(!reachedTerminalState());
|
| + m_state = Initialized;
|
| + m_documentLoader->addSubresourceLoader(this);
|
| + return true;
|
| +}
|
| +
|
| +void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
|
| +{
|
| + // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
|
| + KURL previousURL = request().url();
|
| + RefPtr<SubresourceLoader> protect(this);
|
| +
|
| + ASSERT(!newRequest.isNull());
|
| + if (!redirectResponse.isNull()) {
|
| + if (!m_documentLoader->cachedResourceLoader()->canRequest(m_resource->type(), newRequest.url())) {
|
| + cancel();
|
| + return;
|
| + }
|
| + if (m_resource->type() == CachedResource::ImageResource && m_documentLoader->cachedResourceLoader()->shouldDeferImageLoad(newRequest.url())) {
|
| + cancel();
|
| + return;
|
| + }
|
| + m_resource->willSendRequest(newRequest, redirectResponse);
|
| + }
|
| +
|
| + if (newRequest.isNull() || reachedTerminalState())
|
| + return;
|
| +
|
| + ResourceLoader::willSendRequest(newRequest, redirectResponse);
|
| + if (newRequest.isNull())
|
| + cancel();
|
| +}
|
| +
|
| +void SubresourceLoader::didReceiveResponse(const ResourceResponse& response)
|
| +{
|
| + ASSERT(!response.isNull());
|
| + ASSERT(m_state == Initialized);
|
| +
|
| + // Reference the object in this method since the additional processing can do
|
| + // anything including removing the last reference to this object; one example of this is 3266216.
|
| + RefPtr<SubresourceLoader> protect(this);
|
| +
|
| + if (m_resource->resourceToRevalidate()) {
|
| + if (response.httpStatusCode() == 304) {
|
| + // 304 Not modified / Use local copy
|
| + // Existing resource is ok, just use it updating the expiration time.
|
| + m_resource->setResponse(response);
|
| + memoryCache()->revalidationSucceeded(m_resource, response);
|
| + if (!reachedTerminalState())
|
| + ResourceLoader::didReceiveResponse(response);
|
| + return;
|
| + }
|
| + // Did not get 304 response, continue as a regular resource load.
|
| + memoryCache()->revalidationFailed(m_resource);
|
| + }
|
| +
|
| + m_resource->responseReceived(response);
|
| + if (reachedTerminalState())
|
| + return;
|
| + ResourceLoader::didReceiveResponse(response);
|
| +
|
| + // FIXME: Main resources have a different set of rules for multipart than images do.
|
| + // Hopefully we can merge those 2 paths.
|
| + if (response.isMultipart() && m_resource->type() != CachedResource::MainResource) {
|
| + m_loadingMultipartContent = true;
|
| +
|
| + // We don't count multiParts in a CachedResourceLoader's request count
|
| + m_requestCountTracker.clear();
|
| + if (!m_resource->isImage()) {
|
| + cancel();
|
| + return;
|
| + }
|
| + }
|
| +
|
| + RefPtr<ResourceBuffer> buffer = resourceData();
|
| + if (m_loadingMultipartContent && buffer && buffer->size()) {
|
| + sendDataToResource(buffer->data(), buffer->size());
|
| + clearResourceData();
|
| + // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
|
| + // After the first multipart section is complete, signal to delegates that this load is "finished"
|
| + m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
|
| + didFinishLoadingOnePart(0);
|
| + }
|
| +
|
| + checkForHTTPStatusCodeError();
|
| +}
|
| +
|
| +bool SubresourceLoader::checkForHTTPStatusCodeError()
|
| +{
|
| + if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnoreHTTPStatusCodeErrors())
|
| + return false;
|
| +
|
| + m_state = Finishing;
|
| + m_resource->error(CachedResource::LoadError);
|
| + cancel();
|
| + return true;
|
| +}
|
| +
|
| +void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length)
|
| +{
|
| + ASSERT(m_state == Initialized);
|
| + ASSERT(!m_resource->resourceToRevalidate());
|
| + m_resource->setSerializedCachedMetadata(data, length);
|
| +}
|
| +
|
| +void SubresourceLoader::didFinishLoading(double finishTime)
|
| +{
|
| + if (m_state != Initialized)
|
| + return;
|
| + ASSERT(!reachedTerminalState());
|
| + ASSERT(!m_resource->resourceToRevalidate());
|
| + ASSERT(!m_resource->errorOccurred());
|
| + LOG(ResourceLoading, "Received '%s'.", m_resource->url().string().latin1().data());
|
| +
|
| + RefPtr<SubresourceLoader> protect(this);
|
| + CachedResourceHandle<CachedResource> protectResource(m_resource);
|
| + m_state = Finishing;
|
| + m_resource->setLoadFinishTime(finishTime);
|
| + m_resource->data(resourceData(), true);
|
| + m_resource->finish();
|
| + ResourceLoader::didFinishLoading(finishTime);
|
| +}
|
| +
|
| +void SubresourceLoader::didFail(const ResourceError& error)
|
| +{
|
| + if (m_state != Initialized)
|
| + return;
|
| + ASSERT(!reachedTerminalState());
|
| + LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().latin1().data());
|
| +
|
| + RefPtr<SubresourceLoader> protect(this);
|
| + CachedResourceHandle<CachedResource> protectResource(m_resource);
|
| + m_state = Finishing;
|
| + if (m_resource->resourceToRevalidate())
|
| + memoryCache()->revalidationFailed(m_resource);
|
| + m_resource->setResourceError(error);
|
| + m_resource->error(CachedResource::LoadError);
|
| + if (!m_resource->isPreloaded())
|
| + memoryCache()->remove(m_resource);
|
| + ResourceLoader::didFail(error);
|
| +}
|
| +
|
| +void SubresourceLoader::releaseResources()
|
| +{
|
| + ASSERT(!reachedTerminalState());
|
| + if (m_state != Uninitialized) {
|
| + m_requestCountTracker.clear();
|
| + m_documentLoader->cachedResourceLoader()->loadDone(m_resource);
|
| + if (reachedTerminalState())
|
| + return;
|
| + m_resource->stopLoading();
|
| + m_documentLoader->removeSubresourceLoader(this);
|
| + }
|
| + ResourceLoader::releaseResources();
|
| +}
|
| +
|
| +}
|
|
|