2b03e385ccaf0e439bfff863422d084115945e93
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkResourceLoader.cpp
1 /*
2  * Copyright (C) 2012-2014 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 #if ENABLE(NETWORK_PROCESS)
30
31 #include "AuthenticationManager.h"
32 #include "DataReference.h"
33 #include "Logging.h"
34 #include "NetworkBlobRegistry.h"
35 #include "NetworkCache.h"
36 #include "NetworkConnectionToWebProcess.h"
37 #include "NetworkProcess.h"
38 #include "NetworkProcessConnectionMessages.h"
39 #include "NetworkResourceLoadParameters.h"
40 #include "RemoteNetworkingContext.h"
41 #include "ShareableResource.h"
42 #include "SharedMemory.h"
43 #include "WebCoreArgumentCoders.h"
44 #include "WebErrors.h"
45 #include "WebResourceLoaderMessages.h"
46 #include <WebCore/BlobDataFileReference.h>
47 #include <WebCore/CertificateInfo.h>
48 #include <WebCore/HTTPHeaderNames.h>
49 #include <WebCore/NotImplemented.h>
50 #include <WebCore/ResourceHandle.h>
51 #include <WebCore/SharedBuffer.h>
52 #include <WebCore/SynchronousLoaderClient.h>
53 #include <wtf/CurrentTime.h>
54 #include <wtf/MainThread.h>
55
56 using namespace WebCore;
57
58 namespace WebKit {
59
60 struct NetworkResourceLoader::SynchronousLoadData {
61     SynchronousLoadData(PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply)
62         : delayedReply(reply)
63     {
64         ASSERT(delayedReply);
65     }
66     WebCore::ResourceRequest currentRequest;
67     RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
68     WebCore::ResourceResponse response;
69     WebCore::ResourceError error;
70 };
71
72 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, WebCore::SharedBuffer* buffer)
73 {
74     ASSERT(data.delayedReply);
75     ASSERT(!data.response.isNull() || !data.error.isNull());
76
77     Vector<char> responseBuffer;
78     if (buffer && buffer->size())
79         responseBuffer.append(buffer->data(), buffer->size());
80
81     data.delayedReply->send(data.error, data.response, responseBuffer);
82     data.delayedReply = nullptr;
83 }
84
85 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> synchronousReply)
86     : m_parameters(parameters)
87     , m_connection(connection)
88     , m_bytesReceived(0)
89     , m_bufferedDataEncodedDataLength(0)
90     , m_didConvertHandleToDownload(false)
91     , m_didConsumeSandboxExtensions(false)
92     , m_defersLoading(parameters.defersLoading)
93     , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
94 {
95     ASSERT(RunLoop::isMain());
96     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
97     //        Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
98     ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials);
99
100     if (originalRequest().httpBody()) {
101         for (const FormDataElement& element : originalRequest().httpBody()->elements()) {
102             if (element.m_type == FormDataElement::Type::EncodedBlob)
103                 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
104         }
105     }
106
107     if (originalRequest().url().protocolIs("blob")) {
108         ASSERT(!m_parameters.resourceSandboxExtension);
109         m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
110     }
111
112     if (synchronousReply)
113         m_synchronousLoadData = std::make_unique<SynchronousLoadData>(synchronousReply);
114 }
115
116 NetworkResourceLoader::~NetworkResourceLoader()
117 {
118     ASSERT(RunLoop::isMain());
119     ASSERT(!m_handle);
120     ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
121 }
122
123 bool NetworkResourceLoader::isSynchronous() const
124 {
125     return !!m_synchronousLoadData;
126 }
127
128 void NetworkResourceLoader::start()
129 {
130     ASSERT(RunLoop::isMain());
131
132     if (m_defersLoading)
133         return;
134
135     m_currentRequest = originalRequest();
136
137 #if ENABLE(NETWORK_CACHE)
138     if (!NetworkCache::singleton().isEnabled() || sessionID().isEphemeral()) {
139         startNetworkLoad();
140         return;
141     }
142
143     RefPtr<NetworkResourceLoader> loader(this);
144     NetworkCache::singleton().retrieve(originalRequest(), m_parameters.webPageID, [loader](std::unique_ptr<NetworkCache::Entry> entry) {
145         if (loader->hasOneRef()) {
146             // The loader has been aborted and is only held alive by this lambda.
147             return;
148         }
149         if (!entry) {
150             loader->startNetworkLoad();
151             return;
152         }
153         if (loader->m_parameters.needsCertificateInfo && !entry->response.containsCertificateInfo()) {
154             loader->startNetworkLoad();
155             return;
156         }
157         if (entry->needsRevalidation) {
158             loader->validateCacheEntry(WTF::move(entry));
159             return;
160         }
161         loader->didRetrieveCacheEntry(WTF::move(entry));
162     });
163 #else
164     startNetworkLoad();
165 #endif
166 }
167
168 void NetworkResourceLoader::startNetworkLoad()
169 {
170     m_networkingContext = RemoteNetworkingContext::create(sessionID(), m_parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
171
172     consumeSandboxExtensions();
173
174     if (isSynchronous() || m_parameters.maximumBufferingTime > 0_ms)
175         m_bufferedData = WebCore::SharedBuffer::create();
176
177 #if ENABLE(NETWORK_CACHE)
178     if (NetworkCache::singleton().isEnabled())
179         m_bufferedDataForCache = WebCore::SharedBuffer::create();
180 #endif
181
182     bool shouldSniff = m_parameters.contentSniffingPolicy == SniffContent;
183     m_handle = ResourceHandle::create(m_networkingContext.get(), m_currentRequest, this, m_defersLoading, shouldSniff);
184 }
185
186 void NetworkResourceLoader::setDefersLoading(bool defers)
187 {
188     if (m_defersLoading == defers)
189         return;
190     m_defersLoading = defers;
191     if (m_handle) {
192         m_handle->setDefersLoading(defers);
193         return;
194     }
195     if (!m_defersLoading)
196         start();
197 }
198
199 void NetworkResourceLoader::cleanup()
200 {
201     ASSERT(RunLoop::isMain());
202
203     m_bufferingTimer.stop();
204
205     invalidateSandboxExtensions();
206
207     NetworkProcess::singleton().networkResourceLoadScheduler().removeLoader(this);
208
209     m_handle = nullptr;
210
211     // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
212     m_connection->didCleanupResourceLoader(*this);
213 }
214
215 void NetworkResourceLoader::didConvertHandleToDownload()
216 {
217     ASSERT(m_handle);
218     m_didConvertHandleToDownload = true;
219 }
220
221 void NetworkResourceLoader::abort()
222 {
223     ASSERT(RunLoop::isMain());
224
225     if (m_handle && !m_didConvertHandleToDownload)
226         m_handle->cancel();
227
228     cleanup();
229 }
230
231 #if ENABLE(NETWORK_CACHE)
232 static bool isConditionalRequest(const WebCore::ResourceRequest& request)
233 {
234     if (!request.httpHeaderField(WebCore::HTTPHeaderName::IfNoneMatch).isEmpty())
235         return true;
236     if (!request.httpHeaderField(WebCore::HTTPHeaderName::IfModifiedSince).isEmpty())
237         return true;
238     return false;
239 }
240 #endif
241
242 void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& receivedResponse)
243 {
244     ASSERT_UNUSED(handle, handle == m_handle);
245
246     m_response = receivedResponse;
247
248     m_response.setSource(ResourceResponse::Source::Network);
249     if (m_parameters.needsCertificateInfo)
250         m_response.includeCertificateInfo();
251     // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
252     if (!isSynchronous() && m_response.isMultipart())
253         m_bufferedData = nullptr;
254
255     bool shouldSendDidReceiveResponse = true;
256 #if ENABLE(NETWORK_CACHE)
257     if (m_cacheEntryForValidation) {
258         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
259         if (validationSucceeded)
260             NetworkCache::singleton().update(originalRequest(), *m_cacheEntryForValidation, m_response);
261         if (!validationSucceeded || isConditionalRequest(originalRequest()))
262             m_cacheEntryForValidation = nullptr;
263     }
264     shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
265 #endif
266
267     if (shouldSendDidReceiveResponse) {
268         if (isSynchronous())
269             m_synchronousLoadData->response = m_response;
270         else {
271             if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(m_response, m_parameters.isMainResource)))
272                 return;
273         }
274     }
275
276     // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
277     bool shouldContinueDidReceiveResponse = !m_parameters.isMainResource;
278 #if ENABLE(NETWORK_CACHE)
279     shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
280 #endif
281     if (!shouldContinueDidReceiveResponse)
282         return;
283
284     m_handle->continueDidReceiveResponse();
285 }
286
287 void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */)
288 {
289     // The NetworkProcess should never get a didReceiveData callback.
290     // We should always be using didReceiveBuffer.
291     ASSERT_NOT_REACHED();
292 }
293
294 void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int reportedEncodedDataLength)
295 {
296     ASSERT_UNUSED(handle, handle == m_handle);
297 #if ENABLE(NETWORK_CACHE)
298     ASSERT(!m_cacheEntryForValidation);
299
300     if (m_bufferedDataForCache)
301         m_bufferedDataForCache->append(buffer.get());
302 #endif
303     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
304     unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
305
306     m_bytesReceived += buffer->size();
307     if (m_bufferedData) {
308         m_bufferedData->append(buffer.get());
309         m_bufferedDataEncodedDataLength += encodedDataLength;
310         startBufferingTimerIfNeeded();
311         return;
312     }
313     sendBufferMaybeAborting(*buffer, encodedDataLength);
314 }
315
316 void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double finishTime)
317 {
318     ASSERT_UNUSED(handle, handle == m_handle);
319
320 #if ENABLE(NETWORK_CACHE)
321     if (NetworkCache::singleton().isEnabled()) {
322         if (m_cacheEntryForValidation) {
323             // 304 Not Modified
324             ASSERT(m_response.httpStatusCode() == 304);
325             LOG(NetworkCache, "(NetworkProcess) revalidated");
326             didRetrieveCacheEntry(WTF::move(m_cacheEntryForValidation));
327             return;
328         }
329         bool allowStale = originalRequest().cachePolicy() >= ReturnCacheDataElseLoad;
330         bool hasCacheableRedirect = m_response.isHTTP() && WebCore::redirectChainAllowsReuse(m_redirectChainCacheStatus, allowStale ? WebCore::ReuseExpiredRedirection : WebCore::DoNotReuseExpiredRedirection);
331         if (hasCacheableRedirect && m_redirectChainCacheStatus.status == RedirectChainCacheStatus::CachedRedirection) {
332             // FIXME: Cache the actual redirects instead of the end result.
333             double now = currentTime();
334             double responseEndOfValidity = now + WebCore::computeFreshnessLifetimeForHTTPFamily(m_response, now) - WebCore::computeCurrentAge(m_response, now);
335             hasCacheableRedirect = responseEndOfValidity <= m_redirectChainCacheStatus.endOfValidity;
336         }
337
338         bool isPrivate = sessionID().isEphemeral();
339         if (hasCacheableRedirect && !isPrivate) {
340             // Keep the connection alive.
341             RefPtr<NetworkConnectionToWebProcess> connection(connectionToWebProcess());
342             RefPtr<NetworkResourceLoader> loader(this);
343             NetworkCache::singleton().store(originalRequest(), m_response, WTF::move(m_bufferedDataForCache), [loader, connection](NetworkCache::MappedBody& mappedBody) {
344 #if ENABLE(SHAREABLE_RESOURCE)
345                 if (mappedBody.shareableResourceHandle.isNull())
346                     return;
347                 LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
348                 loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
349 #endif
350             });
351         }
352     }
353 #endif
354
355     if (isSynchronous())
356         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
357     else {
358         if (m_bufferedData && m_bufferedData->size()) {
359             // FIXME: Pass a real value or remove the encoded data size feature.
360             bool shouldContinue = sendBufferMaybeAborting(*m_bufferedData, -1);
361             if (!shouldContinue)
362                 return;
363         }
364         send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
365     }
366
367     cleanup();
368 }
369
370 void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError& error)
371 {
372     ASSERT_UNUSED(handle, !handle || handle == m_handle);
373
374 #if ENABLE(NETWORK_CACHE)
375     m_cacheEntryForValidation = nullptr;
376 #endif
377
378     if (isSynchronous()) {
379         m_synchronousLoadData->error = error;
380         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
381     } else
382         send(Messages::WebResourceLoader::DidFailResourceLoad(error));
383
384     cleanup();
385 }
386
387 void NetworkResourceLoader::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse)
388 {
389     ASSERT_UNUSED(handle, handle == m_handle);
390
391     // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect.
392     ASSERT(!redirectResponse.isNull());
393     ASSERT(RunLoop::isMain());
394
395     m_currentRequest = request;
396
397 #if ENABLE(NETWORK_CACHE)
398     WebCore::updateRedirectChainStatus(m_redirectChainCacheStatus, redirectResponse);
399 #endif
400
401     if (isSynchronous()) {
402         // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
403         // This includes at least updating host records, and comparing the current request instead of the original request here.
404         if (!protocolHostAndPortAreEqual(originalRequest().url(), m_currentRequest.url())) {
405             ASSERT(m_synchronousLoadData->error.isNull());
406             m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
407             m_currentRequest = ResourceRequest();
408         }
409         continueWillSendRequest(m_currentRequest);
410         return;
411     }
412     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(m_currentRequest, redirectResponse));
413 }
414
415 void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest)
416 {
417 #if PLATFORM(COCOA)
418     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
419 #elif USE(SOUP)
420     // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127.
421     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest);
422 #endif
423
424     if (m_currentRequest.isNull()) {
425         m_handle->cancel();
426         didFail(m_handle.get(), cancelledError(m_currentRequest));
427         return;
428     }
429
430     m_handle->continueWillSendRequest(m_currentRequest);
431 }
432
433 void NetworkResourceLoader::continueDidReceiveResponse()
434 {
435     // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
436     // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
437     if (!m_handle)
438         return;
439
440     m_handle->continueDidReceiveResponse();
441 }
442
443 void NetworkResourceLoader::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
444 {
445     ASSERT_UNUSED(handle, handle == m_handle);
446
447     if (!isSynchronous())
448         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
449 }
450
451 void NetworkResourceLoader::wasBlocked(ResourceHandle* handle)
452 {
453     ASSERT_UNUSED(handle, handle == m_handle);
454
455     didFail(handle, WebKit::blockedError(m_currentRequest));
456 }
457
458 void NetworkResourceLoader::cannotShowURL(ResourceHandle* handle)
459 {
460     ASSERT_UNUSED(handle, handle == m_handle);
461
462     didFail(handle, WebKit::cannotShowURLError(m_currentRequest));
463 }
464
465 bool NetworkResourceLoader::shouldUseCredentialStorage(ResourceHandle* handle)
466 {
467     ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
468
469     // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
470     // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
471
472     // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
473
474     return m_parameters.allowStoredCredentials == AllowStoredCredentials;
475 }
476
477 void NetworkResourceLoader::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
478 {
479     ASSERT_UNUSED(handle, handle == m_handle);
480     // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
481     ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
482
483     if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
484         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
485         return;
486     }
487
488     NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge);
489 }
490
491 void NetworkResourceLoader::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge&)
492 {
493     ASSERT_UNUSED(handle, handle == m_handle);
494
495     // This function is probably not needed (see <rdar://problem/8960124>).
496     notImplemented();
497 }
498
499 void NetworkResourceLoader::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&)
500 {
501     ASSERT_UNUSED(handle, handle == m_handle);
502
503     m_handle->cancel();
504     didFail(m_handle.get(), cancelledError(m_currentRequest));
505 }
506
507 void NetworkResourceLoader::startBufferingTimerIfNeeded()
508 {
509     if (isSynchronous())
510         return;
511     if (m_bufferingTimer.isActive())
512         return;
513     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
514 }
515
516 void NetworkResourceLoader::bufferingTimerFired()
517 {
518     ASSERT(m_bufferedData);
519     ASSERT(m_handle);
520     if (!m_bufferedData->size())
521         return;
522
523     IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
524     size_t encodedLength = m_bufferedDataEncodedDataLength;
525
526     m_bufferedData = WebCore::SharedBuffer::create();
527     m_bufferedDataEncodedDataLength = 0;
528
529     sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
530 }
531
532 bool NetworkResourceLoader::sendBufferMaybeAborting(WebCore::SharedBuffer& buffer, size_t encodedDataLength)
533 {
534     ASSERT(!isSynchronous());
535
536 #if PLATFORM(COCOA)
537     ShareableResource::Handle shareableResourceHandle;
538     NetworkResourceLoader::tryGetShareableHandleFromSharedBuffer(shareableResourceHandle, buffer);
539     if (!shareableResourceHandle.isNull()) {
540         send(Messages::WebResourceLoader::DidReceiveResource(shareableResourceHandle, currentTime()));
541         abort();
542         return false;
543     }
544 #endif
545
546     IPC::SharedBufferDataReference dataReference(&buffer);
547     return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
548 }
549
550 #if ENABLE(NETWORK_CACHE)
551 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
552 {
553     if (isSynchronous()) {
554         m_synchronousLoadData->response = entry->response;
555         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer.get());
556     } else {
557         sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry->response, m_parameters.isMainResource));
558
559 #if ENABLE(SHAREABLE_RESOURCE)
560         if (!entry->shareableResourceHandle.isNull())
561             send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle, currentTime()));
562         else {
563 #endif
564             bool shouldContinue = sendBufferMaybeAborting(*entry->buffer, entry->buffer->size());
565             if (!shouldContinue)
566                 return;
567             send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
568 #if ENABLE(SHAREABLE_RESOURCE)
569         }
570 #endif
571     }
572
573     cleanup();
574 }
575
576 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
577 {
578     ASSERT(!m_handle);
579
580     String eTag = entry->response.httpHeaderField(WebCore::HTTPHeaderName::ETag);
581     String lastModified = entry->response.httpHeaderField(WebCore::HTTPHeaderName::LastModified);
582     if (!eTag.isEmpty())
583         m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfNoneMatch, eTag);
584     if (!lastModified.isEmpty())
585         m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfModifiedSince, lastModified);
586
587     m_cacheEntryForValidation = WTF::move(entry);
588
589     startNetworkLoad();
590 }
591 #endif
592
593 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
594 {
595     return connectionToWebProcess()->connection();
596 }
597
598 void NetworkResourceLoader::consumeSandboxExtensions()
599 {
600     for (auto& extension : m_parameters.requestBodySandboxExtensions)
601         extension->consume();
602
603     if (auto& extension = m_parameters.resourceSandboxExtension)
604         extension->consume();
605
606     for (auto& fileReference : m_fileReferences)
607         fileReference->prepareForFileAccess();
608
609     m_didConsumeSandboxExtensions = true;
610 }
611
612 void NetworkResourceLoader::invalidateSandboxExtensions()
613 {
614     if (m_didConsumeSandboxExtensions) {
615         for (auto& extension : m_parameters.requestBodySandboxExtensions)
616             extension->revoke();
617         if (auto& extension = m_parameters.resourceSandboxExtension)
618             extension->revoke();
619         for (auto& fileReference : m_fileReferences)
620             fileReference->revokeFileAccess();
621     }
622
623     m_fileReferences.clear();
624
625     m_didConsumeSandboxExtensions = false;
626 }
627
628 template<typename T>
629 bool NetworkResourceLoader::sendAbortingOnFailure(T&& message, unsigned messageSendFlags)
630 {
631     bool result = messageSenderConnection()->send(std::forward<T>(message), messageSenderDestinationID(), messageSendFlags);
632     if (!result)
633         abort();
634     return result;
635 }
636
637 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
638 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
639 {
640     ASSERT(RunLoop::isMain());
641     ASSERT_UNUSED(handle, handle == m_handle);
642
643     // Handle server trust evaluation at platform-level if requested, for performance reasons.
644     if (protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
645         && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
646         continueCanAuthenticateAgainstProtectionSpace(false);
647         return;
648     }
649
650     if (isSynchronous()) {
651         // FIXME: We should ask the WebProcess like the asynchronous case below does.
652         // This is currently impossible as the WebProcess is blocked waiting on this synchronous load.
653         // It's possible that we can jump straight to the UI process to resolve this.
654         continueCanAuthenticateAgainstProtectionSpace(true);
655         return;
656     }
657     sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace));
658 }
659
660 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
661 {
662     m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
663 }
664 #endif
665
666 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
667 bool NetworkResourceLoader::supportsDataArray()
668 {
669     notImplemented();
670     return false;
671 }
672
673 void NetworkResourceLoader::didReceiveDataArray(ResourceHandle*, CFArrayRef)
674 {
675     ASSERT_NOT_REACHED();
676     notImplemented();
677 }
678 #endif
679
680 } // namespace WebKit
681
682 #endif // ENABLE(NETWORK_PROCESS)