2 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "NetworkResourceLoader.h"
29 #include "DataReference.h"
31 #include "NetworkBlobRegistry.h"
32 #include "NetworkCache.h"
33 #include "NetworkConnectionToWebProcess.h"
34 #include "NetworkLoad.h"
35 #include "NetworkProcess.h"
36 #include "NetworkProcessConnectionMessages.h"
37 #include "SessionTracker.h"
38 #include "WebCoreArgumentCoders.h"
39 #include "WebErrors.h"
40 #include "WebResourceLoaderMessages.h"
41 #include <WebCore/BlobDataFileReference.h>
42 #include <WebCore/CertificateInfo.h>
43 #include <WebCore/DiagnosticLoggingKeys.h>
44 #include <WebCore/HTTPHeaderNames.h>
45 #include <WebCore/NetworkLoadMetrics.h>
46 #include <WebCore/ProtectionSpace.h>
47 #include <WebCore/SharedBuffer.h>
48 #include <WebCore/SynchronousLoaderClient.h>
49 #include <wtf/CurrentTime.h>
50 #include <wtf/RunLoop.h>
52 using namespace WebCore;
54 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
55 #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
59 struct NetworkResourceLoader::SynchronousLoadData {
60 SynchronousLoadData(RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
61 : delayedReply(WTFMove(reply))
65 ResourceRequest currentRequest;
66 RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
67 ResourceResponse response;
71 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
73 ASSERT(data.delayedReply);
74 ASSERT(!data.response.isNull() || !data.error.isNull());
76 Vector<char> responseBuffer;
77 if (buffer && buffer->size())
78 responseBuffer.append(buffer->data(), buffer->size());
80 data.delayedReply->send(data.error, data.response, responseBuffer);
81 data.delayedReply = nullptr;
84 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
85 : m_parameters { parameters }
86 , m_connection { connection }
87 , m_defersLoading { parameters.defersLoading }
88 , m_isAllowedToAskUserForCredentials { parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
89 , m_bufferingTimer { *this, &NetworkResourceLoader::bufferingTimerFired }
90 , m_cache { sessionID().isEphemeral() ? nullptr : NetworkProcess::singleton().cache() }
92 ASSERT(RunLoop::isMain());
93 // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
94 // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
95 ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
97 if (originalRequest().httpBody()) {
98 for (const auto& element : originalRequest().httpBody()->elements()) {
99 if (element.m_type == FormDataElement::Type::EncodedBlob)
100 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
104 #if !USE(NETWORK_SESSION)
105 if (originalRequest().url().protocolIsBlob()) {
106 ASSERT(!m_parameters.resourceSandboxExtension);
107 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
112 if (synchronousReply)
113 m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
116 NetworkResourceLoader::~NetworkResourceLoader()
118 ASSERT(RunLoop::isMain());
119 ASSERT(!m_networkLoad);
120 ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
123 bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
127 ASSERT(!sessionID().isEphemeral());
129 if (!request.url().protocolIsInHTTPFamily())
131 if (originalRequest().cachePolicy() == WebCore::DoNotUseAnyCache)
137 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
139 if (!canUseCache(request))
141 // Limit cached redirects to avoid cycles and other trouble.
142 // Networking layer follows over 30 redirects but caching that many seems unnecessary.
143 static const unsigned maximumCachedRedirectCount { 5 };
144 if (m_redirectCount > maximumCachedRedirectCount)
150 bool NetworkResourceLoader::isSynchronous() const
152 return !!m_synchronousLoadData;
155 void NetworkResourceLoader::start()
157 ASSERT(RunLoop::isMain());
159 if (m_defersLoading) {
160 RELEASE_LOG_IF_ALLOWED("start: Loading is deferred (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
164 ASSERT(!m_wasStarted);
167 if (canUseCache(originalRequest())) {
168 RELEASE_LOG_IF_ALLOWED("start: Checking cache for resource (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
169 retrieveCacheEntry(originalRequest());
173 startNetworkLoad(originalRequest());
176 void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
178 ASSERT(canUseCache(request));
180 RefPtr<NetworkResourceLoader> loader(this);
181 m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [this, loader = WTFMove(loader), request](auto entry) {
182 if (loader->hasOneRef()) {
183 // The loader has been aborted and is only held alive by this lambda.
187 RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource not in cache (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
188 loader->startNetworkLoad(request);
191 if (entry->redirectRequest()) {
192 RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Handling redirect (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
193 loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry));
196 if (loader->m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) {
197 RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource does not have required certificate (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
198 loader->startNetworkLoad(request);
201 if (entry->needsValidation() || request.cachePolicy() == WebCore::RefreshAnyCacheData) {
202 RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Validating cache entry (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
203 loader->validateCacheEntry(WTFMove(entry));
206 RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Retrieved resource from cache (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
207 loader->didRetrieveCacheEntry(WTFMove(entry));
211 void NetworkResourceLoader::startNetworkLoad(const ResourceRequest& request)
213 RELEASE_LOG_IF_ALLOWED("startNetworkLoad: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
215 consumeSandboxExtensions();
217 if (isSynchronous() || m_parameters.maximumBufferingTime > 0_s)
218 m_bufferedData = SharedBuffer::create();
220 if (canUseCache(request))
221 m_bufferedDataForCache = SharedBuffer::create();
223 NetworkLoadParameters parameters = m_parameters;
224 parameters.defersLoading = m_defersLoading;
225 parameters.request = request;
227 #if USE(NETWORK_SESSION)
228 if (request.url().protocolIsBlob())
229 parameters.blobFileReferences = NetworkBlobRegistry::singleton().filesInBlob(m_connection, originalRequest().url());
231 auto* networkSession = SessionTracker::networkSession(parameters.sessionID);
232 if (!networkSession) {
233 WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", parameters.sessionID.sessionID());
234 RELEASE_LOG_ERROR_IF_ALLOWED("startNetworkLoad: Attempted to create a NetworkLoad with a session that does not exist (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", sessionID=%" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, parameters.sessionID.sessionID());
235 NetworkProcess::singleton().logDiagnosticMessage(m_parameters.webPageID, WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::invalidSessionIDKey(), WebCore::ShouldSample::No);
236 didFailLoading(internalError(request.url()));
239 m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters), *networkSession);
241 m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters));
244 if (m_defersLoading) {
245 RELEASE_LOG_IF_ALLOWED("startNetworkLoad: Created, but deferred (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
246 m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
250 void NetworkResourceLoader::setDefersLoading(bool defers)
252 if (m_defersLoading == defers)
254 m_defersLoading = defers;
257 RELEASE_LOG_IF_ALLOWED("setDefersLoading: Deferring resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
259 RELEASE_LOG_IF_ALLOWED("setDefersLoading: Resuming deferred resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
262 m_networkLoad->setDefersLoading(defers);
266 if (!m_defersLoading && !m_wasStarted)
269 RELEASE_LOG_IF_ALLOWED("setDefersLoading: defers = %d, but nothing to do (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_defersLoading, m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
272 void NetworkResourceLoader::cleanup()
274 ASSERT(RunLoop::isMain());
276 m_bufferingTimer.stop();
278 invalidateSandboxExtensions();
280 m_networkLoad = nullptr;
282 // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
283 m_connection->didCleanupResourceLoader(*this);
286 void NetworkResourceLoader::convertToDownload(DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
288 ASSERT(m_networkLoad);
289 NetworkProcess::singleton().downloadManager().convertNetworkLoadToDownload(downloadID, std::exchange(m_networkLoad, nullptr), WTFMove(m_fileReferences), request, response);
292 void NetworkResourceLoader::abort()
294 ASSERT(RunLoop::isMain());
296 RELEASE_LOG_IF_ALLOWED("abort: Canceling resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
297 m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
300 if (canUseCache(m_networkLoad->currentRequest())) {
301 // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
302 if (!m_response.isNull())
303 m_cache->remove(m_networkLoad->currentRequest());
305 m_networkLoad->cancel();
311 auto NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse) -> ShouldContinueDidReceiveResponse
313 RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", httpStatusCode = %d, length = %" PRId64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, receivedResponse.httpStatusCode(), receivedResponse.expectedContentLength());
315 m_response = WTFMove(receivedResponse);
317 // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
318 if (!isSynchronous() && m_response.isMultipart())
319 m_bufferedData = nullptr;
321 if (m_response.isMultipart())
322 m_bufferedDataForCache = nullptr;
324 if (m_cacheEntryForValidation) {
325 bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
326 if (validationSucceeded) {
327 m_cacheEntryForValidation = m_cache->update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
328 // If the request was conditional then this revalidation was not triggered by the network cache and we pass the 304 response to WebCore.
329 if (originalRequest().isConditional())
330 m_cacheEntryForValidation = nullptr;
332 m_cacheEntryForValidation = nullptr;
334 bool shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
336 bool shouldWaitContinueDidReceiveResponse = isMainResource();
337 if (shouldSendDidReceiveResponse) {
339 m_synchronousLoadData->response = m_response;
341 send(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse));
344 // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
345 bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse || m_cacheEntryForValidation;
347 if (shouldContinueDidReceiveResponse) {
348 RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Should not wait for message from WebContent process before continuing resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
349 return ShouldContinueDidReceiveResponse::Yes;
352 RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Should wait for message from WebContent process before continuing resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
353 return ShouldContinueDidReceiveResponse::No;
356 void NetworkResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
358 if (!m_numBytesReceived) {
359 RELEASE_LOG_IF_ALLOWED("didReceiveBuffer: Started receiving data (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
361 m_numBytesReceived += buffer->size();
363 ASSERT(!m_cacheEntryForValidation);
365 if (m_bufferedDataForCache) {
366 // Prevent memory growth in case of streaming data.
367 const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
368 if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
369 m_bufferedDataForCache->append(buffer.get());
371 m_bufferedDataForCache = nullptr;
373 // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
374 unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
376 m_bytesReceived += buffer->size();
377 if (m_bufferedData) {
378 m_bufferedData->append(buffer.get());
379 m_bufferedDataEncodedDataLength += encodedDataLength;
380 startBufferingTimerIfNeeded();
383 sendBuffer(buffer, encodedDataLength);
386 void NetworkResourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
388 RELEASE_LOG_IF_ALLOWED("didFinishLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", length = %zd)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, m_numBytesReceived);
390 if (m_cacheEntryForValidation) {
392 ASSERT(m_response.httpStatusCode() == 304);
393 LOG(NetworkCache, "(NetworkProcess) revalidated");
394 didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
399 sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
401 if (m_bufferedData && !m_bufferedData->isEmpty()) {
402 // FIXME: Pass a real value or remove the encoded data size feature.
403 sendBuffer(*m_bufferedData, -1);
405 send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
408 tryStoreAsCacheEntry();
413 void NetworkResourceLoader::didFailLoading(const ResourceError& error)
415 RELEASE_LOG_IF_ALLOWED("didFailLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isTimeout = %d, isCancellation = %d, errCode = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, error.isTimeout(), error.isCancellation(), error.errorCode());
417 ASSERT(!error.isNull());
419 m_cacheEntryForValidation = nullptr;
421 if (isSynchronous()) {
422 m_synchronousLoadData->error = error;
423 sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
424 } else if (auto* connection = messageSenderConnection())
425 connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
430 void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, WebCore::ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
434 if (isSynchronous()) {
435 ResourceRequest overridenRequest = redirectRequest;
436 // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
437 // This includes at least updating host records, and comparing the current request instead of the original request here.
438 if (!protocolHostAndPortAreEqual(originalRequest().url(), redirectRequest.url())) {
439 ASSERT(m_synchronousLoadData->error.isNull());
440 m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
441 m_networkLoad->clearCurrentRequest();
442 overridenRequest = ResourceRequest();
444 // We do not support prompting for credentials for synchronous loads. If we ever change this policy then
445 // we need to take care to prompt if and only if request and redirectRequest are not mixed content.
446 continueWillSendRequest(WTFMove(overridenRequest), false);
449 send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
451 if (canUseCachedRedirect(request))
452 m_cache->storeRedirect(request, redirectResponse, redirectRequest);
455 void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
457 RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
459 m_isAllowedToAskUserForCredentials = isAllowedToAskUserForCredentials;
461 // If there is a match in the network cache, we need to reuse the original cache policy and partition.
462 newRequest.setCachePolicy(originalRequest().cachePolicy());
463 newRequest.setCachePartition(originalRequest().cachePartition());
465 if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
466 m_isWaitingContinueWillSendRequestForCachedRedirect = false;
468 LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
470 if (canUseCachedRedirect(newRequest))
471 retrieveCacheEntry(newRequest);
473 startNetworkLoad(newRequest);
479 m_networkLoad->continueWillSendRequest(WTFMove(newRequest));
482 void NetworkResourceLoader::continueDidReceiveResponse()
484 // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
485 // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
487 m_networkLoad->continueDidReceiveResponse();
490 void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
492 if (!isSynchronous())
493 send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
496 void NetworkResourceLoader::startBufferingTimerIfNeeded()
500 if (m_bufferingTimer.isActive())
502 m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
505 void NetworkResourceLoader::bufferingTimerFired()
507 ASSERT(m_bufferedData);
508 ASSERT(m_networkLoad);
510 if (m_bufferedData->isEmpty())
513 IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
514 size_t encodedLength = m_bufferedDataEncodedDataLength;
516 m_bufferedData = SharedBuffer::create();
517 m_bufferedDataEncodedDataLength = 0;
519 send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
522 void NetworkResourceLoader::sendBuffer(SharedBuffer& buffer, size_t encodedDataLength)
524 ASSERT(!isSynchronous());
526 IPC::SharedBufferDataReference dataReference(&buffer);
527 send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
530 void NetworkResourceLoader::tryStoreAsCacheEntry()
532 if (!canUseCache(m_networkLoad->currentRequest()))
534 if (!m_bufferedDataForCache)
537 m_cache->store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader = makeRef(*this)](auto& mappedBody) mutable {
538 #if ENABLE(SHAREABLE_RESOURCE)
539 if (mappedBody.shareableResourceHandle.isNull())
541 LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
542 loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
547 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
549 if (isSynchronous()) {
550 m_synchronousLoadData->response = entry->response();
551 sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
556 bool needsContinueDidReceiveResponseMessage = isMainResource();
557 send(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
559 if (entry->sourceStorageRecord().bodyHash && !m_parameters.derivedCachedDataTypesToRetrieve.isEmpty()) {
560 auto bodyHash = *entry->sourceStorageRecord().bodyHash;
561 auto* entryPtr = entry.release();
562 auto retrieveCount = m_parameters.derivedCachedDataTypesToRetrieve.size();
564 for (auto& type : m_parameters.derivedCachedDataTypesToRetrieve) {
565 NetworkCache::DataKey key { originalRequest().cachePartition(), type, bodyHash };
566 m_cache->retrieveData(key, [loader = makeRef(*this), entryPtr, type, retrieveCount] (const uint8_t* data, size_t size) mutable {
567 loader->m_retrievedDerivedDataCount++;
568 bool retrievedAll = loader->m_retrievedDerivedDataCount == retrieveCount;
569 std::unique_ptr<NetworkCache::Entry> entry(retrievedAll ? entryPtr : nullptr);
570 if (loader->hasOneRef())
573 IPC::DataReference dataReference(data, size);
574 loader->send(Messages::WebResourceLoader::DidRetrieveDerivedData(type, dataReference));
577 loader->sendResultForCacheEntry(WTFMove(entry));
585 sendResultForCacheEntry(WTFMove(entry));
590 void NetworkResourceLoader::sendResultForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
592 #if ENABLE(SHAREABLE_RESOURCE)
593 if (!entry->shareableResourceHandle().isNull()) {
594 send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle()));
599 WebCore::NetworkLoadMetrics networkLoadMetrics;
600 networkLoadMetrics.markComplete();
601 networkLoadMetrics.requestHeaderBytesSent = 0;
602 networkLoadMetrics.requestBodyBytesSent = 0;
603 networkLoadMetrics.responseHeaderBytesReceived = 0;
604 networkLoadMetrics.responseBodyBytesReceived = 0;
605 networkLoadMetrics.responseBodyDecodedSize = 0;
607 sendBuffer(*entry->buffer(), entry->buffer()->size());
608 send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
611 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
613 ASSERT(!m_networkLoad);
615 // If the request is already conditional then the revalidation was not triggered by the disk cache
616 // and we should not overwrite the existing conditional headers.
617 ResourceRequest revalidationRequest = originalRequest();
618 if (!revalidationRequest.isConditional()) {
619 String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
620 String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
622 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
623 if (!lastModified.isEmpty())
624 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
627 m_cacheEntryForValidation = WTFMove(entry);
629 startNetworkLoad(revalidationRequest);
632 void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
634 ASSERT(entry->redirectRequest());
635 ASSERT(!m_isWaitingContinueWillSendRequestForCachedRedirect);
637 LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
640 send(Messages::WebResourceLoader::WillSendRequest(*entry->redirectRequest(), entry->response()));
641 m_isWaitingContinueWillSendRequestForCachedRedirect = true;
644 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
646 return &connectionToWebProcess().connection();
649 void NetworkResourceLoader::consumeSandboxExtensions()
651 ASSERT(!m_didConsumeSandboxExtensions);
653 for (auto& extension : m_parameters.requestBodySandboxExtensions)
654 extension->consume();
656 if (auto& extension = m_parameters.resourceSandboxExtension)
657 extension->consume();
659 for (auto& fileReference : m_fileReferences)
660 fileReference->prepareForFileAccess();
662 m_didConsumeSandboxExtensions = true;
665 void NetworkResourceLoader::invalidateSandboxExtensions()
667 if (m_didConsumeSandboxExtensions) {
668 for (auto& extension : m_parameters.requestBodySandboxExtensions)
670 if (auto& extension = m_parameters.resourceSandboxExtension)
672 for (auto& fileReference : m_fileReferences)
673 fileReference->revokeFileAccess();
675 m_didConsumeSandboxExtensions = false;
678 m_fileReferences.clear();
681 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
682 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(const ProtectionSpace& protectionSpace)
684 NetworkProcess::singleton().canAuthenticateAgainstProtectionSpace(*this, protectionSpace);
687 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
690 m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(result);
694 bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
696 return sessionID().isAlwaysOnLoggingAllowed();
699 bool NetworkResourceLoader::shouldCaptureExtraNetworkLoadMetrics() const
701 return m_connection->captureExtraNetworkLoadMetricsEnabled();
704 } // namespace WebKit