blob: a11e0c31d6a9fa6fed063f31aca70a5d0657dd5c [file] [log] [blame]
/*
* Copyright (C) 2009 Google 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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 "ResourceHandle.h"
#include "PlatformBridge.h"
#include "ResourceHandleClient.h"
#include "ResourceRequest.h"
#include "SharedBuffer.h"
#include "WebKit.h"
#include "WebKitClient.h"
#include "WebURLError.h"
#include "WebURLLoader.h"
#include "WebURLLoaderClient.h"
#include "WebURLRequest.h"
#include "WebURLResponse.h"
#include "WrappedResourceRequest.h"
#include "WrappedResourceResponse.h"
using namespace WebKit;
namespace WebCore {
// ResourceHandleInternal -----------------------------------------------------
class ResourceHandleInternal : public WebURLLoaderClient {
public:
ResourceHandleInternal(const ResourceRequest& request, ResourceHandleClient* client)
: m_request(request)
, m_owner(0)
, m_client(client)
, m_state(ConnectionStateNew)
{
}
void start();
void cancel();
void setDefersLoading(bool);
bool allowStoredCredentials() const;
// WebURLLoaderClient methods:
virtual void willSendRequest(WebURLLoader*, WebURLRequest&, const WebURLResponse&);
virtual void didSendData(
WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(WebURLLoader*, const WebURLResponse&);
virtual void didReceiveData(WebURLLoader*, const char* data, int dataLength, int encodedDataLength);
virtual void didReceiveCachedMetadata(WebURLLoader*, const char* data, int dataLength);
virtual void didFinishLoading(WebURLLoader*, double finishTime);
virtual void didFail(WebURLLoader*, const WebURLError&);
enum ConnectionState {
ConnectionStateNew,
ConnectionStateStarted,
ConnectionStateReceivedResponse,
ConnectionStateReceivingData,
ConnectionStateFinishedLoading,
ConnectionStateCanceled,
ConnectionStateFailed,
};
ResourceRequest m_request;
ResourceHandle* m_owner;
ResourceHandleClient* m_client;
OwnPtr<WebURLLoader> m_loader;
// Used for sanity checking to make sure we don't experience illegal state
// transitions.
ConnectionState m_state;
};
void ResourceHandleInternal::start()
{
if (m_state != ConnectionStateNew)
CRASH();
m_state = ConnectionStateStarted;
m_loader.set(webKitClient()->createURLLoader());
ASSERT(m_loader.get());
WrappedResourceRequest wrappedRequest(m_request);
wrappedRequest.setAllowStoredCredentials(allowStoredCredentials());
m_loader->loadAsynchronously(wrappedRequest, this);
}
void ResourceHandleInternal::cancel()
{
m_state = ConnectionStateCanceled;
m_loader->cancel();
// Do not make any further calls to the client.
m_client = 0;
}
void ResourceHandleInternal::setDefersLoading(bool value)
{
m_loader->setDefersLoading(value);
}
bool ResourceHandleInternal::allowStoredCredentials() const
{
return m_client && m_client->shouldUseCredentialStorage(m_owner);
}
void ResourceHandleInternal::willSendRequest(
WebURLLoader*, WebURLRequest& request, const WebURLResponse& response)
{
ASSERT(m_client);
ASSERT(!request.isNull());
ASSERT(!response.isNull());
m_client->willSendRequest(m_owner, request.toMutableResourceRequest(), response.toResourceResponse());
}
void ResourceHandleInternal::didSendData(
WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
ASSERT(m_client);
m_client->didSendData(m_owner, bytesSent, totalBytesToBeSent);
}
void ResourceHandleInternal::didReceiveResponse(WebURLLoader*, const WebURLResponse& response)
{
ASSERT(m_client);
ASSERT(!response.isNull());
bool isMultipart = response.isMultipartPayload();
bool isValidStateTransition = (m_state == ConnectionStateStarted || m_state == ConnectionStateReceivedResponse);
// In the case of multipart loads, calls to didReceiveData & didReceiveResponse can be interleaved.
if (!isMultipart && !isValidStateTransition)
CRASH();
m_state = ConnectionStateReceivedResponse;
m_client->didReceiveResponse(m_owner, response.toResourceResponse());
}
void ResourceHandleInternal::didReceiveData(WebURLLoader*, const char* data, int dataLength, int encodedDataLength)
{
ASSERT(m_client);
if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
CRASH();
m_state = ConnectionStateReceivingData;
m_client->didReceiveData(m_owner, data, dataLength, encodedDataLength);
}
void ResourceHandleInternal::didReceiveCachedMetadata(WebURLLoader*, const char* data, int dataLength)
{
ASSERT(m_client);
if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
CRASH();
m_client->didReceiveCachedMetadata(m_owner, data, dataLength);
}
void ResourceHandleInternal::didFinishLoading(WebURLLoader*, double finishTime)
{
ASSERT(m_client);
if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
CRASH();
m_state = ConnectionStateFinishedLoading;
m_client->didFinishLoading(m_owner, finishTime);
}
void ResourceHandleInternal::didFail(WebURLLoader*, const WebURLError& error)
{
ASSERT(m_client);
m_state = ConnectionStateFailed;
m_client->didFail(m_owner, error);
}
// ResourceHandle -------------------------------------------------------------
ResourceHandle::ResourceHandle(const ResourceRequest& request,
ResourceHandleClient* client,
bool defersLoading,
bool shouldContentSniff)
: d(new ResourceHandleInternal(request, client))
{
d->m_owner = this;
// FIXME: Figure out what to do with the bool params.
}
PassRefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context,
const ResourceRequest& request,
ResourceHandleClient* client,
bool defersLoading,
bool shouldContentSniff)
{
RefPtr<ResourceHandle> newHandle = adoptRef(new ResourceHandle(
request, client, defersLoading, shouldContentSniff));
if (newHandle->start(context))
return newHandle.release();
return 0;
}
ResourceRequest& ResourceHandle::firstRequest()
{
return d->m_request;
}
ResourceHandleClient* ResourceHandle::client() const
{
return d->m_client;
}
void ResourceHandle::setClient(ResourceHandleClient* client)
{
d->m_client = client;
}
void ResourceHandle::setDefersLoading(bool value)
{
d->setDefersLoading(value);
}
bool ResourceHandle::start(NetworkingContext* context)
{
d->start();
return true;
}
bool ResourceHandle::hasAuthenticationChallenge() const
{
return false;
}
void ResourceHandle::clearAuthentication()
{
}
void ResourceHandle::cancel()
{
d->cancel();
}
ResourceHandle::~ResourceHandle()
{
d->m_owner = 0;
}
PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
{
return 0;
}
bool ResourceHandle::loadsBlocked()
{
return false; // This seems to be related to sync XMLHttpRequest...
}
// static
bool ResourceHandle::supportsBufferedData()
{
return false; // The loader will buffer manually if it needs to.
}
// static
void ResourceHandle::loadResourceSynchronously(NetworkingContext* context,
const ResourceRequest& request,
StoredCredentials storedCredentials,
ResourceError& error,
ResourceResponse& response,
Vector<char>& data)
{
OwnPtr<WebURLLoader> loader(webKitClient()->createURLLoader());
ASSERT(loader.get());
WrappedResourceRequest requestIn(request);
requestIn.setAllowStoredCredentials(storedCredentials == AllowStoredCredentials);
WrappedResourceResponse responseOut(response);
WebURLError errorOut;
WebData dataOut;
loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut);
error = errorOut;
data.clear();
data.append(dataOut.data(), dataOut.size());
}
// static
bool ResourceHandle::willLoadFromCache(ResourceRequest& request, Frame*)
{
// This method is used to determine if a POST request can be repeated from
// cache, but you cannot really know until you actually try to read from the
// cache. Even if we checked now, something else could come along and wipe
// out the cache entry by the time we fetch it.
//
// So, we always say yes here, to prevent the FrameLoader from initiating a
// reload. Then in FrameLoaderClientImpl::dispatchWillSendRequest, we
// fix-up the cache policy of the request to force a load from the cache.
//
ASSERT(request.httpMethod() == "POST");
return true;
}
// static
void ResourceHandle::cacheMetadata(const ResourceResponse& response, const Vector<char>& data)
{
PlatformBridge::cacheMetadata(response.url(), response.responseTime(), data);
}
} // namespace WebCore