blob: aba9a5560dbdd17f16c2878514253cd68278344c [file] [log] [blame]
/*
* Copyright (C) 2012 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "NetworkRequest.h"
#if ENABLE(NETWORK_PROCESS)
#include "BlockingResponseMap.h"
#include "Logging.h"
#include "NetworkConnectionToWebProcess.h"
#include "NetworkProcess.h"
#include "NetworkProcessConnectionMessages.h"
#include "RemoteNetworkingContext.h"
#include "SharedMemory.h"
#include "WebCoreArgumentCoders.h"
#include <WebCore/NotImplemented.h>
#include <WebCore/ResourceBuffer.h>
#include <WebCore/ResourceHandle.h>
#include <wtf/MainThread.h>
using namespace WebCore;
namespace WebKit {
NetworkRequest::NetworkRequest(const WebCore::ResourceRequest& request, ResourceLoadIdentifier identifier, ContentSniffingPolicy contentSniffingPolicy, NetworkConnectionToWebProcess* connection)
: m_request(request)
, m_identifier(identifier)
, m_contentSniffingPolicy(contentSniffingPolicy)
, m_connection(connection)
{
ASSERT(isMainThread());
connection->registerObserver(this);
}
NetworkRequest::~NetworkRequest()
{
ASSERT(isMainThread());
if (m_connection)
m_connection->unregisterObserver(this);
}
void NetworkRequest::start()
{
ASSERT(isMainThread());
// Explicit ref() balanced by a deref() in NetworkRequest::stop()
ref();
// FIXME (NetworkProcess): Create RemoteNetworkingContext with actual settings.
m_networkingContext = RemoteNetworkingContext::create(false, false);
// FIXME (NetworkProcess): Pass an actual value for defersLoading
m_handle = ResourceHandle::create(m_networkingContext.get(), m_request, this, false /* defersLoading */, m_contentSniffingPolicy == SniffContent);
}
static bool stopRequestsCalled = false;
static Mutex& requestsToStopMutex()
{
DEFINE_STATIC_LOCAL(Mutex, mutex, ());
return mutex;
}
static HashSet<NetworkRequest*>& requestsToStop()
{
DEFINE_STATIC_LOCAL(HashSet<NetworkRequest*>, requests, ());
return requests;
}
void NetworkRequest::scheduleStopOnMainThread()
{
MutexLocker locker(requestsToStopMutex());
requestsToStop().add(this);
if (!stopRequestsCalled) {
stopRequestsCalled = true;
callOnMainThread(NetworkRequest::performStops, 0);
}
}
void NetworkRequest::performStops(void*)
{
ASSERT(stopRequestsCalled);
Vector<NetworkRequest*> requests;
{
MutexLocker locker(requestsToStopMutex());
copyToVector(requestsToStop(), requests);
requestsToStop().clear();
stopRequestsCalled = false;
}
for (size_t i = 0; i < requests.size(); ++i)
requests[i]->stop();
}
void NetworkRequest::stop()
{
ASSERT(isMainThread());
// Remove this load identifier soon so we can start more network requests.
NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoadIdentifier(m_identifier);
// Explicit deref() balanced by a ref() in NetworkRequest::stop()
// This might cause the NetworkRequest to be destroyed and therefore we do it last.
deref();
}
void NetworkRequest::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
{
ASSERT_ARG(connection, connection == m_connection.get());
m_connection->unregisterObserver(this);
m_connection = 0;
}
void NetworkRequest::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
{
// FIXME (NetworkProcess): Cache the response.
connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidReceiveResponse(m_identifier, response), 0);
}
void NetworkRequest::didReceiveData(ResourceHandle*, const char* data, int length, int /*encodedDataLength*/)
{
// FIXME (NetworkProcess): We have to progressively notify the WebProcess as data is received.
if (!m_buffer)
m_buffer = ResourceBuffer::create();
m_buffer->append(data, length);
}
void NetworkRequest::didFinishLoading(ResourceHandle*, double finishTime)
{
// FIXME (NetworkProcess): Currently this callback can come in on a non-main thread.
// This is okay for now since resource buffers are per-NetworkRequest.
// Once we manage memory in an actual memory cache that also includes SharedMemory blocks this will get complicated.
// Maybe we should marshall it to the main thread?
ShareableResource::Handle handle;
if (m_buffer && m_buffer->size()) {
// FIXME (NetworkProcess): We shouldn't be creating this SharedMemory on demand here.
// SharedMemory blocks need to be managed as part of the cache backing store.
RefPtr<SharedMemory> sharedBuffer = SharedMemory::create(m_buffer->size());
memcpy(sharedBuffer->data(), m_buffer->data(), m_buffer->size());
RefPtr<ShareableResource> shareableResource = ShareableResource::create(sharedBuffer.release(), 0, m_buffer->size());
// FIXME (NetworkProcess): Handle errors from createHandle();
if (!shareableResource->createHandle(handle))
LOG_ERROR("Failed to create handle to shareable resource memory\n");
}
connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidReceiveResource(m_identifier, handle, finishTime), 0);
scheduleStopOnMainThread();
}
void NetworkRequest::didFail(ResourceHandle*, const ResourceError& error)
{
connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidFailResourceLoad(m_identifier, error), 0);
scheduleStopOnMainThread();
}
// FIXME (NetworkProcess): Many of the following ResourceHandleClient methods definitely need implementations. A few will not.
// Once we know what they are they can be removed.
static BlockingResponseMap<ResourceRequest*>& responseMap()
{
AtomicallyInitializedStatic(BlockingResponseMap<ResourceRequest*>&, responseMap = *new BlockingResponseMap<ResourceRequest*>);
return responseMap;
}
static uint64_t generateWillSendRequestID()
{
static int64_t uniqueWillSendRequestID;
return OSAtomicIncrement64Barrier(&uniqueWillSendRequestID);
}
void didReceiveWillSendRequestHandled(uint64_t requestID, const ResourceRequest& request)
{
responseMap().didReceiveResponse(requestID, adoptPtr(new ResourceRequest(request)));
}
void NetworkRequest::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
// We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect
ASSERT(!redirectResponse.isNull());
uint64_t requestID = generateWillSendRequestID();
if (!connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::WillSendRequest(requestID, m_identifier, request, redirectResponse), 0)) {
// FIXME (NetworkProcess): What should we do if we can't send the message?
return;
}
OwnPtr<ResourceRequest> newRequest = responseMap().waitForResponse(requestID);
request = *newRequest;
NetworkProcess::shared().networkResourceLoadScheduler().receivedRedirect(m_identifier, request.url());
}
void NetworkRequest::didSendData(WebCore::ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/)
{
notImplemented();
}
void NetworkRequest::didReceiveCachedMetadata(WebCore::ResourceHandle*, const char*, int)
{
notImplemented();
}
void NetworkRequest::wasBlocked(WebCore::ResourceHandle*)
{
notImplemented();
}
void NetworkRequest::cannotShowURL(WebCore::ResourceHandle*)
{
notImplemented();
}
void NetworkRequest::willCacheResponse(WebCore::ResourceHandle*, WebCore::CacheStoragePolicy&)
{
notImplemented();
}
bool NetworkRequest::shouldUseCredentialStorage(WebCore::ResourceHandle*)
{
notImplemented();
return false;
}
void NetworkRequest::didReceiveAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
{
notImplemented();
}
void NetworkRequest::didCancelAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
{
notImplemented();
}
void NetworkRequest::receivedCancellation(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
{
notImplemented();
}
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
bool NetworkRequest::canAuthenticateAgainstProtectionSpace(WebCore::ResourceHandle*, const WebCore::ProtectionSpace&)
{
notImplemented();
return false;
}
#endif
#if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
bool NetworkRequest::supportsDataArray()
{
notImplemented();
return false;
}
void NetworkRequest::didReceiveDataArray(WebCore::ResourceHandle*, CFArrayRef)
{
notImplemented();
}
#endif
#if PLATFORM(MAC)
#if USE(CFNETWORK)
CFCachedURLResponseRef NetworkRequest::willCacheResponse(WebCore::ResourceHandle*, CFCachedURLResponseRef response)
{
notImplemented();
return response;
}
#else
NSCachedURLResponse* NetworkRequest::willCacheResponse(WebCore::ResourceHandle*, NSCachedURLResponse* response)
{
notImplemented();
return response;
}
#endif
void NetworkRequest::willStopBufferingData(WebCore::ResourceHandle*, const char*, int)
{
notImplemented();
}
#endif // PLATFORM(MAC)
#if ENABLE(BLOB)
WebCore::AsyncFileStream* NetworkRequest::createAsyncFileStream(WebCore::FileStreamClient*)
{
notImplemented();
return 0;
}
#endif
} // namespace WebKit
#endif // ENABLE(NETWORK_PROCESS)