<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[285594] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/285594">285594</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2021-11-10 11:14:25 -0800 (Wed, 10 Nov 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitSharedEntryPointUtilitiesCocoaXPCServiceXPCServiceEntryPointh">trunk/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIAPIPageConfigurationcpp">trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIAPIPageConfigurationh">trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIAPIWebsitePoliciescpp">trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIAPIWebsitePoliciesh">trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebpagePreferencesh">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKWebpagePreferencesmm">trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaWebProcessPoolCocoamm">trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessLauncherProcessLauncherh">trunk/Source/WebKit/UIProcess/Launcher/ProcessLauncher.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessLaunchermacProcessLauncherMacmm">trunk/Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessSuspendedPageProxycpp">trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessSuspendedPageProxyh">trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxycpp">trunk/Source/WebKit/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxyh">trunk/Source/WebKit/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessCachecpp">trunk/Source/WebKit/UIProcess/WebProcessCache.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessCacheh">trunk/Source/WebKit/UIProcess/WebProcessCache.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessPoolcpp">trunk/Source/WebKit/UIProcess/WebProcessPool.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessPoolh">trunk/Source/WebKit/UIProcess/WebProcessPool.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessProxycpp">trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessProxyh">trunk/Source/WebKit/UIProcess/WebProcessProxy.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPIConfigurationsTestWebKitAPIiOSentitlements">trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaProcessSwapOnNavigationmm">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,77 @@
</span><ins>+2021-11-10  Chris Dumez  <cdumez@apple.com>
+
+        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):
+
</ins><span class="cx"> 2021-11-10  Per Arne Vollan <pvollan@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS][GPUP] Remove sandbox read access to files
</span></span></pre></div>
<a id="trunkSourceWebKitSharedEntryPointUtilitiesCocoaXPCServiceXPCServiceEntryPointh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -89,6 +89,13 @@
</span><span class="cx">     if (initializerMessage) {
</span><span class="cx">         if (xpc_dictionary_get_bool(initializerMessage, "configure-jsc-for-testing"))
</span><span class="cx">             JSC::Config::configureForTesting();
</span><ins>+        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;
+        }
</ins><span class="cx">         if (xpc_dictionary_get_bool(initializerMessage, "disable-jit"))
</span><span class="cx">             JSC::ExecutableAllocator::setJITEnabled(false);
</span><span class="cx">         if (xpc_dictionary_get_bool(initializerMessage, "enable-shared-array-buffer")) {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIAPIPageConfigurationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -197,6 +197,13 @@
</span><span class="cx">     m_urlSchemeHandlers.set(scheme, WTFMove(handler));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool PageConfiguration::captivePortalModeEnabled() const
+{
+    if (m_defaultWebsitePolicies)
+        return m_defaultWebsitePolicies->captivePortalModeEnabled();
+    return captivePortalModeEnabledBySystem();
+}
+
</ins><span class="cx"> #if ENABLE(APPLICATION_MANIFEST)
</span><span class="cx"> ApplicationManifest* PageConfiguration::applicationManifest() const
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIAPIPageConfigurationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -189,6 +189,8 @@
</span><span class="cx">     void setRequiresUserActionForEditingControlsManager(bool value) { m_requiresUserActionForEditingControlsManager = value; }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    bool captivePortalModeEnabled() const;
+
</ins><span class="cx"> private:
</span><span class="cx"> 
</span><span class="cx">     RefPtr<WebKit::WebProcessPool> m_processPool;
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIAPIWebsitePoliciescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "APIWebsitePolicies.h"
</span><span class="cx"> 
</span><ins>+#include "WebProcessPool.h"
</ins><span class="cx"> #include "WebUserContentControllerProxy.h"
</span><span class="cx"> #include "WebsiteDataStore.h"
</span><span class="cx"> #include "WebsitePoliciesData.h"
</span><span class="lines">@@ -72,6 +73,7 @@
</span><span class="cx">     policies->setAllowSiteSpecificQuirksToOverrideContentMode(m_allowSiteSpecificQuirksToOverrideContentMode);
</span><span class="cx">     policies->setApplicationNameForDesktopUserAgent(m_applicationNameForDesktopUserAgent);
</span><span class="cx">     policies->setAllowsContentJavaScript(m_allowsContentJavaScript);
</span><ins>+    policies->setCaptivePortalModeEnabled(m_captivePortalModeEnabled);
</ins><span class="cx">     policies->setMouseEventPolicy(m_mouseEventPolicy);
</span><span class="cx">     return policies;
</span><span class="cx"> }
</span><span class="lines">@@ -123,5 +125,10 @@
</span><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool WebsitePolicies::captivePortalModeEnabled() const
+{
+    return m_captivePortalModeEnabled ? *m_captivePortalModeEnabled : WebKit::captivePortalModeEnabledBySystem();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+}
+
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIAPIWebsitePoliciesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/APIWebsitePolicies.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -125,6 +125,9 @@
</span><span class="cx">     WebCore::AllowsContentJavaScript allowsContentJavaScript() const { return m_allowsContentJavaScript; }
</span><span class="cx">     void setAllowsContentJavaScript(WebCore::AllowsContentJavaScript allows) { m_allowsContentJavaScript = allows; }
</span><span class="cx"> 
</span><ins>+    bool captivePortalModeEnabled() const;
+    void setCaptivePortalModeEnabled(std::optional<bool> captivePortalModeEnabled) { m_captivePortalModeEnabled = captivePortalModeEnabled; }
+
</ins><span class="cx">     WebCore::MouseEventPolicy mouseEventPolicy() const { return m_mouseEventPolicy; }
</span><span class="cx">     void setMouseEventPolicy(WebCore::MouseEventPolicy policy) { m_mouseEventPolicy = policy; }
</span><span class="cx"> 
</span><span class="lines">@@ -157,6 +160,7 @@
</span><span class="cx">     WebCore::AllowsContentJavaScript m_allowsContentJavaScript { WebCore::AllowsContentJavaScript::Yes };
</span><span class="cx">     WebCore::MouseEventPolicy m_mouseEventPolicy { WebCore::MouseEventPolicy::Default };
</span><span class="cx">     bool m_idempotentModeAutosizingOnlyHonorsPercentages { false };
</span><ins>+    std::optional<bool> m_captivePortalModeEnabled;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace API
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebpagePreferencesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -71,4 +71,9 @@
</span><span class="cx"> */
</span><span class="cx"> @property (nonatomic) BOOL allowsContentJavaScript WK_API_AVAILABLE(macos(11.0), ios(14.0));
</span><span class="cx"> 
</span><ins>+/*! @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));
+
</ins><span class="cx"> @end
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKWebpagePreferencesmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebpagePreferences.mm (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -36,6 +36,10 @@
</span><span class="cx"> #import <WebCore/WebCoreObjCExtras.h>
</span><span class="cx"> #import <wtf/RetainPtr.h>
</span><span class="cx"> 
</span><ins>+#if PLATFORM(IOS_FAMILY)
+#import <wtf/cocoa/Entitlements.h>
+#endif
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS_FAMILY)
</span><span class="lines">@@ -387,8 +391,22 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)setCaptivePortalModeEnabled:(BOOL)captivePortalModeEnabled
+{
</ins><span class="cx"> #if PLATFORM(IOS_FAMILY)
</span><ins>+    if (!WTF::processHasEntitlement("com.apple.developer.web-browser"))
+        return;
+#endif
+    _websitePolicies->setCaptivePortalModeEnabled(!!captivePortalModeEnabled);
+}
</ins><span class="cx"> 
</span><ins>+- (BOOL)captivePortalModeEnabled
+{
+    return _websitePolicies->captivePortalModeEnabled();
+}
+
+#if PLATFORM(IOS_FAMILY)
+
</ins><span class="cx"> - (void)setPreferredContentMode:(WKContentMode)contentMode
</span><span class="cx"> {
</span><span class="cx">     _websitePolicies->setPreferredContentMode(WebKit::webContentMode(contentMode));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaWebProcessPoolCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -961,6 +961,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS_FAMILY)
</span><ins>+
+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;
+}
+
</ins><span class="cx"> void WebProcessPool::applicationIsAboutToSuspend()
</span><span class="cx"> {
</span><span class="cx">     WEBPROCESSPOOL_RELEASE_LOG(ProcessSuspension, "applicationIsAboutToSuspend: Terminating non-critical processes");
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessLauncherProcessLauncherh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Launcher/ProcessLauncher.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx">         virtual bool shouldConfigureJSCForTesting() const { return false; }
</span><span class="cx">         virtual bool isJITEnabled() const { return true; }
</span><span class="cx">         virtual bool shouldEnableSharedArrayBuffer() const { return false; }
</span><ins>+        virtual bool shouldEnableCaptivePortalMode() const { return false; }
</ins><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">         virtual RefPtr<XPCEventHandler> xpcEventHandler() const { return nullptr; }
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessLaunchermacProcessLauncherMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -203,6 +203,8 @@
</span><span class="cx">             xpc_dictionary_set_bool(bootstrapMessage.get(), "disable-jit", true);
</span><span class="cx">         if (m_client->shouldEnableSharedArrayBuffer())
</span><span class="cx">             xpc_dictionary_set_bool(bootstrapMessage.get(), "enable-shared-array-buffer", true);
</span><ins>+        if (m_client->shouldEnableCaptivePortalMode())
+            xpc_dictionary_set_bool(bootstrapMessage.get(), "enable-captive-portal-mode", true);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     xpc_dictionary_set_string(bootstrapMessage.get(), "message-name", "bootstrap");
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessSuspendedPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -34,7 +34,6 @@
</span><span class="cx"> #include "WebPageProxyMessages.h"
</span><span class="cx"> #include "WebProcessMessages.h"
</span><span class="cx"> #include "WebProcessPool.h"
</span><del>-#include "WebProcessProxy.h"
</del><span class="cx"> #include <wtf/DebugUtilities.h>
</span><span class="cx"> #include <wtf/HexNumber.h>
</span><span class="cx"> #include <wtf/URL.h>
</span><span class="lines">@@ -50,11 +49,11 @@
</span><span class="cx">     return map;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RefPtr<WebProcessProxy> SuspendedPageProxy::findReusableSuspendedPageProcess(WebProcessPool& processPool, const RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore)
</del><ins>+RefPtr<WebProcessProxy> SuspendedPageProxy::findReusableSuspendedPageProcess(WebProcessPool& processPool, const RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
</ins><span class="cx"> {
</span><span class="cx">     for (auto* suspendedPage : allSuspendedPages()) {
</span><span class="cx">         auto& process = suspendedPage->process();
</span><del>-        if (&process.processPool() == &processPool && process.registrableDomain() == registrableDomain && &process.websiteDataStore() == &dataStore && process.crossOriginMode() != CrossOriginMode::Isolated)
</del><ins>+        if (&process.processPool() == &processPool && process.registrableDomain() == registrableDomain && &process.websiteDataStore() == &dataStore && process.crossOriginMode() != CrossOriginMode::Isolated && process.captivePortalMode() == captivePortalMode)
</ins><span class="cx">             return &process;
</span><span class="cx">     }
</span><span class="cx">     return nullptr;
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessSuspendedPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include "ProcessThrottler.h"
</span><span class="cx"> #include "WebBackForwardListItem.h"
</span><span class="cx"> #include "WebPageProxyMessagesReplies.h"
</span><ins>+#include "WebProcessProxy.h"
</ins><span class="cx"> #include <WebCore/FrameIdentifier.h>
</span><span class="cx"> #include <wtf/RefCounted.h>
</span><span class="cx"> #include <wtf/WeakPtr.h>
</span><span class="lines">@@ -43,7 +44,6 @@
</span><span class="cx"> class WebBackForwardCache;
</span><span class="cx"> class WebPageProxy;
</span><span class="cx"> class WebProcessPool;
</span><del>-class WebProcessProxy;
</del><span class="cx"> class WebsiteDataStore;
</span><span class="cx"> 
</span><span class="cx"> #if HAVE(VISIBILITY_PROPAGATION_VIEW)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx">     SuspendedPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, WebCore::FrameIdentifier mainFrameID, ShouldDelayClosingUntilFirstLayerFlush);
</span><span class="cx">     ~SuspendedPageProxy();
</span><span class="cx"> 
</span><del>-    static RefPtr<WebProcessProxy> findReusableSuspendedPageProcess(WebProcessPool&, const WebCore::RegistrableDomain&, WebsiteDataStore&);
</del><ins>+    static RefPtr<WebProcessProxy> findReusableSuspendedPageProcess(WebProcessPool&, const WebCore::RegistrableDomain&, WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
</ins><span class="cx"> 
</span><span class="cx">     WebPageProxy& page() const { return m_page; }
</span><span class="cx">     WebCore::PageIdentifier webPageID() const { return m_webPageID; }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -861,7 +861,7 @@
</span><span class="cx">     if (relatedPage && !relatedPage->isClosed())
</span><span class="cx">         m_process = relatedPage->ensureRunningProcess();
</span><span class="cx">     else
</span><del>-        m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), this, registrableDomain);
</del><ins>+        m_process = processPool.processForRegistrableDomain(m_websiteDataStore.get(), registrableDomain, shouldEnableCaptivePortalMode() ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled);
</ins><span class="cx">     m_hasRunningProcess = true;
</span><span class="cx"> 
</span><span class="cx">     m_process->addExistingWebPage(*this, WebProcessProxy::BeginsUsingDataStore::Yes);
</span><span class="lines">@@ -3436,7 +3436,8 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    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(),
</del><ins>+    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(),
</ins><span class="cx">         policies = WTFMove(policies), sender = WTFMove(sender), processSwapRequestedByClient] (Ref<WebProcessProxy>&& processForNavigation, SuspendedPageProxy* destinationSuspendedPage, const String& reason) mutable {
</span><span class="cx">         // If the navigation has been destroyed, then no need to proceed.
</span><span class="cx">         if (isClosed() || !navigationState().hasNavigation(navigation->navigationID())) {
</span><span class="lines">@@ -5639,9 +5640,9 @@
</span><span class="cx"> 
</span><span class="cx">     RefPtr<WebProcessProxy> processForNavigation;
</span><span class="cx">     if (browsingContextGroupSwitchDecision == BrowsingContextGroupSwitchDecision::NewIsolatedGroup)
</span><del>-        processForNavigation = m_process->processPool().createNewWebProcess(&websiteDataStore(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Isolated);
</del><ins>+        processForNavigation = m_process->processPool().createNewWebProcess(&websiteDataStore(), m_process->captivePortalMode(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Isolated);
</ins><span class="cx">     else
</span><del>-        processForNavigation = m_process->processPool().processForRegistrableDomain(websiteDataStore(), this, responseDomain);
</del><ins>+        processForNavigation = m_process->processPool().processForRegistrableDomain(websiteDataStore(), responseDomain, m_process->captivePortalMode());
</ins><span class="cx"> 
</span><span class="cx">     continueNavigationInNewProcess(*navigation, nullptr, processForNavigation.releaseNonNull(), ProcessSwapRequestedByClient::No, ShouldTreatAsContinuingLoad::YesAfterProvisionalLoadStarted, nullptr, existingNetworkResourceLoadIdentifierToResume);
</span><span class="cx">     completionHandler(true);
</span><span class="lines">@@ -8322,6 +8323,7 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
</span><span class="cx"> {
</span><ins>+    launchInitialProcessIfNecessary();
</ins><span class="cx">     sendWithAsyncReply(Messages::WebProcess::IsJITEnabled(), WTFMove(completionHandler), 0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -10870,6 +10872,11 @@
</span><span class="cx">     send(Messages::WebPage::ScrollToRect(targetRect, origin));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool WebPageProxy::shouldEnableCaptivePortalMode() const
+{
+    return m_configuration->captivePortalModeEnabled();
+}
+
</ins><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx"> void WebPageProxy::appPrivacyReportTestingData(CompletionHandler<void(const AppPrivacyReportTestingData&)>&& completionHandler)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -494,6 +494,8 @@
</span><span class="cx"> 
</span><span class="cx">     void addPreviouslyVisitedPath(const String&);
</span><span class="cx"> 
</span><ins>+    bool shouldEnableCaptivePortalMode() const;
+
</ins><span class="cx"> #if ENABLE(DATA_DETECTION)
</span><span class="cx">     NSArray *dataDetectionResults() { return m_dataDetectionResults.get(); }
</span><span class="cx">     void detectDataInAllFrames(OptionSet<WebCore::DataDetectorType>, CompletionHandler<void(const DataDetectionResult&)>&&);
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessCache.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -29,7 +29,6 @@
</span><span class="cx"> #include "LegacyGlobalSettings.h"
</span><span class="cx"> #include "Logging.h"
</span><span class="cx"> #include "WebProcessPool.h"
</span><del>-#include "WebProcessProxy.h"
</del><span class="cx"> #include <wtf/RAMSize.h>
</span><span class="cx"> #include <wtf/StdLibExtras.h>
</span><span class="cx"> 
</span><span class="lines">@@ -148,7 +147,7 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RefPtr<WebProcessProxy> WebProcessCache::takeProcess(const WebCore::RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore)
</del><ins>+RefPtr<WebProcessProxy> WebProcessCache::takeProcess(const WebCore::RegistrableDomain& registrableDomain, WebsiteDataStore& dataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
</ins><span class="cx"> {
</span><span class="cx">     auto it = m_processesPerRegistrableDomain.find(registrableDomain);
</span><span class="cx">     if (it == m_processesPerRegistrableDomain.end())
</span><span class="lines">@@ -157,6 +156,9 @@
</span><span class="cx">     if (&it->value->process().websiteDataStore() != &dataStore)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><ins>+    if (it->value->process().captivePortalMode() != captivePortalMode)
+        return nullptr;
+
</ins><span class="cx">     auto process = it->value->takeProcess();
</span><span class="cx">     m_processesPerRegistrableDomain.remove(it);
</span><span class="cx">     WEBPROCESSCACHE_RELEASE_LOG("takeProcess: Taking process from WebProcess cache (size=%u, capacity=%u)", process->processIdentifier(), size(), capacity());
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessCache.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include "WebProcessProxy.h"
</ins><span class="cx"> #include <WebCore/RegistrableDomain.h>
</span><span class="cx"> #include <pal/SessionID.h>
</span><span class="cx"> #include <wtf/HashMap.h>
</span><span class="lines">@@ -35,7 +36,6 @@
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> class WebProcessPool;
</span><del>-class WebProcessProxy;
</del><span class="cx"> class WebsiteDataStore;
</span><span class="cx"> 
</span><span class="cx"> class WebProcessCache {
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx">     explicit WebProcessCache(WebProcessPool&);
</span><span class="cx"> 
</span><span class="cx">     bool addProcessIfPossible(Ref<WebProcessProxy>&&);
</span><del>-    RefPtr<WebProcessProxy> takeProcess(const WebCore::RegistrableDomain&, WebsiteDataStore&);
</del><ins>+    RefPtr<WebProcessProxy> takeProcess(const WebCore::RegistrableDomain&, WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
</ins><span class="cx"> 
</span><span class="cx">     void updateCapacity(WebProcessPool&);
</span><span class="cx">     unsigned capacity() const { return m_capacity; }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessPoolcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -617,7 +617,7 @@
</span><span class="cx">     platformResolvePathsForSandboxExtensions();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<WebProcessProxy> WebProcessPool::createNewWebProcess(WebsiteDataStore* websiteDataStore, WebProcessProxy::IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
</del><ins>+Ref<WebProcessProxy> WebProcessPool::createNewWebProcess(WebsiteDataStore* websiteDataStore, WebProcessProxy::CaptivePortalMode captivePortalMode, WebProcessProxy::IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
</ins><span class="cx"> {
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">     m_tccPreferenceEnabled = doesAppHaveITPEnabled();
</span><span class="lines">@@ -625,7 +625,7 @@
</span><span class="cx">         websiteDataStore->setResourceLoadStatisticsEnabled(m_tccPreferenceEnabled);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    auto processProxy = WebProcessProxy::create(*this, websiteDataStore, isPrewarmed, crossOriginMode);
</del><ins>+    auto processProxy = WebProcessProxy::create(*this, websiteDataStore, captivePortalMode, isPrewarmed, crossOriginMode);
</ins><span class="cx">     initializeNewWebProcess(processProxy, websiteDataStore, isPrewarmed);
</span><span class="cx">     m_processes.append(processProxy.copyRef());
</span><span class="cx"> 
</span><span class="lines">@@ -632,7 +632,7 @@
</span><span class="cx">     return processProxy;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore)
</del><ins>+RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore, WebProcessProxy::CaptivePortalMode captivePortalMode)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_prewarmedProcess)
</span><span class="cx">         return nullptr;
</span><span class="lines">@@ -645,6 +645,9 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (m_prewarmedProcess->captivePortalMode() != captivePortalMode)
+        return nullptr;
+
</ins><span class="cx"> #if PLATFORM(GTK) || PLATFORM(WPE)
</span><span class="cx">     // In platforms using Bubblewrap for sandboxing, prewarmed process is launched using the WebProcessPool primary WebsiteDataStore,
</span><span class="cx">     // so we don't use it in case of using a different WebsiteDataStore.
</span><span class="lines">@@ -893,7 +896,12 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     WEBPROCESSPOOL_RELEASE_LOG(PerformanceLogging, "prewarmProcess: Prewarming a WebProcess for performance");
</span><del>-    createNewWebProcess(nullptr, WebProcessProxy::IsPrewarmed::Yes);
</del><ins>+
+    auto captivePortalMode = WebProcessProxy::CaptivePortalMode::Disabled;
+    if (!m_processes.isEmpty())
+        captivePortalMode = m_processes.last()->captivePortalMode();
+
+    createNewWebProcess(nullptr, captivePortalMode, WebProcessProxy::IsPrewarmed::Yes);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebProcessPool::enableProcessTermination()
</span><span class="lines">@@ -993,16 +1001,16 @@
</span><span class="cx">     removeProcessFromOriginCacheSet(process);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<WebProcessProxy> WebProcessPool::processForRegistrableDomain(WebsiteDataStore& websiteDataStore, WebPageProxy* page, const RegistrableDomain& registrableDomain)
</del><ins>+Ref<WebProcessProxy> WebProcessPool::processForRegistrableDomain(WebsiteDataStore& websiteDataStore, const RegistrableDomain& registrableDomain, WebProcessProxy::CaptivePortalMode captivePortalMode)
</ins><span class="cx"> {
</span><span class="cx">     if (!registrableDomain.isEmpty()) {
</span><del>-        if (auto process = webProcessCache().takeProcess(registrableDomain, websiteDataStore)) {
</del><ins>+        if (auto process = webProcessCache().takeProcess(registrableDomain, websiteDataStore, captivePortalMode)) {
</ins><span class="cx">             ASSERT(m_processes.contains(*process));
</span><span class="cx">             return process.releaseNonNull();
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // Check if we have a suspended page for the given registrable domain and use its process if we do, for performance reasons.
</span><del>-        if (auto process = SuspendedPageProxy::findReusableSuspendedPageProcess(*this, registrableDomain, websiteDataStore)) {
</del><ins>+        if (auto process = SuspendedPageProxy::findReusableSuspendedPageProcess(*this, registrableDomain, websiteDataStore, captivePortalMode)) {
</ins><span class="cx">             WEBPROCESSPOOL_RELEASE_LOG(ProcessSwapping, "processForRegistrableDomain: Using WebProcess from a SuspendedPage (process=%p, PID=%i)", process.get(), process->processIdentifier());
</span><span class="cx">             ASSERT(m_processes.contains(*process));
</span><span class="cx">             return process.releaseNonNull();
</span><span class="lines">@@ -1009,7 +1017,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (auto process = tryTakePrewarmedProcess(websiteDataStore)) {
</del><ins>+    if (auto process = tryTakePrewarmedProcess(websiteDataStore, captivePortalMode)) {
</ins><span class="cx">         WEBPROCESSPOOL_RELEASE_LOG(ProcessSwapping, "processForRegistrableDomain: Using prewarmed process (process=%p, PID=%i)", process.get(), process->processIdentifier());
</span><span class="cx">         if (!registrableDomain.isEmpty())
</span><span class="cx">             tryPrewarmWithDomainInformation(*process, registrableDomain);
</span><span class="lines">@@ -1036,7 +1044,7 @@
</span><span class="cx">             return process;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    return createNewWebProcess(&websiteDataStore);
</del><ins>+    return createNewWebProcess(&websiteDataStore, captivePortalMode);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="lines">@@ -1067,6 +1075,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RefPtr<WebProcessProxy> process;
</span><ins>+    auto captivePortalMode = pageConfiguration->captivePortalModeEnabled() ? WebProcessProxy::CaptivePortalMode::Enabled : WebProcessProxy::CaptivePortalMode::Disabled;
</ins><span class="cx">     auto* relatedPage = pageConfiguration->relatedPage();
</span><span class="cx">     if (relatedPage && !relatedPage->isClosed()) {
</span><span class="cx">         // Sharing processes, e.g. when creating the page via window.open().
</span><span class="lines">@@ -1078,12 +1087,12 @@
</span><span class="cx">         // In the common case, we delay process launch until something is actually loaded in the page.
</span><span class="cx">         process = dummyProcessProxy(pageConfiguration->websiteDataStore()->sessionID());
</span><span class="cx">         if (!process) {
</span><del>-            process = WebProcessProxy::create(*this, pageConfiguration->websiteDataStore(), WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Shared, WebProcessProxy::ShouldLaunchProcess::No);
</del><ins>+            process = WebProcessProxy::create(*this, pageConfiguration->websiteDataStore(), captivePortalMode, WebProcessProxy::IsPrewarmed::No, CrossOriginMode::Shared, WebProcessProxy::ShouldLaunchProcess::No);
</ins><span class="cx">             m_dummyProcessProxies.add(pageConfiguration->websiteDataStore()->sessionID(), *process);
</span><span class="cx">             m_processes.append(*process);
</span><span class="cx">         }
</span><span class="cx">     } else
</span><del>-        process = processForRegistrableDomain(*pageConfiguration->websiteDataStore(), nullptr, { });
</del><ins>+        process = processForRegistrableDomain(*pageConfiguration->websiteDataStore(), { }, captivePortalMode);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr<WebUserContentControllerProxy> userContentController = pageConfiguration->userContentController();
</span><span class="cx">     
</span><span class="lines">@@ -1804,9 +1813,9 @@
</span><span class="cx">         m_swappedProcessesPerRegistrableDomain.remove(registrableDomain);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-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)
</del><ins>+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)
</ins><span class="cx"> {
</span><del>-    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 {
</del><ins>+    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 {
</ins><span class="cx">         // We are process-swapping so automatic process prewarming would be beneficial if the client has not explicitly enabled / disabled it.
</span><span class="cx">         bool doingAnAutomaticProcessSwap = processSwapRequestedByClient == ProcessSwapRequestedByClient::No && process.ptr() != sourceProcess.ptr();
</span><span class="cx">         if (doingAnAutomaticProcessSwap && !configuration().wasAutomaticProcessWarmingSetByClient() && !configuration().clientWouldBenefitFromAutomaticProcessPrewarming()) {
</span><span class="lines">@@ -1829,18 +1838,21 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-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)
</del><ins>+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)
</ins><span class="cx"> {
</span><span class="cx">     auto& targetURL = navigation.currentRequest().url();
</span><span class="cx">     auto targetRegistrableDomain = WebCore::RegistrableDomain { targetURL };
</span><span class="cx"> 
</span><del>-    auto createNewProcess = [this, protectedThis = Ref { *this }, page = Ref { page }, targetRegistrableDomain, dataStore] () -> Ref<WebProcessProxy> {
-        return processForRegistrableDomain(dataStore, page.ptr(), targetRegistrableDomain);
</del><ins>+    auto createNewProcess = [this, protectedThis = Ref { *this }, targetRegistrableDomain, dataStore, captivePortalMode] () -> Ref<WebProcessProxy> {
+        return processForRegistrableDomain(dataStore, targetRegistrableDomain, captivePortalMode);
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     if (usesSingleWebProcess())
</span><span class="cx">         return completionHandler(WTFMove(sourceProcess), nullptr, "Single WebProcess mode is enabled"_s);
</span><span class="cx"> 
</span><ins>+    if (sourceProcess->captivePortalMode() != captivePortalMode)
+        return completionHandler(createNewProcess(), nullptr, "Process swap due to captive portal mode change"_s);
+
</ins><span class="cx">     if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
</span><span class="cx">         return completionHandler(createNewProcess(), nullptr, "Process swap was requested by the client"_s);
</span><span class="cx"> 
</span><span class="lines">@@ -2108,4 +2120,11 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if !PLATFORM(IOS_FAMILY)
+bool captivePortalModeEnabledBySystem()
+{
+    return false;
+}
+#endif
+
</ins><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessPoolh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -119,6 +119,7 @@
</span><span class="cx"> int webProcessLatencyQOS();
</span><span class="cx"> int webProcessThroughputQOS();
</span><span class="cx"> #endif
</span><ins>+bool captivePortalModeEnabledBySystem();
</ins><span class="cx"> 
</span><span class="cx"> enum class CallDownloadDidStart : bool;
</span><span class="cx"> enum class ProcessSwapRequestedByClient : bool;
</span><span class="lines">@@ -303,7 +304,7 @@
</span><span class="cx"> 
</span><span class="cx">     void reportWebContentCPUTime(Seconds cpuTime, uint64_t activityState);
</span><span class="cx"> 
</span><del>-    Ref<WebProcessProxy> processForRegistrableDomain(WebsiteDataStore&, WebPageProxy*, const WebCore::RegistrableDomain&); // Will return an existing one if limit is met or due to caching.
</del><ins>+    Ref<WebProcessProxy> processForRegistrableDomain(WebsiteDataStore&, const WebCore::RegistrableDomain&, WebProcessProxy::CaptivePortalMode); // Will return an existing one if limit is met or due to caching.
</ins><span class="cx"> 
</span><span class="cx">     void prewarmProcess();
</span><span class="cx"> 
</span><span class="lines">@@ -438,7 +439,7 @@
</span><span class="cx">     bool hasForegroundWebProcesses() const { return m_foregroundWebProcessCounter.value(); }
</span><span class="cx">     bool hasBackgroundWebProcesses() const { return m_backgroundWebProcessCounter.value(); }
</span><span class="cx"> 
</span><del>-    void processForNavigation(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
</del><ins>+    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&)>&&);
</ins><span class="cx"> 
</span><span class="cx">     void didReachGoodTimeToPrewarm();
</span><span class="cx"> 
</span><span class="lines">@@ -507,7 +508,7 @@
</span><span class="cx">     static String containerTemporaryDirectory();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    Ref<WebProcessProxy> createNewWebProcess(WebsiteDataStore*, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared);
</del><ins>+    Ref<WebProcessProxy> createNewWebProcess(WebsiteDataStore*, WebProcessProxy::CaptivePortalMode, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void platformInitialize();
</span><span class="lines">@@ -515,9 +516,9 @@
</span><span class="cx">     void platformInitializeWebProcess(const WebProcessProxy&, WebProcessCreationParameters&);
</span><span class="cx">     void platformInvalidateContext();
</span><span class="cx"> 
</span><del>-    void processForNavigationInternal(WebPageProxy&, const API::Navigation&, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient, const FrameInfoData&, Ref<WebsiteDataStore>&&, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&&);
</del><ins>+    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&)>&&);
</ins><span class="cx"> 
</span><del>-    RefPtr<WebProcessProxy> tryTakePrewarmedProcess(WebsiteDataStore&);
</del><ins>+    RefPtr<WebProcessProxy> tryTakePrewarmedProcess(WebsiteDataStore&, WebProcessProxy::CaptivePortalMode);
</ins><span class="cx"> 
</span><span class="cx">     void initializeNewWebProcess(WebProcessProxy&, WebsiteDataStore*, WebProcessProxy::IsPrewarmed = WebProcessProxy::IsPrewarmed::No);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -164,9 +164,9 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, ShouldLaunchProcess shouldLaunchProcess)
</del><ins>+Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, CaptivePortalMode captivePortalMode, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, ShouldLaunchProcess shouldLaunchProcess)
</ins><span class="cx"> {
</span><del>-    auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed, crossOriginMode));
</del><ins>+    auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed, crossOriginMode, captivePortalMode));
</ins><span class="cx">     if (shouldLaunchProcess == ShouldLaunchProcess::Yes) {
</span><span class="cx">         if (liveProcessesLRU().size() >= s_maxProcessCount) {
</span><span class="cx">             for (auto& processPool : WebProcessPool::allProcessPools())
</span><span class="lines">@@ -184,7 +184,7 @@
</span><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="cx"> Ref<WebProcessProxy> WebProcessProxy::createForServiceWorkers(WebProcessPool& processPool, RegistrableDomain&& registrableDomain, WebsiteDataStore& websiteDataStore)
</span><span class="cx"> {
</span><del>-    auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared));
</del><ins>+    auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No, CrossOriginMode::Shared, CaptivePortalMode::Disabled));
</ins><span class="cx">     proxy->m_registrableDomain = WTFMove(registrableDomain);
</span><span class="cx">     proxy->enableServiceWorkers(processPool.userContentControllerIdentifierForServiceWorkers());
</span><span class="cx">     proxy->connect();
</span><span class="lines">@@ -220,7 +220,7 @@
</span><span class="cx"> };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode)
</del><ins>+WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, CrossOriginMode crossOriginMode, CaptivePortalMode captivePortalMode)
</ins><span class="cx">     : AuxiliaryProcessProxy(processPool.alwaysRunsAtBackgroundPriority())
</span><span class="cx">     , m_backgroundResponsivenessTimer(*this)
</span><span class="cx">     , m_processPool(processPool, isPrewarmed == IsPrewarmed::Yes ? IsWeak::Yes : IsWeak::No)
</span><span class="lines">@@ -237,6 +237,7 @@
</span><span class="cx">     , m_userMediaCaptureManagerProxy(makeUnique<UserMediaCaptureManagerProxy>(makeUniqueRef<UIProxyForCapture>(*this)))
</span><span class="cx"> #endif
</span><span class="cx">     , m_isPrewarmed(isPrewarmed == IsPrewarmed::Yes)
</span><ins>+    , m_captivePortalMode(captivePortalMode)
</ins><span class="cx">     , m_crossOriginMode(crossOriginMode)
</span><span class="cx">     , m_shutdownPreventingScopeCounter([this](RefCounterEvent event) { if (event == RefCounterEvent::Decrement) maybeShutDown(); })
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -134,8 +134,9 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     enum class ShouldLaunchProcess : bool { No, Yes };
</span><ins>+    enum class CaptivePortalMode : bool { Disabled, Enabled };
</ins><span class="cx"> 
</span><del>-    static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared, ShouldLaunchProcess = ShouldLaunchProcess::Yes);
</del><ins>+    static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore*, CaptivePortalMode, IsPrewarmed, WebCore::CrossOriginMode = WebCore::CrossOriginMode::Shared, ShouldLaunchProcess = ShouldLaunchProcess::Yes);
</ins><span class="cx">     static Ref<WebProcessProxy> createForServiceWorkers(WebProcessPool&, WebCore::RegistrableDomain&&, WebsiteDataStore&);
</span><span class="cx"> 
</span><span class="cx">     ~WebProcessProxy();
</span><span class="lines">@@ -427,9 +428,10 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     WebCore::CrossOriginMode crossOriginMode() const { return m_crossOriginMode; }
</span><ins>+    CaptivePortalMode captivePortalMode() const { return m_captivePortalMode; }
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><del>-    WebProcessProxy(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode);
</del><ins>+    WebProcessProxy(WebProcessPool&, WebsiteDataStore*, IsPrewarmed, WebCore::CrossOriginMode, CaptivePortalMode);
</ins><span class="cx"> 
</span><span class="cx">     // AuxiliaryProcessProxy
</span><span class="cx">     ASCIILiteral processName() const final { return "WebContent"_s; }
</span><span class="lines">@@ -440,16 +442,16 @@
</span><span class="cx">     void processWillShutDown(IPC::Connection&) override;
</span><span class="cx">     bool shouldSendPendingMessage(const PendingMessage&) final;
</span><span class="cx">     
</span><del>-    // ProcessLauncher::Client
-    void didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier) override;
-
</del><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">     void cacheMediaMIMETypesInternal(const Vector<String>&);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    // ProcessLauncher::Client
+    void didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier) override;
</ins><span class="cx">     bool shouldConfigureJSCForTesting() const final;
</span><span class="cx">     bool isJITEnabled() const final;
</span><span class="cx">     bool shouldEnableSharedArrayBuffer() const final { return m_crossOriginMode == WebCore::CrossOriginMode::Isolated; }
</span><ins>+    bool shouldEnableCaptivePortalMode() const final { return m_captivePortalMode == CaptivePortalMode::Enabled; }
</ins><span class="cx"> 
</span><span class="cx">     void validateFreezerStatus();
</span><span class="cx"> 
</span><span class="lines">@@ -622,6 +624,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool m_hasCommittedAnyProvisionalLoads { false };
</span><span class="cx">     bool m_isPrewarmed;
</span><ins>+    CaptivePortalMode m_captivePortalMode { CaptivePortalMode::Disabled };
</ins><span class="cx">     WebCore::CrossOriginMode m_crossOriginMode { WebCore::CrossOriginMode::Shared };
</span><span class="cx"> #if ENABLE(ATTACHMENT_ELEMENT)
</span><span class="cx">     bool m_hasIssuedAttachmentElementRelatedSandboxExtensions { false };
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2021-11-10 19:04:38 UTC (rev 285593)
+++ trunk/Tools/ChangeLog       2021-11-10 19:14:25 UTC (rev 285594)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2021-11-10  Chris Dumez  <cdumez@apple.com>
+
+        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:
+
</ins><span class="cx"> 2021-11-10  Tyler Wilcock  <tyler_w@apple.com>
</span><span class="cx"> 
</span><span class="cx">         AX: Make ancestor computation cheaper by setting flags upon child insertion
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIConfigurationsTestWebKitAPIiOSentitlements"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI-iOS.entitlements (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -10,5 +10,7 @@
</span><span class="cx">  <true/>
</span><span class="cx">  <key>com.apple.Pasteboard.paste-unchecked</key>
</span><span class="cx">  <true/>
</span><ins>+       <key>com.apple.developer.web-browser</key>
+       <true/>
</ins><span class="cx"> </dict>
</span><span class="cx"> </plist>
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaProcessSwapOnNavigationmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (285593 => 285594)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -7624,3 +7624,123 @@
</span><span class="cx"> {
</span><span class="cx">     runCOOPProcessSwapTest("same-origin-allow-popup", "unsafe-none", "unsafe-none", "unsafe-none", IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No);
</span><span class="cx"> }
</span><ins>+
+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 = [[NSBundle 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 = [[NSBundle 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 = [[NSBundle 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 = [[NSBundle 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 = [[NSBundle 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 = [[NSBundle 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]);
+}
</ins></span></pre>
</div>
</div>

</body>
</html>