1/* 2 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "ResourceHandle.h" 28#include "ResourceHandleInternal.h" 29 30#include "Logging.h" 31#include "NetworkingContext.h" 32#include "NotImplemented.h" 33#include "ResourceHandleClient.h" 34#include "Timer.h" 35#include <algorithm> 36#include <wtf/MainThread.h> 37#include <wtf/text/CString.h> 38 39namespace WebCore { 40 41static bool shouldForceContentSniffing; 42 43typedef HashMap<AtomicString, ResourceHandle::BuiltinConstructor> BuiltinResourceHandleConstructorMap; 44static BuiltinResourceHandleConstructorMap& builtinResourceHandleConstructorMap() 45{ 46#if PLATFORM(IOS) 47 ASSERT(WebThreadIsLockedOrDisabled()); 48#else 49 ASSERT(isMainThread()); 50#endif 51 DEPRECATED_DEFINE_STATIC_LOCAL(BuiltinResourceHandleConstructorMap, map, ()); 52 return map; 53} 54 55void ResourceHandle::registerBuiltinConstructor(const AtomicString& protocol, ResourceHandle::BuiltinConstructor constructor) 56{ 57 builtinResourceHandleConstructorMap().add(protocol, constructor); 58} 59 60typedef HashMap<AtomicString, ResourceHandle::BuiltinSynchronousLoader> BuiltinResourceHandleSynchronousLoaderMap; 61static BuiltinResourceHandleSynchronousLoaderMap& builtinResourceHandleSynchronousLoaderMap() 62{ 63 ASSERT(isMainThread()); 64 DEPRECATED_DEFINE_STATIC_LOCAL(BuiltinResourceHandleSynchronousLoaderMap, map, ()); 65 return map; 66} 67 68void ResourceHandle::registerBuiltinSynchronousLoader(const AtomicString& protocol, ResourceHandle::BuiltinSynchronousLoader loader) 69{ 70 builtinResourceHandleSynchronousLoaderMap().add(protocol, loader); 71} 72 73ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff) 74 : d(adoptPtr(new ResourceHandleInternal(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url())))) 75{ 76 if (!request.url().isValid()) { 77 scheduleFailure(InvalidURLFailure); 78 return; 79 } 80 81 if (!portAllowed(request.url())) { 82 scheduleFailure(BlockedFailure); 83 return; 84 } 85} 86 87PassRefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff) 88{ 89 BuiltinResourceHandleConstructorMap::iterator protocolMapItem = builtinResourceHandleConstructorMap().find(request.url().protocol()); 90 91 if (protocolMapItem != builtinResourceHandleConstructorMap().end()) 92 return protocolMapItem->value(request, client); 93 94 RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(context, request, client, defersLoading, shouldContentSniff))); 95 96 if (newHandle->d->m_scheduledFailureType != NoFailure) 97 return newHandle.release(); 98 99 if (newHandle->start()) 100 return newHandle.release(); 101 102 return 0; 103} 104 105void ResourceHandle::scheduleFailure(FailureType type) 106{ 107 d->m_scheduledFailureType = type; 108 d->m_failureTimer.startOneShot(0); 109} 110 111void ResourceHandle::failureTimerFired(Timer<ResourceHandle>&) 112{ 113 if (!client()) 114 return; 115 116 switch (d->m_scheduledFailureType) { 117 case NoFailure: 118 ASSERT_NOT_REACHED(); 119 return; 120 case BlockedFailure: 121 d->m_scheduledFailureType = NoFailure; 122 client()->wasBlocked(this); 123 return; 124 case InvalidURLFailure: 125 d->m_scheduledFailureType = NoFailure; 126 client()->cannotShowURL(this); 127 return; 128 } 129 130 ASSERT_NOT_REACHED(); 131} 132 133void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data) 134{ 135 BuiltinResourceHandleSynchronousLoaderMap::iterator protocolMapItem = builtinResourceHandleSynchronousLoaderMap().find(request.url().protocol()); 136 137 if (protocolMapItem != builtinResourceHandleSynchronousLoaderMap().end()) { 138 protocolMapItem->value(context, request, storedCredentials, error, response, data); 139 return; 140 } 141 142 platformLoadResourceSynchronously(context, request, storedCredentials, error, response, data); 143} 144 145ResourceHandleClient* ResourceHandle::client() const 146{ 147 return d->m_client; 148} 149 150void ResourceHandle::setClient(ResourceHandleClient* client) 151{ 152 d->m_client = client; 153} 154 155#if !PLATFORM(COCOA) && !USE(CFNETWORK) && !USE(SOUP) 156// ResourceHandle never uses async client calls on these platforms yet. 157void ResourceHandle::continueWillSendRequest(const ResourceRequest&) 158{ 159 notImplemented(); 160} 161 162void ResourceHandle::continueDidReceiveResponse() 163{ 164 notImplemented(); 165} 166 167#if USE(PROTECTION_SPACE_AUTH_CALLBACK) 168void ResourceHandle::continueCanAuthenticateAgainstProtectionSpace(bool) 169{ 170 notImplemented(); 171} 172#endif 173#endif 174 175ResourceRequest& ResourceHandle::firstRequest() 176{ 177 return d->m_firstRequest; 178} 179 180NetworkingContext* ResourceHandle::context() const 181{ 182 return d->m_context.get(); 183} 184 185const String& ResourceHandle::lastHTTPMethod() const 186{ 187 return d->m_lastHTTPMethod; 188} 189 190bool ResourceHandle::hasAuthenticationChallenge() const 191{ 192 return !d->m_currentWebChallenge.isNull(); 193} 194 195void ResourceHandle::clearAuthentication() 196{ 197#if PLATFORM(COCOA) 198 d->m_currentMacChallenge = nil; 199#endif 200 d->m_currentWebChallenge.nullify(); 201} 202 203bool ResourceHandle::shouldContentSniff() const 204{ 205 return d->m_shouldContentSniff; 206} 207 208bool ResourceHandle::shouldContentSniffURL(const URL& url) 209{ 210#if PLATFORM(COCOA) 211 if (shouldForceContentSniffing) 212 return true; 213#endif 214 // We shouldn't content sniff file URLs as their MIME type should be established via their extension. 215 return !url.protocolIs("file"); 216} 217 218void ResourceHandle::forceContentSniffing() 219{ 220 shouldForceContentSniffing = true; 221} 222 223void ResourceHandle::setDefersLoading(bool defers) 224{ 225 LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false"); 226 227 ASSERT(d->m_defersLoading != defers); // Deferring is not counted, so calling setDefersLoading() repeatedly is likely to be in error. 228 d->m_defersLoading = defers; 229 230 if (defers) { 231 ASSERT(d->m_failureTimer.isActive() == (d->m_scheduledFailureType != NoFailure)); 232 if (d->m_failureTimer.isActive()) 233 d->m_failureTimer.stop(); 234 } else if (d->m_scheduledFailureType != NoFailure) { 235 ASSERT(!d->m_failureTimer.isActive()); 236 d->m_failureTimer.startOneShot(0); 237 } 238 239 platformSetDefersLoading(defers); 240} 241 242void ResourceHandle::didChangePriority(ResourceLoadPriority) 243{ 244 // Optionally implemented by platform. 245} 246 247} // namespace WebCore 248