Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebKit / WebProcess / Network / WebLoaderStrategy.cpp
index 86b9509..65cf423 100644 (file)
@@ -33,6 +33,7 @@
 #include "NetworkProcessConnection.h"
 #include "NetworkResourceLoadParameters.h"
 #include "SessionTracker.h"
+#include "SharedBufferDataReference.h"
 #include "WebCompiledContentRuleList.h"
 #include "WebCoreArgumentCoders.h"
 #include "WebErrors.h"
@@ -56,6 +57,7 @@
 #include <WebCore/Frame.h>
 #include <WebCore/FrameLoader.h>
 #include <WebCore/NetscapePlugInStreamLoader.h>
+#include <WebCore/NetworkLoadInformation.h>
 #include <WebCore/PlatformStrategies.h>
 #include <WebCore/ReferrerPolicy.h>
 #include <WebCore/ResourceLoader.h>
 #include <WebCore/QuickLook.h>
 #endif
 
-using namespace WebCore;
-
 #define RELEASE_LOG_IF_ALLOWED(permissionChecker, fmt, ...) RELEASE_LOG_IF(permissionChecker.isAlwaysOnLoggingAllowed(), Network, "%p - WebLoaderStrategy::" fmt, this, ##__VA_ARGS__)
 #define RELEASE_LOG_ERROR_IF_ALLOWED(permissionChecker, fmt, ...) RELEASE_LOG_ERROR_IF(permissionChecker.isAlwaysOnLoggingAllowed(), Network, "%p - WebLoaderStrategy::" fmt, this, ##__VA_ARGS__)
 
 namespace WebKit {
+using namespace WebCore;
 
 WebLoaderStrategy::WebLoaderStrategy()
     : m_internallyFailedLoadTimer(RunLoop::main(), this, &WebLoaderStrategy::internallyFailedLoadTimerFired)
@@ -114,31 +115,31 @@ static Seconds maximumBufferingTime(CachedResource* resource)
         return 0_s;
 
     switch (resource->type()) {
-    case CachedResource::Beacon:
-    case CachedResource::CSSStyleSheet:
-    case CachedResource::Script:
+    case CachedResource::Type::Beacon:
+    case CachedResource::Type::CSSStyleSheet:
+    case CachedResource::Type::Script:
 #if ENABLE(SVG_FONTS)
-    case CachedResource::SVGFontResource:
+    case CachedResource::Type::SVGFontResource:
 #endif
-    case CachedResource::FontResource:
+    case CachedResource::Type::FontResource:
 #if ENABLE(APPLICATION_MANIFEST)
-    case CachedResource::ApplicationManifest:
+    case CachedResource::Type::ApplicationManifest:
 #endif
         return Seconds::infinity();
-    case CachedResource::ImageResource:
+    case CachedResource::Type::ImageResource:
         return 500_ms;
-    case CachedResource::MediaResource:
+    case CachedResource::Type::MediaResource:
         return 50_ms;
-    case CachedResource::MainResource:
-    case CachedResource::Icon:
-    case CachedResource::RawResource:
-    case CachedResource::SVGDocumentResource:
-    case CachedResource::LinkPrefetch:
+    case CachedResource::Type::MainResource:
+    case CachedResource::Type::Icon:
+    case CachedResource::Type::RawResource:
+    case CachedResource::Type::SVGDocumentResource:
+    case CachedResource::Type::LinkPrefetch:
 #if ENABLE(VIDEO_TRACK)
-    case CachedResource::TextTrackResource:
+    case CachedResource::Type::TextTrackResource:
 #endif
 #if ENABLE(XSLT)
-    case CachedResource::XSLStyleSheet:
+    case CachedResource::Type::XSLStyleSheet:
 #endif
         return 0_s;
     }
@@ -155,8 +156,8 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou
     auto& frameLoaderClient = resourceLoader.frameLoader()->client();
 
     WebResourceLoader::TrackingParameters trackingParameters;
-    trackingParameters.pageID = frameLoaderClient.pageID().value();
-    trackingParameters.frameID = frameLoaderClient.frameID().value();
+    trackingParameters.pageID = frameLoaderClient.pageID().value_or(0);
+    trackingParameters.frameID = frameLoaderClient.frameID().value_or(0);
     trackingParameters.resourceID = identifier;
     auto sessionID = frameLoaderClient.sessionID();
 
@@ -253,7 +254,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
 
     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()));
 
-    ContentSniffingPolicy contentSniffingPolicy = resourceLoader.shouldSniffContent() ? SniffContent : DoNotSniffContent;
+    ContentSniffingPolicy contentSniffingPolicy = resourceLoader.shouldSniffContent() ? ContentSniffingPolicy::SniffContent : ContentSniffingPolicy::DoNotSniffContent;
     ContentEncodingSniffingPolicy contentEncodingSniffingPolicy = resourceLoader.shouldSniffContentEncoding() ? ContentEncodingSniffingPolicy::Sniff : ContentEncodingSniffingPolicy::DoNotSniff;
     StoredCredentialsPolicy storedCredentialsPolicy = resourceLoader.shouldUseCredentialStorage() ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse;
 
@@ -301,20 +302,20 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
     }
 #endif
 
+    // FIXME: All loaders should provide their origin if navigation mode is cors/no-cors/same-origin.
+    // As a temporary approach, we use the document origin if available or the HTTP Origin header otherwise.
+    if (resourceLoader.isSubresourceLoader())
+        loadParameters.sourceOrigin = static_cast<SubresourceLoader&>(resourceLoader).origin();
+
+    if (!loadParameters.sourceOrigin && document)
+        loadParameters.sourceOrigin = &document->securityOrigin();
+    if (!loadParameters.sourceOrigin) {
+        auto origin = request.httpOrigin();
+        if (!origin.isNull())
+            loadParameters.sourceOrigin = SecurityOrigin::createFromString(origin);
+    }
+
     if (loadParameters.options.mode != FetchOptions::Mode::Navigate) {
-        // FIXME: All loaders should provide their origin if navigation mode is cors/no-cors/same-origin.
-        // As a temporary approach, we use the document origin if available or the HTTP Origin header otherwise.
-        if (resourceLoader.isSubresourceLoader())
-            loadParameters.sourceOrigin = static_cast<SubresourceLoader&>(resourceLoader).origin();
-
-        auto* document = resourceLoader.frame() ? resourceLoader.frame()->document() : nullptr;
-        if (!loadParameters.sourceOrigin && document)
-            loadParameters.sourceOrigin = &document->securityOrigin();
-        if (!loadParameters.sourceOrigin) {
-            auto origin = request.httpOrigin();
-            if (!origin.isNull())
-                loadParameters.sourceOrigin = SecurityOrigin::createFromString(origin);
-        }
         ASSERT(loadParameters.sourceOrigin);
         if (!loadParameters.sourceOrigin) {
             scheduleInternallyFailedLoad(resourceLoader);
@@ -322,20 +323,16 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
         }
     }
 
-    // FIXME: We should also sanitize redirect response for navigations.
-    loadParameters.shouldRestrictHTTPResponseAccess = RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess() && resourceLoader.options().mode != FetchOptions::Mode::Navigate;
+    loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks();
 
-    bool isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate;
+    loadParameters.isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate;
 
-    loadParameters.shouldEnableFromOriginResponseHeader = RuntimeEnabledFeatures::sharedFeatures().fromOriginResponseHeaderEnabled() && !isMainFrameNavigation;
-    if (loadParameters.shouldEnableFromOriginResponseHeader) {
-        Vector<RefPtr<WebCore::SecurityOrigin>> frameAncestorOrigins;
-        for (auto* frame = resourceLoader.frame(); frame; frame = frame->tree().parent()) {
-            if (frame->document())
-                frameAncestorOrigins.append(makeRefPtr(frame->document()->securityOrigin()));
-            if (frame->isMainFrame())
-                break;
-        }
+    loadParameters.shouldEnableCrossOriginResourcePolicy = RuntimeEnabledFeatures::sharedFeatures().crossOriginResourcePolicyEnabled() && !loadParameters.isMainFrameNavigation;
+
+    if (resourceLoader.options().mode == FetchOptions::Mode::Navigate) {
+        Vector<RefPtr<SecurityOrigin>> frameAncestorOrigins;
+        for (auto* frame = resourceLoader.frame()->tree().parent(); frame; frame = frame->tree().parent())
+            frameAncestorOrigins.append(makeRefPtr(frame->document()->securityOrigin()));
         loadParameters.frameAncestorOrigins = WTFMove(frameAncestorOrigins);
     }
 
@@ -405,7 +402,7 @@ void WebLoaderStrategy::remove(ResourceLoader* resourceLoader)
     }
 
 #if ENABLE(SERVICE_WORKER)
-    if (WebServiceWorkerProvider::singleton().cancelFetch(identifier))
+    if (WebServiceWorkerProvider::singleton().cancelFetch(makeObjectIdentifier<FetchIdentifierType>(identifier)))
         return;
 #endif
 
@@ -421,9 +418,9 @@ void WebLoaderStrategy::remove(ResourceLoader* resourceLoader)
     loader->detachFromCoreLoader();
 }
 
-void WebLoaderStrategy::setDefersLoading(ResourceLoader* resourceLoader, bool defers)
+void WebLoaderStrategy::setDefersLoading(ResourceLoader& resourceLoader, bool defers)
 {
-    ResourceLoadIdentifier identifier = resourceLoader->identifier();
+    ResourceLoadIdentifier identifier = resourceLoader.identifier();
     WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetDefersLoading(identifier, defers), 0);
 }
 
@@ -453,8 +450,10 @@ void WebLoaderStrategy::networkProcessCrashed()
 {
     RELEASE_LOG_ERROR(Network, "WebLoaderStrategy::networkProcessCrashed: failing all pending resource loaders");
 
-    for (auto& loader : m_webResourceLoaders)
-        scheduleInternallyFailedLoad(*loader.value->resourceLoader());
+    for (auto& loader : m_webResourceLoaders.values()) {
+        scheduleInternallyFailedLoad(*loader->resourceLoader());
+        loader->detachFromCoreLoader();
+    }
 
     m_webResourceLoaders.clear();
 
@@ -476,6 +475,26 @@ static bool shouldClearReferrerOnHTTPSToHTTPRedirect(Frame* frame)
     return true;
 }
 
+std::optional<WebLoaderStrategy::SyncLoadResult> WebLoaderStrategy::tryLoadingSynchronouslyUsingURLSchemeHandler(FrameLoader& frameLoader, ResourceLoadIdentifier identifier, const ResourceRequest& request)
+{
+    auto* webFrameLoaderClient = toWebFrameLoaderClient(frameLoader.client());
+    auto* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : nullptr;
+    auto* webPage = webFrame ? webFrame->page() : nullptr;
+    if (!webPage)
+        return std::nullopt;
+
+    auto* handler = webPage->urlSchemeHandlerForScheme(request.url().protocol().toStringWithoutCopying());
+    if (!handler)
+        return std::nullopt;
+
+    LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, sync load to URL '%s' will be handled by a UIProcess URL scheme handler.", request.url().string().utf8().data());
+
+    SyncLoadResult result;
+    handler->loadSynchronously(identifier, request, result.response, result.error, result.data);
+
+    return WTFMove(result);
+}
+
 void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsigned long resourceLoadIdentifier, const ResourceRequest& request, ClientCredentialPolicy clientCredentialPolicy,  const FetchOptions& options, const HTTPHeaderMap& originalRequestHeaders, ResourceError& error, ResourceResponse& response, Vector<char>& data)
 {
     auto* document = frameLoader.frame().document();
@@ -484,6 +503,13 @@ void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsi
         return;
     }
 
+    if (auto syncLoadResult = tryLoadingSynchronouslyUsingURLSchemeHandler(frameLoader, resourceLoadIdentifier, request)) {
+        error = WTFMove(syncLoadResult->error);
+        response = WTFMove(syncLoadResult->response);
+        data = WTFMove(syncLoadResult->data);
+        return;
+    }
+
     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frameLoader.client());
     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : nullptr;
     WebPage* webPage = webFrame ? webFrame->page() : nullptr;
@@ -494,12 +520,12 @@ void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsi
     loadParameters.webFrameID = webFrame ? webFrame->frameID() : 0;
     loadParameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
     loadParameters.request = request;
-    loadParameters.contentSniffingPolicy = SniffContent;
+    loadParameters.contentSniffingPolicy = ContentSniffingPolicy::SniffContent;
     loadParameters.contentEncodingSniffingPolicy = ContentEncodingSniffingPolicy::Sniff;
     loadParameters.storedCredentialsPolicy = options.credentials == FetchOptions::Credentials::Omit ? StoredCredentialsPolicy::DoNotUse : StoredCredentialsPolicy::Use;
     loadParameters.clientCredentialPolicy = clientCredentialPolicy;
     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = shouldClearReferrerOnHTTPSToHTTPRedirect(webFrame ? webFrame->coreFrame() : nullptr);
-    loadParameters.shouldRestrictHTTPResponseAccess = RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess();
+    loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks();
 
     loadParameters.options = options;
     loadParameters.sourceOrigin = &document->securityOrigin();
@@ -513,7 +539,7 @@ void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsi
 
     HangDetectionDisabler hangDetectionDisabler;
 
-    if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad(loadParameters), Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::Reply(error, response, data), 0, Seconds::infinity(), IPC::SendSyncOption::DoNotProcessIncomingMessagesWhenWaitingForSyncReply)) {
+    if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad(loadParameters), Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::Reply(error, response, data), 0)) {
         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);
         if (auto* page = webPage->corePage())
             page->diagnosticLoggingClient().logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::synchronousMessageFailedKey(), WebCore::ShouldSample::No);
@@ -522,6 +548,11 @@ void WebLoaderStrategy::loadResourceSynchronously(FrameLoader& frameLoader, unsi
     }
 }
 
+void WebLoaderStrategy::pageLoadCompleted(uint64_t webPageID)
+{
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::PageLoadCompleted(webPageID), 0);
+}
+
 static uint64_t generateLoadIdentifier()
 {
     static uint64_t identifier = 0;
@@ -546,7 +577,7 @@ void WebLoaderStrategy::startPingLoad(Frame& frame, ResourceRequest& request, co
     loadParameters.options = options;
     loadParameters.originalRequestHeaders = originalRequestHeaders;
     loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = shouldClearReferrerOnHTTPSToHTTPRedirect(&frame);
-    loadParameters.shouldRestrictHTTPResponseAccess = RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess();
+    loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks();
     if (!document->shouldBypassMainWorldContentSecurityPolicy()) {
         if (auto * contentSecurityPolicy = document->contentSecurityPolicy())
             loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
@@ -574,7 +605,7 @@ void WebLoaderStrategy::didFinishPingLoad(uint64_t pingLoadIdentifier, ResourceE
         completionHandler(WTFMove(error), WTFMove(response));
 }
 
-void WebLoaderStrategy::preconnectTo(FrameLoader& frameLoader, const WebCore::URL& url, StoredCredentialsPolicy storedCredentialsPolicy, PreconnectCompletionHandler&& completionHandler)
+void WebLoaderStrategy::preconnectTo(FrameLoader& frameLoader, const URL& url, StoredCredentialsPolicy storedCredentialsPolicy, PreconnectCompletionHandler&& completionHandler)
 {
     uint64_t preconnectionIdentifier = generateLoadIdentifier();
     auto addResult = m_preconnectCompletionHandlers.add(preconnectionIdentifier, WTFMove(completionHandler));
@@ -603,7 +634,7 @@ void WebLoaderStrategy::preconnectTo(FrameLoader& frameLoader, const WebCore::UR
     parameters.sessionID = webPage ? webPage->sessionID() : PAL::SessionID::defaultSessionID();
     parameters.storedCredentialsPolicy = storedCredentialsPolicy;
     parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
-    parameters.shouldRestrictHTTPResponseAccess = RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess();
+    parameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks();
     // FIXME: Use the proper destination once all fetch options are passed.
     parameters.options.destination = FetchOptions::Destination::EmptyString;
 
@@ -619,8 +650,7 @@ void WebLoaderStrategy::didFinishPreconnection(uint64_t preconnectionIdentifier,
 void WebLoaderStrategy::storeDerivedDataToCache(const SHA1::Digest& bodyHash, const String& type, const String& partition, WebCore::SharedBuffer& data)
 {
     NetworkCache::DataKey key { partition, type, bodyHash };
-    IPC::SharedBufferDataReference dataReference { &data };
-    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::StoreDerivedDataToCache(key, dataReference), 0);
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::StoreDerivedDataToCache(key, { data }), 0);
 }
 
 bool WebLoaderStrategy::isOnLine() const
@@ -652,10 +682,17 @@ void WebLoaderStrategy::setCaptureExtraNetworkLoadMetricsEnabled(bool enabled)
 ResourceResponse WebLoaderStrategy::responseFromResourceLoadIdentifier(uint64_t resourceLoadIdentifier)
 {
     ResourceResponse response;
-    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::TakeNetworkLoadInformationResponse { resourceLoadIdentifier }, Messages::NetworkConnectionToWebProcess::TakeNetworkLoadInformationResponse::Reply { response }, 0);
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::GetNetworkLoadInformationResponse { resourceLoadIdentifier }, Messages::NetworkConnectionToWebProcess::GetNetworkLoadInformationResponse::Reply { response }, 0);
     return response;
 }
 
+Vector<NetworkTransactionInformation> WebLoaderStrategy::intermediateLoadInformationFromResourceLoadIdentifier(uint64_t resourceLoadIdentifier)
+{
+    Vector<NetworkTransactionInformation> information;
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::GetNetworkLoadIntermediateInformation { resourceLoadIdentifier }, Messages::NetworkConnectionToWebProcess::GetNetworkLoadIntermediateInformation::Reply { information }, 0);
+    return information;
+}
+
 NetworkLoadMetrics WebLoaderStrategy::networkMetricsFromResourceLoadIdentifier(uint64_t resourceLoadIdentifier)
 {
     NetworkLoadMetrics networkMetrics;
@@ -663,4 +700,32 @@ NetworkLoadMetrics WebLoaderStrategy::networkMetricsFromResourceLoadIdentifier(u
     return networkMetrics;
 }
 
+bool WebLoaderStrategy::shouldPerformSecurityChecks() const
+{
+    return RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess();
+}
+
+bool WebLoaderStrategy::havePerformedSecurityChecks(const ResourceResponse& response) const
+{
+    if (!shouldPerformSecurityChecks())
+        return false;
+    switch (response.source()) {
+    case ResourceResponse::Source::ApplicationCache:
+    case ResourceResponse::Source::MemoryCache:
+    case ResourceResponse::Source::MemoryCacheAfterValidation:
+    case ResourceResponse::Source::ServiceWorker:
+        return false;
+    case ResourceResponse::Source::DiskCache:
+    case ResourceResponse::Source::DiskCacheAfterValidation:
+    case ResourceResponse::Source::Network:
+    case ResourceResponse::Source::Unknown:
+        return true;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
 } // namespace WebKit
+
+#undef RELEASE_LOG_IF_ALLOWED
+#undef RELEASE_LOG_ERROR_IF_ALLOWED