Clean up NETWORK_SESSION code after r191848
[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     auto size = buffer->size();
474     sharedDidReceiveBuffer(WTF::move(buffer), size);
475 }
476
477 void NetworkResourceLoader::didCompleteWithError(const WebCore::ResourceError& error)
478 {
479     if (error.isNull())
480         sharedDidFinishLoading(WTF::monotonicallyIncreasingTime());
481     else
482         sharedDidFail(error);
483 }
484
485 #else
486
487 void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse& receivedResponse)
488 {
489     ASSERT_UNUSED(handle, handle == m_handle);
490     if (sharedDidReceiveResponse(receivedResponse) == ShouldContinueDidReceiveResponse::Yes)
491         m_handle->continueDidReceiveResponse();
492 }
493
494 void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int /* encodedDataLength */)
495 {
496     // The NetworkProcess should never get a didReceiveData callback.
497     // We should always be using didReceiveBuffer.
498     ASSERT_NOT_REACHED();
499 }
500
501 void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<WebCore::SharedBuffer> buffer, int reportedEncodedDataLength)
502 {
503     ASSERT_UNUSED(handle, handle == m_handle);
504     sharedDidReceiveBuffer(WTF::move(buffer), reportedEncodedDataLength);
505 }
506
507 void NetworkResourceLoader::didFinishLoading(ResourceHandle* handle, double finishTime)
508 {
509     ASSERT_UNUSED(handle, handle == m_handle);
510     sharedDidFinishLoading(finishTime);
511 }
512
513 void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError& error)
514 {
515     ASSERT_UNUSED(handle, !handle || handle == m_handle);
516     sharedDidFail(error);
517 }
518
519 void NetworkResourceLoader::willSendRequestAsync(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& redirectResponse)
520 {
521     ASSERT_UNUSED(handle, handle == m_handle);
522     sharedWillSendRedirectedRequest(request, redirectResponse);
523 }
524
525 #endif // USE(NETWORK_SESSION)
526     
527 void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest& newRequest)
528 {
529 #if PLATFORM(COCOA)
530     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest.nsURLRequest(DoNotUpdateHTTPBody));
531 #elif USE(SOUP)
532     // FIXME: Implement ResourceRequest::updateFromDelegatePreservingOldProperties. See https://bugs.webkit.org/show_bug.cgi?id=126127.
533     m_currentRequest.updateFromDelegatePreservingOldProperties(newRequest);
534 #endif
535
536     if (m_currentRequest.isNull()) {
537 #if USE(NETWORK_SESSION)
538         // FIXME: Do something here.
539         notImplemented();
540 #else
541         m_handle->cancel();
542         didFail(m_handle.get(), cancelledError(m_currentRequest));
543 #endif
544         return;
545     }
546
547 #if USE(NETWORK_SESSION)
548     // FIXME: Do something here.
549     notImplemented();
550 #else
551     m_handle->continueWillSendRequest(m_currentRequest);
552 #endif
553 }
554
555 void NetworkResourceLoader::continueDidReceiveResponse()
556 {
557     // FIXME: Remove this check once BlobResourceHandle implements didReceiveResponseAsync correctly.
558     // Currently, it does not wait for response, so the load is likely to finish before continueDidReceiveResponse.
559 #if USE(NETWORK_SESSION)
560     // FIXME: Do something here.
561     notImplemented();
562 #else
563     if (!m_handle)
564         return;
565
566     m_handle->continueDidReceiveResponse();
567 #endif
568 }
569
570 #if !USE(NETWORK_SESSION)
571
572 void NetworkResourceLoader::didSendData(ResourceHandle* handle, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
573 {
574     ASSERT_UNUSED(handle, handle == m_handle);
575
576     if (!isSynchronous())
577         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
578 }
579
580 void NetworkResourceLoader::wasBlocked(ResourceHandle* handle)
581 {
582     ASSERT_UNUSED(handle, handle == m_handle);
583
584     didFail(handle, WebKit::blockedError(m_currentRequest));
585 }
586
587 void NetworkResourceLoader::cannotShowURL(ResourceHandle* handle)
588 {
589     ASSERT_UNUSED(handle, handle == m_handle);
590
591     didFail(handle, WebKit::cannotShowURLError(m_currentRequest));
592 }
593
594 bool NetworkResourceLoader::shouldUseCredentialStorage(ResourceHandle* handle)
595 {
596     ASSERT_UNUSED(handle, handle == m_handle || !m_handle); // m_handle will be 0 if called from ResourceHandle::start().
597
598     // When the WebProcess is handling loading a client is consulted each time this shouldUseCredentialStorage question is asked.
599     // In NetworkProcess mode we ask the WebProcess client up front once and then reuse the cached answer.
600
601     // We still need this sync version, because ResourceHandle itself uses it internally, even when the delegate uses an async one.
602
603     return m_parameters.allowStoredCredentials == AllowStoredCredentials;
604 }
605
606 void NetworkResourceLoader::didReceiveAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge& challenge)
607 {
608     ASSERT_UNUSED(handle, handle == m_handle);
609     // NetworkResourceLoader does not know whether the request is cross origin, so Web process computes an applicable credential policy for it.
610     ASSERT(m_parameters.clientCredentialPolicy != DoNotAskClientForCrossOriginCredentials);
611
612     if (m_parameters.clientCredentialPolicy == DoNotAskClientForAnyCredentials) {
613         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
614         return;
615     }
616
617     NetworkProcess::singleton().authenticationManager().didReceiveAuthenticationChallenge(m_parameters.webPageID, m_parameters.webFrameID, challenge);
618 }
619
620 void NetworkResourceLoader::didCancelAuthenticationChallenge(ResourceHandle* handle, const AuthenticationChallenge&)
621 {
622     ASSERT_UNUSED(handle, handle == m_handle);
623
624     // This function is probably not needed (see <rdar://problem/8960124>).
625     notImplemented();
626 }
627
628 void NetworkResourceLoader::receivedCancellation(ResourceHandle* handle, const AuthenticationChallenge&)
629 {
630     ASSERT_UNUSED(handle, handle == m_handle);
631
632     m_handle->cancel();
633     didFail(m_handle.get(), cancelledError(m_currentRequest));
634 }
635
636 #endif // !USE(NETWORK_SESSION)
637
638 void NetworkResourceLoader::startBufferingTimerIfNeeded()
639 {
640     if (isSynchronous())
641         return;
642     if (m_bufferingTimer.isActive())
643         return;
644     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
645 }
646
647 void NetworkResourceLoader::bufferingTimerFired()
648 {
649     ASSERT(m_bufferedData);
650 #if !USE(NETWORK_SESSION)
651     ASSERT(m_handle);
652 #endif
653     if (!m_bufferedData->size())
654         return;
655
656     IPC::SharedBufferDataReference dataReference(m_bufferedData.get());
657     size_t encodedLength = m_bufferedDataEncodedDataLength;
658
659     m_bufferedData = WebCore::SharedBuffer::create();
660     m_bufferedDataEncodedDataLength = 0;
661
662     sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedLength));
663 }
664
665 bool NetworkResourceLoader::sendBufferMaybeAborting(const WebCore::SharedBuffer& buffer, size_t encodedDataLength)
666 {
667     ASSERT(!isSynchronous());
668
669 #if PLATFORM(COCOA)
670     ShareableResource::Handle shareableResourceHandle;
671     NetworkResourceLoader::tryGetShareableHandleFromSharedBuffer(shareableResourceHandle, const_cast<WebCore::SharedBuffer&>(buffer));
672     if (!shareableResourceHandle.isNull()) {
673         send(Messages::WebResourceLoader::DidReceiveResource(shareableResourceHandle, currentTime()));
674         abort();
675         return false;
676     }
677 #endif
678
679     IPC::SharedBufferDataReference dataReference(&const_cast<WebCore::SharedBuffer&>(buffer));
680     return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
681 }
682
683 #if ENABLE(NETWORK_CACHE)
684 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
685 {
686     if (isSynchronous()) {
687         m_synchronousLoadData->response = entry->response();
688         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
689     } else {
690         if (entry->response().url() != originalRequest().url()) {
691             // This is a cached redirect. Synthesize a minimal redirect so we get things like referer header right.
692             // FIXME: We should cache the actual redirects.
693             ResourceRequest syntheticRedirectRequest(entry->response().url());
694             ResourceResponse syntheticRedirectResponse(originalRequest().url(), { }, 0, { });
695             sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(syntheticRedirectRequest, syntheticRedirectResponse));
696         }
697
698         bool needsContinueDidReceiveResponseMessage = originalRequest().requester() == ResourceRequest::Requester::Main;
699         sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry->response(), needsContinueDidReceiveResponseMessage));
700
701 #if ENABLE(SHAREABLE_RESOURCE)
702         if (!entry->shareableResourceHandle().isNull())
703             send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle(), currentTime()));
704         else {
705 #endif
706             bool shouldContinue = sendBufferMaybeAborting(*entry->buffer(), entry->buffer()->size());
707             if (!shouldContinue)
708                 return;
709             send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
710 #if ENABLE(SHAREABLE_RESOURCE)
711         }
712 #endif
713     }
714
715     cleanup();
716 }
717
718 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
719 {
720 #if !USE(NETWORK_SESSION)
721     ASSERT(!m_handle);
722 #endif
723
724     // If the request is already conditional then the revalidation was not triggered by the disk cache
725     // and we should not overwrite the existing conditional headers.
726     if (!m_currentRequest.isConditional()) {
727         String eTag = entry->response().httpHeaderField(WebCore::HTTPHeaderName::ETag);
728         String lastModified = entry->response().httpHeaderField(WebCore::HTTPHeaderName::LastModified);
729         if (!eTag.isEmpty())
730             m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfNoneMatch, eTag);
731         if (!lastModified.isEmpty())
732             m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfModifiedSince, lastModified);
733     }
734
735     m_cacheEntryForValidation = WTF::move(entry);
736
737     startNetworkLoad();
738 }
739 #endif
740
741 IPC::Connection* NetworkResourceLoader::messageSenderConnection()
742 {
743     return connectionToWebProcess()->connection();
744 }
745
746 void NetworkResourceLoader::consumeSandboxExtensions()
747 {
748     for (auto& extension : m_parameters.requestBodySandboxExtensions)
749         extension->consume();
750
751     if (auto& extension = m_parameters.resourceSandboxExtension)
752         extension->consume();
753
754     for (auto& fileReference : m_fileReferences)
755         fileReference->prepareForFileAccess();
756
757     m_didConsumeSandboxExtensions = true;
758 }
759
760 void NetworkResourceLoader::invalidateSandboxExtensions()
761 {
762     if (m_didConsumeSandboxExtensions) {
763         for (auto& extension : m_parameters.requestBodySandboxExtensions)
764             extension->revoke();
765         if (auto& extension = m_parameters.resourceSandboxExtension)
766             extension->revoke();
767         for (auto& fileReference : m_fileReferences)
768             fileReference->revokeFileAccess();
769     }
770
771     m_fileReferences.clear();
772
773     m_didConsumeSandboxExtensions = false;
774 }
775
776 template<typename T>
777 bool NetworkResourceLoader::sendAbortingOnFailure(T&& message, unsigned messageSendFlags)
778 {
779     bool result = messageSenderConnection()->send(std::forward<T>(message), messageSenderDestinationID(), messageSendFlags);
780     if (!result)
781         abort();
782     return result;
783 }
784
785 #if USE(PROTECTION_SPACE_AUTH_CALLBACK) && !USE(NETWORK_SESSION)
786 void NetworkResourceLoader::canAuthenticateAgainstProtectionSpaceAsync(ResourceHandle* handle, const ProtectionSpace& protectionSpace)
787 {
788     ASSERT(RunLoop::isMain());
789     ASSERT_UNUSED(handle, handle == m_handle);
790
791     // Handle server trust evaluation at platform-level if requested, for performance reasons.
792     if (protectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested
793         && !NetworkProcess::singleton().canHandleHTTPSServerTrustEvaluation()) {
794         continueCanAuthenticateAgainstProtectionSpace(false);
795         return;
796     }
797
798     if (isSynchronous()) {
799         // FIXME: We should ask the WebProcess like the asynchronous case below does.
800         // This is currently impossible as the WebProcess is blocked waiting on this synchronous load.
801         // It's possible that we can jump straight to the UI process to resolve this.
802         continueCanAuthenticateAgainstProtectionSpace(true);
803         return;
804     }
805     sendAbortingOnFailure(Messages::WebResourceLoader::CanAuthenticateAgainstProtectionSpace(protectionSpace));
806 }
807 #endif
808
809 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
810 void NetworkResourceLoader::continueCanAuthenticateAgainstProtectionSpace(bool result)
811 {
812 #if USE(NETWORK_SESSION)
813     // FIXME: Do something here.
814     notImplemented();
815 #else
816     m_handle->continueCanAuthenticateAgainstProtectionSpace(result);
817 #endif
818 }
819 #endif
820
821 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK) && !USE(NETWORK_SESSION)
822 bool NetworkResourceLoader::supportsDataArray()
823 {
824     notImplemented();
825     return false;
826 }
827
828 void NetworkResourceLoader::didReceiveDataArray(ResourceHandle*, CFArrayRef)
829 {
830     ASSERT_NOT_REACHED();
831     notImplemented();
832 }
833 #endif
834
835 } // namespace WebKit
836
837 #endif // ENABLE(NETWORK_PROCESS)