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 #if HAVE(CFNETWORK_STORAGE_PARTITIONING) && !RELEASE_LOG_DISABLED
53 #include <WebCore/NetworkStorageSession.h>
54 #include <WebCore/PlatformCookieJar.h>
57 using namespace WebCore;
59 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
60 #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
64 struct NetworkResourceLoader::SynchronousLoadData {
65 SynchronousLoadData(RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
66 : delayedReply(WTFMove(reply))
70 ResourceRequest currentRequest;
71 RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
72 ResourceResponse response;
76 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
78 ASSERT(data.delayedReply);
79 ASSERT(!data.response.isNull() || !data.error.isNull());
81 Vector<char> responseBuffer;
82 if (buffer && buffer->size())
83 responseBuffer.append(buffer->data(), buffer->size());
85 data.delayedReply->send(data.error, data.response, responseBuffer);
86 data.delayedReply = nullptr;
89 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
90 : m_parameters { parameters }
91 , m_connection { connection }
92 , m_defersLoading { parameters.defersLoading }
93 , m_isAllowedToAskUserForCredentials { parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
94 , m_bufferingTimer { *this, &NetworkResourceLoader::bufferingTimerFired }
95 , m_cache { sessionID().isEphemeral() ? nullptr : NetworkProcess::singleton().cache() }
97 ASSERT(RunLoop::isMain());
98 // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
99 // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
100 ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
102 if (originalRequest().httpBody()) {
103 for (const auto& element : originalRequest().httpBody()->elements()) {
104 if (element.m_type == FormDataElement::Type::EncodedBlob)
105 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
109 #if !USE(NETWORK_SESSION)
110 if (originalRequest().url().protocolIsBlob()) {
111 ASSERT(!m_parameters.resourceSandboxExtension);
112 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
117 if (synchronousReply)
118 m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
121 NetworkResourceLoader::~NetworkResourceLoader()
123 ASSERT(RunLoop::isMain());
124 ASSERT(!m_networkLoad);
125 ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
128 bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
132 ASSERT(!sessionID().isEphemeral());
134 if (!request.url().protocolIsInHTTPFamily())
136 if (originalRequest().cachePolicy() == WebCore::DoNotUseAnyCache)
142 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
144 if (!canUseCache(request))
146 // Limit cached redirects to avoid cycles and other trouble.
147 // Networking layer follows over 30 redirects but caching that many seems unnecessary.
148 static const unsigned maximumCachedRedirectCount { 5 };
149 if (m_redirectCount > maximumCachedRedirectCount)
155 bool NetworkResourceLoader::isSynchronous() const
157 return !!m_synchronousLoadData;
160 void NetworkResourceLoader::start()
162 ASSERT(RunLoop::isMain());
164 if (m_defersLoading) {
165 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());
169 ASSERT(!m_wasStarted);
172 if (canUseCache(originalRequest())) {
173 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());
174 retrieveCacheEntry(originalRequest());
178 startNetworkLoad(originalRequest());
181 void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
183 ASSERT(canUseCache(request));
185 RefPtr<NetworkResourceLoader> loader(this);
186 m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [this, loader = WTFMove(loader), request](auto entry) {
187 if (loader->hasOneRef()) {
188 // The loader has been aborted and is only held alive by this lambda.
192 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());
193 loader->startNetworkLoad(request);
196 if (entry->redirectRequest()) {
197 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());
198 loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry));
201 if (loader->m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) {
202 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());
203 loader->startNetworkLoad(request);
206 if (entry->needsValidation() || request.cachePolicy() == WebCore::RefreshAnyCacheData) {
207 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());
208 loader->validateCacheEntry(WTFMove(entry));
211 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());
212 loader->didRetrieveCacheEntry(WTFMove(entry));
216 void NetworkResourceLoader::startNetworkLoad(const ResourceRequest& request)
218 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());
220 consumeSandboxExtensions();
222 if (isSynchronous() || m_parameters.maximumBufferingTime > 0_s)
223 m_bufferedData = SharedBuffer::create();
225 if (canUseCache(request))
226 m_bufferedDataForCache = SharedBuffer::create();
228 NetworkLoadParameters parameters = m_parameters;
229 parameters.defersLoading = m_defersLoading;
230 parameters.request = request;
232 #if USE(NETWORK_SESSION)
233 if (request.url().protocolIsBlob())
234 parameters.blobFileReferences = NetworkBlobRegistry::singleton().filesInBlob(m_connection, originalRequest().url());
236 auto* networkSession = SessionTracker::networkSession(parameters.sessionID);
237 if (!networkSession) {
238 WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", parameters.sessionID.sessionID());
239 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());
240 NetworkProcess::singleton().logDiagnosticMessage(m_parameters.webPageID, WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::invalidSessionIDKey(), WebCore::ShouldSample::No);
241 didFailLoading(internalError(request.url()));
244 m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters), *networkSession);
246 m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters));
249 if (m_defersLoading) {
250 RELEASE_LOG_IF_ALLOWED("startNetworkLoad: Created, but deferred (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
251 m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
255 void NetworkResourceLoader::setDefersLoading(bool defers)
257 if (m_defersLoading == defers)
259 m_defersLoading = defers;
262 RELEASE_LOG_IF_ALLOWED("setDefersLoading: Deferring resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
264 RELEASE_LOG_IF_ALLOWED("setDefersLoading: Resuming deferred resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
267 m_networkLoad->setDefersLoading(defers);
271 if (!m_defersLoading && !m_wasStarted)
274 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);
277 void NetworkResourceLoader::cleanup()
279 ASSERT(RunLoop::isMain());
281 m_bufferingTimer.stop();
283 invalidateSandboxExtensions();
285 m_networkLoad = nullptr;
287 // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
288 m_connection->didCleanupResourceLoader(*this);
291 void NetworkResourceLoader::convertToDownload(DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
293 ASSERT(m_networkLoad);
294 NetworkProcess::singleton().downloadManager().convertNetworkLoadToDownload(downloadID, std::exchange(m_networkLoad, nullptr), WTFMove(m_fileReferences), request, response);
297 void NetworkResourceLoader::abort()
299 ASSERT(RunLoop::isMain());
301 RELEASE_LOG_IF_ALLOWED("abort: Canceling resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
302 m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
305 if (canUseCache(m_networkLoad->currentRequest())) {
306 // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
307 if (!m_response.isNull())
308 m_cache->remove(m_networkLoad->currentRequest());
310 m_networkLoad->cancel();
316 auto NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse) -> ShouldContinueDidReceiveResponse
318 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());
320 m_response = WTFMove(receivedResponse);
322 // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
323 if (!isSynchronous() && m_response.isMultipart())
324 m_bufferedData = nullptr;
326 if (m_response.isMultipart())
327 m_bufferedDataForCache = nullptr;
329 if (m_cacheEntryForValidation) {
330 bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
331 if (validationSucceeded) {
332 m_cacheEntryForValidation = m_cache->update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
333 // If the request was conditional then this revalidation was not triggered by the network cache and we pass the 304 response to WebCore.
334 if (originalRequest().isConditional())
335 m_cacheEntryForValidation = nullptr;
337 m_cacheEntryForValidation = nullptr;
339 bool shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
341 bool shouldWaitContinueDidReceiveResponse = isMainResource();
342 if (shouldSendDidReceiveResponse) {
344 m_synchronousLoadData->response = m_response;
346 send(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse));
349 // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
350 bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse || m_cacheEntryForValidation;
352 if (shouldContinueDidReceiveResponse) {
353 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);
354 return ShouldContinueDidReceiveResponse::Yes;
357 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);
358 return ShouldContinueDidReceiveResponse::No;
361 void NetworkResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
363 if (!m_numBytesReceived) {
364 RELEASE_LOG_IF_ALLOWED("didReceiveBuffer: Started receiving data (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
366 m_numBytesReceived += buffer->size();
368 ASSERT(!m_cacheEntryForValidation);
370 if (m_bufferedDataForCache) {
371 // Prevent memory growth in case of streaming data.
372 const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
373 if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
374 m_bufferedDataForCache->append(buffer.get());
376 m_bufferedDataForCache = nullptr;
378 // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
379 unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
381 m_bytesReceived += buffer->size();
382 if (m_bufferedData) {
383 m_bufferedData->append(buffer.get());
384 m_bufferedDataEncodedDataLength += encodedDataLength;
385 startBufferingTimerIfNeeded();
388 sendBuffer(buffer, encodedDataLength);
391 void NetworkResourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
393 RELEASE_LOG_IF_ALLOWED("didFinishLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", length = %zd)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, m_numBytesReceived);
395 if (m_cacheEntryForValidation) {
397 ASSERT(m_response.httpStatusCode() == 304);
398 LOG(NetworkCache, "(NetworkProcess) revalidated");
399 didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
403 #if HAVE(CFNETWORK_STORAGE_PARTITIONING) && !RELEASE_LOG_DISABLED
404 if (shouldLogCookieInformation())
405 logCookieInformation();
409 sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
411 if (m_bufferedData && !m_bufferedData->isEmpty()) {
412 // FIXME: Pass a real value or remove the encoded data size feature.
413 sendBuffer(*m_bufferedData, -1);
415 send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
418 tryStoreAsCacheEntry();
423 void NetworkResourceLoader::didFailLoading(const ResourceError& error)
425 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());
427 ASSERT(!error.isNull());
429 m_cacheEntryForValidation = nullptr;
431 if (isSynchronous()) {
432 m_synchronousLoadData->error = error;
433 sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
434 } else if (auto* connection = messageSenderConnection())
435 connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
440 void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, WebCore::ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
444 if (isSynchronous()) {
445 ResourceRequest overridenRequest = redirectRequest;
446 // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
447 // This includes at least updating host records, and comparing the current request instead of the original request here.
448 if (!protocolHostAndPortAreEqual(originalRequest().url(), redirectRequest.url())) {
449 ASSERT(m_synchronousLoadData->error.isNull());
450 m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
451 m_networkLoad->clearCurrentRequest();
452 overridenRequest = ResourceRequest();
454 // We do not support prompting for credentials for synchronous loads. If we ever change this policy then
455 // we need to take care to prompt if and only if request and redirectRequest are not mixed content.
456 continueWillSendRequest(WTFMove(overridenRequest), false);
459 send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
461 if (canUseCachedRedirect(request))
462 m_cache->storeRedirect(request, redirectResponse, redirectRequest);
465 void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
467 RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
469 m_isAllowedToAskUserForCredentials = isAllowedToAskUserForCredentials;
471 // If there is a match in the network cache, we need to reuse the original cache policy and partition.
472 newRequest.setCachePolicy(originalRequest().cachePolicy());
473 newRequest.setCachePartition(originalRequest().cachePartition());
475 if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
476 m_isWaitingContinueWillSendRequestForCachedRedirect = false;
478 LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
480 if (canUseCachedRedirect(newRequest))
481 retrieveCacheEntry(newRequest);
483 startNetworkLoad(newRequest);
489 m_networkLoad->continueWillSendRequest(WTFMove(newRequest));
492 void NetworkResourceLoader::continueDidReceiveResponse()
494 // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
495 // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
497 m_networkLoad->continueDidReceiveResponse();
500 void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
502 if (!isSynchronous())
503 send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
506 void NetworkResourceLoader::startBufferingTimerIfNeeded()
510 if (m_bufferingTimer.isActive())
512 m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
515 void NetworkResourceLoader::bufferingTimerFired()
517 ASSERT(m_bufferedData);
518 ASSERT(m_networkLoad);
520 if (m_bufferedData->isEmpty())
523 IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
524 size_t encodedLength = m_bufferedDataEncodedDataLength;
526 m_bufferedData = SharedBuffer::create();
527 m_bufferedDataEncodedDataLength = 0;
529 send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
532 void NetworkResourceLoader::sendBuffer(SharedBuffer& buffer, size_t encodedDataLength)
534 ASSERT(!isSynchronous());
536 IPC::SharedBufferDataReference dataReference(&buffer);
537 send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
540 void NetworkResourceLoader::tryStoreAsCacheEntry()
542 if (!canUseCache(m_networkLoad->currentRequest()))
544 if (!m_bufferedDataForCache)
547 m_cache->store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader = makeRef(*this)](auto& mappedBody) mutable {
548 #if ENABLE(SHAREABLE_RESOURCE)
549 if (mappedBody.shareableResourceHandle.isNull())
551 LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
552 loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
557 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
559 if (isSynchronous()) {
560 m_synchronousLoadData->response = entry->response();
561 sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
566 bool needsContinueDidReceiveResponseMessage = isMainResource();
567 send(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
569 if (entry->sourceStorageRecord().bodyHash && !m_parameters.derivedCachedDataTypesToRetrieve.isEmpty()) {
570 auto bodyHash = *entry->sourceStorageRecord().bodyHash;
571 auto* entryPtr = entry.release();
572 auto retrieveCount = m_parameters.derivedCachedDataTypesToRetrieve.size();
574 for (auto& type : m_parameters.derivedCachedDataTypesToRetrieve) {
575 NetworkCache::DataKey key { originalRequest().cachePartition(), type, bodyHash };
576 m_cache->retrieveData(key, [loader = makeRef(*this), entryPtr, type, retrieveCount] (const uint8_t* data, size_t size) mutable {
577 loader->m_retrievedDerivedDataCount++;
578 bool retrievedAll = loader->m_retrievedDerivedDataCount == retrieveCount;
579 std::unique_ptr<NetworkCache::Entry> entry(retrievedAll ? entryPtr : nullptr);
580 if (loader->hasOneRef())
583 IPC::DataReference dataReference(data, size);
584 loader->send(Messages::WebResourceLoader::DidRetrieveDerivedData(type, dataReference));
587 loader->sendResultForCacheEntry(WTFMove(entry));
595 sendResultForCacheEntry(WTFMove(entry));
600 void NetworkResourceLoader::sendResultForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
602 #if ENABLE(SHAREABLE_RESOURCE)
603 if (!entry->shareableResourceHandle().isNull()) {
604 send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle()));
609 #if HAVE(CFNETWORK_STORAGE_PARTITIONING) && !RELEASE_LOG_DISABLED
610 if (shouldLogCookieInformation())
611 logCookieInformation();
614 WebCore::NetworkLoadMetrics networkLoadMetrics;
615 networkLoadMetrics.markComplete();
616 networkLoadMetrics.requestHeaderBytesSent = 0;
617 networkLoadMetrics.requestBodyBytesSent = 0;
618 networkLoadMetrics.responseHeaderBytesReceived = 0;
619 networkLoadMetrics.responseBodyBytesReceived = 0;
620 networkLoadMetrics.responseBodyDecodedSize = 0;
622 sendBuffer(*entry->buffer(), entry->buffer()->size());
623 send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
626 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
628 ASSERT(!m_networkLoad);
630 // If the request is already conditional then the revalidation was not triggered by the disk cache
631 // and we should not overwrite the existing conditional headers.
632 ResourceRequest revalidationRequest = originalRequest();
633 if (!revalidationRequest.isConditional()) {
634 String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
635 String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
637 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
638 if (!lastModified.isEmpty())
639 revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
642 m_cacheEntryForValidation = WTFMove(entry);
644 startNetworkLoad(revalidationRequest);
647 void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
649 ASSERT(entry->redirectRequest());
650 ASSERT(!m_isWaitingContinueWillSendRequestForCachedRedirect);
652 LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
655 send(Messages::WebResourceLoader::WillSendRequest(*entry->redirectRequest(), entry->response()));
656 m_isWaitingContinueWillSendRequestForCachedRedirect = true;
659 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
661 return &connectionToWebProcess().connection();
664 void NetworkResourceLoader::consumeSandboxExtensions()
666 ASSERT(!m_didConsumeSandboxExtensions);
668 for (auto& extension : m_parameters.requestBodySandboxExtensions)
669 extension->consume();
671 if (auto& extension = m_parameters.resourceSandboxExtension)
672 extension->consume();
674 for (auto& fileReference : m_fileReferences)
675 fileReference->prepareForFileAccess();
677 m_didConsumeSandboxExtensions = true;
680 void NetworkResourceLoader::invalidateSandboxExtensions()
682 if (m_didConsumeSandboxExtensions) {
683 for (auto& extension : m_parameters.requestBodySandboxExtensions)
685 if (auto& extension = m_parameters.resourceSandboxExtension)
687 for (auto& fileReference : m_fileReferences)
688 fileReference->revokeFileAccess();
690 m_didConsumeSandboxExtensions = false;
693 m_fileReferences.clear();
696 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
697 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(const ProtectionSpace& protectionSpace)
699 NetworkProcess::singleton().canAuthenticateAgainstProtectionSpace(*this, protectionSpace);
702 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
705 m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(result);
709 bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
711 return sessionID().isAlwaysOnLoggingAllowed();
714 bool NetworkResourceLoader::shouldCaptureExtraNetworkLoadMetrics() const
716 return m_connection->captureExtraNetworkLoadMetricsEnabled();
719 #if HAVE(CFNETWORK_STORAGE_PARTITIONING) && !RELEASE_LOG_DISABLED
720 bool NetworkResourceLoader::shouldLogCookieInformation() const
722 return NetworkProcess::singleton().shouldLogCookieInformation();
725 void NetworkResourceLoader::logCookieInformation() const
727 auto networkStorageSession = WebCore::NetworkStorageSession::storageSession(sessionID());
728 ASSERT(networkStorageSession);
730 auto url = originalRequest().url();
731 auto partition = WebCore::URL(ParsedURLString, networkStorageSession->cookieStoragePartition(originalRequest(), frameID(), pageID()));
733 Vector<WebCore::Cookie> cookies;
734 bool result = WebCore::getRawCookies(*networkStorageSession, partition, url, frameID(), pageID(), cookies);
737 #define LOCAL_LOG(str, ...) \
738 RELEASE_LOG_IF_ALLOWED("logCookieInformation: pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ": " str, pageID(), frameID(), identifier(), ##__VA_ARGS__)
740 LOCAL_LOG(R"({ "url": "%{public}s",)", url.string().utf8().data());
741 LOCAL_LOG(R"( "partition": "%{public}s",)", partition.string().utf8().data());
742 LOCAL_LOG(R"( "referer": "%{public}s",)", originalRequest().httpReferrer().utf8().data());
743 LOCAL_LOG(R"( "cookies": [)");
745 auto size = cookies.size();
746 decltype(size) count = 0;
747 for (const auto& cookie : cookies) {
748 const char* trailingComma = ",";
752 LOCAL_LOG(R"( { "name": "%{public}s")", cookie.name.utf8().data());
753 LOCAL_LOG(R"( "value": "%{public}s")", cookie.value.utf8().data());
754 LOCAL_LOG(R"( "domain": "%{public}s")", cookie.domain.utf8().data());
755 LOCAL_LOG(R"( "path": "%{public}s")", cookie.path.utf8().data());
756 LOCAL_LOG(R"( "created": %f)", cookie.created);
757 LOCAL_LOG(R"( "expires": %f)", cookie.expires);
758 LOCAL_LOG(R"( "httpOnly": %{public}s)", cookie.httpOnly ? "true" : "false");
759 LOCAL_LOG(R"( "secure": %{public}s)", cookie.secure ? "true" : "false");
760 LOCAL_LOG(R"( "session": %{public}s)", cookie.session ? "true" : "false");
761 LOCAL_LOG(R"( "comment": "%{public}s")", cookie.comment.utf8().data());
762 LOCAL_LOG(R"( "commentURL": "%{public}s")", cookie.commentURL.string().utf8().data());
763 LOCAL_LOG(R"( }%{public}s)", trailingComma);
771 } // namespace WebKit