Title: [285594] trunk
Revision
285594
Author
[email protected]
Date
2021-11-10 11:14:25 -0800 (Wed, 10 Nov 2021)

Log Message

Add basic support for launching CaptivePortalMode WebProcesses
https://bugs.webkit.org/show_bug.cgi?id=232737
<rdar://84473037>

Reviewed by Brent Fulgham.

Source/WebKit:

Add new `WKWebpagePreferences.captivePortalModeEnabled` API to allow clients apps to opt in or
out of captive portal mode for each navigation (WKWebpagePreferences is passed with the navigation
policy decision). For setting the default state of this setting, the client can set
`WebWebViewConfiguration.defaultWebpagePreferences.captivePortalModeEnabled` (will impact all views
using this configuration).

Note that both this property can only be set by apps with the browser entitlement on iOS (no
restriction on macOS). On iOS, the default value of WKWebpagePreferences.captivePortalModeEnabled
depends on the corresponding system setting. For now, this is simulated by a NSUserDefault but it
will eventually come from somewhere else (TCC?).

Whenever transitioning in or out of captive portal mode, we process-swap on navigation policy
decision. Whenever captive portal mode is enabled, we turn off JIT, generational and concurrent GC
in the WebProcess, as soon as it launches.

Covered by new API tests.

* Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h:
(WebKit::XPCServiceInitializer):
* UIProcess/API/APIPageConfiguration.cpp:
(API::PageConfiguration::captivePortalModeEnabled const):
* UIProcess/API/APIPageConfiguration.h:
* UIProcess/API/APIWebsitePolicies.cpp:
(API::WebsitePolicies::copy const):
(API::WebsitePolicies::captivePortalModeEnabled const):
* UIProcess/API/APIWebsitePolicies.h:
* UIProcess/API/Cocoa/WKWebpagePreferences.h:
* UIProcess/API/Cocoa/WKWebpagePreferences.mm:
(-[WKWebpagePreferences setCaptivePortalModeEnabled:]):
(-[WKWebpagePreferences captivePortalModeEnabled]):
* UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::captivePortalModeEnabledBySystem):
* UIProcess/Launcher/ProcessLauncher.h:
(WebKit::ProcessLauncher::Client::shouldEnableCaptivePortalMode const):
* UIProcess/Launcher/mac/ProcessLauncherMac.mm:
(WebKit::ProcessLauncher::launchProcess):
* UIProcess/SuspendedPageProxy.cpp:
(WebKit::SuspendedPageProxy::findReusableSuspendedPageProcess):
* UIProcess/SuspendedPageProxy.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::launchProcess):
(WebKit::WebPageProxy::receivedNavigationPolicyDecision):
(WebKit::WebPageProxy::triggerBrowsingContextGroupSwitchForNavigation):
(WebKit::WebPageProxy::isJITEnabled):
(WebKit::WebPageProxy::shouldEnableCaptivePortalMode const):
* UIProcess/WebPageProxy.h:
* UIProcess/WebProcessCache.cpp:
(WebKit::WebProcessCache::takeProcess):
* UIProcess/WebProcessCache.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::createNewWebProcess):
(WebKit::WebProcessPool::tryTakePrewarmedProcess):
(WebKit::WebProcessPool::prewarmProcess):
(WebKit::WebProcessPool::processForRegistrableDomain):
(WebKit::WebProcessPool::createWebPage):
(WebKit::WebProcessPool::processForNavigation):
(WebKit::WebProcessPool::processForNavigationInternal):
(WebKit::captivePortalModeEnabledBySystem):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::create):
(WebKit::WebProcessProxy::createForServiceWorkers):
(WebKit::WebProcessProxy::WebProcessProxy):
* UIProcess/WebProcessProxy.h:
(WebKit::WebProcessProxy::captivePortalMode const):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (285593 => 285594)


--- trunk/Source/WebKit/ChangeLog	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/ChangeLog	2021-11-10 19:14:25 UTC (rev 285594)
@@ -1,3 +1,77 @@
+2021-11-10  Chris Dumez  <[email protected]>
+
+        Add basic support for launching CaptivePortalMode WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=232737
+        <rdar://84473037>
+
+        Reviewed by Brent Fulgham.
+
+        Add new `WKWebpagePreferences.captivePortalModeEnabled` API to allow clients apps to opt in or
+        out of captive portal mode for each navigation (WKWebpagePreferences is passed with the navigation
+        policy decision). For setting the default state of this setting, the client can set
+        `WebWebViewConfiguration.defaultWebpagePreferences.captivePortalModeEnabled` (will impact all views
+        using this configuration).
+
+        Note that both this property can only be set by apps with the browser entitlement on iOS (no
+        restriction on macOS). On iOS, the default value of WKWebpagePreferences.captivePortalModeEnabled
+        depends on the corresponding system setting. For now, this is simulated by a NSUserDefault but it
+        will eventually come from somewhere else (TCC?).
+
+        Whenever transitioning in or out of captive portal mode, we process-swap on navigation policy
+        decision. Whenever captive portal mode is enabled, we turn off JIT, generational and concurrent GC
+        in the WebProcess, as soon as it launches.
+
+        Covered by new API tests.
+
+        * Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h:
+        (WebKit::XPCServiceInitializer):
+        * UIProcess/API/APIPageConfiguration.cpp:
+        (API::PageConfiguration::captivePortalModeEnabled const):
+        * UIProcess/API/APIPageConfiguration.h:
+        * UIProcess/API/APIWebsitePolicies.cpp:
+        (API::WebsitePolicies::copy const):
+        (API::WebsitePolicies::captivePortalModeEnabled const):
+        * UIProcess/API/APIWebsitePolicies.h:
+        * UIProcess/API/Cocoa/WKWebpagePreferences.h:
+        * UIProcess/API/Cocoa/WKWebpagePreferences.mm:
+        (-[WKWebpagePreferences setCaptivePortalModeEnabled:]):
+        (-[WKWebpagePreferences captivePortalModeEnabled]):
+        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
+        (WebKit::captivePortalModeEnabledBySystem):
+        * UIProcess/Launcher/ProcessLauncher.h:
+        (WebKit::ProcessLauncher::Client::shouldEnableCaptivePortalMode const):
+        * UIProcess/Launcher/mac/ProcessLauncherMac.mm:
+        (WebKit::ProcessLauncher::launchProcess):
+        * UIProcess/SuspendedPageProxy.cpp:
+        (WebKit::SuspendedPageProxy::findReusableSuspendedPageProcess):
+        * UIProcess/SuspendedPageProxy.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::launchProcess):
+        (WebKit::WebPageProxy::receivedNavigationPolicyDecision):
+        (WebKit::WebPageProxy::triggerBrowsingContextGroupSwitchForNavigation):
+        (WebKit::WebPageProxy::isJITEnabled):
+        (WebKit::WebPageProxy::shouldEnableCaptivePortalMode const):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebProcessCache.cpp:
+        (WebKit::WebProcessCache::takeProcess):
+        * UIProcess/WebProcessCache.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::createNewWebProcess):
+        (WebKit::WebProcessPool::tryTakePrewarmedProcess):
+        (WebKit::WebProcessPool::prewarmProcess):
+        (WebKit::WebProcessPool::processForRegistrableDomain):
+        (WebKit::WebProcessPool::createWebPage):
+        (WebKit::WebProcessPool::processForNavigation):
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        (WebKit::captivePortalModeEnabledBySystem):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::create):
+        (WebKit::WebProcessProxy::createForServiceWorkers):
+        (WebKit::WebProcessProxy::WebProcessProxy):
+        * UIProcess/WebProcessProxy.h:
+        (WebKit::WebProcessProxy::captivePortalMode const):
+
 2021-11-10  Per Arne Vollan <[email protected]>
 
         [iOS][GPUP] Remove sandbox read access to files

Modified: trunk/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h (285593 => 285594)


--- trunk/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -89,6 +89,13 @@
     if (initializerMessage) {
         if (xpc_dictionary_get_bool(initializerMessage, "configure-jsc-for-testing"))
             JSC::Config::configureForTesting();
+        if (xpc_dictionary_get_bool(initializerMessage, "enable-captive-portal-mode")) {
+            JSC::ExecutableAllocator::setJITEnabled(false);
+            JSC::Options::initialize();
+            JSC::Options::AllowUnfinalizedAccessScope scope;
+            JSC::Options::useGenerationalGC() = false;
+            JSC::Options::useConcurrentGC() = false;
+        }
         if (xpc_dictionary_get_bool(initializerMessage, "disable-jit"))
             JSC::ExecutableAllocator::setJITEnabled(false);
         if (xpc_dictionary_get_bool(initializerMessage, "enable-shared-array-buffer")) {

Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -197,6 +197,13 @@
     m_urlSchemeHandlers.set(scheme, WTFMove(handler));
 }
 
+bool PageConfiguration::captivePortalModeEnabled() const
+{
+    if (m_defaultWebsitePolicies)
+        return m_defaultWebsitePolicies->captivePortalModeEnabled();
+    return captivePortalModeEnabledBySystem();
+}
+
 #if ENABLE(APPLICATION_MANIFEST)
 ApplicationManifest* PageConfiguration::applicationManifest() const
 {

Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -189,6 +189,8 @@
     void setRequiresUserActionForEditingControlsManager(bool value) { m_requiresUserActionForEditingControlsManager = value; }
 #endif
 
+    bool captivePortalModeEnabled() const;
+
 private:
 
     RefPtr<WebKit::WebProcessPool> m_processPool;

Modified: trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "APIWebsitePolicies.h"
 
+#include "WebProcessPool.h"
 #include "WebUserContentControllerProxy.h"
 #include "WebsiteDataStore.h"
 #include "WebsitePoliciesData.h"
@@ -72,6 +73,7 @@
     policies->setAllowSiteSpecificQuirksToOverrideContentMode(m_allowSiteSpecificQuirksToOverrideContentMode);
     policies->setApplicationNameForDesktopUserAgent(m_applicationNameForDesktopUserAgent);
     policies->setAllowsContentJavaScript(m_allowsContentJavaScript);
+    policies->setCaptivePortalModeEnabled(m_captivePortalModeEnabled);
     policies->setMouseEventPolicy(m_mouseEventPolicy);
     return policies;
 }
@@ -123,5 +125,10 @@
     };
 }
 
+bool WebsitePolicies::captivePortalModeEnabled() const
+{
+    return m_captivePortalModeEnabled ? *m_captivePortalModeEnabled : WebKit::captivePortalModeEnabledBySystem();
 }
 
+}
+

Modified: trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -125,6 +125,9 @@
     WebCore::AllowsContentJavaScript allowsContentJavaScript() const { return m_allowsContentJavaScript; }
     void setAllowsContentJavaScript(WebCore::AllowsContentJavaScript allows) { m_allowsContentJavaScript = allows; }
 
+    bool captivePortalModeEnabled() const;
+    void setCaptivePortalModeEnabled(std::optional<bool> captivePortalModeEnabled) { m_captivePortalModeEnabled = captivePortalModeEnabled; }
+
     WebCore::MouseEventPolicy mouseEventPolicy() const { return m_mouseEventPolicy; }
     void setMouseEventPolicy(WebCore::MouseEventPolicy policy) { m_mouseEventPolicy = policy; }
 
@@ -157,6 +160,7 @@
     WebCore::AllowsContentJavaScript m_allowsContentJavaScript { WebCore::AllowsContentJavaScript::Yes };
     WebCore::MouseEventPolicy m_mouseEventPolicy { WebCore::MouseEventPolicy::Default };
     bool m_idempotentModeAutosizingOnlyHonorsPercentages { false };
+    std::optional<bool> m_captivePortalModeEnabled;
 };
 
 } // namespace API

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -71,4 +71,9 @@
 */
 @property (nonatomic) BOOL allowsContentJavaScript WK_API_AVAILABLE(macos(11.0), ios(14.0));
 
+/*! @abstract A boolean indicating whether Captive Portal mode is enabled.
+ @discussion The default value is NO on macOS. On iOS, the default value depends on the system setting.
+ */
+@property (nonatomic) BOOL captivePortalModeEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @end

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm	2021-11-10 19:14:25 UTC (rev 285594)
@@ -36,6 +36,10 @@
 #import <WebCore/WebCoreObjCExtras.h>
 #import <wtf/RetainPtr.h>
 
+#if PLATFORM(IOS_FAMILY)
+#import <wtf/cocoa/Entitlements.h>
+#endif
+
 namespace WebKit {
 
 #if PLATFORM(IOS_FAMILY)
@@ -387,8 +391,22 @@
     }
 }
 
+- (void)setCaptivePortalModeEnabled:(BOOL)captivePortalModeEnabled
+{
 #if PLATFORM(IOS_FAMILY)
+    if (!WTF::processHasEntitlement("com.apple.developer.web-browser"))
+        return;
+#endif
+    _websitePolicies->setCaptivePortalModeEnabled(!!captivePortalModeEnabled);
+}
 
+- (BOOL)captivePortalModeEnabled
+{
+    return _websitePolicies->captivePortalModeEnabled();
+}
+
+#if PLATFORM(IOS_FAMILY)
+
 - (void)setPreferredContentMode:(WKContentMode)contentMode
 {
     _websitePolicies->setPreferredContentMode(WebKit::webContentMode(contentMode));

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm	2021-11-10 19:14:25 UTC (rev 285594)
@@ -961,6 +961,18 @@
 }
 
 #if PLATFORM(IOS_FAMILY)
+
+bool captivePortalModeEnabledBySystem()
+{
+    static std::optional<bool> cachedCaptivePortalModeEnabledGlobally;
+    // FIXME: We should invalidate the cached value when the NSUserDefault changes.
+    if (!cachedCaptivePortalModeEnabledGlobally) {
+        // FIXME: Using NSUserDefaults is a temporary workaround. This setting should be stored elsewhere (TCC?).
+        cachedCaptivePortalModeEnabledGlobally = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitCaptivePortalModeEnabled"];
+    }
+    return *cachedCaptivePortalModeEnabledGlobally;
+}
+
 void WebProcessPool::applicationIsAboutToSuspend()
 {
     WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "applicationIsAboutToSuspend: Terminating non-critical processes");

Modified: trunk/Source/WebKit/UIProcess/Launcher/ProcessLauncher.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/Launcher/ProcessLauncher.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/Launcher/ProcessLauncher.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -62,6 +62,7 @@
         virtual bool shouldConfigureJSCForTesting() const { return false; }
         virtual bool isJITEnabled() const { return true; }
         virtual bool shouldEnableSharedArrayBuffer() const { return false; }
+        virtual bool shouldEnableCaptivePortalMode() const { return false; }
 #if PLATFORM(COCOA)
         virtual RefPtr<XPCEventHandler> xpcEventHandler() const { return nullptr; }
 #endif

Modified: trunk/Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm	2021-11-10 19:14:25 UTC (rev 285594)
@@ -203,6 +203,8 @@
             xpc_dictionary_set_bool(bootstrapMessage.get(), "disable-jit", true);
         if (m_client->shouldEnableSharedArrayBuffer())
             xpc_dictionary_set_bool(bootstrapMessage.get(), "enable-shared-array-buffer", true);
+        if (m_client->shouldEnableCaptivePortalMode())
+            xpc_dictionary_set_bool(bootstrapMessage.get(), "enable-captive-portal-mode", true);
     }
 
     xpc_dictionary_set_string(bootstrapMessage.get(), "message-name", "bootstrap");

Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -34,7 +34,6 @@
 #include "WebPageProxyMessages.h"
 #include "WebProcessMessages.h"
 #include "WebProcessPool.h"
-#include "WebProcessProxy.h"
 #include <wtf/DebugUtilities.h>
 #include <wtf/HexNumber.h>
 #include <wtf/URL.h>
@@ -50,11 +49,11 @@
     return map;
 }
 
-RefPtr<WebProcessProxy> SuspendedPageProxy::findReusableSuspendedPageProcess(WebProcessPool& processPool, const RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore)
+RefPtr<WebProcessProxy> SuspendedPageProxy::findReusableSuspendedPageProcess(WebProcessPool& processPool, const RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
 {
     for (auto* suspendedPage : allSuspendedPages()) {
         auto& process = suspendedPage->process();
-        if (&process.processPool() == &processPool && process.registrableDomain() == registrableDomain && &process.websiteDataStore() == &dataStore && process.crossOriginMode() != CrossOriginMode::Isolated)
+        if (&process.processPool() == &processPool && process.registrableDomain() == registrableDomain && &process.websiteDataStore() == &dataStore && process.crossOriginMode() != CrossOriginMode::Isolated && process.captivePortalMode() == captivePortalMode)
             return &process;
     }
     return nullptr;

Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -30,6 +30,7 @@
 #include "ProcessThrottler.h"
 #include "WebBackForwardListItem.h"
 #include "WebPageProxyMessagesReplies.h"
+#include "WebProcessProxy.h"
 #include <WebCore/FrameIdentifier.h>
 #include <wtf/RefCounted.h>
 #include <wtf/WeakPtr.h>
@@ -43,7 +44,6 @@
 class WebBackForwardCache;
 class WebPageProxy;
 class WebProcessPool;
-class WebProcessProxy;
 class WebsiteDataStore;
 
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
@@ -58,7 +58,7 @@
     SuspendedPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, WebCore::FrameIdentifier mainFrameID, ShouldDelayClosingUntilFirstLayerFlush);
     ~SuspendedPageProxy();
 
-    static RefPtr<WebProcessProxy> findReusableSuspendedPageProcess(WebProcessPool&, const WebCore::RegistrableDomain&, WebsiteDataStore&);
+    static RefPtr<WebProcessProxy> findReusableSuspendedPageProcess(WebProcessPool&, const WebCore::RegistrableDomain&, WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
 
     WebPageProxy& page() const { return m_page; }
     WebCore::PageIdentifier webPageID() const { return m_webPageID; }

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -861,7 +861,7 @@
     if (relatedPage && !relatedPage->isClosed())
         m_process = relatedPage->ensureRunningProcess();
     else
-        m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), this, registrableDomain);
+        m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), registrableDomain, shouldEnableCaptivePortalMode() ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled);
     m_hasRunningProcess = true;
 
     m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
@@ -3436,7 +3436,8 @@
         }
     }
 
-    process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, frameInfo, WTFMove(websiteDataStore), [this, protectedThis = Ref { *this }, policyAction, navigation = Ref { *navigation }, navigationAction = WTFMove(navigationAction), sourceProcess = sourceProcess.copyRef(),
+    auto captivePortalMode = (policies ? policies->captivePortalModeEnabled() : shouldEnableCaptivePortalMode()) ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled;
+    process().processPool().processForNavigation(*this, *navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, captivePortalMode, frameInfo, WTFMove(websiteDataStore), [this, protectedThis = Ref { *this }, policyAction, navigation = Ref { *navigation }, navigationAction = WTFMove(navigationAction), sourceProcess = sourceProcess.copyRef(),
         policies = WTFMove(policies), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
         // If the navigation has been destroyed, then no need to proceed.
         if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
@@ -5639,9 +5640,9 @@
 
     RefPtr<WebProcessProxy> processForNavigation;
     if (browsingContextGroupSwitchDecision == BrowsingContextGroupSwitchDecision::NewIsolatedGroup)
-        processForNavigation = m_process->processPool().createNewWebProcess(&websiteDataStore(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Isolated);
+        processForNavigation = m_process->processPool().createNewWebProcess(&websiteDataStore(), m_process->captivePortalMode(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Isolated);
     else
-        processForNavigation = m_process->processPool().processForRegistrableDomain(websiteDataStore(), this, responseDomain);
+        processForNavigation = m_process->processPool().processForRegistrableDomain(websiteDataStore(), responseDomain, m_process->captivePortalMode());
 
     continueNavigationInNewProcess(*navigation, nullptr, processForNavigation.releaseNonNull(), ProcessSwapRequestedByClient::No, ShouldTreatAsContinuingLoad::YesAfterProvisionalLoadStarted, nullptr, existingNetworkResourceLoadIdentifierToResume);
     completionHandler(true);
@@ -8322,6 +8323,7 @@
 
 void WebPageProxy::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
 {
+    launchInitialProcessIfNecessary();
     sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), WTFMove(completionHandler), 0);
 }
 
@@ -10870,6 +10872,11 @@
     send(Messages::WebPage::ScrollToRect(targetRect, origin));
 }
 
+bool WebPageProxy::shouldEnableCaptivePortalMode() const
+{
+    return m_configuration->captivePortalModeEnabled();
+}
+
 #if PLATFORM(COCOA)
 void WebPageProxy::appPrivacyReportTestingData(CompletionHandler<void(const AppPrivacyReportTestingData&)>&& completionHandler)
 {

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -494,6 +494,8 @@
 
     void addPreviouslyVisitedPath(const String&);
 
+    bool shouldEnableCaptivePortalMode() const;
+
 #if ENABLE(DATA_DETECTION)
     NSArray *dataDetectionResults() { return m_dataDetectionResults.get(); }
     void detectDataInAllFrames(OptionSet<WebCore::DataDetectorType>, CompletionHandler<void(const DataDetectionResult&)>&&);

Modified: trunk/Source/WebKit/UIProcess/WebProcessCache.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessCache.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessCache.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -29,7 +29,6 @@
 #include "LegacyGlobalSettings.h"
 #include "Logging.h"
 #include "WebProcessPool.h"
-#include "WebProcessProxy.h"
 #include <wtf/RAMSize.h>
 #include <wtf/StdLibExtras.h>
 
@@ -148,7 +147,7 @@
     return true;
 }
 
-RefPtr<WebProcessProxy> WebProcessCache::takeProcess(const WebCore::RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore)
+RefPtr<WebProcessProxy> WebProcessCache::takeProcess(const WebCore::RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
 {
     auto it = m_processesPerRegistrableDomain.find(registrableDomain);
     if (it == m_processesPerRegistrableDomain.end())
@@ -157,6 +156,9 @@
     if (&it->value->process().websiteDataStore() != &dataStore)
         return nullptr;
 
+    if (it->value->process().captivePortalMode() != captivePortalMode)
+        return nullptr;
+
     auto process = it->value->takeProcess();
     m_processesPerRegistrableDomain.remove(it);
     WEBPROCESSCACHE_RELEASE_LOG("takeProcess: Taking process from WebProcess cache (size=%u, capacity=%u)", process->processIdentifier(), size(), capacity());

Modified: trunk/Source/WebKit/UIProcess/WebProcessCache.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessCache.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessCache.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include "WebProcessProxy.h"
 #include <WebCore/RegistrableDomain.h>
 #include <pal/SessionID.h>
 #include <wtf/HashMap.h>
@@ -35,7 +36,6 @@
 namespace WebKit {
 
 class WebProcessPool;
-class WebProcessProxy;
 class WebsiteDataStore;
 
 class WebProcessCache {
@@ -44,7 +44,7 @@
     explicit WebProcessCache(WebProcessPool&);
 
     bool addProcessIfPossible(Ref<WebProcessProxy>&&);
-    RefPtr<WebProcessProxy> takeProcess(const WebCore::RegistrableDomain&, WebsiteDataStore&);
+    RefPtr<WebProcessProxy> takeProcess(const WebCore::RegistrableDomain&, WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
 
     void updateCapacity(WebProcessPool&);
     unsigned capacity() const { return m_capacity; }

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -617,7 +617,7 @@
     platformResolvePathsForSandboxExtensions();
 }
 
-Ref<WebProcessProxy> WebProcessPool::createNewWebProcess(WebsiteDataStore* websiteDataStore, WebProcessProxy::IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
+Ref<WebProcessProxy> WebProcessPool::createNewWebProcess(WebsiteDataStore* websiteDataStore, WebProcessProxy::CaptivePortalMode captivePortalMode, WebProcessProxy::IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
 {
 #if PLATFORM(COCOA)
     m_tccPreferenceEnabled = doesAppHaveITPEnabled();
@@ -625,7 +625,7 @@
         websiteDataStore->setResourceLoadStatisticsEnabled(m_tccPreferenceEnabled);
 #endif
 
-    auto processProxy = WebProcessProxy::create(*this, websiteDataStore, isPrewarmed, crossOriginMode);
+    auto processProxy = WebProcessProxy::create(*this, websiteDataStore, captivePortalMode, isPrewarmed, crossOriginMode);
     initializeNewWebProcess(processProxy, websiteDataStore, isPrewarmed);
     m_processes.append(processProxy.copyRef());
 
@@ -632,7 +632,7 @@
     return processProxy;
 }
 
-RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore)
+RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
 {
     if (!m_prewarmedProcess)
         return nullptr;
@@ -645,6 +645,9 @@
         return nullptr;
     }
 
+    if (m_prewarmedProcess->captivePortalMode() != captivePortalMode)
+        return nullptr;
+
 #if PLATFORM(GTK) || PLATFORM(WPE)
     // In platforms using Bubblewrap for sandboxing, prewarmed process is launched using the WebProcessPool primary WebsiteDataStore,
     // so we don't use it in case of using a different WebsiteDataStore.
@@ -893,7 +896,12 @@
         return;
 
     WEBPROCESSPOOL_RELEASE_LOG(PerformanceLogging, "prewarmProcess: Prewarming a WebProcess for performance");
-    createNewWebProcess(nullptr, WebProcessProxy::IsPrewarmed::Yes);
+
+    auto captivePortalMode = WebProcessProxy::CaptivePortalMode::Disabled;
+    if (!m_processes.isEmpty())
+        captivePortalMode = m_processes.last()->captivePortalMode();
+
+    createNewWebProcess(nullptr, captivePortalMode, WebProcessProxy::IsPrewarmed::Yes);
 }
 
 void WebProcessPool::enableProcessTermination()
@@ -993,16 +1001,16 @@
     removeProcessFromOriginCacheSet(process);
 }
 
-Ref<WebProcessProxy> WebProcessPool::processForRegistrableDomain(WebsiteDataStore& websiteDataStore, WebPageProxy* page, const RegistrableDomain& registrableDomain)
+Ref<WebProcessProxy> WebProcessPool::processForRegistrableDomain(WebsiteDataStore& websiteDataStore, const RegistrableDomain& registrableDomain, WebProcessProxy::CaptivePortalMode captivePortalMode)
 {
     if (!registrableDomain.isEmpty()) {
-        if (auto process = webProcessCache().takeProcess(registrableDomain, websiteDataStore)) {
+        if (auto process = webProcessCache().takeProcess(registrableDomain, websiteDataStore, captivePortalMode)) {
             ASSERT(m_processes.contains(*process));
             return process.releaseNonNull();
         }
 
         // Check if we have a suspended page for the given registrable domain and use its process if we do, for performance reasons.
-        if (auto process = SuspendedPageProxy::findReusableSuspendedPageProcess(*this, registrableDomain, websiteDataStore)) {
+        if (auto process = SuspendedPageProxy::findReusableSuspendedPageProcess(*this, registrableDomain, websiteDataStore, captivePortalMode)) {
             WEBPROCESSPOOL_RELEASE_LOG(ProcessSwapping, "processForRegistrableDomain: Using WebProcess from a SuspendedPage (process=%p, PID=%i)", process.get(), process->processIdentifier());
             ASSERT(m_processes.contains(*process));
             return process.releaseNonNull();
@@ -1009,7 +1017,7 @@
         }
     }
 
-    if (auto process = tryTakePrewarmedProcess(websiteDataStore)) {
+    if (auto process = tryTakePrewarmedProcess(websiteDataStore, captivePortalMode)) {
         WEBPROCESSPOOL_RELEASE_LOG(ProcessSwapping, "processForRegistrableDomain: Using prewarmed process (process=%p, PID=%i)", process.get(), process->processIdentifier());
         if (!registrableDomain.isEmpty())
             tryPrewarmWithDomainInformation(*process, registrableDomain);
@@ -1036,7 +1044,7 @@
             return process;
         }
     }
-    return createNewWebProcess(&websiteDataStore);
+    return createNewWebProcess(&websiteDataStore, captivePortalMode);
 }
 
 #if ENABLE(SERVICE_WORKER)
@@ -1067,6 +1075,7 @@
     }
 
     RefPtr<WebProcessProxy> process;
+    auto captivePortalMode = pageConfiguration->captivePortalModeEnabled() ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled;
     auto* relatedPage = pageConfiguration->relatedPage();
     if (relatedPage && !relatedPage->isClosed()) {
         // Sharing processes, e.g. when creating the page via window.open().
@@ -1078,12 +1087,12 @@
         // In the common case, we delay process launch until something is actually loaded in the page.
         process = dummyProcessProxy(pageConfiguration->websiteDataStore()->sessionID());
         if (!process) {
-            process = WebProcessProxy::create(*this, pageConfiguration->websiteDataStore(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Shared, WebProcessProxy::ShouldLaunchProcess::No);
+            process = WebProcessProxy::create(*this, pageConfiguration->websiteDataStore(), captivePortalMode, WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Shared, WebProcessProxy::ShouldLaunchProcess::No);
             m_dummyProcessProxies.add(pageConfiguration->websiteDataStore()->sessionID(), *process);
             m_processes.append(*process);
         }
     } else
-        process = processForRegistrableDomain(*pageConfiguration->websiteDataStore(), nullptr, { });
+        process = processForRegistrableDomain(*pageConfiguration->websiteDataStore(), { }, captivePortalMode);
 
     RefPtr<WebUserContentControllerProxy> userContentController = pageConfiguration->userContentController();
     
@@ -1804,9 +1813,9 @@
         m_swappedProcessesPerRegistrableDomain.remove(registrableDomain);
 }
 
-void WebProcessPool::processForNavigation(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, const FrameInfoData& frameInfo, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
+void WebProcessPool::processForNavigation(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, WebProcessProxy::CaptivePortalMode captivePortalMode, const FrameInfoData& frameInfo, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
 {
-    processForNavigationInternal(page, navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, frameInfo, WTFMove(dataStore), [this, page = Ref { page }, navigation = Ref { navigation }, sourceProcess = sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, completionHandler = WTFMove(completionHandler)](Ref<WebProcessProxy>&& process, SuspendedPageProxy* suspendedPage, const String& reason) mutable {
+    processForNavigationInternal(page, navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, captivePortalMode, frameInfo, WTFMove(dataStore), [this, page = Ref { page }, navigation = Ref { navigation }, sourceProcess = sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, completionHandler = WTFMove(completionHandler)](Ref<WebProcessProxy>&& process, SuspendedPageProxy* suspendedPage, const String& reason) mutable {
         // We are process-swapping so automatic process prewarming would be beneficial if the client has not explicitly enabled / disabled it.
         bool doingAnAutomaticProcessSwap = processSwapRequestedByClient == ProcessSwapRequestedByClient::No && process.ptr() != sourceProcess.ptr();
         if (doingAnAutomaticProcessSwap && !configuration().wasAutomaticProcessWarmingSetByClient() && !configuration().clientWouldBenefitFromAutomaticProcessPrewarming()) {
@@ -1829,18 +1838,21 @@
     });
 }
 
-void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& pageSourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, const FrameInfoData& frameInfo, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
+void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& pageSourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, WebProcessProxy::CaptivePortalMode captivePortalMode, const FrameInfoData& frameInfo, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
 {
     auto& targetURL = navigation.currentRequest().url();
     auto targetRegistrableDomain = WebCore::RegistrableDomain { targetURL };
 
-    auto createNewProcess = [this, protectedThis = Ref { *this }, page = Ref { page }, targetRegistrableDomain, dataStore] () -> Ref<WebProcessProxy> {
-        return processForRegistrableDomain(dataStore, page.ptr(), targetRegistrableDomain);
+    auto createNewProcess = [this, protectedThis = Ref { *this }, targetRegistrableDomain, dataStore, captivePortalMode] () -> Ref<WebProcessProxy> {
+        return processForRegistrableDomain(dataStore, targetRegistrableDomain, captivePortalMode);
     };
 
     if (usesSingleWebProcess())
         return completionHandler(WTFMove(sourceProcess), nullptr, "Single WebProcess mode is enabled"_s);
 
+    if (sourceProcess->captivePortalMode() != captivePortalMode)
+        return completionHandler(createNewProcess(), nullptr, "Process swap due to captive portal mode change"_s);
+
     if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
         return completionHandler(createNewProcess(), nullptr, "Process swap was requested by the client"_s);
 
@@ -2108,4 +2120,11 @@
 }
 #endif
 
+#if !PLATFORM(IOS_FAMILY)
+bool captivePortalModeEnabledBySystem()
+{
+    return false;
+}
+#endif
+
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -119,6 +119,7 @@
 int webProcessLatencyQOS();
 int webProcessThroughputQOS();
 #endif
+bool captivePortalModeEnabledBySystem();
 
 enum class CallDownloadDidStart : bool;
 enum class ProcessSwapRequestedByClient : bool;
@@ -303,7 +304,7 @@
 
     void reportWebContentCPUTime(Seconds cpuTime, uint64_t activityState);
 
-    Ref<WebProcessProxy> processForRegistrableDomain(WebsiteDataStore&, WebPageProxy*, const WebCore::RegistrableDomain&); // Will return an existing one if limit is met or due to caching.
+    Ref<WebProcessProxy> processForRegistrableDomain(WebsiteDataStore&, const WebCore::RegistrableDomain&, WebProcessProxy::CaptivePortalMode); // Will return an existing one if limit is met or due to caching.
 
     void prewarmProcess();
 
@@ -438,7 +439,7 @@
     bool hasForegroundWebProcesses() const { return m_foregroundWebProcessCounter.value(); }
     bool hasBackgroundWebProcesses() const { return m_backgroundWebProcessCounter.value(); }
 
-    void processForNavigation(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
+    void processForNavigation(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, WebProcessProxy::CaptivePortalMode, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
 
     void didReachGoodTimeToPrewarm();
 
@@ -507,7 +508,7 @@
     static String containerTemporaryDirectory();
 #endif
 
-    Ref<WebProcessProxy> createNewWebProcess(WebsiteDataStore*, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared);
+    Ref<WebProcessProxy> createNewWebProcess(WebsiteDataStore*, WebProcessProxy::CaptivePortalMode, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared);
 
 private:
     void platformInitialize();
@@ -515,9 +516,9 @@
     void platformInitializeWebProcess(const WebProcessProxy&, WebProcessCreationParameters&);
     void platformInvalidateContext();
 
-    void processForNavigationInternal(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
+    void processForNavigationInternal(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, WebProcessProxy::CaptivePortalMode, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
 
-    RefPtr<WebProcessProxy> tryTakePrewarmedProcess(WebsiteDataStore&);
+    RefPtr<WebProcessProxy> tryTakePrewarmedProcess(WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
 
     void initializeNewWebProcess(WebProcessProxy&, WebsiteDataStore*, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No);
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2021-11-10 19:14:25 UTC (rev 285594)
@@ -164,9 +164,9 @@
     }
 }
 
-Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, ShouldLaunchProcess shouldLaunchProcess)
+Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, CaptivePortalMode captivePortalMode, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, ShouldLaunchProcess shouldLaunchProcess)
 {
-    auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed, crossOriginMode));
+    auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed, crossOriginMode, captivePortalMode));
     if (shouldLaunchProcess == ShouldLaunchProcess::Yes) {
         if (liveProcessesLRU().size() >= s_maxProcessCount) {
             for (auto& processPool : WebProcessPool::allProcessPools())
@@ -184,7 +184,7 @@
 #if ENABLE(SERVICE_WORKER)
 Ref<WebProcessProxy> WebProcessProxy::createForServiceWorkers(WebProcessPool& processPool, RegistrableDomain&& registrableDomain, WebsiteDataStore& websiteDataStore)
 {
-    auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared));
+    auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared, CaptivePortalMode::Disabled));
     proxy->m_registrableDomain = WTFMove(registrableDomain);
     proxy->enableServiceWorkers(processPool.userContentControllerIdentifierForServiceWorkers());
     proxy->connect();
@@ -220,7 +220,7 @@
 };
 #endif
 
-WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
+WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, CaptivePortalMode captivePortalMode)
     : AuxiliaryProcessProxy(processPool.alwaysRunsAtBackgroundPriority())
     , m_backgroundResponsivenessTimer(*this)
     , m_processPool(processPool, isPrewarmed == IsPrewarmed::Yes ? IsWeak::Yes : IsWeak::No)
@@ -237,6 +237,7 @@
     , m_userMediaCaptureManagerProxy(makeUnique<UserMediaCaptureManagerProxy>(makeUniqueRef<UIProxyForCapture>(*this)))
 #endif
     , m_isPrewarmed(isPrewarmed == IsPrewarmed::Yes)
+    , m_captivePortalMode(captivePortalMode)
     , m_crossOriginMode(crossOriginMode)
     , m_shutdownPreventingScopeCounter([this](RefCounterEvent event) { if (event == RefCounterEvent::Decrement) maybeShutDown(); })
 {

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (285593 => 285594)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2021-11-10 19:14:25 UTC (rev 285594)
@@ -134,8 +134,9 @@
     };
 
     enum class ShouldLaunchProcess : bool { No, Yes };
+    enum class CaptivePortalMode : bool { Disabled, Enabled };
 
-    static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared, ShouldLaunchProcess = ShouldLaunchProcess::Yes);
+    static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, CaptivePortalMode, IsPrewarmed, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared, ShouldLaunchProcess = ShouldLaunchProcess::Yes);
     static Ref<WebProcessProxy> createForServiceWorkers(WebProcessPool&, WebCore::RegistrableDomain&&, WebsiteDataStore&);
 
     ~WebProcessProxy();
@@ -427,9 +428,10 @@
 #endif
 
     WebCore::CrossOriginMode crossOriginMode() const { return m_crossOriginMode; }
+    CaptivePortalMode captivePortalMode() const { return m_captivePortalMode; }
 
 protected:
-    WebProcessProxy(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode);
+    WebProcessProxy(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode, CaptivePortalMode);
 
     // AuxiliaryProcessProxy
     ASCIILiteral processName() const final { return "WebContent"_s; }
@@ -440,16 +442,16 @@
     void processWillShutDown(IPC::Connection&) override;
     bool shouldSendPendingMessage(const PendingMessage&) final;
     
-    // ProcessLauncher::Client
-    void didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier) override;
-
 #if PLATFORM(COCOA)
     void cacheMediaMIMETypesInternal(const Vector<String>&);
 #endif
 
+    // ProcessLauncher::Client
+    void didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier) override;
     bool shouldConfigureJSCForTesting() const final;
     bool isJITEnabled() const final;
     bool shouldEnableSharedArrayBuffer() const final { return m_crossOriginMode == WebCore::CrossOriginMode::Isolated; }
+    bool shouldEnableCaptivePortalMode() const final { return m_captivePortalMode == CaptivePortalMode::Enabled; }
 
     void validateFreezerStatus();
 
@@ -622,6 +624,7 @@
 
     bool m_hasCommittedAnyProvisionalLoads { false };
     bool m_isPrewarmed;
+    CaptivePortalMode m_captivePortalMode { CaptivePortalMode::Disabled };
     WebCore::CrossOriginMode m_crossOriginMode { WebCore::CrossOriginMode::Shared };
 #if ENABLE(ATTACHMENT_ELEMENT)
     bool m_hasIssuedAttachmentElementRelatedSandboxExtensions { false };

Modified: trunk/Tools/ChangeLog (285593 => 285594)


--- trunk/Tools/ChangeLog	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Tools/ChangeLog	2021-11-10 19:14:25 UTC (rev 285594)
@@ -1,3 +1,15 @@
+2021-11-10  Chris Dumez  <[email protected]>
+
+        Add basic support for launching CaptivePortalMode WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=232737
+        <rdar://84473037>
+
+        Reviewed by Brent Fulgham.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2021-11-10  Tyler Wilcock  <[email protected]>
 
         AX: Make ancestor computation cheaper by setting flags upon child insertion

Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements (285593 => 285594)


--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements	2021-11-10 19:14:25 UTC (rev 285594)
@@ -10,5 +10,7 @@
 	<true/>
 	<key>com.apple.Pasteboard.paste-unchecked</key>
 	<true/>
+	<key>com.apple.developer.web-browser</key>
+	<true/>
 </dict>
 </plist>

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (285593 => 285594)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2021-11-10 19:14:25 UTC (rev 285594)
@@ -7624,3 +7624,123 @@
 {
     runCOOPProcessSwapTest("same-origin-allow-popup", "unsafe-none", "unsafe-none", "unsafe-none", IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No);
 }
+
+static bool isJITEnabled(WKWebView *webView)
+{
+    __block bool gotResponse = false;
+    __block bool isJITEnabledResult = false;
+    [webView _isJITEnabled:^(BOOL isJITEnabled) {
+        isJITEnabledResult = isJITEnabled;
+        gotResponse = true;
+    }];
+    TestWebKitAPI::Util::run(&gotResponse);
+    EXPECT_NE([webView _webProcessIdentifier], 0);
+    return isJITEnabledResult;
+}
+
+TEST(ProcessSwap, NavigatingToCaptivePortalMode)
+{
+    auto webView = adoptNS([WKWebView new]);
+    auto delegate = adoptNS([TestNavigationDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    EXPECT_TRUE(isJITEnabled(webView.get()));
+
+    __block bool finishedNavigation = false;
+    delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) {
+        finishedNavigation = true;
+    };
+
+    NSURL *url = "" mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+
+    pid_t pid1 = [webView _webProcessIdentifier];
+    EXPECT_NE(pid1, 0);
+
+    EXPECT_TRUE(isJITEnabled(webView.get()));
+
+    delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) {
+        EXPECT_FALSE(preferences.captivePortalModeEnabled);
+        preferences.captivePortalModeEnabled = YES;
+        completionHandler(WKNavigationActionPolicyAllow, preferences);
+    };
+
+    finishedNavigation = false;
+    url = "" mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+
+    // We should have process-swap for transitioning to captive portal mode.
+    EXPECT_NE(pid1, [webView _webProcessIdentifier]);
+    EXPECT_FALSE(isJITEnabled(webView.get()));
+}
+
+TEST(ProcessSwap, CaptivePortalModeEnabledByDefaultThenOptOut)
+{
+    auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]);
+    EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences.captivePortalModeEnabled);
+    webViewConfiguration.get().defaultWebpagePreferences.captivePortalModeEnabled = YES;
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto delegate = adoptNS([TestNavigationDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    EXPECT_FALSE(isJITEnabled(webView.get()));
+    pid_t pid1 = [webView _webProcessIdentifier];
+
+    __block bool finishedNavigation = false;
+    delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) {
+        finishedNavigation = true;
+    };
+
+    delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) {
+        EXPECT_TRUE(preferences.captivePortalModeEnabled);
+        completionHandler(WKNavigationActionPolicyAllow, preferences);
+    };
+
+    NSURL *url = "" mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+
+    EXPECT_FALSE(isJITEnabled(webView.get()));
+    EXPECT_EQ(pid1, [webView _webProcessIdentifier]);
+
+    finishedNavigation = false;
+    url = "" mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+
+    EXPECT_EQ(pid1, [webView _webProcessIdentifier]); // Shouldn't have process-swapped since we're staying in captive portal mode.
+    EXPECT_FALSE(isJITEnabled(webView.get()));
+
+    delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) {
+        EXPECT_TRUE(preferences.captivePortalModeEnabled);
+        preferences.captivePortalModeEnabled = NO; // Opt out of captive portal mode for this load.
+        completionHandler(WKNavigationActionPolicyAllow, preferences);
+    };
+
+    finishedNavigation = false;
+    url = "" mainBundle] URLForResource:@"simple3" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+
+    // We should have process-swapped to get out of captive portal mode.
+    EXPECT_NE(pid1, [webView _webProcessIdentifier]);
+    EXPECT_TRUE(isJITEnabled(webView.get()));
+
+    // captive portal mode should be disabled in new WebViews since it is not enabled globally.
+    auto webView2 = adoptNS([WKWebView new]);
+    [webView2 setNavigationDelegate:delegate.get()];
+    EXPECT_TRUE(isJITEnabled(webView2.get()));
+    pid_t pid2 = [webView2 _webProcessIdentifier];
+
+    delegate.get().decidePolicyForNavigationActionWithPreferences = nil;
+
+    finishedNavigation = false;
+    url = "" mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView2 loadRequest:[NSURLRequest requestWithURL:url]];
+    TestWebKitAPI::Util::run(&finishedNavigation);
+    EXPECT_TRUE(isJITEnabled(webView2.get()));
+    EXPECT_EQ(pid2, [webView2 _webProcessIdentifier]);
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to