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