4367a4ee7e922d395babdb3305038e6047109a28
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkResourceLoader.cpp
1 /*
2  * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkResourceLoader.h"
28
29 #include "DataReference.h"
30 #include "Logging.h"
31 #include "NetworkBlobRegistry.h"
32 #include "NetworkCache.h"
33 #include "NetworkConnectionToWebProcess.h"
34 #include "NetworkLoad.h"
35 #include "NetworkProcessConnectionMessages.h"
36 #include "WebCoreArgumentCoders.h"
37 #include "WebResourceLoaderMessages.h"
38 #include <WebCore/BlobDataFileReference.h>
39 #include <WebCore/CertificateInfo.h>
40 #include <WebCore/HTTPHeaderNames.h>
41 #include <WebCore/ProtectionSpace.h>
42 #include <WebCore/SharedBuffer.h>
43 #include <WebCore/SynchronousLoaderClient.h>
44 #include <wtf/CurrentTime.h>
45 #include <wtf/RunLoop.h>
46
47 using namespace WebCore;
48
49 #define NETWORKRESOURCELOADER_LOG_ALWAYS(...) LOG_ALWAYS(isAlwaysOnLoggingAllowed(), __VA_ARGS__)
50 #define NETWORKRESOURCELOADER_LOG_ALWAYS_ERROR(...) LOG_ALWAYS_ERROR(isAlwaysOnLoggingAllowed(), __VA_ARGS__)
51
52 namespace WebKit {
53
54 struct NetworkResourceLoader::SynchronousLoadData {
55     SynchronousLoadData(RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
56         : delayedReply(WTFMove(reply))
57     {
58         ASSERT(delayedReply);
59     }
60     ResourceRequest currentRequest;
61     RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
62     ResourceResponse response;
63     ResourceError error;
64 };
65
66 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
67 {
68     ASSERT(data.delayedReply);
69     ASSERT(!data.response.isNull() || !data.error.isNull());
70
71     Vector<char> responseBuffer;
72     if (buffer && buffer->size())
73         responseBuffer.append(buffer->data(), buffer->size());
74
75     data.delayedReply->send(data.error, data.response, responseBuffer);
76     data.delayedReply = nullptr;
77 }
78
79 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess& connection, RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& synchronousReply)
80     : m_parameters(parameters)
81     , m_connection(connection)
82     , m_defersLoading(parameters.defersLoading)
83     , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
84 {
85     ASSERT(RunLoop::isMain());
86     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
87     //        Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
88     ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials);
89
90     if (originalRequest().httpBody()) {
91         for (const auto& element : originalRequest().httpBody()->elements()) {
92             if (element.m_type == FormDataElement::Type::EncodedBlob)
93                 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
94         }
95     }
96
97     if (originalRequest().url().protocolIsBlob()) {
98         ASSERT(!m_parameters.resourceSandboxExtension);
99         m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
100     }
101
102     if (synchronousReply)
103         m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
104 }
105
106 NetworkResourceLoader::~NetworkResourceLoader()
107 {
108     ASSERT(RunLoop::isMain());
109     ASSERT(!m_networkLoad);
110     ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
111 }
112
113 #if ENABLE(NETWORK_CACHE)
114 bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
115 {
116     if (!NetworkCache::singleton().isEnabled())
117         return false;
118     if (sessionID().isEphemeral())
119         return false;
120     if (!request.url().protocolIsInHTTPFamily())
121         return false;
122
123     return true;
124 }
125
126 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
127 {
128     if (!canUseCache(request))
129         return false;
130     // Limit cached redirects to avoid cycles and other trouble.
131     // Networking layer follows over 30 redirects but caching that many seems unnecessary.
132     static const unsigned maximumCachedRedirectCount { 5 };
133     if (m_redirectCount > maximumCachedRedirectCount)
134         return false;
135
136     return true;
137 }
138 #endif
139
140 bool NetworkResourceLoader::isSynchronous() const
141 {
142     return !!m_synchronousLoadData;
143 }
144
145 void NetworkResourceLoader::start()
146 {
147     ASSERT(RunLoop::isMain());
148
149     if (m_defersLoading)
150         return;
151
152 #if ENABLE(NETWORK_CACHE)
153     if (canUseCache(originalRequest())) {
154         retrieveCacheEntry(originalRequest());
155         return;
156     }
157 #endif
158
159     startNetworkLoad(originalRequest());
160 }
161
162 #if ENABLE(NETWORK_CACHE)
163 void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
164 {
165     ASSERT(canUseCache(request));
166
167     RefPtr<NetworkResourceLoader> loader(this);
168     NetworkCache::singleton().retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [loader, request](std::unique_ptr<NetworkCache::Entry> entry) {
169         if (loader->hasOneRef()) {
170             // The loader has been aborted and is only held alive by this lambda.
171             return;
172         }
173         if (!entry) {
174             loader->startNetworkLoad(request);
175             return;
176         }
177         if (entry->redirectRequest()) {
178             loader->dispatchWillSendRequestForCacheEntry(WTFMove(entry));
179             return;
180         }
181         if (loader->m_parameters.needsCertificateInfo && !entry->response().containsCertificateInfo()) {
182             loader->startNetworkLoad(request);
183             return;
184         }
185         if (entry->needsValidation()) {
186             loader->validateCacheEntry(WTFMove(entry));
187             return;
188         }
189         loader->didRetrieveCacheEntry(WTFMove(entry));
190     });
191 }
192 #endif
193
194 void NetworkResourceLoader::startNetworkLoad(const ResourceRequest& request)
195 {
196     consumeSandboxExtensions();
197
198     if (isSynchronous() || m_parameters.maximumBufferingTime > 0ms)
199         m_bufferedData = SharedBuffer::create();
200
201 #if ENABLE(NETWORK_CACHE)
202     if (canUseCache(request))
203         m_bufferedDataForCache = SharedBuffer::create();
204 #endif
205
206     NETWORKRESOURCELOADER_LOG_ALWAYS("Starting network resource load: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, m_parameters.webPageID, m_parameters.webFrameID, isMainResource(), isSynchronous());
207
208     NetworkLoadParameters parameters = m_parameters;
209     parameters.defersLoading = m_defersLoading;
210     parameters.request = request;
211     m_networkLoad = std::make_unique<NetworkLoad>(*this, parameters);
212 }
213
214 void NetworkResourceLoader::setDefersLoading(bool defers)
215 {
216     if (m_defersLoading == defers)
217         return;
218     m_defersLoading = defers;
219
220     if (m_networkLoad) {
221         m_networkLoad->setDefersLoading(defers);
222         return;
223     }
224
225     if (!m_defersLoading)
226         start();
227 }
228
229 void NetworkResourceLoader::cleanup()
230 {
231     ASSERT(RunLoop::isMain());
232
233     m_bufferingTimer.stop();
234
235     invalidateSandboxExtensions();
236
237     m_networkLoad = nullptr;
238
239     // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
240     m_connection->didCleanupResourceLoader(*this);
241 }
242
243 void NetworkResourceLoader::didConvertToDownload()
244 {
245     ASSERT(!m_didConvertToDownload);
246     ASSERT(m_networkLoad);
247     m_didConvertToDownload = true;
248 }
249     
250 #if USE(NETWORK_SESSION)
251 void NetworkResourceLoader::didBecomeDownload()
252 {
253     ASSERT(m_didConvertToDownload);
254     ASSERT(m_networkLoad);
255     m_networkLoad = nullptr;
256 }
257 #endif
258
259 void NetworkResourceLoader::abort()
260 {
261     ASSERT(RunLoop::isMain());
262
263     if (m_networkLoad && !m_didConvertToDownload) {
264 #if ENABLE(NETWORK_CACHE)
265         if (canUseCache(m_networkLoad->currentRequest())) {
266             // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
267             if (!m_response.isNull())
268                 NetworkCache::singleton().remove(m_networkLoad->currentRequest());
269         }
270 #endif
271         m_networkLoad->cancel();
272     }
273
274     cleanup();
275 }
276
277 auto NetworkResourceLoader::didReceiveResponse(const ResourceResponse& receivedResponse) -> ShouldContinueDidReceiveResponse
278 {
279     NETWORKRESOURCELOADER_LOG_ALWAYS("Received network resource response: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d, httpStatusCode = %d", this, m_parameters.webPageID, m_parameters.webFrameID, isMainResource(), isSynchronous(), receivedResponse.httpStatusCode());
280
281     m_response = receivedResponse;
282
283     // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
284     if (!isSynchronous() && m_response.isMultipart())
285         m_bufferedData = nullptr;
286
287     bool shouldSendDidReceiveResponse = true;
288 #if ENABLE(NETWORK_CACHE)
289     if (m_response.isMultipart())
290         m_bufferedDataForCache = nullptr;
291
292     if (m_cacheEntryForValidation) {
293         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
294         if (validationSucceeded) {
295             NetworkCache::singleton().update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
296             // If the request was conditional then this revalidation was not triggered by the network cache and we pass the
297             // 304 response to WebCore.
298             if (originalRequest().isConditional())
299                 m_cacheEntryForValidation = nullptr;
300         } else
301             m_cacheEntryForValidation = nullptr;
302     }
303     shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
304 #endif
305
306     bool shouldWaitContinueDidReceiveResponse = isMainResource();
307     if (shouldSendDidReceiveResponse) {
308         if (isSynchronous())
309             m_synchronousLoadData->response = m_response;
310         else {
311             NETWORKRESOURCELOADER_LOG_ALWAYS("Sending didReceiveResponse message to the WebContent process: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
312             if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse))) {
313                 NETWORKRESOURCELOADER_LOG_ALWAYS_ERROR("Failed to send the didReceiveResponse IPC message to the WebContent process: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
314                 return ShouldContinueDidReceiveResponse::No;
315             }
316         }
317     }
318
319     // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
320     bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse;
321 #if ENABLE(NETWORK_CACHE)
322     shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
323 #endif
324
325     if (shouldContinueDidReceiveResponse) {
326         NETWORKRESOURCELOADER_LOG_ALWAYS("Should wait for message from WebContent process before continuing resource load: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
327         return ShouldContinueDidReceiveResponse::Yes;
328     }
329
330     NETWORKRESOURCELOADER_LOG_ALWAYS("Should not wait for message from WebContent process before continuing resource load: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
331     return ShouldContinueDidReceiveResponse::No;
332 }
333
334 void NetworkResourceLoader::didReceiveBuffer(RefPtr<SharedBuffer>&& buffer, int reportedEncodedDataLength)
335 {
336 #if ENABLE(NETWORK_CACHE)
337     ASSERT(!m_cacheEntryForValidation);
338
339     if (m_bufferedDataForCache) {
340         // Prevent memory growth in case of streaming data.
341         const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
342         if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
343             m_bufferedDataForCache->append(buffer.get());
344         else
345             m_bufferedDataForCache = nullptr;
346     }
347 #endif
348     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
349     unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
350
351     m_bytesReceived += buffer->size();
352     if (m_bufferedData) {
353         m_bufferedData->append(buffer.get());
354         m_bufferedDataEncodedDataLength += encodedDataLength;
355         startBufferingTimerIfNeeded();
356         return;
357     }
358     sendBufferMaybeAborting(*buffer, encodedDataLength);
359 }
360
361 void NetworkResourceLoader::didFinishLoading(double finishTime)
362 {
363     NETWORKRESOURCELOADER_LOG_ALWAYS("Finished loading network resource: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
364
365 #if ENABLE(NETWORK_CACHE)
366     if (m_cacheEntryForValidation) {
367         // 304 Not Modified
368         ASSERT(m_response.httpStatusCode() == 304);
369         LOG(NetworkCache, "(NetworkProcess) revalidated");
370         didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
371         return;
372     }
373 #endif
374
375     if (isSynchronous())
376         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
377     else {
378         if (m_bufferedData && !m_bufferedData->isEmpty()) {
379             // FIXME: Pass a real value or remove the encoded data size feature.
380             bool shouldContinue = sendBufferMaybeAborting(*m_bufferedData, -1);
381             if (!shouldContinue)
382                 return;
383         }
384         send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
385     }
386
387 #if ENABLE(NETWORK_CACHE)
388     tryStoreAsCacheEntry();
389 #endif
390
391     cleanup();
392 }
393
394 void NetworkResourceLoader::didFailLoading(const ResourceError& error)
395 {
396     NETWORKRESOURCELOADER_LOG_ALWAYS("Failed loading network resource: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d, isTimeout = %d, isCancellation = %d, errCode = %d", this, m_parameters.webPageID, m_parameters.webFrameID, isMainResource(), isSynchronous(), error.isTimeout(), error.isCancellation(), error.errorCode());
397
398     ASSERT(!error.isNull());
399
400 #if ENABLE(NETWORK_CACHE)
401     m_cacheEntryForValidation = nullptr;
402 #endif
403
404     if (isSynchronous()) {
405         m_synchronousLoadData->error = error;
406         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
407     } else
408         send(Messages::WebResourceLoader::DidFailResourceLoad(error));
409
410     cleanup();
411 }
412
413 void NetworkResourceLoader::willSendRedirectedRequest(const ResourceRequest& request, const WebCore::ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
414 {
415     ++m_redirectCount;
416
417     if (isSynchronous()) {
418         ResourceRequest overridenRequest = redirectRequest;
419         // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
420         // This includes at least updating host records, and comparing the current request instead of the original request here.
421         if (!protocolHostAndPortAreEqual(originalRequest().url(), redirectRequest.url())) {
422             ASSERT(m_synchronousLoadData->error.isNull());
423             m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
424             m_networkLoad->clearCurrentRequest();
425             overridenRequest = ResourceRequest();
426         }
427         continueWillSendRequest(overridenRequest);
428         return;
429     }
430     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
431
432 #if ENABLE(NETWORK_CACHE)
433     if (canUseCachedRedirect(request))
434         NetworkCache::singleton().storeRedirect(request, redirectResponse, redirectRequest);
435 #else
436     UNUSED_PARAM(request);
437 #endif
438 }
439
440 void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest)
441 {
442     NETWORKRESOURCELOADER_LOG_ALWAYS("Following redirect of network resource: loader = %p, pageID = %llu, frameID = %llu, isMainResource = %d, isSynchronous = %d", this, static_cast<unsigned long long>(m_parameters.webPageID), static_cast<unsigned long long>(m_parameters.webFrameID), isMainResource(), isSynchronous());
443
444 #if ENABLE(NETWORK_CACHE)
445     if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
446         LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
447
448         if (canUseCachedRedirect(newRequest))
449             retrieveCacheEntry(newRequest);
450         else
451             startNetworkLoad(newRequest);
452
453         m_isWaitingContinueWillSendRequestForCachedRedirect = false;
454         return;
455     }
456 #endif
457     m_networkLoad->continueWillSendRequest(newRequest);
458 }
459
460 void NetworkResourceLoader::continueDidReceiveResponse()
461 {
462     // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
463     // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
464     if (m_networkLoad)
465         m_networkLoad->continueDidReceiveResponse();
466 }
467
468 void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
469 {
470     if (!isSynchronous())
471         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
472 }
473
474 void NetworkResourceLoader::startBufferingTimerIfNeeded()
475 {
476     if (isSynchronous())
477         return;
478     if (m_bufferingTimer.isActive())
479         return;
480     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
481 }
482
483 void NetworkResourceLoader::bufferingTimerFired()
484 {
485     ASSERT(m_bufferedData);
486     ASSERT(m_networkLoad);
487
488     if (m_bufferedData->isEmpty())
489         return;
490
491     IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
492     size_t encodedLength = m_bufferedDataEncodedDataLength;
493
494     m_bufferedData = SharedBuffer::create();
495     m_bufferedDataEncodedDataLength = 0;
496
497     sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
498 }
499
500 bool NetworkResourceLoader::sendBufferMaybeAborting(SharedBuffer& buffer, size_t encodedDataLength)
501 {
502     ASSERT(!isSynchronous());
503
504     IPC::SharedBufferDataReference dataReference(&buffer);
505     return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
506 }
507
508 #if ENABLE(NETWORK_CACHE)
509 void NetworkResourceLoader::tryStoreAsCacheEntry()
510 {
511     if (!canUseCache(m_networkLoad->currentRequest()))
512         return;
513     if (!m_bufferedDataForCache)
514         return;
515
516     // Keep the connection alive.
517     RefPtr<NetworkConnectionToWebProcess> connection(&connectionToWebProcess());
518     RefPtr<NetworkResourceLoader> loader(this);
519     NetworkCache::singleton().store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader, connection](NetworkCache::MappedBody& mappedBody) {
520 #if ENABLE(SHAREABLE_RESOURCE)
521         if (mappedBody.shareableResourceHandle.isNull())
522             return;
523         LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
524         loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
525 #endif
526     });
527 }
528
529 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
530 {
531     if (isSynchronous()) {
532         m_synchronousLoadData->response = entry->response();
533         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
534     } else {
535         bool needsContinueDidReceiveResponseMessage = isMainResource();
536         sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
537
538 #if ENABLE(SHAREABLE_RESOURCE)
539         if (!entry->shareableResourceHandle().isNull())
540             send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle(), currentTime()));
541         else {
542 #endif
543             bool shouldContinue = sendBufferMaybeAborting(*entry->buffer(), entry->buffer()->size());
544             if (!shouldContinue)
545                 return;
546             send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
547 #if ENABLE(SHAREABLE_RESOURCE)
548         }
549 #endif
550     }
551
552     cleanup();
553 }
554
555 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
556 {
557     ASSERT(!m_networkLoad);
558
559     // If the request is already conditional then the revalidation was not triggered by the disk cache
560     // and we should not overwrite the existing conditional headers.
561     ResourceRequest revalidationRequest = originalRequest();
562     if (!revalidationRequest.isConditional()) {
563         String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
564         String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
565         if (!eTag.isEmpty())
566             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
567         if (!lastModified.isEmpty())
568             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
569     }
570
571     m_cacheEntryForValidation = WTFMove(entry);
572
573     startNetworkLoad(revalidationRequest);
574 }
575
576 void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
577 {
578     ASSERT(entry->redirectRequest());
579     LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
580
581     ++m_redirectCount;
582     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(*entry->redirectRequest(), entry->response()));
583     m_isWaitingContinueWillSendRequestForCachedRedirect = true;
584 }
585 #endif
586
587 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
588 {
589     return connectionToWebProcess().connection();
590 }
591
592 void NetworkResourceLoader::consumeSandboxExtensions()
593 {
594     ASSERT(!m_didConsumeSandboxExtensions);
595
596     for (auto& extension : m_parameters.requestBodySandboxExtensions)
597         extension->consume();
598
599     if (auto& extension = m_parameters.resourceSandboxExtension)
600         extension->consume();
601
602     for (auto& fileReference : m_fileReferences)
603         fileReference->prepareForFileAccess();
604
605     m_didConsumeSandboxExtensions = true;
606 }
607
608 void NetworkResourceLoader::invalidateSandboxExtensions()
609 {
610     if (m_didConsumeSandboxExtensions) {
611         for (auto& extension : m_parameters.requestBodySandboxExtensions)
612             extension->revoke();
613         if (auto& extension = m_parameters.resourceSandboxExtension)
614             extension->revoke();
615         for (auto& fileReference : m_fileReferences)
616             fileReference->revokeFileAccess();
617
618         m_didConsumeSandboxExtensions = false;
619     }
620
621     m_fileReferences.clear();
622 }
623
624 template<typename T>
625 bool NetworkResourceLoader::sendAbortingOnFailure(T&& message, unsigned messageSendFlags)
626 {
627     bool result = messageSenderConnection()->send(std::forward<T>(message), messageSenderDestinationID(), messageSendFlags);
628     if (!result)
629         abort();
630     return result;
631 }
632
633 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(const ProtectionSpace& protectionSpace)
634 {
635 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
636     sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace));
637 #else
638     UNUSED_PARAM(protectionSpace);
639 #endif
640 }
641
642 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
643 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
644 {
645     m_networkLoad->continueCanAuthenticateAgainstProtectionSpace(result);
646 }
647 #endif
648
649 bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
650 {
651     return sessionID().isAlwaysOnLoggingAllowed();
652 }
653
654 } // namespace WebKit