Use normal loading path for ping loads
[WebKit-https.git] / Source / WebKit / NetworkProcess / NetworkResourceLoader.cpp
1 /*
2  * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkResourceLoader.h"
28
29 #include "DataReference.h"
30 #include "FormDataReference.h"
31 #include "Logging.h"
32 #include "NetworkCache.h"
33 #include "NetworkConnectionToWebProcess.h"
34 #include "NetworkLoad.h"
35 #include "NetworkLoadChecker.h"
36 #include "NetworkProcess.h"
37 #include "NetworkProcessConnectionMessages.h"
38 #include "NetworkSession.h"
39 #include "SharedBufferDataReference.h"
40 #include "WebCoreArgumentCoders.h"
41 #include "WebErrors.h"
42 #include "WebPageMessages.h"
43 #include "WebResourceLoaderMessages.h"
44 #include "WebsiteDataStoreParameters.h"
45 #include <WebCore/BlobDataFileReference.h>
46 #include <WebCore/CertificateInfo.h>
47 #include <WebCore/ContentSecurityPolicy.h>
48 #include <WebCore/DiagnosticLoggingKeys.h>
49 #include <WebCore/HTTPParsers.h>
50 #include <WebCore/NetworkLoadMetrics.h>
51 #include <WebCore/NetworkStorageSession.h>
52 #include <WebCore/RegistrableDomain.h>
53 #include <WebCore/SameSiteInfo.h>
54 #include <WebCore/SecurityOrigin.h>
55 #include <WebCore/SharedBuffer.h>
56 #include <wtf/RunLoop.h>
57
58 #if USE(QUICK_LOOK)
59 #include <WebCore/PreviewConverter.h>
60 #endif
61
62 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
63 #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Network, "%p - NetworkResourceLoader::" fmt, this, ##__VA_ARGS__)
64
65 namespace WebKit {
66 using namespace WebCore;
67
68 struct NetworkResourceLoader::SynchronousLoadData {
69     WTF_MAKE_STRUCT_FAST_ALLOCATED;
70
71     SynchronousLoadData(Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply&& reply)
72         : delayedReply(WTFMove(reply))
73     {
74         ASSERT(delayedReply);
75     }
76     ResourceRequest currentRequest;
77     Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply delayedReply;
78     ResourceResponse response;
79     ResourceError error;
80 };
81
82 static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
83 {
84     ASSERT(data.delayedReply);
85     ASSERT(!data.response.isNull() || !data.error.isNull());
86
87     Vector<char> responseBuffer;
88     if (buffer && buffer->size())
89         responseBuffer.append(buffer->data(), buffer->size());
90
91     data.delayedReply(data.error, data.response, responseBuffer);
92     data.delayedReply = nullptr;
93 }
94
95 NetworkResourceLoader::NetworkResourceLoader(NetworkResourceLoadParameters&& parameters, NetworkConnectionToWebProcess& connection, Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply&& synchronousReply)
96     : m_parameters { WTFMove(parameters) }
97     , m_connection { connection }
98     , m_fileReferences(connection.resolveBlobReferences(m_parameters))
99     , m_isAllowedToAskUserForCredentials { m_parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
100     , m_bufferingTimer { *this, &NetworkResourceLoader::bufferingTimerFired }
101     , m_cache { sessionID().isEphemeral() ? nullptr : connection.networkProcess().cache() }
102     , m_shouldCaptureExtraNetworkLoadMetrics(m_connection->captureExtraNetworkLoadMetricsEnabled())
103 {
104     ASSERT(RunLoop::isMain());
105     // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
106     //        Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
107     ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
108
109     if (synchronousReply || parameters.shouldRestrictHTTPResponseAccess || parameters.options.keepAlive) {
110         NetworkLoadChecker::LoadType requestLoadType = isMainFrameLoad() ? NetworkLoadChecker::LoadType::MainFrame : NetworkLoadChecker::LoadType::Other;
111         m_networkLoadChecker = std::make_unique<NetworkLoadChecker>(connection.networkProcess(), FetchOptions { m_parameters.options }, m_parameters.sessionID, m_parameters.webPageID, m_parameters.webFrameID, HTTPHeaderMap { m_parameters.originalRequestHeaders }, URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.preflightPolicy, originalRequest().httpReferrer(), m_parameters.isHTTPSUpgradeEnabled, shouldCaptureExtraNetworkLoadMetrics(), requestLoadType);
112         if (m_parameters.cspResponseHeaders)
113             m_networkLoadChecker->setCSPResponseHeaders(ContentSecurityPolicyResponseHeaders { m_parameters.cspResponseHeaders.value() });
114 #if ENABLE(CONTENT_EXTENSIONS)
115         m_networkLoadChecker->setContentExtensionController(URL { m_parameters.mainDocumentURL }, m_parameters.userContentControllerIdentifier);
116 #endif
117     }
118     if (synchronousReply)
119         m_synchronousLoadData = std::make_unique<SynchronousLoadData>(WTFMove(synchronousReply));
120 }
121
122 NetworkResourceLoader::~NetworkResourceLoader()
123 {
124     ASSERT(RunLoop::isMain());
125     ASSERT(!m_networkLoad);
126     ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
127     ASSERT(m_fileReferences.isEmpty());
128     if (m_responseCompletionHandler)
129         m_responseCompletionHandler(PolicyAction::Ignore);
130 }
131
132 bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
133 {
134     if (!m_cache)
135         return false;
136     ASSERT(!sessionID().isEphemeral());
137
138     if (!request.url().protocolIsInHTTPFamily())
139         return false;
140     if (originalRequest().cachePolicy() == WebCore::ResourceRequestCachePolicy::DoNotUseAnyCache)
141         return false;
142
143     return true;
144 }
145
146 bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
147 {
148     if (!canUseCache(request) || m_cacheEntryForMaxAgeCapValidation)
149         return false;
150     // Limit cached redirects to avoid cycles and other trouble.
151     // Networking layer follows over 30 redirects but caching that many seems unnecessary.
152     static const unsigned maximumCachedRedirectCount { 5 };
153     if (m_redirectCount > maximumCachedRedirectCount)
154         return false;
155
156     return true;
157 }
158
159 bool NetworkResourceLoader::isSynchronous() const
160 {
161     return !!m_synchronousLoadData;
162 }
163
164 void NetworkResourceLoader::start()
165 {
166     ASSERT(RunLoop::isMain());
167
168     m_networkActivityTracker = m_connection->startTrackingResourceLoad(m_parameters.webPageID, m_parameters.identifier, isMainResource(), sessionID());
169
170     ASSERT(!m_wasStarted);
171     m_wasStarted = true;
172
173     if (m_networkLoadChecker) {
174         m_networkLoadChecker->check(ResourceRequest { originalRequest() }, this, [this] (auto&& result) {
175             WTF::switchOn(result,
176                 [this] (ResourceError& error) {
177                     RELEASE_LOG_IF_ALLOWED("start: error checking (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d, parentPID = %d, error.domain = %{public}s, error.code = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, this->isMainResource(), this->isSynchronous(), m_parameters.parentPID, error.domain().utf8().data(), error.errorCode());
178                     if (!error.isCancellation())
179                         this->didFailLoading(error);
180                 },
181                 [this] (NetworkLoadChecker::RedirectionTriplet& triplet) {
182                     this->m_isWaitingContinueWillSendRequestForCachedRedirect = true;
183                     this->willSendRedirectedRequest(WTFMove(triplet.request), WTFMove(triplet.redirectRequest), WTFMove(triplet.redirectResponse));
184                     RELEASE_LOG_IF_ALLOWED("start: synthetic redirect sent because request URL was modified (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d, parentPID = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, this->isMainResource(), this->isSynchronous(), m_parameters.parentPID);
185                 },
186                 [this] (ResourceRequest& request) {
187                     if (this->canUseCache(request)) {
188                         RELEASE_LOG_IF_ALLOWED("start: Checking cache for resource (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d, parentPID = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, this->isMainResource(), this->isSynchronous(), m_parameters.parentPID);
189                         this->retrieveCacheEntry(request);
190                         return;
191                     }
192
193                     this->startNetworkLoad(WTFMove(request), FirstLoad::Yes);
194                 }
195             );
196         });
197         return;
198     }
199     // FIXME: Remove that code path once m_networkLoadChecker is used for all network loads.
200     if (canUseCache(originalRequest())) {
201         RELEASE_LOG_IF_ALLOWED("start: Checking cache for resource (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d, parentPID = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous(), m_parameters.parentPID);
202         retrieveCacheEntry(originalRequest());
203         return;
204     }
205
206     startNetworkLoad(ResourceRequest { originalRequest() }, FirstLoad::Yes);
207 }
208
209 void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
210 {
211     ASSERT(canUseCache(request));
212
213     RefPtr<NetworkResourceLoader> loader(this);
214     m_cache->retrieve(request, { m_parameters.webPageID, m_parameters.webFrameID }, [this, loader = WTFMove(loader), request = ResourceRequest { request }](auto entry, auto info) mutable {
215         if (loader->hasOneRef()) {
216             // The loader has been aborted and is only held alive by this lambda.
217             return;
218         }
219
220         loader->logSlowCacheRetrieveIfNeeded(info);
221
222         if (!entry) {
223             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource not in cache (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
224             loader->startNetworkLoad(WTFMove(request), FirstLoad::Yes);
225             return;
226         }
227 #if ENABLE(RESOURCE_LOAD_STATISTICS)
228         if (entry->hasReachedPrevalentResourceAgeCap()) {
229             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource has reached prevalent resource age cap (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
230             m_cacheEntryForMaxAgeCapValidation = WTFMove(entry);
231             ResourceRequest revalidationRequest = originalRequest();
232             loader->startNetworkLoad(WTFMove(revalidationRequest), FirstLoad::Yes);
233             return;
234         }
235 #endif
236         if (entry->redirectRequest()) {
237             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Handling redirect (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
238             loader->dispatchWillSendRequestForCacheEntry(WTFMove(request), WTFMove(entry));
239             return;
240         }
241         if (loader->m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) {
242             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Resource does not have required certificate (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
243             loader->startNetworkLoad(WTFMove(request), FirstLoad::Yes);
244             return;
245         }
246         if (entry->needsValidation() || request.cachePolicy() == WebCore::ResourceRequestCachePolicy::RefreshAnyCacheData) {
247             RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Validating cache entry (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
248             loader->validateCacheEntry(WTFMove(entry));
249             return;
250         }
251         RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Retrieved resource from cache (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
252         loader->didRetrieveCacheEntry(WTFMove(entry));
253     });
254 }
255
256 void NetworkResourceLoader::startNetworkLoad(ResourceRequest&& request, FirstLoad load)
257 {
258     if (load == FirstLoad::Yes) {
259         RELEASE_LOG_IF_ALLOWED("startNetworkLoad: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isMainResource = %d, isSynchronous = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, isMainResource(), isSynchronous());
260
261         consumeSandboxExtensions();
262
263         if (isSynchronous() || m_parameters.maximumBufferingTime > 0_s)
264             m_bufferedData = SharedBuffer::create();
265
266         if (canUseCache(request))
267             m_bufferedDataForCache = SharedBuffer::create();
268     }
269
270     NetworkLoadParameters parameters = m_parameters;
271     parameters.networkActivityTracker = m_networkActivityTracker;
272     if (parameters.storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use && m_networkLoadChecker)
273         parameters.storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy();
274
275     if (request.url().protocolIsBlob())
276         parameters.blobFileReferences = m_connection->filesInBlob(originalRequest().url());
277
278     auto* networkSession = m_connection->networkProcess().networkSession(parameters.sessionID);
279     if (!networkSession && parameters.sessionID.isEphemeral()) {
280         m_connection->networkProcess().addWebsiteDataStore(WebsiteDataStoreParameters::privateSessionParameters(parameters.sessionID));
281         networkSession = m_connection->networkProcess().networkSession(parameters.sessionID);
282     }
283     if (!networkSession) {
284         WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", parameters.sessionID.sessionID());
285         RELEASE_LOG_ERROR_IF_ALLOWED("startNetworkLoad: Attempted to create a NetworkLoad with a session that does not exist (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", sessionID=%" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, parameters.sessionID.sessionID());
286         m_connection->networkProcess().logDiagnosticMessage(m_parameters.webPageID, WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::invalidSessionIDKey(), WebCore::ShouldSample::No);
287         didFailLoading(internalError(request.url()));
288         return;
289     }
290
291     parameters.request = WTFMove(request);
292     m_networkLoad = std::make_unique<NetworkLoad>(*this, &m_connection->blobRegistry(), WTFMove(parameters), *networkSession);
293
294     RELEASE_LOG_IF_ALLOWED("startNetworkLoad: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", description = %{public}s)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, m_networkLoad->description().utf8().data());
295 }
296
297 void NetworkResourceLoader::cleanup(LoadResult result)
298 {
299     ASSERT(RunLoop::isMain());
300
301     m_connection->stopTrackingResourceLoad(m_parameters.identifier,
302         result == LoadResult::Success ? NetworkActivityTracker::CompletionCode::Success :
303         result == LoadResult::Failure ? NetworkActivityTracker::CompletionCode::Failure :
304         NetworkActivityTracker::CompletionCode::None);
305
306     m_bufferingTimer.stop();
307
308     invalidateSandboxExtensions();
309
310     m_networkLoad = nullptr;
311
312     // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
313     m_connection->didCleanupResourceLoader(*this);
314 }
315
316 void NetworkResourceLoader::convertToDownload(DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
317 {
318     // This can happen if the resource came from the disk cache.
319     if (!m_networkLoad) {
320         m_connection->networkProcess().downloadManager().startDownload(m_parameters.sessionID, downloadID, request);
321         abort();
322         return;
323     }
324
325     if (m_responseCompletionHandler)
326         m_connection->networkProcess().downloadManager().convertNetworkLoadToDownload(downloadID, std::exchange(m_networkLoad, nullptr), WTFMove(m_responseCompletionHandler), WTFMove(m_fileReferences), request, response);
327 }
328
329 void NetworkResourceLoader::abort()
330 {
331     ASSERT(RunLoop::isMain());
332
333     RELEASE_LOG_IF_ALLOWED("abort: Canceling resource load (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")",
334         m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
335
336     if (m_parameters.options.keepAlive && m_response.isNull() && !m_isKeptAlive) {
337         m_isKeptAlive = true;
338         m_connection->transferKeptAliveLoad(*this);
339         return;
340     }
341
342     if (m_networkLoad) {
343         if (canUseCache(m_networkLoad->currentRequest())) {
344             // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
345             if (!m_response.isNull())
346                 m_cache->remove(m_networkLoad->currentRequest());
347         }
348         m_networkLoad->cancel();
349     }
350
351     cleanup(LoadResult::Cancel);
352 }
353
354 bool NetworkResourceLoader::shouldInterruptLoadForXFrameOptions(const String& xFrameOptions, const URL& url)
355 {
356     if (isMainFrameLoad())
357         return false;
358
359     switch (parseXFrameOptionsHeader(xFrameOptions)) {
360     case XFrameOptionsNone:
361     case XFrameOptionsAllowAll:
362         return false;
363     case XFrameOptionsDeny:
364         return true;
365     case XFrameOptionsSameOrigin: {
366         auto origin = SecurityOrigin::create(url);
367         auto topFrameOrigin = m_parameters.frameAncestorOrigins.last();
368         if (!origin->isSameSchemeHostPort(*topFrameOrigin))
369             return true;
370         for (auto& ancestorOrigin : m_parameters.frameAncestorOrigins) {
371             if (!origin->isSameSchemeHostPort(*ancestorOrigin))
372                 return true;
373         }
374         return false;
375     }
376     case XFrameOptionsConflict: {
377         String errorMessage = "Multiple 'X-Frame-Options' headers with conflicting values ('" + xFrameOptions + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.";
378         send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
379         return true;
380     }
381     case XFrameOptionsInvalid: {
382         String errorMessage = "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + xFrameOptions + "' is not a recognized directive. The header will be ignored.";
383         send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
384         return false;
385     }
386     }
387     ASSERT_NOT_REACHED();
388     return false;
389 }
390
391 bool NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(const ResourceResponse& response)
392 {
393     ASSERT(isMainResource());
394
395 #if USE(QUICK_LOOK)
396     if (PreviewConverter::supportsMIMEType(response.mimeType()))
397         return false;
398 #endif
399
400     auto url = response.url();
401     ContentSecurityPolicy contentSecurityPolicy { URL { url }, this };
402     contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders { response }, originalRequest().httpReferrer());
403     if (!contentSecurityPolicy.allowFrameAncestors(m_parameters.frameAncestorOrigins, url))
404         return true;
405
406     if (!contentSecurityPolicy.overridesXFrameOptions()) {
407         String xFrameOptions = m_response.httpHeaderField(HTTPHeaderName::XFrameOptions);
408         if (!xFrameOptions.isNull() && shouldInterruptLoadForXFrameOptions(xFrameOptions, response.url())) {
409             String errorMessage = "Refused to display '" + response.url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + xFrameOptions + "'.";
410             send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  MessageSource::Security, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
411             return true;
412         }
413     }
414     return false;
415 }
416
417 void NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse, ResponseCompletionHandler&& completionHandler)
418 {
419     RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", httpStatusCode = %d, length = %" PRId64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, receivedResponse.httpStatusCode(), receivedResponse.expectedContentLength());
420
421     m_response = WTFMove(receivedResponse);
422
423     if (shouldCaptureExtraNetworkLoadMetrics() && m_networkLoadChecker) {
424         auto information = m_networkLoadChecker->takeNetworkLoadInformation();
425         information.response = m_response;
426         m_connection->addNetworkLoadInformation(identifier(), WTFMove(information));
427     }
428
429     // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
430     if (!isSynchronous() && m_response.isMultipart())
431         m_bufferedData = nullptr;
432
433     if (m_response.isMultipart())
434         m_bufferedDataForCache = nullptr;
435
436     if (m_cacheEntryForValidation) {
437         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
438         if (validationSucceeded) {
439             m_cacheEntryForValidation = m_cache->update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
440             // If the request was conditional then this revalidation was not triggered by the network cache and we pass the 304 response to WebCore.
441             if (originalRequest().isConditional())
442                 m_cacheEntryForValidation = nullptr;
443         } else
444             m_cacheEntryForValidation = nullptr;
445     }
446     if (m_cacheEntryForValidation)
447         return completionHandler(PolicyAction::Use);
448
449     if (isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(m_response)) {
450         auto response = sanitizeResponseIfPossible(ResourceResponse { m_response }, ResourceResponse::SanitizationType::CrossOriginSafe);
451         send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { response });
452         return completionHandler(PolicyAction::Ignore);
453     }
454
455     if (m_networkLoadChecker) {
456         auto error = m_networkLoadChecker->validateResponse(m_response);
457         if (!error.isNull()) {
458             RunLoop::main().dispatch([protectedThis = makeRef(*this), error = WTFMove(error)] {
459                 if (protectedThis->m_networkLoad)
460                     protectedThis->didFailLoading(error);
461             });
462             return completionHandler(PolicyAction::Ignore);
463         }
464     }
465
466     auto response = sanitizeResponseIfPossible(ResourceResponse { m_response }, ResourceResponse::SanitizationType::CrossOriginSafe);
467     if (isSynchronous()) {
468         m_synchronousLoadData->response = WTFMove(response);
469         return completionHandler(PolicyAction::Use);
470     }
471
472     // We wait to receive message NetworkResourceLoader::ContinueDidReceiveResponse before continuing a load for
473     // a main resource because the embedding client must decide whether to allow the load.
474     bool willWaitForContinueDidReceiveResponse = isMainResource();
475     send(Messages::WebResourceLoader::DidReceiveResponse { response, willWaitForContinueDidReceiveResponse });
476
477     if (willWaitForContinueDidReceiveResponse) {
478         m_responseCompletionHandler = WTFMove(completionHandler);
479         return;
480     }
481
482     if (m_isKeptAlive) {
483         m_responseCompletionHandler = WTFMove(completionHandler);
484         RunLoop::main().dispatch([protectedThis = makeRef(*this)] {
485             protectedThis->didFinishLoading(NetworkLoadMetrics { });
486         });
487         return;
488     }
489
490     completionHandler(PolicyAction::Use);
491 }
492
493 void NetworkResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
494 {
495     if (!m_numBytesReceived)
496         RELEASE_LOG_IF_ALLOWED("didReceiveBuffer: Started receiving data (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
497     m_numBytesReceived += buffer->size();
498
499     ASSERT(!m_cacheEntryForValidation);
500
501     if (m_bufferedDataForCache) {
502         // Prevent memory growth in case of streaming data.
503         const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
504         if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
505             m_bufferedDataForCache->append(buffer.get());
506         else
507             m_bufferedDataForCache = nullptr;
508     }
509     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
510     unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
511
512     if (m_bufferedData) {
513         m_bufferedData->append(buffer.get());
514         m_bufferedDataEncodedDataLength += encodedDataLength;
515         startBufferingTimerIfNeeded();
516         return;
517     }
518     sendBuffer(buffer, encodedDataLength);
519 }
520
521 void NetworkResourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
522 {
523     RELEASE_LOG_IF_ALLOWED("didFinishLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", length = %zd)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, m_numBytesReceived);
524
525     if (shouldCaptureExtraNetworkLoadMetrics())
526         m_connection->addNetworkLoadInformationMetrics(identifier(), networkLoadMetrics);
527
528     if (m_cacheEntryForValidation) {
529         // 304 Not Modified
530         ASSERT(m_response.httpStatusCode() == 304);
531         LOG(NetworkCache, "(NetworkProcess) revalidated");
532         didRetrieveCacheEntry(WTFMove(m_cacheEntryForValidation));
533         return;
534     }
535
536 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
537     if (shouldLogCookieInformation(m_connection, sessionID()))
538         logCookieInformation();
539 #endif
540
541     if (isSynchronous())
542         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
543     else {
544         if (m_bufferedData && !m_bufferedData->isEmpty()) {
545             // FIXME: Pass a real value or remove the encoded data size feature.
546             sendBuffer(*m_bufferedData, -1);
547         }
548         send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
549     }
550
551     tryStoreAsCacheEntry();
552
553     cleanup(LoadResult::Success);
554 }
555
556 void NetworkResourceLoader::didFailLoading(const ResourceError& error)
557 {
558     RELEASE_LOG_IF_ALLOWED("didFailLoading: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", isTimeout = %d, isCancellation = %d, isAccessControl = %d, errCode = %d)", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier, error.isTimeout(), error.isCancellation(), error.isAccessControl(), error.errorCode());
559
560     if (shouldCaptureExtraNetworkLoadMetrics())
561         m_connection->removeNetworkLoadInformation(identifier());
562
563     ASSERT(!error.isNull());
564
565     m_cacheEntryForValidation = nullptr;
566
567     if (isSynchronous()) {
568         m_synchronousLoadData->error = error;
569         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
570     } else if (auto* connection = messageSenderConnection())
571         connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
572
573     cleanup(LoadResult::Failure);
574 }
575
576 void NetworkResourceLoader::didBlockAuthenticationChallenge()
577 {
578     send(Messages::WebResourceLoader::DidBlockAuthenticationChallenge());
579 }
580
581 Optional<Seconds> NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation(const ResourceRequest& request, const ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
582 {
583 #if ENABLE(RESOURCE_LOAD_STATISTICS)
584     bool existingCacheEntryMatchesNewResponse = false;
585     if (m_cacheEntryForMaxAgeCapValidation) {
586         ASSERT(redirectResponse.source() == ResourceResponse::Source::Network);
587         ASSERT(redirectResponse.isRedirection());
588         if (redirectResponse.httpHeaderField(WebCore::HTTPHeaderName::Location) == m_cacheEntryForMaxAgeCapValidation->response().httpHeaderField(WebCore::HTTPHeaderName::Location))
589             existingCacheEntryMatchesNewResponse = true;
590
591         m_cache->remove(m_cacheEntryForMaxAgeCapValidation->key());
592         m_cacheEntryForMaxAgeCapValidation = nullptr;
593     }
594     
595     if (!existingCacheEntryMatchesNewResponse) {
596         if (auto* networkStorageSession = m_connection->networkProcess().storageSession(sessionID()))
597             return networkStorageSession->maxAgeCacheCap(request);
598     }
599 #endif
600     return WTF::nullopt;
601 }
602
603 void NetworkResourceLoader::handleAdClickAttributionConversion(AdClickAttribution::Conversion&& conversion, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest)
604 {
605     ASSERT(!sessionID().isEphemeral());
606
607     RegistrableDomain redirectDomain { redirectRequest.url() };
608     auto& firstPartyURL = redirectRequest.firstPartyForCookies();
609     NetworkSession* networkSession = nullptr;
610     // The redirect has to be done by the same registrable domain and it has to be a third-party request.
611     if (redirectDomain.matches(requestURL) && !redirectDomain.matches(firstPartyURL) && (networkSession = m_connection->networkProcess().networkSession(sessionID())))
612         networkSession->convertAdClickAttribution(AdClickAttribution::Source { WTFMove(redirectDomain) }, AdClickAttribution::Destination { firstPartyURL }, WTFMove(conversion));
613 }
614
615 void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
616 {
617     ++m_redirectCount;
618
619     Optional<AdClickAttribution::Conversion> adClickConversion;
620     if (!sessionID().isEphemeral())
621         adClickConversion = AdClickAttribution::parseConversionRequest(redirectRequest.url());
622
623     auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, redirectRequest, redirectResponse);
624     if (redirectResponse.source() == ResourceResponse::Source::Network && canUseCachedRedirect(request))
625         m_cache->storeRedirect(request, redirectResponse, redirectRequest, maxAgeCap);
626
627     if (m_networkLoadChecker) {
628         if (adClickConversion)
629             m_networkLoadChecker->enableContentExtensionsCheck();
630         m_networkLoadChecker->storeRedirectionIfNeeded(request, redirectResponse);
631         m_networkLoadChecker->checkRedirection(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), this, [protectedThis = makeRef(*this), this, storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy(), adClickConversion = WTFMove(adClickConversion)](auto&& result) mutable {
632             if (!result.has_value()) {
633                 if (result.error().isCancellation())
634                     return;
635
636                 this->didFailLoading(result.error());
637                 return;
638             }
639
640             if (m_parameters.options.redirect == FetchOptions::Redirect::Manual) {
641                 this->didFinishWithRedirectResponse(WTFMove(result->redirectResponse));
642                 return;
643             }
644
645             if (this->isSynchronous()) {
646                 if (storedCredentialsPolicy != m_networkLoadChecker->storedCredentialsPolicy()) {
647                     // We need to restart the load to update the session according the new credential policy.
648                     this->restartNetworkLoad(WTFMove(result->redirectRequest));
649                     return;
650                 }
651
652                 // We do not support prompting for credentials for synchronous loads. If we ever change this policy then
653                 // we need to take care to prompt if and only if request and redirectRequest are not mixed content.
654                 this->continueWillSendRequest(WTFMove(result->redirectRequest), false);
655                 return;
656             }
657
658             m_shouldRestartLoad = storedCredentialsPolicy != m_networkLoadChecker->storedCredentialsPolicy();
659             this->continueWillSendRedirectedRequest(WTFMove(result->request), WTFMove(result->redirectRequest), WTFMove(result->redirectResponse), WTFMove(adClickConversion));
660         });
661         return;
662     }
663     continueWillSendRedirectedRequest(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), WTFMove(adClickConversion));
664 }
665
666 void NetworkResourceLoader::continueWillSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse, Optional<AdClickAttribution::Conversion>&& adClickConversion)
667 {
668     ASSERT(!isSynchronous());
669
670     if (m_isKeptAlive) {
671         continueWillSendRequest(WTFMove(request), false);
672         return;
673     }
674
675     if (adClickConversion)
676         handleAdClickAttributionConversion(WTFMove(*adClickConversion), request.url(), redirectRequest);
677     send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, sanitizeResponseIfPossible(WTFMove(redirectResponse), ResourceResponse::SanitizationType::Redirection)));
678 }
679
680 void NetworkResourceLoader::didFinishWithRedirectResponse(ResourceResponse&& redirectResponse)
681 {
682     redirectResponse.setType(ResourceResponse::Type::Opaqueredirect);
683     didReceiveResponse(WTFMove(redirectResponse), [] (auto) { });
684
685     WebCore::NetworkLoadMetrics networkLoadMetrics;
686     networkLoadMetrics.markComplete();
687     networkLoadMetrics.responseBodyBytesReceived = 0;
688     networkLoadMetrics.responseBodyDecodedSize = 0;
689     send(Messages::WebResourceLoader::DidFinishResourceLoad { networkLoadMetrics });
690
691     cleanup(LoadResult::Success);
692 }
693
694 ResourceResponse NetworkResourceLoader::sanitizeResponseIfPossible(ResourceResponse&& response, ResourceResponse::SanitizationType type)
695 {
696     if (m_parameters.shouldRestrictHTTPResponseAccess)
697         response.sanitizeHTTPHeaderFields(type);
698
699     return WTFMove(response);
700 }
701
702 void NetworkResourceLoader::restartNetworkLoad(WebCore::ResourceRequest&& newRequest)
703 {
704     if (m_networkLoad)
705         m_networkLoad->cancel();
706
707     startNetworkLoad(WTFMove(newRequest), FirstLoad::No);
708 }
709
710 void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
711 {
712     if (m_shouldRestartLoad) {
713         m_shouldRestartLoad = false;
714         restartNetworkLoad(WTFMove(newRequest));
715         return;
716     }
717
718     if (m_networkLoadChecker) {
719         // FIXME: We should be doing this check when receiving the redirection and not allow about protocol as per fetch spec.
720         if (!newRequest.url().protocolIsInHTTPFamily() && !newRequest.url().protocolIsAbout() && m_redirectCount) {
721             didFailLoading(ResourceError { String { }, 0, newRequest.url(), "Redirection to URL with a scheme that is not HTTP(S)"_s, ResourceError::Type::AccessControl });
722             return;
723         }
724     }
725
726     RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_parameters.webPageID, m_parameters.webFrameID, m_parameters.identifier);
727
728     m_isAllowedToAskUserForCredentials = isAllowedToAskUserForCredentials;
729
730     // If there is a match in the network cache, we need to reuse the original cache policy and partition.
731     newRequest.setCachePolicy(originalRequest().cachePolicy());
732     newRequest.setCachePartition(originalRequest().cachePartition());
733
734     if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
735         m_isWaitingContinueWillSendRequestForCachedRedirect = false;
736
737         LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
738
739         if (canUseCachedRedirect(newRequest))
740             retrieveCacheEntry(newRequest);
741         else
742             startNetworkLoad(WTFMove(newRequest), FirstLoad::Yes);
743
744         return;
745     }
746
747     if (m_networkLoad)
748         m_networkLoad->continueWillSendRequest(WTFMove(newRequest));
749 }
750
751 void NetworkResourceLoader::continueDidReceiveResponse()
752 {
753     if (m_cacheEntryWaitingForContinueDidReceiveResponse) {
754         sendResultForCacheEntry(WTFMove(m_cacheEntryWaitingForContinueDidReceiveResponse));
755         cleanup(LoadResult::Success);
756         return;
757     }
758
759     if (m_responseCompletionHandler)
760         m_responseCompletionHandler(PolicyAction::Use);
761 }
762
763 void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
764 {
765     if (!isSynchronous())
766         send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
767 }
768
769 void NetworkResourceLoader::startBufferingTimerIfNeeded()
770 {
771     if (isSynchronous())
772         return;
773     if (m_bufferingTimer.isActive())
774         return;
775     m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
776 }
777
778 void NetworkResourceLoader::bufferingTimerFired()
779 {
780     ASSERT(m_bufferedData);
781     ASSERT(m_networkLoad);
782
783     if (m_bufferedData->isEmpty())
784         return;
785
786     send(Messages::WebResourceLoader::DidReceiveData({ *m_bufferedData }, m_bufferedDataEncodedDataLength));
787
788     m_bufferedData = SharedBuffer::create();
789     m_bufferedDataEncodedDataLength = 0;
790 }
791
792 void NetworkResourceLoader::sendBuffer(SharedBuffer& buffer, size_t encodedDataLength)
793 {
794     ASSERT(!isSynchronous());
795
796     send(Messages::WebResourceLoader::DidReceiveData({ buffer }, encodedDataLength));
797 }
798
799 void NetworkResourceLoader::tryStoreAsCacheEntry()
800 {
801     if (!canUseCache(m_networkLoad->currentRequest()))
802         return;
803     if (!m_bufferedDataForCache)
804         return;
805
806     m_cache->store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader = makeRef(*this)](auto& mappedBody) mutable {
807 #if ENABLE(SHAREABLE_RESOURCE)
808         if (mappedBody.shareableResourceHandle.isNull())
809             return;
810         LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
811         loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle, loader->sessionID()));
812 #endif
813     });
814 }
815
816 void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
817 {
818     auto response = entry->response();
819
820     if (isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(response)) {
821         response = sanitizeResponseIfPossible(WTFMove(response), ResourceResponse::SanitizationType::CrossOriginSafe);
822         send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { response });
823         return;
824     }
825     if (m_networkLoadChecker) {
826         auto error = m_networkLoadChecker->validateResponse(response);
827         if (!error.isNull()) {
828             didFailLoading(error);
829             return;
830         }
831     }
832
833     response = sanitizeResponseIfPossible(WTFMove(response), ResourceResponse::SanitizationType::CrossOriginSafe);
834     if (isSynchronous()) {
835         m_synchronousLoadData->response = WTFMove(response);
836         sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
837         cleanup(LoadResult::Success);
838         return;
839     }
840
841     bool needsContinueDidReceiveResponseMessage = isMainResource();
842     send(Messages::WebResourceLoader::DidReceiveResponse { response, needsContinueDidReceiveResponseMessage });
843
844     if (needsContinueDidReceiveResponseMessage)
845         m_cacheEntryWaitingForContinueDidReceiveResponse = WTFMove(entry);
846     else {
847         sendResultForCacheEntry(WTFMove(entry));
848         cleanup(LoadResult::Success);
849     }
850 }
851
852 void NetworkResourceLoader::sendResultForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
853 {
854 #if ENABLE(SHAREABLE_RESOURCE)
855     if (!entry->shareableResourceHandle().isNull()) {
856         send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle()));
857         return;
858     }
859 #endif
860
861 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
862     if (shouldLogCookieInformation(m_connection, sessionID()))
863         logCookieInformation();
864 #endif
865
866     WebCore::NetworkLoadMetrics networkLoadMetrics;
867     networkLoadMetrics.markComplete();
868     networkLoadMetrics.requestHeaderBytesSent = 0;
869     networkLoadMetrics.requestBodyBytesSent = 0;
870     networkLoadMetrics.responseHeaderBytesReceived = 0;
871     networkLoadMetrics.responseBodyBytesReceived = 0;
872     networkLoadMetrics.responseBodyDecodedSize = 0;
873
874     sendBuffer(*entry->buffer(), entry->buffer()->size());
875     send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
876 }
877
878 void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
879 {
880     ASSERT(!m_networkLoad);
881
882     // If the request is already conditional then the revalidation was not triggered by the disk cache
883     // and we should not overwrite the existing conditional headers.
884     ResourceRequest revalidationRequest = originalRequest();
885     if (!revalidationRequest.isConditional()) {
886         String eTag = entry->response().httpHeaderField(HTTPHeaderName::ETag);
887         String lastModified = entry->response().httpHeaderField(HTTPHeaderName::LastModified);
888         if (!eTag.isEmpty())
889             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
890         if (!lastModified.isEmpty())
891             revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
892     }
893
894     m_cacheEntryForValidation = WTFMove(entry);
895
896     startNetworkLoad(WTFMove(revalidationRequest), FirstLoad::Yes);
897 }
898
899 void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(ResourceRequest&& request, std::unique_ptr<NetworkCache::Entry>&& entry)
900 {
901     ASSERT(entry->redirectRequest());
902     ASSERT(!m_isWaitingContinueWillSendRequestForCachedRedirect);
903
904     LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
905
906     m_isWaitingContinueWillSendRequestForCachedRedirect = true;
907     willSendRedirectedRequest(WTFMove(request), ResourceRequest { *entry->redirectRequest() }, ResourceResponse { entry->response() });
908 }
909
910 IPC::Connection* NetworkResourceLoader::messageSenderConnection() const
911 {
912     return &connectionToWebProcess().connection();
913 }
914
915 void NetworkResourceLoader::consumeSandboxExtensions()
916 {
917     ASSERT(!m_didConsumeSandboxExtensions);
918
919     for (auto& extension : m_parameters.requestBodySandboxExtensions)
920         extension->consume();
921
922     if (auto& extension = m_parameters.resourceSandboxExtension)
923         extension->consume();
924
925     for (auto& fileReference : m_fileReferences)
926         fileReference->prepareForFileAccess();
927
928     m_didConsumeSandboxExtensions = true;
929 }
930
931 void NetworkResourceLoader::invalidateSandboxExtensions()
932 {
933     if (m_didConsumeSandboxExtensions) {
934         for (auto& extension : m_parameters.requestBodySandboxExtensions)
935             extension->revoke();
936         if (auto& extension = m_parameters.resourceSandboxExtension)
937             extension->revoke();
938         for (auto& fileReference : m_fileReferences)
939             fileReference->revokeFileAccess();
940
941         m_didConsumeSandboxExtensions = false;
942     }
943
944     m_fileReferences.clear();
945 }
946
947 bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
948 {
949     if (m_connection->networkProcess().sessionIsControlledByAutomation(sessionID()))
950         return true;
951
952     return sessionID().isAlwaysOnLoggingAllowed();
953 }
954
955 bool NetworkResourceLoader::shouldCaptureExtraNetworkLoadMetrics() const
956 {
957     return m_shouldCaptureExtraNetworkLoadMetrics;
958 }
959
960 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
961 bool NetworkResourceLoader::shouldLogCookieInformation(NetworkConnectionToWebProcess& connection, const PAL::SessionID& sessionID)
962 {
963     if (auto session = connection.networkProcess().networkSession(sessionID))
964         return session->shouldLogCookieInformation();
965     return false;
966 }
967
968 static String escapeForJSON(String s)
969 {
970     return s.replace('\\', "\\\\").replace('"', "\\\"");
971 }
972
973 static String escapeIDForJSON(const Optional<uint64_t>& value)
974 {
975     return value ? String::number(value.value()) : String("None"_s);
976 };
977
978 void NetworkResourceLoader::logCookieInformation() const
979 {
980     ASSERT(shouldLogCookieInformation(m_connection, sessionID()));
981
982     auto* networkStorageSession = m_connection->networkProcess().storageSession(sessionID());
983     ASSERT(networkStorageSession);
984
985     logCookieInformation(m_connection, "NetworkResourceLoader", reinterpret_cast<const void*>(this), *networkStorageSession, originalRequest().firstPartyForCookies(), SameSiteInfo::create(originalRequest()), originalRequest().url(), originalRequest().httpReferrer(), frameID(), pageID(), identifier());
986 }
987
988 static void logBlockedCookieInformation(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const WebCore::NetworkStorageSession& networkStorageSession, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<uint64_t> frameID, Optional<uint64_t> pageID, Optional<uint64_t> identifier)
989 {
990     ASSERT(NetworkResourceLoader::shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
991
992     auto escapedURL = escapeForJSON(url.string());
993     auto escapedFirstParty = escapeForJSON(firstParty.string());
994     auto escapedFrameID = escapeIDForJSON(frameID);
995     auto escapedPageID = escapeIDForJSON(pageID);
996     auto escapedIdentifier = escapeIDForJSON(identifier);
997     auto escapedReferrer = escapeForJSON(referrer);
998
999 #define LOCAL_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(networkStorageSession.sessionID().isAlwaysOnLoggingAllowed(), Network, "%p - %s::" fmt, loggedObject, label.utf8().data(), ##__VA_ARGS__)
1000 #define LOCAL_LOG(str, ...) \
1001     LOCAL_LOG_IF_ALLOWED("logCookieInformation: BLOCKED cookie access for pageID = %s, frameID = %s, resourceID = %s, firstParty = %s: " str, escapedPageID.utf8().data(), escapedFrameID.utf8().data(), escapedIdentifier.utf8().data(), escapedFirstParty.utf8().data(), ##__VA_ARGS__)
1002
1003     LOCAL_LOG(R"({ "url": "%{public}s",)", escapedURL.utf8().data());
1004     LOCAL_LOG(R"(  "partition": "%{public}s",)", "BLOCKED");
1005     LOCAL_LOG(R"(  "hasStorageAccess": %{public}s,)", "false");
1006     LOCAL_LOG(R"(  "referer": "%{public}s",)", escapedReferrer.utf8().data());
1007     LOCAL_LOG(R"(  "isSameSite": "%{public}s",)", sameSiteInfo.isSameSite ? "true" : "false");
1008     LOCAL_LOG(R"(  "isTopSite": "%{public}s",)", sameSiteInfo.isTopSite ? "true" : "false");
1009     LOCAL_LOG(R"(  "cookies": [])");
1010     LOCAL_LOG(R"(  })");
1011 #undef LOCAL_LOG
1012 #undef LOCAL_LOG_IF_ALLOWED
1013 }
1014
1015 static void logCookieInformationInternal(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const WebCore::NetworkStorageSession& networkStorageSession, const URL& firstParty, const WebCore::SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<uint64_t> frameID, Optional<uint64_t> pageID, Optional<uint64_t> identifier)
1016 {
1017     ASSERT(NetworkResourceLoader::shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
1018
1019     Vector<WebCore::Cookie> cookies;
1020     if (!networkStorageSession.getRawCookies(firstParty, sameSiteInfo, url, frameID, pageID, cookies))
1021         return;
1022
1023     auto escapedURL = escapeForJSON(url.string());
1024     auto escapedPartition = escapeForJSON(emptyString());
1025     auto escapedReferrer = escapeForJSON(referrer);
1026     auto escapedFrameID = escapeIDForJSON(frameID);
1027     auto escapedPageID = escapeIDForJSON(pageID);
1028     auto escapedIdentifier = escapeIDForJSON(identifier);
1029     bool hasStorageAccess = (frameID && pageID) ? networkStorageSession.hasStorageAccess(WebCore::RegistrableDomain { url }, WebCore::RegistrableDomain { firstParty }, frameID.value(), pageID.value()) : false;
1030
1031 #define LOCAL_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(networkStorageSession.sessionID().isAlwaysOnLoggingAllowed(), Network, "%p - %s::" fmt, loggedObject, label.utf8().data(), ##__VA_ARGS__)
1032 #define LOCAL_LOG(str, ...) \
1033     LOCAL_LOG_IF_ALLOWED("logCookieInformation: pageID = %s, frameID = %s, resourceID = %s: " str, escapedPageID.utf8().data(), escapedFrameID.utf8().data(), escapedIdentifier.utf8().data(), ##__VA_ARGS__)
1034
1035     LOCAL_LOG(R"({ "url": "%{public}s",)", escapedURL.utf8().data());
1036     LOCAL_LOG(R"(  "partition": "%{public}s",)", escapedPartition.utf8().data());
1037     LOCAL_LOG(R"(  "hasStorageAccess": %{public}s,)", hasStorageAccess ? "true" : "false");
1038     LOCAL_LOG(R"(  "referer": "%{public}s",)", escapedReferrer.utf8().data());
1039     LOCAL_LOG(R"(  "isSameSite": "%{public}s",)", sameSiteInfo.isSameSite ? "true" : "false");
1040     LOCAL_LOG(R"(  "isTopSite": "%{public}s",)", sameSiteInfo.isTopSite ? "true" : "false");
1041     LOCAL_LOG(R"(  "cookies": [)");
1042
1043     auto size = cookies.size();
1044     decltype(size) count = 0;
1045     for (const auto& cookie : cookies) {
1046         const char* trailingComma = ",";
1047         if (++count == size)
1048             trailingComma = "";
1049
1050         auto escapedName = escapeForJSON(cookie.name);
1051         auto escapedValue = escapeForJSON(cookie.value);
1052         auto escapedDomain = escapeForJSON(cookie.domain);
1053         auto escapedPath = escapeForJSON(cookie.path);
1054         auto escapedComment = escapeForJSON(cookie.comment);
1055         auto escapedCommentURL = escapeForJSON(cookie.commentURL.string());
1056         // FIXME: Log Same-Site policy for each cookie. See <https://bugs.webkit.org/show_bug.cgi?id=184894>.
1057
1058         LOCAL_LOG(R"(  { "name": "%{public}s",)", escapedName.utf8().data());
1059         LOCAL_LOG(R"(    "value": "%{public}s",)", escapedValue.utf8().data());
1060         LOCAL_LOG(R"(    "domain": "%{public}s",)", escapedDomain.utf8().data());
1061         LOCAL_LOG(R"(    "path": "%{public}s",)", escapedPath.utf8().data());
1062         LOCAL_LOG(R"(    "created": %f,)", cookie.created);
1063         LOCAL_LOG(R"(    "expires": %f,)", cookie.expires);
1064         LOCAL_LOG(R"(    "httpOnly": %{public}s,)", cookie.httpOnly ? "true" : "false");
1065         LOCAL_LOG(R"(    "secure": %{public}s,)", cookie.secure ? "true" : "false");
1066         LOCAL_LOG(R"(    "session": %{public}s,)", cookie.session ? "true" : "false");
1067         LOCAL_LOG(R"(    "comment": "%{public}s",)", escapedComment.utf8().data());
1068         LOCAL_LOG(R"(    "commentURL": "%{public}s")", escapedCommentURL.utf8().data());
1069         LOCAL_LOG(R"(  }%{public}s)", trailingComma);
1070     }
1071     LOCAL_LOG(R"(]})");
1072 #undef LOCAL_LOG
1073 #undef LOCAL_LOG_IF_ALLOWED
1074 }
1075
1076 void NetworkResourceLoader::logCookieInformation(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const NetworkStorageSession& networkStorageSession, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<uint64_t> frameID, Optional<uint64_t> pageID, Optional<uint64_t> identifier)
1077 {
1078     ASSERT(shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
1079
1080     if (networkStorageSession.shouldBlockCookies(firstParty, url, frameID, pageID))
1081         logBlockedCookieInformation(connection, label, loggedObject, networkStorageSession, firstParty, sameSiteInfo, url, referrer, frameID, pageID, identifier);
1082     else
1083         logCookieInformationInternal(connection, label, loggedObject, networkStorageSession, firstParty, sameSiteInfo, url, referrer, frameID, pageID, identifier);
1084 }
1085 #endif
1086
1087 void NetworkResourceLoader::addConsoleMessage(MessageSource messageSource, MessageLevel messageLevel, const String& message, unsigned long)
1088 {
1089     send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID,  messageSource, messageLevel, message, identifier() }, m_parameters.webPageID);
1090 }
1091
1092 void NetworkResourceLoader::sendCSPViolationReport(URL&& reportURL, Ref<FormData>&& report)
1093 {
1094     send(Messages::WebPage::SendCSPViolationReport { m_parameters.webFrameID, WTFMove(reportURL), IPC::FormDataReference { WTFMove(report) } }, m_parameters.webPageID);
1095 }
1096
1097 void NetworkResourceLoader::enqueueSecurityPolicyViolationEvent(WebCore::SecurityPolicyViolationEvent::Init&& eventInit)
1098 {
1099     send(Messages::WebPage::EnqueueSecurityPolicyViolationEvent { m_parameters.webFrameID, WTFMove(eventInit) }, m_parameters.webPageID);
1100 }
1101
1102 void NetworkResourceLoader::logSlowCacheRetrieveIfNeeded(const NetworkCache::Cache::RetrieveInfo& info)
1103 {
1104 #if RELEASE_LOG_DISABLED
1105     UNUSED_PARAM(info);
1106 #else
1107     if (!isAlwaysOnLoggingAllowed())
1108         return;
1109     auto duration = info.completionTime - info.startTime;
1110     if (duration < 1_s)
1111         return;
1112     RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Took %.0fms, priority %d", duration.milliseconds(), info.priority);
1113     if (info.wasSpeculativeLoad)
1114         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Was speculative load");
1115     if (!info.storageTimings.startTime)
1116         return;
1117     RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Storage retrieve time %.0fms", (info.storageTimings.completionTime - info.storageTimings.startTime).milliseconds());
1118     if (info.storageTimings.dispatchTime) {
1119         auto time = (info.storageTimings.dispatchTime - info.storageTimings.startTime).milliseconds();
1120         auto count = info.storageTimings.dispatchCountAtDispatch - info.storageTimings.dispatchCountAtStart;
1121         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Dispatch delay %.0fms, dispatched %lu resources first", time, count);
1122     }
1123     if (info.storageTimings.recordIOStartTime)
1124         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Record I/O time %.0fms", (info.storageTimings.recordIOEndTime - info.storageTimings.recordIOStartTime).milliseconds());
1125     if (info.storageTimings.blobIOStartTime)
1126         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Blob I/O time %.0fms", (info.storageTimings.blobIOEndTime - info.storageTimings.blobIOStartTime).milliseconds());
1127     if (info.storageTimings.synchronizationInProgressAtDispatch)
1128         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Synchronization was in progress");
1129     if (info.storageTimings.shrinkInProgressAtDispatch)
1130         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Shrink was in progress");
1131     if (info.storageTimings.wasCanceled)
1132         RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Retrieve was canceled");
1133 #endif
1134 }
1135
1136 } // namespace WebKit
1137
1138 #undef RELEASE_LOG_IF_ALLOWED
1139 #undef RELEASE_LOG_ERROR_IF_ALLOWED