1/* 2 * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "NetworkResourceLoader.h" 28 29#if ENABLE(NETWORK_PROCESS) 30 31#include "AsynchronousNetworkLoaderClient.h" 32#include "AuthenticationManager.h" 33#include "DataReference.h" 34#include "Logging.h" 35#include "NetworkBlobRegistry.h" 36#include "NetworkConnectionToWebProcess.h" 37#include "NetworkProcess.h" 38#include "NetworkProcessConnectionMessages.h" 39#include "NetworkResourceLoadParameters.h" 40#include "RemoteNetworkingContext.h" 41#include "ShareableResource.h" 42#include "SharedMemory.h" 43#include "SynchronousNetworkLoaderClient.h" 44#include "WebCoreArgumentCoders.h" 45#include "WebErrors.h" 46#include "WebResourceLoaderMessages.h" 47#include <WebCore/BlobDataFileReference.h> 48#include <WebCore/NotImplemented.h> 49#include <WebCore/ResourceBuffer.h> 50#include <WebCore/ResourceHandle.h> 51#include <wtf/MainThread.h> 52 53using namespace WebCore; 54 55namespace WebKit { 56 57NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply) 58 : m_bytesReceived(0) 59 , m_handleConvertedToDownload(false) 60 , m_identifier(parameters.identifier) 61 , m_webPageID(parameters.webPageID) 62 , m_webFrameID(parameters.webFrameID) 63 , m_sessionID(parameters.sessionID) 64 , m_request(parameters.request) 65 , m_priority(parameters.priority) 66 , m_contentSniffingPolicy(parameters.contentSniffingPolicy) 67 , m_allowStoredCredentials(parameters.allowStoredCredentials) 68 , m_clientCredentialPolicy(parameters.clientCredentialPolicy) 69 , m_shouldClearReferrerOnHTTPSToHTTPRedirect(parameters.shouldClearReferrerOnHTTPSToHTTPRedirect) 70 , m_isLoadingMainResource(parameters.isMainResource) 71 , m_defersLoading(parameters.defersLoading) 72 , m_sandboxExtensionsAreConsumed(false) 73 , m_connection(connection) 74{ 75 // Either this loader has both a webPageID and webFrameID, or it is not allowed to ask the client for authentication credentials. 76 // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore. 77 // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID" 78 ASSERT((m_webPageID && m_webFrameID) || m_clientCredentialPolicy == DoNotAskClientForAnyCredentials); 79 80 for (size_t i = 0, count = parameters.requestBodySandboxExtensions.size(); i < count; ++i) { 81 if (RefPtr<SandboxExtension> extension = SandboxExtension::create(parameters.requestBodySandboxExtensions[i])) 82 m_requestBodySandboxExtensions.append(extension); 83 } 84 85 if (m_request.httpBody()) { 86 for (const FormDataElement& element : m_request.httpBody()->elements()) { 87 if (element.m_type == FormDataElement::Type::EncodedBlob) 88 m_fileReferences.appendVector(NetworkBlobRegistry::shared().filesInBlob(connection, element.m_url)); 89 } 90 } 91 92 if (m_request.url().protocolIs("blob")) { 93 ASSERT(!SandboxExtension::create(parameters.resourceSandboxExtension)); 94 m_fileReferences.appendVector(NetworkBlobRegistry::shared().filesInBlob(connection, m_request.url())); 95 } else 96 97 if (RefPtr<SandboxExtension> resourceSandboxExtension = SandboxExtension::create(parameters.resourceSandboxExtension)) 98 m_resourceSandboxExtensions.append(resourceSandboxExtension); 99 100 ASSERT(RunLoop::isMain()); 101 102 if (reply || parameters.shouldBufferResource) 103 m_bufferedData = WebCore::SharedBuffer::create(); 104 105 if (reply) 106 m_networkLoaderClient = std::make_unique<SynchronousNetworkLoaderClient>(m_request, reply); 107 else 108 m_networkLoaderClient = std::make_unique<AsynchronousNetworkLoaderClient>(); 109} 110 111NetworkResourceLoader::~NetworkResourceLoader() 112{ 113 ASSERT(RunLoop::isMain()); 114 ASSERT(!m_handle); 115 ASSERT(!m_hostRecord); 116} 117 118bool NetworkResourceLoader::isSynchronous() const 119{ 120 return m_networkLoaderClient->isSynchronous(); 121} 122 123void NetworkResourceLoader::start() 124{ 125 ASSERT(RunLoop::isMain()); 126 127 if (m_defersLoading) { 128 m_deferredRequest = m_request; 129 return; 130 } 131 132 // Explicit ref() balanced by a deref() in NetworkResourceLoader::cleanup() 133 ref(); 134 135 // FIXME (NetworkProcess): Set platform specific settings. 136 m_networkingContext = RemoteNetworkingContext::create(m_sessionID, m_shouldClearReferrerOnHTTPSToHTTPRedirect); 137 138 consumeSandboxExtensions(); 139 140 // FIXME (NetworkProcess): Pass an actual value for defersLoading 141 m_handle = ResourceHandle::create(m_networkingContext.get(), m_request, this, false /* defersLoading */, m_contentSniffingPolicy == SniffContent); 142} 143 144void NetworkResourceLoader::setDefersLoading(bool defers) 145{ 146 m_defersLoading = defers; 147 if (m_handle) 148 m_handle->setDefersLoading(defers); 149 if (!defers && !m_deferredRequest.isNull()) { 150 m_request = m_deferredRequest; 151 m_deferredRequest = ResourceRequest(); 152 start(); 153 } 154} 155 156void NetworkResourceLoader::cleanup() 157{ 158 ASSERT(RunLoop::isMain()); 159 160 invalidateSandboxExtensions(); 161 162 // Tell the scheduler about this finished loader soon so it can start more network requests. 163 NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoader(this); 164 165 if (m_handle) { 166 // Explicit deref() balanced by a ref() in NetworkResourceLoader::start() 167 // This might cause the NetworkResourceLoader to be destroyed and therefore we do it last. 168 m_handle = 0; 169 deref(); 170 } 171} 172 173void NetworkResourceLoader::didConvertHandleToDownload() 174{ 175 ASSERT(m_handle); 176 m_handleConvertedToDownload = true; 177} 178 179void NetworkResourceLoader::abort() 180{ 181 ASSERT(RunLoop::isMain()); 182 183 if (m_handle && !m_handleConvertedToDownload) 184 m_handle->cancel(); 185 186 cleanup(); 187} 188 189void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& response) 190{ 191 ASSERT_UNUSED(handle, handle == m_handle); 192 193 m_networkLoaderClient->didReceiveResponse(this, response); 194 195 // m_handle will be 0 if the request got aborted above. 196 if (!m_handle) 197 return; 198 199 if (!m_isLoadingMainResource) { 200 // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message. 201 m_handle->continueDidReceiveResponse(); 202 } 203} 204 205void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */) 206{ 207 // The NetworkProcess should never get a didReceiveData callback. 208 // We should always be using didReceiveBuffer. 209 ASSERT_NOT_REACHED(); 210} 211 212void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int encodedDataLength) 213{ 214 ASSERT_UNUSED(handle, handle == m_handle); 215 216 // FIXME (NetworkProcess): For the memory cache we'll also need to cache the response data here. 217 // Such buffering will need to be thread safe, as this callback is happening on a background thread. 218 219 m_bytesReceived += buffer->size(); 220 if (m_bufferedData) 221 m_bufferedData->append(buffer.get()); 222 else 223 m_networkLoaderClient->didReceiveBuffer(this, buffer.get(), encodedDataLength); 224} 225 226void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double finishTime) 227{ 228 ASSERT_UNUSED(handle, handle == m_handle); 229 230 // Send the full resource data if we were buffering it. 231 if (m_bufferedData && m_bufferedData->size()) 232 m_networkLoaderClient->didReceiveBuffer(this, m_bufferedData.get(), m_bufferedData->size()); 233 234 m_networkLoaderClient->didFinishLoading(this, finishTime); 235 236 cleanup(); 237} 238 239void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError& error) 240{ 241 ASSERT_UNUSED(handle, handle == m_handle); 242 243 m_networkLoaderClient->didFail(this, error); 244 245 cleanup(); 246} 247 248void NetworkResourceLoader::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse) 249{ 250 ASSERT_UNUSED(handle, handle == m_handle); 251 252 // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect. 253 ASSERT(!redirectResponse.isNull()); 254 ASSERT(RunLoop::isMain()); 255 256 ResourceRequest proposedRequest = request; 257 m_suggestedRequestForWillSendRequest = request; 258 259 m_networkLoaderClient->willSendRequest(this, proposedRequest, redirectResponse); 260} 261 262void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest) 263{ 264#if PLATFORM(COCOA) 265 m_suggestedRequestForWillSendRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody)); 266#elif USE(SOUP) 267 // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127. 268 m_suggestedRequestForWillSendRequest.updateFromDelegatePreservingOldProperties(newRequest); 269#endif 270 271 RunLoop::main().dispatch(bind(&NetworkResourceLoadScheduler::receivedRedirect, &NetworkProcess::shared().networkResourceLoadScheduler(), this, m_suggestedRequestForWillSendRequest.url())); 272 273 m_request = m_suggestedRequestForWillSendRequest; 274 m_suggestedRequestForWillSendRequest = ResourceRequest(); 275 276 m_handle->continueWillSendRequest(m_request); 277 278 if (m_request.isNull()) { 279 m_handle->cancel(); 280 didFail(m_handle.get(), cancelledError(m_request)); 281 } 282} 283 284void NetworkResourceLoader::continueDidReceiveResponse() 285{ 286 // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly. 287 // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse. 288 if (!m_handle) 289 return; 290 291 m_handle->continueDidReceiveResponse(); 292} 293 294void NetworkResourceLoader::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 295{ 296 ASSERT_UNUSED(handle, handle == m_handle); 297 298 m_networkLoaderClient->didSendData(this, bytesSent, totalBytesToBeSent); 299} 300 301void NetworkResourceLoader::wasBlocked(ResourceHandle* handle) 302{ 303 ASSERT_UNUSED(handle, handle == m_handle); 304 305 didFail(handle, WebKit::blockedError(request())); 306} 307 308void NetworkResourceLoader::cannotShowURL(ResourceHandle* handle) 309{ 310 ASSERT_UNUSED(handle, handle == m_handle); 311 312 didFail(handle, WebKit::cannotShowURLError(request())); 313} 314 315bool NetworkResourceLoader::shouldUseCredentialStorage(ResourceHandle* handle) 316{ 317 ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start(). 318 319 // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked. 320 // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer. 321 322 // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one. 323 324 return m_allowStoredCredentials == AllowStoredCredentials; 325} 326 327void NetworkResourceLoader::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge) 328{ 329 ASSERT_UNUSED(handle, handle == m_handle); 330 331 // FIXME (http://webkit.org/b/115291): Since we go straight to the UI process for authentication we don't get WebCore's 332 // cross-origin check before asking the client for credentials. 333 // Therefore we are too permissive in the case where the ClientCredentialPolicy is DoNotAskClientForCrossOriginCredentials. 334 if (m_clientCredentialPolicy == DoNotAskClientForAnyCredentials) { 335 challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge); 336 return; 337 } 338 339 NetworkProcess::shared().authenticationManager().didReceiveAuthenticationChallenge(m_webPageID, m_webFrameID, challenge); 340} 341 342void NetworkResourceLoader::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge&) 343{ 344 ASSERT_UNUSED(handle, handle == m_handle); 345 346 // This function is probably not needed (see <rdar://problem/8960124>). 347 notImplemented(); 348} 349 350void NetworkResourceLoader::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&) 351{ 352 ASSERT_UNUSED(handle, handle == m_handle); 353 354 m_handle->cancel(); 355 didFail(m_handle.get(), cancelledError(m_request)); 356} 357 358IPC::Connection* NetworkResourceLoader::messageSenderConnection() 359{ 360 return connectionToWebProcess()->connection(); 361} 362 363void NetworkResourceLoader::consumeSandboxExtensions() 364{ 365 for (RefPtr<SandboxExtension>& extension : m_requestBodySandboxExtensions) 366 extension->consume(); 367 368 for (RefPtr<SandboxExtension>& extension : m_resourceSandboxExtensions) 369 extension->consume(); 370 371 for (RefPtr<BlobDataFileReference>& fileReference : m_fileReferences) 372 fileReference->prepareForFileAccess(); 373 374 m_sandboxExtensionsAreConsumed = true; 375} 376 377void NetworkResourceLoader::invalidateSandboxExtensions() 378{ 379 if (m_sandboxExtensionsAreConsumed) { 380 for (RefPtr<SandboxExtension>& extension : m_requestBodySandboxExtensions) 381 extension->revoke(); 382 for (RefPtr<SandboxExtension>& extension : m_resourceSandboxExtensions) 383 extension->revoke(); 384 for (RefPtr<BlobDataFileReference>& fileReference : m_fileReferences) 385 fileReference->revokeFileAccess(); 386 } 387 388 m_requestBodySandboxExtensions.clear(); 389 m_resourceSandboxExtensions.clear(); 390 m_fileReferences.clear(); 391 392 m_sandboxExtensionsAreConsumed = false; 393} 394 395#if USE(PROTECTION_SPACE_AUTH_CALLBACK) 396void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace) 397{ 398 ASSERT(RunLoop::isMain()); 399 ASSERT_UNUSED(handle, handle == m_handle); 400 401 m_networkLoaderClient->canAuthenticateAgainstProtectionSpace(this, protectionSpace); 402} 403 404void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result) 405{ 406 m_handle->continueCanAuthenticateAgainstProtectionSpace(result); 407} 408 409#endif 410 411#if USE(NETWORK_CFDATA_ARRAY_CALLBACK) 412bool NetworkResourceLoader::supportsDataArray() 413{ 414 notImplemented(); 415 return false; 416} 417 418void NetworkResourceLoader::didReceiveDataArray(ResourceHandle*, CFArrayRef) 419{ 420 ASSERT_NOT_REACHED(); 421 notImplemented(); 422} 423#endif 424 425} // namespace WebKit 426 427#endif // ENABLE(NETWORK_PROCESS) 428