Web Inspector: Include Beacon and Ping requests in Network tab
[WebKit-https.git] / Source / WebKit / WebProcess / Network / WebLoaderStrategy.cpp
1 /*
2  * Copyright (C) 2012, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebLoaderStrategy.h"
28
29 #include "DataReference.h"
30 #include "HangDetectionDisabler.h"
31 #include "Logging.h"
32 #include "NetworkConnectionToWebProcessMessages.h"
33 #include "NetworkProcessConnection.h"
34 #include "NetworkResourceLoadParameters.h"
35 #include "SessionTracker.h"
36 #include "WebCompiledContentRuleList.h"
37 #include "WebCoreArgumentCoders.h"
38 #include "WebErrors.h"
39 #include "WebFrame.h"
40 #include "WebFrameLoaderClient.h"
41 #include "WebFrameNetworkingContext.h"
42 #include "WebPage.h"
43 #include "WebPageProxyMessages.h"
44 #include "WebProcess.h"
45 #include "WebResourceLoader.h"
46 #include "WebURLSchemeHandlerProxy.h"
47 #include "WebURLSchemeTaskProxy.h"
48 #include <WebCore/ApplicationCacheHost.h>
49 #include <WebCore/CachedResource.h>
50 #include <WebCore/ContentSecurityPolicy.h>
51 #include <WebCore/DiagnosticLoggingClient.h>
52 #include <WebCore/DiagnosticLoggingKeys.h>
53 #include <WebCore/Document.h>
54 #include <WebCore/DocumentLoader.h>
55 #include <WebCore/FetchOptions.h>
56 #include <WebCore/Frame.h>
57 #include <WebCore/FrameLoader.h>
58 #include <WebCore/NetscapePlugInStreamLoader.h>
59 #include <WebCore/PlatformStrategies.h>
60 #include <WebCore/ReferrerPolicy.h>
61 #include <WebCore/ResourceLoader.h>
62 #include <WebCore/SecurityOrigin.h>
63 #include <WebCore/Settings.h>
64 #include <WebCore/SubresourceLoader.h>
65 #include <WebCore/UserContentProvider.h>
66 #include <pal/SessionID.h>
67 #include <wtf/text/CString.h>
68
69 #if USE(QUICK_LOOK)
70 #include <WebCore/QuickLook.h>
71 #endif
72
73 using namespace WebCore;
74
75 #define RELEASE_LOG_IF_ALLOWED(permissionChecker, fmt, ...) RELEASE_LOG_IF(permissionChecker.isAlwaysOnLoggingAllowed(), Network, "%p - WebLoaderStrategy::" fmt, this, ##__VA_ARGS__)
76 #define RELEASE_LOG_ERROR_IF_ALLOWED(permissionChecker, fmt, ...) RELEASE_LOG_ERROR_IF(permissionChecker.isAlwaysOnLoggingAllowed(), Network, "%p - WebLoaderStrategy::" fmt, this, ##__VA_ARGS__)
77
78 namespace WebKit {
79
80 WebLoaderStrategy::WebLoaderStrategy()
81     : m_internallyFailedLoadTimer(RunLoop::main(), this, &WebLoaderStrategy::internallyFailedLoadTimerFired)
82 {
83 }
84
85 WebLoaderStrategy::~WebLoaderStrategy()
86 {
87 }
88
89 RefPtr<SubresourceLoader> WebLoaderStrategy::loadResource(Frame& frame, CachedResource& resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
90 {
91     RefPtr<SubresourceLoader> loader = SubresourceLoader::create(frame, resource, request, options);
92     if (loader)
93         scheduleLoad(*loader, &resource, frame.document()->referrerPolicy() == ReferrerPolicy::NoReferrerWhenDowngrade);
94     else
95         RELEASE_LOG_IF_ALLOWED(frame, "loadResource: Unable to create SubresourceLoader (frame = %p", &frame);
96     return loader;
97 }
98
99 RefPtr<NetscapePlugInStreamLoader> WebLoaderStrategy::schedulePluginStreamLoad(Frame& frame, NetscapePlugInStreamLoaderClient& client, const ResourceRequest& request)
100 {
101     RefPtr<NetscapePlugInStreamLoader> loader = NetscapePlugInStreamLoader::create(frame, client, request);
102     if (loader)
103         scheduleLoad(*loader, 0, frame.document()->referrerPolicy() == ReferrerPolicy::NoReferrerWhenDowngrade);
104     return loader;
105 }
106
107 static Seconds maximumBufferingTime(CachedResource* resource)
108 {
109     if (!resource)
110         return 0_s;
111
112     switch (resource->type()) {
113     case CachedResource::Beacon:
114     case CachedResource::CSSStyleSheet:
115     case CachedResource::Script:
116 #if ENABLE(SVG_FONTS)
117     case CachedResource::SVGFontResource:
118 #endif
119     case CachedResource::FontResource:
120         return Seconds::infinity();
121     case CachedResource::ImageResource:
122         return 500_ms;
123     case CachedResource::MediaResource:
124         return 50_ms;
125     case CachedResource::MainResource:
126     case CachedResource::Icon:
127     case CachedResource::RawResource:
128     case CachedResource::SVGDocumentResource:
129 #if ENABLE(LINK_PREFETCH)
130     case CachedResource::LinkPrefetch:
131     case CachedResource::LinkSubresource:
132 #endif
133 #if ENABLE(VIDEO_TRACK)
134     case CachedResource::TextTrackResource:
135 #endif
136 #if ENABLE(XSLT)
137     case CachedResource::XSLStyleSheet:
138 #endif
139         return 0_s;
140     }
141
142     ASSERT_NOT_REACHED();
143     return 0_s;
144 }
145
146 void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResource* resource, bool shouldClearReferrerOnHTTPSToHTTPRedirect)
147 {
148     ResourceLoadIdentifier identifier = resourceLoader.identifier();
149     ASSERT(identifier);
150
151     // FIXME: Some entities in WebCore use WebCore's "EmptyFrameLoaderClient" instead of having a proper WebFrameLoaderClient.
152     // EmptyFrameLoaderClient shouldn't exist and everything should be using a WebFrameLoaderClient,
153     // but in the meantime we have to make sure not to mis-cast.
154     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(resourceLoader.frameLoader()->client());
155     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : nullptr;
156     WebPage* webPage = webFrame ? webFrame->page() : nullptr;
157
158     WebResourceLoader::TrackingParameters trackingParameters;
159     trackingParameters.pageID = webPage ? webPage->pageID() : 0;
160     trackingParameters.frameID = webFrame ? webFrame->frameID() : 0;
161     trackingParameters.resourceID = identifier;
162
163 #if ENABLE(WEB_ARCHIVE) || ENABLE(MHTML)
164     // If the DocumentLoader schedules this as an archive resource load,
165     // then we should remember the ResourceLoader in our records but not schedule it in the NetworkProcess.
166     if (resourceLoader.documentLoader()->scheduleArchiveLoad(resourceLoader, resourceLoader.request())) {
167         LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be handled as an archive resource.", resourceLoader.url().string().utf8().data());
168         RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be handled as an archive resource (frame = %p, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), trackingParameters.pageID, trackingParameters.frameID, identifier);
169         m_webResourceLoaders.set(identifier, WebResourceLoader::create(resourceLoader, trackingParameters));
170         return;
171     }
172 #endif
173
174     if (resourceLoader.documentLoader()->applicationCacheHost().maybeLoadResource(resourceLoader, resourceLoader.request(), resourceLoader.request().url())) {
175         LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be loaded from application cache.", resourceLoader.url().string().utf8().data());
176         RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be loaded from application cache (frame = %p, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), trackingParameters.pageID, trackingParameters.frameID, identifier);
177         m_webResourceLoaders.set(identifier, WebResourceLoader::create(resourceLoader, trackingParameters));
178         return;
179     }
180
181     if (resourceLoader.request().url().protocolIsData()) {
182         LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be loaded as data.", resourceLoader.url().string().utf8().data());
183         RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be loaded as data (frame = %p, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), trackingParameters.pageID, trackingParameters.frameID, identifier);
184         startLocalLoad(resourceLoader);
185         return;
186     }
187
188 #if USE(QUICK_LOOK)
189     if (isQuickLookPreviewURL(resourceLoader.request().url())) {
190         LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be handled as a QuickLook resource.", resourceLoader.url().string().utf8().data());
191         RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be handled as a QuickLook resource (frame = %p, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), trackingParameters.pageID, trackingParameters.frameID, identifier);
192         startLocalLoad(resourceLoader);
193         return;
194     }
195 #endif
196
197 #if USE(SOUP)
198     // For apps that call g_resource_load in a web extension.
199     // https://blogs.gnome.org/alexl/2012/01/26/resources-in-glib/
200     if (resourceLoader.request().url().protocolIs("resource")) {
201         LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be handled as a GResource.", resourceLoader.url().string().utf8().data());
202         RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be handled as a GResource (frame = %p, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), trackingParameters.pageID, trackingParameters.frameID, identifier);
203         startLocalLoad(resourceLoader);
204         return;
205     }
206 #endif
207
208     if (webPage) {
209         if (auto* handler = webPage->urlSchemeHandlerForScheme(resourceLoader.request().url().protocol().toStringWithoutCopying())) {
210             LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, URL '%s' will be handled by a UIProcess URL scheme handler.", resourceLoader.url().string().utf8().data());
211             RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: URL will be handled by a UIProcess URL scheme handler (frame = %p, resourceID = %" PRIu64 ")", resourceLoader.frame(), identifier);
212
213             handler->startNewTask(resourceLoader);
214             return;
215         }
216     }
217
218     LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be scheduled with the NetworkProcess with priority %d", resourceLoader.url().string().latin1().data(), static_cast<int>(resourceLoader.request().priority()));
219
220     ContentSniffingPolicy contentSniffingPolicy = resourceLoader.shouldSniffContent() ? SniffContent : DoNotSniffContent;
221     StoredCredentialsPolicy storedCredentialsPolicy = resourceLoader.shouldUseCredentialStorage() ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse;
222
223     NetworkResourceLoadParameters loadParameters;
224     loadParameters.identifier = identifier;
225     loadParameters.webPageID = webPage ? webPage->pageID() : 0;
226     loadParameters.webFrameID = webFrame ? webFrame->frameID() : 0;
227     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
228     loadParameters.request = resourceLoader.request();
229     loadParameters.contentSniffingPolicy = contentSniffingPolicy;
230     loadParameters.storedCredentialsPolicy = storedCredentialsPolicy;
231     // If there is no WebFrame then this resource cannot be authenticated with the client.
232     loadParameters.clientCredentialPolicy = (webFrame && webPage && resourceLoader.isAllowedToAskUserForCredentials()) ? ClientCredentialPolicy::MayAskClientForCredentials : ClientCredentialPolicy::CannotAskClientForCredentials;
233     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = shouldClearReferrerOnHTTPSToHTTPRedirect;
234     loadParameters.defersLoading = resourceLoader.defersLoading();
235     loadParameters.needsCertificateInfo = resourceLoader.shouldIncludeCertificateInfo();
236     loadParameters.maximumBufferingTime = maximumBufferingTime(resource);
237     loadParameters.derivedCachedDataTypesToRetrieve = resourceLoader.options().derivedCachedDataTypesToRetrieve;
238
239     ASSERT((loadParameters.webPageID && loadParameters.webFrameID) || loadParameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
240
241     RELEASE_LOG_IF_ALLOWED(resourceLoader, "scheduleLoad: Resource is being scheduled with the NetworkProcess (frame = %p, priority = %d, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), static_cast<int>(resourceLoader.request().priority()), loadParameters.webPageID, loadParameters.webFrameID, loadParameters.identifier);
242     if (!WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::ScheduleResourceLoad(loadParameters), 0)) {
243         RELEASE_LOG_ERROR_IF_ALLOWED(resourceLoader, "scheduleLoad: Unable to schedule resource with the NetworkProcess (frame = %p, priority = %d, pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", resourceLoader.frame(), static_cast<int>(resourceLoader.request().priority()), loadParameters.webPageID, loadParameters.webFrameID, loadParameters.identifier);
244         // We probably failed to schedule this load with the NetworkProcess because it had crashed.
245         // This load will never succeed so we will schedule it to fail asynchronously.
246         scheduleInternallyFailedLoad(resourceLoader);
247         return;
248     }
249
250     m_webResourceLoaders.set(identifier, WebResourceLoader::create(resourceLoader, trackingParameters));
251 }
252
253 void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader)
254 {
255     m_internallyFailedResourceLoaders.add(&resourceLoader);
256     m_internallyFailedLoadTimer.startOneShot(0_s);
257 }
258
259 void WebLoaderStrategy::internallyFailedLoadTimerFired()
260 {
261     Vector<RefPtr<ResourceLoader>> internallyFailedResourceLoaders;
262     copyToVector(m_internallyFailedResourceLoaders, internallyFailedResourceLoaders);
263     
264     for (size_t i = 0; i < internallyFailedResourceLoaders.size(); ++i)
265         internallyFailedResourceLoaders[i]->didFail(internalError(internallyFailedResourceLoaders[i]->url()));
266 }
267
268 void WebLoaderStrategy::startLocalLoad(WebCore::ResourceLoader& resourceLoader)
269 {
270     resourceLoader.start();
271     m_webResourceLoaders.set(resourceLoader.identifier(), WebResourceLoader::create(resourceLoader, { }));
272 }
273
274 void WebLoaderStrategy::addURLSchemeTaskProxy(WebURLSchemeTaskProxy& task)
275 {
276     auto result = m_urlSchemeTasks.add(task.identifier(), &task);
277     ASSERT_UNUSED(result, result.isNewEntry);
278 }
279
280 void WebLoaderStrategy::removeURLSchemeTaskProxy(WebURLSchemeTaskProxy& task)
281 {
282     m_urlSchemeTasks.remove(task.identifier());
283 }
284
285 void WebLoaderStrategy::remove(ResourceLoader* resourceLoader)
286 {
287     ASSERT(resourceLoader);
288     LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::remove, url '%s'", resourceLoader->url().string().utf8().data());
289
290     if (auto task = m_urlSchemeTasks.take(resourceLoader->identifier())) {
291         ASSERT(!m_internallyFailedResourceLoaders.contains(resourceLoader));
292         task->stopLoading();
293         return;
294     }
295
296     if (m_internallyFailedResourceLoaders.contains(resourceLoader)) {
297         m_internallyFailedResourceLoaders.remove(resourceLoader);
298         return;
299     }
300     
301     ResourceLoadIdentifier identifier = resourceLoader->identifier();
302     if (!identifier) {
303         LOG_ERROR("WebLoaderStrategy removing a ResourceLoader that has no identifier.");
304         return;
305     }
306     
307     RefPtr<WebResourceLoader> loader = m_webResourceLoaders.take(identifier);
308     // Loader may not be registered if we created it, but haven't scheduled yet (a bundle client can decide to cancel such request via willSendRequest).
309     if (!loader)
310         return;
311
312     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::RemoveLoadIdentifier(identifier), 0);
313
314     // It's possible that this WebResourceLoader might be just about to message back to the NetworkProcess (e.g. ContinueWillSendRequest)
315     // but there's no point in doing so anymore.
316     loader->detachFromCoreLoader();
317 }
318
319 void WebLoaderStrategy::setDefersLoading(ResourceLoader* resourceLoader, bool defers)
320 {
321     ResourceLoadIdentifier identifier = resourceLoader->identifier();
322     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetDefersLoading(identifier, defers), 0);
323 }
324
325 void WebLoaderStrategy::crossOriginRedirectReceived(ResourceLoader*, const URL&)
326 {
327     // We handle cross origin redirects entirely within the NetworkProcess.
328     // We override this call in the WebProcess to make it a no-op.
329 }
330
331 void WebLoaderStrategy::servePendingRequests(ResourceLoadPriority)
332 {
333     // This overrides the base class version.
334     // We don't need to do anything as this is handled by the network process.
335 }
336
337 void WebLoaderStrategy::suspendPendingRequests()
338 {
339     // Network process does keep requests in pending state.
340 }
341
342 void WebLoaderStrategy::resumePendingRequests()
343 {
344     // Network process does keep requests in pending state.
345 }
346
347 void WebLoaderStrategy::networkProcessCrashed()
348 {
349     RELEASE_LOG_ERROR(Network, "WebLoaderStrategy::networkProcessCrashed: failing all pending resource loaders");
350
351     for (auto& loader : m_webResourceLoaders)
352         scheduleInternallyFailedLoad(*loader.value->resourceLoader());
353
354     m_webResourceLoaders.clear();
355
356     auto pingLoadCompletionHandlers = WTFMove(m_pingLoadCompletionHandlers);
357     for (auto& pingLoadCompletionHandler : pingLoadCompletionHandlers.values())
358         pingLoadCompletionHandler(internalError(URL()), { });
359
360     auto preconnectCompletionHandlers = WTFMove(m_preconnectCompletionHandlers);
361     for (auto& preconnectCompletionHandler : preconnectCompletionHandlers.values())
362         preconnectCompletionHandler(internalError(URL()));
363 }
364
365 void WebLoaderStrategy::loadResourceSynchronously(NetworkingContext* context, unsigned long resourceLoadIdentifier, const ResourceRequest& request, StoredCredentialsPolicy storedCredentialsPolicy, ClientCredentialPolicy clientCredentialPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
366 {
367     WebFrameNetworkingContext* webContext = static_cast<WebFrameNetworkingContext*>(context);
368     // FIXME: Some entities in WebCore use WebCore's "EmptyFrameLoaderClient" instead of having a proper WebFrameLoaderClient.
369     // EmptyFrameLoaderClient shouldn't exist and everything should be using a WebFrameLoaderClient,
370     // but in the meantime we have to make sure not to mis-cast.
371     WebFrameLoaderClient* webFrameLoaderClient = webContext->webFrameLoaderClient();
372     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
373     WebPage* webPage = webFrame ? webFrame->page() : 0;
374
375     NetworkResourceLoadParameters loadParameters;
376     loadParameters.identifier = resourceLoadIdentifier;
377     loadParameters.webPageID = webPage ? webPage->pageID() : 0;
378     loadParameters.webFrameID = webFrame ? webFrame->frameID() : 0;
379     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
380     loadParameters.request = request;
381     loadParameters.contentSniffingPolicy = SniffContent;
382     loadParameters.storedCredentialsPolicy = storedCredentialsPolicy;
383     loadParameters.clientCredentialPolicy = clientCredentialPolicy;
384     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = context->shouldClearReferrerOnHTTPSToHTTPRedirect();
385
386     data.shrink(0);
387
388     HangDetectionDisabler hangDetectionDisabler;
389
390     if (!WebProcess::singleton().networkConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad(loadParameters), Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::Reply(error, response, data), 0)) {
391         RELEASE_LOG_ERROR_IF_ALLOWED(loadParameters.sessionID, "loadResourceSynchronously: failed sending synchronous network process message (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", loadParameters.webPageID, loadParameters.webFrameID, loadParameters.identifier);
392         if (auto* page = webPage->corePage())
393             page->diagnosticLoggingClient().logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::synchronousMessageFailedKey(), WebCore::ShouldSample::No);
394         response = ResourceResponse();
395         error = internalError(request.url());
396     }
397 }
398
399 static uint64_t generateLoadIdentifier()
400 {
401     static uint64_t identifier = 0;
402     return ++identifier;
403 }
404
405 void WebLoaderStrategy::startPingLoad(Frame& frame, ResourceRequest& request, const HTTPHeaderMap& originalRequestHeaders, const FetchOptions& options, PingLoadCompletionHandler&& completionHandler)
406 {
407     // It's possible that call to createPingHandle might be made during initial empty Document creation before a NetworkingContext exists.
408     // It is not clear that we should send ping loads during that process anyways.
409     auto* networkingContext = frame.loader().networkingContext();
410     if (!networkingContext) {
411         if (completionHandler)
412             completionHandler(internalError(request.url()), { });
413         return;
414     }
415
416     WebFrameNetworkingContext* webContext = static_cast<WebFrameNetworkingContext*>(networkingContext);
417     WebFrameLoaderClient* webFrameLoaderClient = webContext->webFrameLoaderClient();
418     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : nullptr;
419     WebPage* webPage = webFrame ? webFrame->page() : nullptr;
420
421     auto* document = frame.document();
422     if (!document) {
423         if (completionHandler)
424             completionHandler(internalError(request.url()), { });
425         return;
426     }
427     
428     NetworkResourceLoadParameters loadParameters;
429     loadParameters.identifier = generateLoadIdentifier();
430     loadParameters.request = request;
431     loadParameters.sourceOrigin = &document->securityOrigin();
432     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
433     loadParameters.storedCredentialsPolicy = options.credentials == FetchOptions::Credentials::Omit ? StoredCredentialsPolicy::DoNotUse : StoredCredentialsPolicy::Use;
434     loadParameters.mode = options.mode;
435     loadParameters.shouldFollowRedirects = options.redirect == FetchOptions::Redirect::Follow;
436     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = networkingContext->shouldClearReferrerOnHTTPSToHTTPRedirect();
437     if (!document->shouldBypassMainWorldContentSecurityPolicy()) {
438         if (auto * contentSecurityPolicy = document->contentSecurityPolicy())
439             loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
440     }
441
442 #if ENABLE(CONTENT_EXTENSIONS)
443     loadParameters.mainDocumentURL = document->topDocument().url();
444
445     if (auto* documentLoader = frame.loader().documentLoader()) {
446         if (auto* page = frame.page()) {
447             page->userContentProvider().forEachContentExtension([&loadParameters](const String& identifier, ContentExtensions::ContentExtension& contentExtension) {
448                 loadParameters.contentRuleLists.append(std::make_pair(identifier, static_cast<const WebCompiledContentRuleList&>(contentExtension.compiledExtension()).data()));
449             }, *documentLoader);
450         }
451     }
452 #endif
453
454     if (completionHandler)
455         m_pingLoadCompletionHandlers.add(loadParameters.identifier, WTFMove(completionHandler));
456
457     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::LoadPing(WTFMove(loadParameters), originalRequestHeaders), 0);
458 }
459
460 void WebLoaderStrategy::didFinishPingLoad(uint64_t pingLoadIdentifier, ResourceError&& error, ResourceResponse&& response)
461 {
462     if (auto completionHandler = m_pingLoadCompletionHandlers.take(pingLoadIdentifier))
463         completionHandler(WTFMove(error), WTFMove(response));
464 }
465
466 void WebLoaderStrategy::preconnectTo(NetworkingContext& context, const WebCore::URL& url, StoredCredentialsPolicy storedCredentialsPolicy, PreconnectCompletionHandler&& completionHandler)
467 {
468     uint64_t preconnectionIdentifier = generateLoadIdentifier();
469     auto addResult = m_preconnectCompletionHandlers.add(preconnectionIdentifier, WTFMove(completionHandler));
470     ASSERT_UNUSED(addResult, addResult.isNewEntry);
471
472     auto& webContext = static_cast<WebFrameNetworkingContext&>(context);
473     auto* webFrameLoaderClient = webContext.webFrameLoaderClient();
474     if (!webFrameLoaderClient) {
475         completionHandler(internalError(url));
476         return;
477     }
478     auto* webFrame = webFrameLoaderClient->webFrame();
479     if (!webFrame) {
480         completionHandler(internalError(url));
481         return;
482     }
483     auto* webPage = webFrame->page();
484     if (!webPage) {
485         completionHandler(internalError(url));
486         return;
487     }
488
489     NetworkResourceLoadParameters parameters;
490     parameters.request = ResourceRequest { url };
491     parameters.webPageID = webPage ? webPage->pageID() : 0;
492     parameters.webFrameID = webFrame ? webFrame->frameID() : 0;
493     parameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
494     parameters.storedCredentialsPolicy = storedCredentialsPolicy;
495     parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
496
497     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::PreconnectTo(preconnectionIdentifier, WTFMove(parameters)), 0);
498 }
499
500 void WebLoaderStrategy::didFinishPreconnection(uint64_t preconnectionIdentifier, ResourceError&& error)
501 {
502     if (auto completionHandler = m_preconnectCompletionHandlers.take(preconnectionIdentifier))
503         completionHandler(WTFMove(error));
504 }
505
506 void WebLoaderStrategy::storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer& data)
507 {
508 #if ENABLE(NETWORK_CACHE)
509     NetworkCache::DataKey key { partition, type, bodyHash };
510     IPC::SharedBufferDataReference dataReference { &data };
511     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::StoreDerivedDataToCache(key, dataReference), 0);
512 #else
513     UNUSED_PARAM(bodyHash);
514     UNUSED_PARAM(type);
515     UNUSED_PARAM(partition);
516     UNUSED_PARAM(data);
517 #endif
518 }
519
520 void WebLoaderStrategy::setCaptureExtraNetworkLoadMetricsEnabled(bool enabled)
521 {
522     WebProcess::singleton().networkConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCaptureExtraNetworkLoadMetricsEnabled(enabled), 0);
523 }
524
525 } // namespace WebKit