Incorrect release log message emitted when waiting/not waiting for the WebProcess...
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkResourceLoader.cpp
1 /*
2  * Copyright (C) 2012-2015 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 #include "DataReference.h"
30 #include "Logging.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/ProtectionSpace.h>
46 #include <WebCore/SharedBuffer.h>
47 #include <WebCore/SynchronousLoaderClient.h>
48 #include <wtf/CurrentTime.h>
49 #include <wtf/RunLoop.h>
50
51 using namespace WebCore;
52
53 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
54 #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
55
56 namespace WebKit {
57
58 struct NetworkResourceLoader::SynchronousLoadData {
59     SynchronousLoadData(RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
60         : delayedReply(WTFMove(reply))
61     {
62         ASSERT(delayedReply);
63     }
64     ResourceRequest currentRequest;
65     RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
66     ResourceResponse response;
67     ResourceError error;
68 };
69
70 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
71 {
72     ASSERT(data.delayedReply);
73     ASSERT(!data.response.isNull() || !data.error.isNull());
74
75     Vector<char> responseBuffer;
76     if (buffer && buffer->size())
77         responseBuffer.append(buffer->data(), buffer->size());
78
79     data.delayedReply->send(data.error, data.response, responseBuffer);
80     data.delayedReply = nullptr;
81 }
82
83 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
84     : m_parameters(parameters)
85     , m_connection(connection)
86     , m_defersLoading(parameters.defersLoading)
87     , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
88 {
89     ASSERT(RunLoop::isMain());
90     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
91     //        Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
92     ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
93
94     if (originalRequest().httpBody()) {
95         for (const auto& element : originalRequest().httpBody()->elements()) {
96             if (element.m_type == FormDataElement::Type::EncodedBlob)
97                 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
98         }
99     }
100
101 #if !USE(NETWORK_SESSION)
102     if (originalRequest().url().protocolIsBlob()) {
103         ASSERT(!m_parameters.resourceSandboxExtension);
104         m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
105     }
106 #endif
107
108
109     if (synchronousReply)
110         m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
111 }
112
113 NetworkResourceLoader::~NetworkResourceLoader()
114 {
115     ASSERT(RunLoop::isMain());
116     ASSERT(!m_networkLoad);
117     ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
118 }
119
120 #if ENABLE(NETWORK_CACHE)
121 bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
122 {
123     if (!NetworkCache::singleton().isEnabled())
124         return false;
125     if (sessionID().isEphemeral())
126         return false;
127     if (!request.url().protocolIsInHTTPFamily())
128         return false;
129     if (originalRequest().cachePolicy() == WebCore::DoNotUseAnyCache)
130         return false;
131
132     return true;
133 }
134
135 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
136 {
137     if (!canUseCache(request))
138         return false;
139     // Limit cached redirects to avoid cycles and other trouble.
140     // Networking layer follows over 30 redirects but caching that many seems unnecessary.
141     static const unsigned maximumCachedRedirectCount { 5 };
142     if (m_redirectCount > maximumCachedRedirectCount)
143         return false;
144
145     return true;
146 }
147 #endif
148
149 bool NetworkResourceLoader::isSynchronous() const
150 {
151     return !!m_synchronousLoadData;
152 }
153
154 void NetworkResourceLoader::start()
155 {
156     ASSERT(RunLoop::isMain());
157
158     if (m_defersLoading) {
159         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());
160         return;
161     }
162
163 #if ENABLE(NETWORK_CACHE)
164     if (canUseCache(originalRequest())) {
165         RELEASE_LOG_IF_ALLOWED("start: Retrieving resource from cache (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
166         retrieveCacheEntry(originalRequest());
167         return;
168     }
169 #endif
170
171     startNetworkLoad(originalRequest());
172 }
173
174 #if ENABLE(NETWORK_CACHE)
175 void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
176 {
177     ASSERT(canUseCache(request));
178
179     RefPtr<NetworkResourceLoader> loader(this);
180     NetworkCache::singleton().retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [loader, request](auto entry) {
181         if (loader->hasOneRef()) {
182             // The loader has been aborted and is only held alive by this lambda.
183             return;
184         }
185         if (!entry) {
186             loader->startNetworkLoad(request);
187             return;
188         }
189         if (entry->redirectRequest()) {
190             loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry));
191             return;
192         }
193         if (loader->m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) {
194             loader->startNetworkLoad(request);
195             return;
196         }
197         if (entry->needsValidation() || request.cachePolicy() == WebCore::RefreshAnyCacheData) {
198             loader->validateCacheEntry(WTFMove(entry));
199             return;
200         }
201         loader->didRetrieveCacheEntry(WTFMove(entry));
202     });
203 }
204 #endif
205
206 void NetworkResourceLoader::startNetworkLoad(const ResourceRequest& request)
207 {
208     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());
209
210     consumeSandboxExtensions();
211
212     if (isSynchronous() || m_parameters.maximumBufferingTime > 0ms)
213         m_bufferedData = SharedBuffer::create();
214
215 #if ENABLE(NETWORK_CACHE)
216     if (canUseCache(request))
217         m_bufferedDataForCache = SharedBuffer::create();
218 #endif
219
220     NetworkLoadParameters parameters = m_parameters;
221     parameters.defersLoading = m_defersLoading;
222     parameters.request = request;
223
224 #if USE(NETWORK_SESSION)
225     if (request.url().protocolIsBlob())
226         parameters.blobFileReferences = NetworkBlobRegistry::singleton().filesInBlob(m_connection, originalRequest().url());
227
228     auto* networkSession = SessionTracker::networkSession(parameters.sessionID);
229     if (!networkSession) {
230         WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", parameters.sessionID.sessionID());
231         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());
232         NetworkProcess::singleton().logDiagnosticMessage(m_parameters.webPageID, WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::invalidSessionIDKey(), WebCore::ShouldSample::No);
233         didFailLoading(internalError(request.url()));
234         return;
235     }
236     m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters), *networkSession);
237 #else
238     m_networkLoad = std::make_unique<NetworkLoad>(*this, WTFMove(parameters));
239 #endif
240
241     if (m_defersLoading) {
242         RELEASE_LOG_IF_ALLOWED("startNetworkLoad: Created, but deferred (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
243             m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
244     }
245 }
246
247 void NetworkResourceLoader::setDefersLoading(bool defers)
248 {
249     if (m_defersLoading == defers)
250         return;
251     m_defersLoading = defers;
252
253     if (defers)
254         RELEASE_LOG_IF_ALLOWED("setDefersLoading: Deferring resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
255     else
256         RELEASE_LOG_IF_ALLOWED("setDefersLoading: Resuming deferred resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
257
258     if (m_networkLoad) {
259         m_networkLoad->setDefersLoading(defers);
260         return;
261     }
262
263     if (!m_defersLoading)
264         start();
265     else
266         RELEASE_LOG_IF_ALLOWED("setDefersLoading: defers = TRUE, but nothing to stop (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
267 }
268
269 void NetworkResourceLoader::cleanup()
270 {
271     ASSERT(RunLoop::isMain());
272
273     m_bufferingTimer.stop();
274
275     invalidateSandboxExtensions();
276
277     m_networkLoad = nullptr;
278
279     // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
280     m_connection->didCleanupResourceLoader(*this);
281 }
282
283 void NetworkResourceLoader::convertToDownload(DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
284 {
285     ASSERT(m_networkLoad);
286     NetworkProcess::singleton().downloadManager().convertNetworkLoadToDownload(downloadID, WTFMove(m_networkLoad), WTFMove(m_fileReferences), request, response);
287 }
288
289 void NetworkResourceLoader::abort()
290 {
291     ASSERT(RunLoop::isMain());
292
293     RELEASE_LOG_IF_ALLOWED("abort: Canceling resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
294         m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
295
296     if (m_networkLoad) {
297 #if ENABLE(NETWORK_CACHE)
298         if (canUseCache(m_networkLoad->currentRequest())) {
299             // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
300             if (!m_response.isNull())
301                 NetworkCache::singleton().remove(m_networkLoad->currentRequest());
302         }
303 #endif
304         m_networkLoad->cancel();
305     }
306
307     cleanup();
308 }
309
310 auto NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse) -> ShouldContinueDidReceiveResponse
311 {
312     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());
313
314     m_response = WTFMove(receivedResponse);
315
316     // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
317     if (!isSynchronous() && m_response.isMultipart())
318         m_bufferedData = nullptr;
319
320     bool shouldSendDidReceiveResponse = true;
321 #if ENABLE(NETWORK_CACHE)
322     if (m_response.isMultipart())
323         m_bufferedDataForCache = nullptr;
324
325     if (m_cacheEntryForValidation) {
326         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
327         if (validationSucceeded) {
328             m_cacheEntryForValidation = NetworkCache::singleton().update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
329             // If the request was conditional then this revalidation was not triggered by the network cache and we pass the 304 response to WebCore.
330             if (originalRequest().isConditional())
331                 m_cacheEntryForValidation = nullptr;
332         } else
333             m_cacheEntryForValidation = nullptr;
334     }
335     shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
336 #endif
337
338     bool shouldWaitContinueDidReceiveResponse = isMainResource();
339     if (shouldSendDidReceiveResponse) {
340         if (isSynchronous())
341             m_synchronousLoadData->response = m_response;
342         else
343             send(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse));
344     }
345
346     // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
347     bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse;
348 #if ENABLE(NETWORK_CACHE)
349     shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
350 #endif
351
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;
355     }
356
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;
359 }
360
361 void NetworkResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
362 {
363     if (!m_hasReceivedData) {
364         RELEASE_LOG_IF_ALLOWED("didReceiveBuffer: Started receiving data (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
365         m_hasReceivedData = true;
366     }
367
368 #if ENABLE(NETWORK_CACHE)
369     ASSERT(!m_cacheEntryForValidation);
370
371     if (m_bufferedDataForCache) {
372         // Prevent memory growth in case of streaming data.
373         const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
374         if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
375             m_bufferedDataForCache->append(buffer.get());
376         else
377             m_bufferedDataForCache = nullptr;
378     }
379 #endif
380     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
381     unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
382
383     m_bytesReceived += buffer->size();
384     if (m_bufferedData) {
385         m_bufferedData->append(buffer.get());
386         m_bufferedDataEncodedDataLength += encodedDataLength;
387         startBufferingTimerIfNeeded();
388         return;
389     }
390     sendBuffer(buffer, encodedDataLength);
391 }
392
393 void NetworkResourceLoader::didFinishLoading(double finishTime)
394 {
395     RELEASE_LOG_IF_ALLOWED("didFinishLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
396
397 #if ENABLE(NETWORK_CACHE)
398     if (m_cacheEntryForValidation) {
399         // 304 Not Modified
400         ASSERT(m_response.httpStatusCode() == 304);
401         LOG(NetworkCache, "(NetworkProcess) revalidated");
402         didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
403         return;
404     }
405 #endif
406
407     if (isSynchronous())
408         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
409     else {
410         if (m_bufferedData && !m_bufferedData->isEmpty()) {
411             // FIXME: Pass a real value or remove the encoded data size feature.
412             sendBuffer(*m_bufferedData, -1);
413         }
414         send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
415     }
416
417 #if ENABLE(NETWORK_CACHE)
418     tryStoreAsCacheEntry();
419 #endif
420
421     cleanup();
422 }
423
424 void NetworkResourceLoader::didFailLoading(const ResourceError& error)
425 {
426     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
428     ASSERT(!error.isNull());
429
430 #if ENABLE(NETWORK_CACHE)
431     m_cacheEntryForValidation = nullptr;
432 #endif
433
434     if (isSynchronous()) {
435         m_synchronousLoadData->error = error;
436         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
437     } else if (auto* connection = messageSenderConnection())
438         connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
439
440     cleanup();
441 }
442
443 void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, WebCore::ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
444 {
445     ++m_redirectCount;
446
447     if (isSynchronous()) {
448         ResourceRequest overridenRequest = redirectRequest;
449         // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
450         // This includes at least updating host records, and comparing the current request instead of the original request here.
451         if (!protocolHostAndPortAreEqual(originalRequest().url(), redirectRequest.url())) {
452             ASSERT(m_synchronousLoadData->error.isNull());
453             m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
454             m_networkLoad->clearCurrentRequest();
455             overridenRequest = ResourceRequest();
456         }
457         continueWillSendRequest(WTFMove(overridenRequest));
458         return;
459     }
460     send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
461
462 #if ENABLE(NETWORK_CACHE)
463     if (canUseCachedRedirect(request))
464         NetworkCache::singleton().storeRedirect(request, redirectResponse, redirectRequest);
465 #else
466     UNUSED_PARAM(request);
467 #endif
468 }
469
470 void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest)
471 {
472     RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
473
474     // If there is a match in the network cache, we need to reuse the original cache policy.
475     newRequest.setCachePolicy(originalRequest().cachePolicy());
476
477 #if ENABLE(NETWORK_CACHE)
478     if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
479         LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
480
481         if (canUseCachedRedirect(newRequest))
482             retrieveCacheEntry(newRequest);
483         else
484             startNetworkLoad(newRequest);
485
486         m_isWaitingContinueWillSendRequestForCachedRedirect = false;
487         return;
488     }
489 #endif
490
491     if (m_networkLoad)
492         m_networkLoad->continueWillSendRequest(WTFMove(newRequest));
493 }
494
495 void NetworkResourceLoader::continueDidReceiveResponse()
496 {
497     // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
498     // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
499     if (m_networkLoad)
500         m_networkLoad->continueDidReceiveResponse();
501 }
502
503 void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
504 {
505     if (!isSynchronous())
506         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
507 }
508
509 void NetworkResourceLoader::startBufferingTimerIfNeeded()
510 {
511     if (isSynchronous())
512         return;
513     if (m_bufferingTimer.isActive())
514         return;
515     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
516 }
517
518 void NetworkResourceLoader::bufferingTimerFired()
519 {
520     ASSERT(m_bufferedData);
521     ASSERT(m_networkLoad);
522
523     if (m_bufferedData->isEmpty())
524         return;
525
526     IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
527     size_t encodedLength = m_bufferedDataEncodedDataLength;
528
529     m_bufferedData = SharedBuffer::create();
530     m_bufferedDataEncodedDataLength = 0;
531
532     send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
533 }
534
535 void NetworkResourceLoader::sendBuffer(SharedBuffer& buffer, size_t encodedDataLength)
536 {
537     ASSERT(!isSynchronous());
538
539     IPC::SharedBufferDataReference dataReference(&buffer);
540     send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
541 }
542
543 #if ENABLE(NETWORK_CACHE)
544 void NetworkResourceLoader::tryStoreAsCacheEntry()
545 {
546     if (!canUseCache(m_networkLoad->currentRequest()))
547         return;
548     if (!m_bufferedDataForCache)
549         return;
550
551     NetworkCache::singleton().store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader = makeRef(*this)](auto& mappedBody) mutable {
552 #if ENABLE(SHAREABLE_RESOURCE)
553         if (mappedBody.shareableResourceHandle.isNull())
554             return;
555         LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
556         loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
557 #endif
558     });
559 }
560
561 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
562 {
563     if (isSynchronous()) {
564         m_synchronousLoadData->response = entry->response();
565         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
566     } else {
567         bool needsContinueDidReceiveResponseMessage = isMainResource();
568         send(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
569
570 #if ENABLE(SHAREABLE_RESOURCE)
571         if (!entry->shareableResourceHandle().isNull())
572             send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle(), currentTime()));
573         else {
574 #endif
575             sendBuffer(*entry->buffer(), entry->buffer()->size());
576             send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
577 #if ENABLE(SHAREABLE_RESOURCE)
578         }
579 #endif
580     }
581
582     cleanup();
583 }
584
585 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
586 {
587     ASSERT(!m_networkLoad);
588
589     // If the request is already conditional then the revalidation was not triggered by the disk cache
590     // and we should not overwrite the existing conditional headers.
591     ResourceRequest revalidationRequest = originalRequest();
592     if (!revalidationRequest.isConditional()) {
593         String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
594         String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
595         if (!eTag.isEmpty())
596             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
597         if (!lastModified.isEmpty())
598             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
599     }
600
601     m_cacheEntryForValidation = WTFMove(entry);
602
603     startNetworkLoad(revalidationRequest);
604 }
605
606 void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
607 {
608     ASSERT(entry->redirectRequest());
609     LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
610
611     ++m_redirectCount;
612     send(Messages::WebResourceLoader::WillSendRequest(*entry->redirectRequest(), entry->response()));
613     m_isWaitingContinueWillSendRequestForCachedRedirect = true;
614 }
615 #endif
616
617 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
618 {
619     return &connectionToWebProcess().connection();
620 }
621
622 void NetworkResourceLoader::consumeSandboxExtensions()
623 {
624     ASSERT(!m_didConsumeSandboxExtensions);
625
626     for (auto& extension : m_parameters.requestBodySandboxExtensions)
627         extension->consume();
628
629     if (auto& extension = m_parameters.resourceSandboxExtension)
630         extension->consume();
631
632     for (auto& fileReference : m_fileReferences)
633         fileReference->prepareForFileAccess();
634
635     m_didConsumeSandboxExtensions = true;
636 }
637
638 void NetworkResourceLoader::invalidateSandboxExtensions()
639 {
640     if (m_didConsumeSandboxExtensions) {
641         for (auto& extension : m_parameters.requestBodySandboxExtensions)
642             extension->revoke();
643         if (auto& extension = m_parameters.resourceSandboxExtension)
644             extension->revoke();
645         for (auto& fileReference : m_fileReferences)
646             fileReference->revokeFileAccess();
647
648         m_didConsumeSandboxExtensions = false;
649     }
650
651     m_fileReferences.clear();
652 }
653
654 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
655 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(const ProtectionSpace& protectionSpace)
656 {
657     NetworkProcess::singleton().canAuthenticateAgainstProtectionSpace(*this, protectionSpace);
658 }
659
660 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
661 {
662     if (m_networkLoad)
663         m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(result);
664 }
665 #endif
666
667 bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
668 {
669     return sessionID().isAlwaysOnLoggingAllowed();
670 }
671
672 } // namespace WebKit