ResourceHandle.cpp [plain text]
#include "config.h"
#include "ResourceHandle.h"
#include "ResourceHandleInternal.h"
#include "Logging.h"
#include "NetworkingContext.h"
#include "NotImplemented.h"
#include "ResourceHandleClient.h"
#include "Timer.h"
#include <algorithm>
#include <wtf/MainThread.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/text/AtomicStringHash.h>
#include <wtf/text/CString.h>
namespace WebCore {
static bool shouldForceContentSniffing;
typedef HashMap<AtomicString, ResourceHandle::BuiltinConstructor> BuiltinResourceHandleConstructorMap;
static BuiltinResourceHandleConstructorMap& builtinResourceHandleConstructorMap()
{
#if PLATFORM(IOS)
ASSERT(WebThreadIsLockedOrDisabled());
#else
ASSERT(isMainThread());
#endif
static NeverDestroyed<BuiltinResourceHandleConstructorMap> map;
return map;
}
void ResourceHandle::registerBuiltinConstructor(const AtomicString& protocol, ResourceHandle::BuiltinConstructor constructor)
{
builtinResourceHandleConstructorMap().add(protocol, constructor);
}
typedef HashMap<AtomicString, ResourceHandle::BuiltinSynchronousLoader> BuiltinResourceHandleSynchronousLoaderMap;
static BuiltinResourceHandleSynchronousLoaderMap& builtinResourceHandleSynchronousLoaderMap()
{
ASSERT(isMainThread());
static NeverDestroyed<BuiltinResourceHandleSynchronousLoaderMap> map;
return map;
}
void ResourceHandle::registerBuiltinSynchronousLoader(const AtomicString& protocol, ResourceHandle::BuiltinSynchronousLoader loader)
{
builtinResourceHandleSynchronousLoaderMap().add(protocol, loader);
}
ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
: d(std::make_unique<ResourceHandleInternal>(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url())))
{
if (!request.url().isValid()) {
scheduleFailure(InvalidURLFailure);
return;
}
if (!portAllowed(request.url())) {
scheduleFailure(BlockedFailure);
return;
}
}
RefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
{
BuiltinResourceHandleConstructorMap::iterator protocolMapItem = builtinResourceHandleConstructorMap().find(request.url().protocol());
if (protocolMapItem != builtinResourceHandleConstructorMap().end())
return protocolMapItem->value(request, client);
auto newHandle = adoptRef(*new ResourceHandle(context, request, client, defersLoading, shouldContentSniff));
if (newHandle->d->m_scheduledFailureType != NoFailure)
return WTFMove(newHandle);
if (newHandle->start())
return WTFMove(newHandle);
return nullptr;
}
void ResourceHandle::scheduleFailure(FailureType type)
{
d->m_scheduledFailureType = type;
d->m_failureTimer.startOneShot(0);
}
void ResourceHandle::failureTimerFired()
{
if (!client())
return;
switch (d->m_scheduledFailureType) {
case NoFailure:
ASSERT_NOT_REACHED();
return;
case BlockedFailure:
d->m_scheduledFailureType = NoFailure;
client()->wasBlocked(this);
return;
case InvalidURLFailure:
d->m_scheduledFailureType = NoFailure;
client()->cannotShowURL(this);
return;
}
ASSERT_NOT_REACHED();
}
void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
BuiltinResourceHandleSynchronousLoaderMap::iterator protocolMapItem = builtinResourceHandleSynchronousLoaderMap().find(request.url().protocol());
if (protocolMapItem != builtinResourceHandleSynchronousLoaderMap().end()) {
protocolMapItem->value(context, request, storedCredentials, error, response, data);
return;
}
platformLoadResourceSynchronously(context, request, storedCredentials, error, response, data);
}
ResourceHandleClient* ResourceHandle::client() const
{
return d->m_client;
}
void ResourceHandle::clearClient()
{
d->m_client = nullptr;
}
#if !PLATFORM(COCOA) && !USE(CFNETWORK) && !USE(SOUP)
void ResourceHandle::continueWillSendRequest(ResourceRequest&&)
{
notImplemented();
}
void ResourceHandle::continueDidReceiveResponse()
{
notImplemented();
}
#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
void ResourceHandle::continueCanAuthenticateAgainstProtectionSpace(bool)
{
notImplemented();
}
#endif
#endif
ResourceRequest& ResourceHandle::firstRequest()
{
return d->m_firstRequest;
}
NetworkingContext* ResourceHandle::context() const
{
return d->m_context.get();
}
const String& ResourceHandle::lastHTTPMethod() const
{
return d->m_lastHTTPMethod;
}
bool ResourceHandle::hasAuthenticationChallenge() const
{
return !d->m_currentWebChallenge.isNull();
}
void ResourceHandle::clearAuthentication()
{
#if PLATFORM(COCOA)
d->m_currentMacChallenge = nil;
#endif
d->m_currentWebChallenge.nullify();
}
bool ResourceHandle::shouldContentSniff() const
{
return d->m_shouldContentSniff;
}
bool ResourceHandle::shouldContentSniffURL(const URL& url)
{
#if PLATFORM(COCOA)
if (shouldForceContentSniffing)
return true;
#endif
return !url.protocolIs("file");
}
void ResourceHandle::forceContentSniffing()
{
shouldForceContentSniffing = true;
}
void ResourceHandle::setDefersLoading(bool defers)
{
LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false");
ASSERT(d->m_defersLoading != defers); d->m_defersLoading = defers;
if (defers) {
ASSERT(d->m_failureTimer.isActive() == (d->m_scheduledFailureType != NoFailure));
if (d->m_failureTimer.isActive())
d->m_failureTimer.stop();
} else if (d->m_scheduledFailureType != NoFailure) {
ASSERT(!d->m_failureTimer.isActive());
d->m_failureTimer.startOneShot(0);
}
platformSetDefersLoading(defers);
}
bool ResourceHandle::usesAsyncCallbacks() const
{
return d->m_usesAsyncCallbacks;
}
}