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