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