2c50973b808c8f01396e4f01c08c358e6a52074f
[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/SharedBuffer.h>
51 #include <WebCore/SynchronousLoaderClient.h>
52 #include <wtf/CurrentTime.h>
53 #include <wtf/MainThread.h>
54
55 #if !USE(NETWORK_SESSION)
56 #include <WebCore/ResourceHandle.h>
57 #endif
58
59 using namespace WebCore;
60
61 namespace WebKit {
62
63 struct NetworkResourceLoader::SynchronousLoadData {
64     SynchronousLoadData(PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> reply)
65         : delayedReply(reply)
66     {
67         ASSERT(delayedReply);
68     }
69     WebCore::ResourceRequest currentRequest;
70     RefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> delayedReply;
71     WebCore::ResourceResponse response;
72     WebCore::ResourceError error;
73 };
74
75 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const WebCore::SharedBuffer* buffer)
76 {
77     ASSERT(data.delayedReply);
78     ASSERT(!data.response.isNull() || !data.error.isNull());
79
80     Vector<char> responseBuffer;
81     if (buffer && buffer->size())
82         responseBuffer.append(buffer->data(), buffer->size());
83
84     data.delayedReply->send(data.error, data.response, responseBuffer);
85     data.delayedReply = nullptr;
86 }
87
88 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& parameters, NetworkConnectionToWebProcess* connection, PassRefPtr<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply> synchronousReply)
89     : m_parameters(parameters)
90     , m_connection(connection)
91     , m_bytesReceived(0)
92     , m_bufferedDataEncodedDataLength(0)
93     , m_didConvertHandleToDownload(false)
94     , m_didConsumeSandboxExtensions(false)
95     , m_defersLoading(parameters.defersLoading)
96     , m_bufferingTimer(*this, &NetworkResourceLoader::bufferingTimerFired)
97 {
98     ASSERT(RunLoop::isMain());
99     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
100     //        Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
101     ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials);
102
103     if (originalRequest().httpBody()) {
104         for (const FormDataElement& element : originalRequest().httpBody()->elements()) {
105             if (element.m_type == FormDataElement::Type::EncodedBlob)
106                 m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, element.m_url));
107         }
108     }
109
110     if (originalRequest().url().protocolIs("blob")) {
111         ASSERT(!m_parameters.resourceSandboxExtension);
112         m_fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(connection, originalRequest().url()));
113     }
114
115     if (synchronousReply)
116         m_synchronousLoadData = std::make_unique<SynchronousLoadData>(synchronousReply);
117 }
118
119 NetworkResourceLoader::~NetworkResourceLoader()
120 {
121     ASSERT(RunLoop::isMain());
122 #if USE(NETWORK_SESSION)
123     ASSERT(!m_task);
124 #else
125     ASSERT(!m_handle);
126 #endif
127     ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
128 }
129
130 bool NetworkResourceLoader::isSynchronous() const
131 {
132     return !!m_synchronousLoadData;
133 }
134
135 void NetworkResourceLoader::start()
136 {
137     ASSERT(RunLoop::isMain());
138
139     if (m_defersLoading)
140         return;
141
142     m_currentRequest = originalRequest();
143
144 #if ENABLE(NETWORK_CACHE)
145     if (!NetworkCache::singleton().isEnabled() || sessionID().isEphemeral() || !originalRequest().url().protocolIsInHTTPFamily()) {
146         startNetworkLoad();
147         return;
148     }
149
150     RefPtr<NetworkResourceLoader> loader(this);
151     NetworkCache::singleton().retrieve(originalRequest(), m_parameters.webPageID, [loader](std::unique_ptr<NetworkCache::Entry> entry) {
152         if (loader->hasOneRef()) {
153             // The loader has been aborted and is only held alive by this lambda.
154             return;
155         }
156         if (!entry) {
157             loader->startNetworkLoad();
158             return;
159         }
160         if (loader->m_parameters.needsCertificateInfo && !entry->response().containsCertificateInfo()) {
161             loader->startNetworkLoad();
162             return;
163         }
164         if (entry->needsValidation()) {
165             loader->validateCacheEntry(WTF::move(entry));
166             return;
167         }
168         loader->didRetrieveCacheEntry(WTF::move(entry));
169     });
170 #else
171     startNetworkLoad();
172 #endif
173 }
174
175 void NetworkResourceLoader::startNetworkLoad()
176 {
177     m_networkingContext = RemoteNetworkingContext::create(sessionID(), m_parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
178
179     consumeSandboxExtensions();
180
181     if (isSynchronous() || m_parameters.maximumBufferingTime > 0_ms)
182         m_bufferedData = WebCore::SharedBuffer::create();
183
184 #if ENABLE(NETWORK_CACHE)
185     if (NetworkCache::singleton().isEnabled())
186         m_bufferedDataForCache = WebCore::SharedBuffer::create();
187 #endif
188
189     bool shouldSniff = m_parameters.contentSniffingPolicy == SniffContent;
190 #if USE(NETWORK_SESSION)
191     UNUSED_PARAM(shouldSniff); // FIXME: Use this.
192     m_task = NetworkSession::singleton()->createDataTaskWithRequest(m_currentRequest, *this);
193     m_task->resume();
194 #else
195     m_handle = ResourceHandle::create(m_networkingContext.get(), m_currentRequest, this, m_defersLoading, shouldSniff);
196 #endif
197 }
198
199 void NetworkResourceLoader::setDefersLoading(bool defers)
200 {
201     if (m_defersLoading == defers)
202         return;
203     m_defersLoading = defers;
204 #if USE(NETWORK_SESSION)
205     // FIXME: Do something here.
206     notImplemented();
207 #else
208     if (m_handle) {
209         m_handle->setDefersLoading(defers);
210         return;
211     }
212 #endif
213     if (!m_defersLoading)
214         start();
215 }
216
217 void NetworkResourceLoader::cleanup()
218 {
219     ASSERT(RunLoop::isMain());
220
221     m_bufferingTimer.stop();
222
223     invalidateSandboxExtensions();
224
225 #if USE(NETWORK_SESSION)
226     if (m_task) {
227         m_task->clearClient();
228         m_task = nullptr;
229     }
230 #else
231     if (m_handle) {
232         m_handle->clearClient();
233         m_handle = nullptr;
234     }
235 #endif
236
237     // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
238     m_connection->didCleanupResourceLoader(*this);
239 }
240
241 #if !USE(NETWORK_SESSION)
242 void NetworkResourceLoader::didConvertHandleToDownload()
243 {
244     ASSERT(m_handle);
245     m_didConvertHandleToDownload = true;
246 }
247 #endif
248
249 void NetworkResourceLoader::abort()
250 {
251     ASSERT(RunLoop::isMain());
252
253 #if USE(NETWORK_SESSION)
254     if (m_task)
255         m_task->suspend();
256     // FIXME: Do something with the network cache here.
257     notImplemented();
258 #else
259     if (m_handle && !m_didConvertHandleToDownload) {
260         m_handle->cancel();
261
262 #if ENABLE(NETWORK_CACHE)
263         if (NetworkCache::singleton().isEnabled()) {
264             // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
265             if (!m_response.isNull())
266                 NetworkCache::singleton().remove(originalRequest());
267         }
268 #endif
269     }
270 #endif
271     cleanup();
272 }
273
274 NetworkResourceLoader::ShouldContinueDidReceiveResponse NetworkResourceLoader::sharedDidReceiveResponse(const WebCore::ResourceResponse& receivedResponse)
275 {
276     m_response = receivedResponse;
277
278     m_response.setSource(ResourceResponse::Source::Network);
279     if (m_parameters.needsCertificateInfo)
280         m_response.includeCertificateInfo();
281     // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
282     if (!isSynchronous() && m_response.isMultipart())
283         m_bufferedData = nullptr;
284
285     bool shouldSendDidReceiveResponse = true;
286 #if ENABLE(NETWORK_CACHE)
287     if (m_response.isMultipart())
288         m_bufferedDataForCache = nullptr;
289
290     if (m_cacheEntryForValidation) {
291         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
292         if (validationSucceeded) {
293             NetworkCache::singleton().update(originalRequest(), m_parameters.webPageID, *m_cacheEntryForValidation, m_response);
294             // If the request was conditional then this revalidation was not triggered by the network cache and we pass the
295             // 304 response to WebCore.
296             if (originalRequest().isConditional())
297                 m_cacheEntryForValidation = nullptr;
298         } else
299             m_cacheEntryForValidation = nullptr;
300     }
301     shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
302 #endif
303
304     bool shouldWaitContinueDidReceiveResponse = originalRequest().requester() == ResourceRequest::Requester::Main;
305     if (shouldSendDidReceiveResponse) {
306         if (isSynchronous())
307             m_synchronousLoadData->response = m_response;
308         else {
309             if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(m_response, shouldWaitContinueDidReceiveResponse)))
310                 return ShouldContinueDidReceiveResponse::No;
311         }
312     }
313
314     // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
315     bool shouldContinueDidReceiveResponse = !shouldWaitContinueDidReceiveResponse;
316 #if ENABLE(NETWORK_CACHE)
317     shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
318 #endif
319     if (!shouldContinueDidReceiveResponse)
320         return ShouldContinueDidReceiveResponse::No;
321     return ShouldContinueDidReceiveResponse::Yes;
322 }
323
324 void NetworkResourceLoader::sharedDidReceiveBuffer(RefPtr<WebCore::SharedBuffer>&& buffer, int reportedEncodedDataLength)
325 {
326 #if ENABLE(NETWORK_CACHE)
327     ASSERT(!m_cacheEntryForValidation);
328
329     if (m_bufferedDataForCache) {
330         // Prevent memory growth in case of streaming data.
331         const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
332         if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
333             m_bufferedDataForCache->append(buffer.get());
334         else
335             m_bufferedDataForCache = nullptr;
336     }
337 #endif
338     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
339     unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
340
341     m_bytesReceived += buffer->size();
342     if (m_bufferedData) {
343         m_bufferedData->append(buffer.get());
344         m_bufferedDataEncodedDataLength += encodedDataLength;
345         startBufferingTimerIfNeeded();
346         return;
347     }
348     sendBufferMaybeAborting(*buffer, encodedDataLength);
349 }
350
351 void NetworkResourceLoader::sharedDidFinishLoading(double finishTime)
352 {
353 #if ENABLE(NETWORK_CACHE)
354     if (NetworkCache::singleton().isEnabled()) {
355         if (m_cacheEntryForValidation) {
356             // 304 Not Modified
357             ASSERT(m_response.httpStatusCode() == 304);
358             LOG(NetworkCache, "(NetworkProcess) revalidated");
359             didRetrieveCacheEntry(WTF::move(m_cacheEntryForValidation));
360             return;
361         }
362         bool allowStale = originalRequest().cachePolicy() >= ReturnCacheDataElseLoad;
363         bool hasCacheableRedirect = m_response.isHTTP() && WebCore::redirectChainAllowsReuse(m_redirectChainCacheStatus, allowStale ? WebCore::ReuseExpiredRedirection : WebCore::DoNotReuseExpiredRedirection);
364         if (hasCacheableRedirect && m_redirectChainCacheStatus.status == RedirectChainCacheStatus::CachedRedirection) {
365             // Maybe we should cache the actual redirects instead of the end result?
366             auto now = std::chrono::system_clock::now();
367             auto responseEndOfValidity = now + WebCore::computeFreshnessLifetimeForHTTPFamily(m_response, now) - WebCore::computeCurrentAge(m_response, now);
368             hasCacheableRedirect = responseEndOfValidity <= m_redirectChainCacheStatus.endOfValidity;
369         }
370
371         bool isPrivate = sessionID().isEphemeral();
372         if (m_bufferedDataForCache && hasCacheableRedirect && !isPrivate) {
373             // Keep the connection alive.
374             RefPtr<NetworkConnectionToWebProcess> connection(connectionToWebProcess());
375             RefPtr<NetworkResourceLoader> loader(this);
376             NetworkCache::singleton().store(originalRequest(), m_response, WTF::move(m_bufferedDataForCache), [loader, connection](NetworkCache::MappedBody& mappedBody) {
377 #if ENABLE(SHAREABLE_RESOURCE)
378                 if (mappedBody.shareableResourceHandle.isNull())
379                     return;
380                 LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
381                 loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
382 #endif
383             });
384         } else if (!hasCacheableRedirect) {
385             // Make sure we don't keep a stale entry in the cache.
386             NetworkCache::singleton().remove(originalRequest());
387         }
388     }
389 #endif
390
391     if (isSynchronous())
392         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
393     else {
394         if (m_bufferedData && m_bufferedData->size()) {
395             // FIXME: Pass a real value or remove the encoded data size feature.
396             bool shouldContinue = sendBufferMaybeAborting(*m_bufferedData, -1);
397             if (!shouldContinue)
398                 return;
399         }
400         send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
401     }
402
403     cleanup();
404 }
405
406 void NetworkResourceLoader::sharedDidFail(const WebCore::ResourceError& error)
407 {
408     ASSERT(!error.isNull());
409
410 #if ENABLE(NETWORK_CACHE)
411     m_cacheEntryForValidation = nullptr;
412 #endif
413
414     if (isSynchronous()) {
415         m_synchronousLoadData->error = error;
416         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
417     } else
418         send(Messages::WebResourceLoader::DidFailResourceLoad(error));
419
420     cleanup();
421 }
422
423 void NetworkResourceLoader::sharedWillSendRedirectedRequest(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse& redirectResponse)
424 {
425     // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect.
426     ASSERT(!redirectResponse.isNull());
427     ASSERT(RunLoop::isMain());
428
429     m_currentRequest = request;
430
431 #if ENABLE(NETWORK_CACHE)
432     WebCore::updateRedirectChainStatus(m_redirectChainCacheStatus, redirectResponse);
433 #endif
434
435     if (isSynchronous()) {
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(), m_currentRequest.url())) {
439             ASSERT(m_synchronousLoadData->error.isNull());
440             m_synchronousLoadData->error = SynchronousLoaderClient::platformBadResponseError();
441             m_currentRequest = ResourceRequest();
442         }
443         continueWillSendRequest(m_currentRequest);
444         return;
445     }
446     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(m_currentRequest, redirectResponse));
447 }
448     
449 #if USE(NETWORK_SESSION)
450
451 void NetworkResourceLoader::willPerformHTTPRedirection(const WebCore::ResourceResponse& response, const WebCore::ResourceRequest& request, std::function<void(const WebCore::ResourceRequest&)> completionHandler)
452 {
453     sharedWillSendRedirectedRequest(request, response);
454     completionHandler(request);
455 }
456
457 void NetworkResourceLoader::didReceiveChallenge(const WebCore::AuthenticationChallenge& challenge, std::function<void(AuthenticationChallengeDisposition, const WebCore::Credential&)> completionHandler)
458 {
459     notImplemented();
460     completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, WebCore::Credential());
461 }
462
463 void NetworkResourceLoader::didReceiveResponse(const WebCore::ResourceResponse& response, std::function<void(ResponseDisposition)> completionHandler)
464 {
465     ASSERT(isMainThread());
466     sharedDidReceiveResponse(response);
467     completionHandler(ResponseDisposition::Allow);
468 }
469
470 void NetworkResourceLoader::didReceiveData(RefPtr<WebCore::SharedBuffer>&& buffer)
471 {
472     ASSERT(buffer);
473     sharedDidReceiveBuffer(WTF::move(buffer), buffer->size());
474 }
475
476 void NetworkResourceLoader::didCompleteWithError(const WebCore::ResourceError& error)
477 {
478     if (error.isNull())
479         sharedDidFinishLoading(WTF::monotonicallyIncreasingTime());
480     else
481         sharedDidFail(error);
482 }
483
484 #else
485
486 void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& receivedResponse)
487 {
488     ASSERT_UNUSED(handle, handle == m_handle);
489     if (sharedDidReceiveResponse(receivedResponse) == ShouldContinueDidReceiveResponse::Yes)
490         m_handle->continueDidReceiveResponse();
491 }
492
493 void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */)
494 {
495     // The NetworkProcess should never get a didReceiveData callback.
496     // We should always be using didReceiveBuffer.
497     ASSERT_NOT_REACHED();
498 }
499
500 void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<WebCore::SharedBuffer> buffer, int reportedEncodedDataLength)
501 {
502     ASSERT_UNUSED(handle, handle == m_handle);
503     sharedDidReceiveBuffer(WTF::move(buffer), reportedEncodedDataLength);
504 }
505
506 void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double finishTime)
507 {
508     ASSERT_UNUSED(handle, handle == m_handle);
509     sharedDidFinishLoading(finishTime);
510 }
511
512 void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError& error)
513 {
514     ASSERT_UNUSED(handle, !handle || handle == m_handle);
515     sharedDidFail(error);
516 }
517
518 void NetworkResourceLoader::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse)
519 {
520     ASSERT_UNUSED(handle, handle == m_handle);
521     sharedWillSendRedirectedRequest(request, redirectResponse);
522 }
523
524 #endif // USE(NETWORK_SESSION)
525     
526 void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest)
527 {
528 #if PLATFORM(COCOA)
529     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
530 #elif USE(SOUP)
531     // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127.
532     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest);
533 #endif
534
535     if (m_currentRequest.isNull()) {
536 #if USE(NETWORK_SESSION)
537         // FIXME: Do something here.
538         notImplemented();
539 #else
540         m_handle->cancel();
541         didFail(m_handle.get(), cancelledError(m_currentRequest));
542 #endif
543         return;
544     }
545
546 #if USE(NETWORK_SESSION)
547     // FIXME: Do something here.
548     notImplemented();
549 #else
550     m_handle->continueWillSendRequest(m_currentRequest);
551 #endif
552 }
553
554 void NetworkResourceLoader::continueDidReceiveResponse()
555 {
556     // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
557     // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
558 #if USE(NETWORK_SESSION)
559     // FIXME: Do something here.
560     notImplemented();
561 #else
562     if (!m_handle)
563         return;
564
565     m_handle->continueDidReceiveResponse();
566 #endif
567 }
568
569 #if !USE(NETWORK_SESSION)
570
571 void NetworkResourceLoader::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
572 {
573     ASSERT_UNUSED(handle, handle == m_handle);
574
575     if (!isSynchronous())
576         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
577 }
578
579 void NetworkResourceLoader::wasBlocked(ResourceHandle* handle)
580 {
581     ASSERT_UNUSED(handle, handle == m_handle);
582
583     didFail(handle, WebKit::blockedError(m_currentRequest));
584 }
585
586 void NetworkResourceLoader::cannotShowURL(ResourceHandle* handle)
587 {
588     ASSERT_UNUSED(handle, handle == m_handle);
589
590     didFail(handle, WebKit::cannotShowURLError(m_currentRequest));
591 }
592
593 bool NetworkResourceLoader::shouldUseCredentialStorage(ResourceHandle* handle)
594 {
595     ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
596
597     // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
598     // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
599
600     // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
601
602     return m_parameters.allowStoredCredentials == AllowStoredCredentials;
603 }
604
605 void NetworkResourceLoader::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
606 {
607     ASSERT_UNUSED(handle, handle == m_handle);
608     // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
609     ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
610
611     if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
612         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
613         return;
614     }
615
616     NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge);
617 }
618
619 void NetworkResourceLoader::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge&)
620 {
621     ASSERT_UNUSED(handle, handle == m_handle);
622
623     // This function is probably not needed (see <rdar://problem/8960124>).
624     notImplemented();
625 }
626
627 void NetworkResourceLoader::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&)
628 {
629     ASSERT_UNUSED(handle, handle == m_handle);
630
631     m_handle->cancel();
632     didFail(m_handle.get(), cancelledError(m_currentRequest));
633 }
634
635 #endif // !USE(NETWORK_SESSION)
636
637 void NetworkResourceLoader::startBufferingTimerIfNeeded()
638 {
639     if (isSynchronous())
640         return;
641     if (m_bufferingTimer.isActive())
642         return;
643     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
644 }
645
646 void NetworkResourceLoader::bufferingTimerFired()
647 {
648     ASSERT(m_bufferedData);
649 #if !USE(NETWORK_SESSION)
650     ASSERT(m_handle);
651 #endif
652     if (!m_bufferedData->size())
653         return;
654
655     IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
656     size_t encodedLength = m_bufferedDataEncodedDataLength;
657
658     m_bufferedData = WebCore::SharedBuffer::create();
659     m_bufferedDataEncodedDataLength = 0;
660
661     sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
662 }
663
664 bool NetworkResourceLoader::sendBufferMaybeAborting(const WebCore::SharedBuffer& buffer, size_t encodedDataLength)
665 {
666     ASSERT(!isSynchronous());
667
668 #if PLATFORM(COCOA)
669     ShareableResource::Handle shareableResourceHandle;
670     NetworkResourceLoader::tryGetShareableHandleFromSharedBuffer(shareableResourceHandle, const_cast<WebCore::SharedBuffer&>(buffer));
671     if (!shareableResourceHandle.isNull()) {
672         send(Messages::WebResourceLoader::DidReceiveResource(shareableResourceHandle, currentTime()));
673         abort();
674         return false;
675     }
676 #endif
677
678     IPC::SharedBufferDataReference dataReference(&const_cast<WebCore::SharedBuffer&>(buffer));
679     return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
680 }
681
682 #if ENABLE(NETWORK_CACHE)
683 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
684 {
685     if (isSynchronous()) {
686         m_synchronousLoadData->response = entry->response();
687         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
688     } else {
689         if (entry->response().url() != originalRequest().url()) {
690             // This is a cached redirect. Synthesize a minimal redirect so we get things like referer header right.
691             // FIXME: We should cache the actual redirects.
692             ResourceRequest syntheticRedirectRequest(entry->response().url());
693             ResourceResponse syntheticRedirectResponse(originalRequest().url(), { }, 0, { });
694             sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(syntheticRedirectRequest, syntheticRedirectResponse));
695         }
696
697         bool needsContinueDidReceiveResponseMessage = originalRequest().requester() == ResourceRequest::Requester::Main;
698         sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
699
700 #if ENABLE(SHAREABLE_RESOURCE)
701         if (!entry->shareableResourceHandle().isNull())
702             send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle(), currentTime()));
703         else {
704 #endif
705             bool shouldContinue = sendBufferMaybeAborting(*entry->buffer(), entry->buffer()->size());
706             if (!shouldContinue)
707                 return;
708             send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
709 #if ENABLE(SHAREABLE_RESOURCE)
710         }
711 #endif
712     }
713
714     cleanup();
715 }
716
717 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
718 {
719 #if !USE(NETWORK_SESSION)
720     ASSERT(!m_handle);
721 #endif
722
723     // If the request is already conditional then the revalidation was not triggered by the disk cache
724     // and we should not overwrite the existing conditional headers.
725     if (!m_currentRequest.isConditional()) {
726         String eTag = entry->response().httpHeaderField(WebCore::HTTPHeaderName::ETag);
727         String lastModified = entry->response().httpHeaderField(WebCore::HTTPHeaderName::LastModified);
728         if (!eTag.isEmpty())
729             m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfNoneMatch, eTag);
730         if (!lastModified.isEmpty())
731             m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfModifiedSince, lastModified);
732     }
733
734     m_cacheEntryForValidation = WTF::move(entry);
735
736     startNetworkLoad();
737 }
738 #endif
739
740 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
741 {
742     return connectionToWebProcess()->connection();
743 }
744
745 void NetworkResourceLoader::consumeSandboxExtensions()
746 {
747     for (auto& extension : m_parameters.requestBodySandboxExtensions)
748         extension->consume();
749
750     if (auto& extension = m_parameters.resourceSandboxExtension)
751         extension->consume();
752
753     for (auto& fileReference : m_fileReferences)
754         fileReference->prepareForFileAccess();
755
756     m_didConsumeSandboxExtensions = true;
757 }
758
759 void NetworkResourceLoader::invalidateSandboxExtensions()
760 {
761     if (m_didConsumeSandboxExtensions) {
762         for (auto& extension : m_parameters.requestBodySandboxExtensions)
763             extension->revoke();
764         if (auto& extension = m_parameters.resourceSandboxExtension)
765             extension->revoke();
766         for (auto& fileReference : m_fileReferences)
767             fileReference->revokeFileAccess();
768     }
769
770     m_fileReferences.clear();
771
772     m_didConsumeSandboxExtensions = false;
773 }
774
775 template<typename T>
776 bool NetworkResourceLoader::sendAbortingOnFailure(T&& message, unsigned messageSendFlags)
777 {
778     bool result = messageSenderConnection()->send(std::forward<T>(message), messageSenderDestinationID(), messageSendFlags);
779     if (!result)
780         abort();
781     return result;
782 }
783
784 #if USE(PROTECTION_SPACE_AUTH_CALLBACK) && !USE(NETWORK_SESSION)
785 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
786 {
787     ASSERT(RunLoop::isMain());
788     ASSERT_UNUSED(handle, handle == m_handle);
789
790     // Handle server trust evaluation at platform-level if requested, for performance reasons.
791     if (protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
792         && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
793         continueCanAuthenticateAgainstProtectionSpace(false);
794         return;
795     }
796
797     if (isSynchronous()) {
798         // FIXME: We should ask the WebProcess like the asynchronous case below does.
799         // This is currently impossible as the WebProcess is blocked waiting on this synchronous load.
800         // It's possible that we can jump straight to the UI process to resolve this.
801         continueCanAuthenticateAgainstProtectionSpace(true);
802         return;
803     }
804     sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace));
805 }
806 #endif
807
808 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
809 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
810 {
811 #if USE(NETWORK_SESSION)
812     // FIXME: Do something here.
813     notImplemented();
814 #else
815     m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
816 #endif
817 }
818 #endif
819
820 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK) && !USE(NETWORK_SESSION)
821 bool NetworkResourceLoader::supportsDataArray()
822 {
823     notImplemented();
824     return false;
825 }
826
827 void NetworkResourceLoader::didReceiveDataArray(ResourceHandle*, CFArrayRef)
828 {
829     ASSERT_NOT_REACHED();
830     notImplemented();
831 }
832 #endif
833
834 } // namespace WebKit
835
836 #endif // ENABLE(NETWORK_PROCESS)