Fail navigations to non app-bound domains after use of app-bound APIs
authorkatherine_cheney@apple.com <katherine_cheney@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 May 2020 23:59:40 +0000 (23:59 +0000)
committerkatherine_cheney@apple.com <katherine_cheney@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 May 2020 23:59:40 +0000 (23:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=211647
<rdar://problem/62978159>

Reviewed by Brent Fulgham.

Source/WebCore:

Simplified in-app browser privacy protections check into one, better
named function.

* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::executeScriptInWorld):
* loader/FrameLoaderClient.h:
* page/Frame.cpp:
(WebCore::Frame::injectUserScriptImmediately):
* page/Page.cpp:
(WebCore::Page::injectUserStyleSheet):
* page/WebKitNamespace.cpp:
(WebCore::WebKitNamespace::messageHandlers):
* style/StyleScopeRuleSets.cpp:
(WebCore::Style::ScopeRuleSets::initializeUserStyle):
Rearranged ordering so the message to WebPageProxy only gets sent to
indicate app-bound behavior if user style sheets actually exist.

Source/WebKit:

A lot of this patch is deleting the unnecessary variable/function
hasNavigatedAwayFromAppBoundDomain now that navigating away from an
app-bound domain is not possible.

To address the bug, this sets the default isNavigatingToAppBoundDomain
value to be WTF::nullopt. This will allow app-bound behaviors until
a navigation has been attempted, in which case it will fail or will
update isNavigatingToAppBoundDomain to the correct value.

* Shared/LoadParameters.cpp:
(WebKit::LoadParameters::encode const):
(WebKit::LoadParameters::decode):
* Shared/LoadParameters.h:
* Shared/PolicyDecision.h:
(WebKit::PolicyDecision::encode const):
(WebKit::PolicyDecision::decode):
* UIProcess/ProvisionalPageProxy.cpp:
(WebKit::ProvisionalPageProxy::loadData):
(WebKit::ProvisionalPageProxy::loadRequest):
(WebKit::ProvisionalPageProxy::decidePolicyForNavigationActionSync):
* UIProcess/ProvisionalPageProxy.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::loadRequest):
(WebKit::WebPageProxy::loadRequestWithNavigationShared):
(WebKit::WebPageProxy::loadData):
(WebKit::WebPageProxy::loadDataWithNavigationShared):
(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::continueNavigationInNewProcess):
(WebKit::WebPageProxy::decidePolicyForNavigationActionSyncShared):
(WebKit::WebPageProxy::hasNavigatedAwayFromAppBoundDomain const): Deleted.
Remove hasNavigatedAwayFromAppBoundDomain.

(WebKit::WebPageProxy::setIsNavigatingToAppBoundDomainAndCheckIfPermitted):
Check for new m_hasExecutedAppBoundBehaviorBeforeNavigation parameter
and fail the navigation if a WebView has used app-bound behavior then
tries to navigate to a non app-bound domain.

(WebKit::WebPageProxy::decidePolicyForNavigationAction):
Update error message to be more general now that more than one error
can occur.

* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::setHasExecutedAppBoundBehaviorBeforeNavigation):
* UIProcess/WebPageProxy.messages.in:
New parameter to indicate a WebView has used app-bound APIs before
navigating.

* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForResponse):
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
(WebKit::WebFrameLoaderClient::shouldEnableInAppBrowserPrivacyProtections):
(WebKit::WebFrameLoaderClient::hasNavigatedAwayFromAppBoundDomain): Deleted.
(WebKit::WebFrameLoaderClient::needsInAppBrowserPrivacyQuirks const): Deleted.
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
Combined two functions into a simpler function:
shouldEnableInAppBrowserPrivacyProtections().

* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_limitsNavigationsToAppBoundDomains):
(WebKit::WebPage::updatePreferences):
Store the special app-bound domain flag to gate the service worker
API. This should be stored separately from
m_isNavigatingToAppBoundDomain, because in the WebPage constructor we
don't yet know whether the WKAppBoundDomains key exists.

(WebKit::WebPage::loadRequest):
(WebKit::WebPage::loadDataImpl):
(WebKit::WebPage::loadData):
(WebKit::WebPage::loadAlternateHTML):
(WebKit::WebPage::didReceivePolicyDecision):
Remove hasNavigatedAwayFromAppBoundDomain.

(WebKit::WebPage::runJavaScript):
(WebKit::WebPage::setIsNavigatingToAppBoundDomain):
(WebKit::WebPage::shouldEnableInAppBrowserPrivacyProtections):
If m_needsInAppBrowserPrivacyQuirks are on for testing, don't enable
protections. Only notify the WebPageProxy of app-bound behavior if
a navigation has not occured and we know the webView is not app-bound
(in order to limit IPC).

(WebKit::m_isNavigatingToAppBoundDomain): Deleted.
* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::isNavigatingToAppBoundDomain const):
(WebKit::WebPage::setIsNavigatingToAppBoundDomain): Deleted.
(WebKit::WebPage::hasNavigatedAwayFromAppBoundDomain const): Deleted.
(WebKit::WebPage::setHasNavigatedAwayFromAppBoundDomain): Deleted.
(WebKit::WebPage::needsInAppBrowserPrivacyQuirks const): Deleted.

Tools:

Added a new test to confirm a non-app bound navigation fails after
using script injection.

This fix also required changing any test which uses a restricted API
to confirm behavior of another restricted API. Tests can set
_setNeedsInAppBrowserPrivacyQuirks in the configuration to indicate
APIs should not be blocked, then toggle it to test actual behavior.

Also, we can remove any calls to _setInAppBrowserPrivacyEnabled
now that this is just an internal test flag.

* TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
(-[AppBoundDomainDelegate webView:didFinishNavigation:]):
(-[AppBoundDomainDelegate webView:didFailProvisionalNavigation:withError:]):
(-[AppBoundDomainDelegate waitForDidFinishNavigation]):
(-[AppBoundDomainDelegate waitForDidFailProvisionalNavigationError]):
(TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261506 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/ScriptController.cpp
Source/WebCore/loader/FrameLoaderClient.h
Source/WebCore/page/Frame.cpp
Source/WebCore/page/Page.cpp
Source/WebCore/page/WebKitNamespace.cpp
Source/WebCore/style/StyleScopeRuleSets.cpp
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
Source/WebKit/Shared/LoadParameters.cpp
Source/WebKit/Shared/LoadParameters.h
Source/WebKit/Shared/PolicyDecision.h
Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
Source/WebKit/UIProcess/ProvisionalPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm

index 2291753..bd0e614 100644 (file)
@@ -1,3 +1,28 @@
+2020-05-11  Kate Cheney  <katherine_cheney@apple.com>
+
+        Fail navigations to non app-bound domains after use of app-bound APIs
+        https://bugs.webkit.org/show_bug.cgi?id=211647
+        <rdar://problem/62978159>
+
+        Reviewed by Brent Fulgham.
+
+        Simplified in-app browser privacy protections check into one, better
+        named function.
+
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::executeScriptInWorld):
+        * loader/FrameLoaderClient.h:
+        * page/Frame.cpp:
+        (WebCore::Frame::injectUserScriptImmediately):
+        * page/Page.cpp:
+        (WebCore::Page::injectUserStyleSheet):
+        * page/WebKitNamespace.cpp:
+        (WebCore::WebKitNamespace::messageHandlers):
+        * style/StyleScopeRuleSets.cpp:
+        (WebCore::Style::ScopeRuleSets::initializeUserStyle):
+        Rearranged ordering so the message to WebPageProxy only gets sent to
+        indicate app-bound behavior if user style sheets actually exist.
+
 2020-05-11  Peng Liu  <peng.liu6@apple.com>
 
         Enable the mock video presentation mode in related layout tests and fix test failures
index ae2885c..372fbbc 100644 (file)
@@ -579,12 +579,13 @@ JSC::JSValue ScriptController::executeScriptInWorldIgnoringException(DOMWrapperW
 
 ValueOrException ScriptController::executeScriptInWorld(DOMWrapperWorld& world, RunJavaScriptParameters&& parameters)
 {
-    if (m_frame.loader().client().hasNavigatedAwayFromAppBoundDomain() && !m_frame.loader().client().needsInAppBrowserPrivacyQuirks()) {
+    if (m_frame.loader().client().shouldEnableInAppBrowserPrivacyProtections()) {
         if (auto* document = m_frame.document())
             document->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, "Ignoring user script injection for non-app bound domain.");
         RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "executeScriptInWorld: Ignoring user script injection for non app-bound domain");
         return makeUnexpected(ExceptionDetails { "Ignoring user script injection for non-app bound domain"_s });
     }
+    m_frame.loader().client().notifyPageOfAppBoundBehavior();
 
     UserGestureIndicator gestureIndicator(parameters.forceUserGesture == ForceUserGesture::Yes ? Optional<ProcessingUserGestureState>(ProcessingUserGesture) : WTF::nullopt);
 
index 1e5425e..9231b45 100644 (file)
@@ -379,8 +379,8 @@ public:
 
     virtual AllowsContentJavaScript allowsContentJavaScriptFromMostRecentNavigation() const { return AllowsContentJavaScript::Yes; }
 
-    virtual bool hasNavigatedAwayFromAppBoundDomain() { return false; }
-    virtual bool needsInAppBrowserPrivacyQuirks() const { return false; }
+    virtual bool shouldEnableInAppBrowserPrivacyProtections() const { return false; }
+    virtual void notifyPageOfAppBoundBehavior() { }
 };
 
 } // namespace WebCore
index 76066f5..540f456 100644 (file)
@@ -651,12 +651,13 @@ void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
 
 void Frame::injectUserScriptImmediately(DOMWrapperWorld& world, const UserScript& script)
 {
-    if (loader().client().hasNavigatedAwayFromAppBoundDomain() && !loader().client().needsInAppBrowserPrivacyQuirks()) {
+    if (loader().client().shouldEnableInAppBrowserPrivacyProtections()) {
         if (auto* document = this->document())
             document->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, "Ignoring user script injection for non-app bound domain."_s);
         RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "injectUserScriptImmediately: Ignoring user script injection for non app-bound domain");
         return;
     }
+    loader().client().notifyPageOfAppBoundBehavior();
 
     auto* document = this->document();
     if (!document)
index 06818c8..ec24d07 100644 (file)
@@ -3162,11 +3162,12 @@ void Page::revealCurrentSelection()
 
 void Page::injectUserStyleSheet(UserStyleSheet& userStyleSheet)
 {
-    if (m_mainFrame->loader().client().hasNavigatedAwayFromAppBoundDomain()) {
+    if (m_mainFrame->loader().client().shouldEnableInAppBrowserPrivacyProtections()) {
         if (auto* document = m_mainFrame->document())
             document->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, "Ignoring user style sheet for non-app bound domain."_s);
         return;
     }
+    m_mainFrame->loader().client().notifyPageOfAppBoundBehavior();
 
     // We need to wait until we're no longer displaying the initial empty document before we can inject the stylesheets.
     if (m_mainFrame->loader().stateMachine().isDisplayingInitialEmptyDocument()) {
index ac1247c..018dc65 100644 (file)
@@ -50,9 +50,12 @@ WebKitNamespace::~WebKitNamespace() = default;
 
 UserMessageHandlersNamespace* WebKitNamespace::messageHandlers()
 {
-    if (frame() && frame()->loader().client().hasNavigatedAwayFromAppBoundDomain()) {
-        RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "Ignoring messageHandlers() request for non app-bound domain");
-        return nullptr;
+    if (frame()) {
+        if (frame()->loader().client().shouldEnableInAppBrowserPrivacyProtections()) {
+            RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "Ignoring messageHandlers() request for non app-bound domain");
+            return nullptr;
+        }
+        frame()->loader().client().notifyPageOfAppBoundBehavior();
     }
 
     return &m_messageHandlerNamespace.get();
index 295df40..06ec7e9 100644 (file)
@@ -92,10 +92,13 @@ void ScopeRuleSets::initializeUserStyle()
     if (CSSStyleSheet* pageUserSheet = extensionStyleSheets.pageUserSheet())
         tempUserStyle->addRulesFromSheet(pageUserSheet->contents(), nullptr, mediaQueryEvaluator, m_styleResolver);
     auto* page = m_styleResolver.document().page();
-    if (page && page->mainFrame().loader().client().hasNavigatedAwayFromAppBoundDomain() && !extensionStyleSheets.injectedUserStyleSheets().isEmpty())
+    if (!extensionStyleSheets.injectedUserStyleSheets().isEmpty() && page && page->mainFrame().loader().client().shouldEnableInAppBrowserPrivacyProtections())
         m_styleResolver.document().addConsoleMessage(MessageSource::Security, MessageLevel::Warning, "Ignoring user style sheet for non-app bound domain."_s);
-    else
+    else {
         collectRulesFromUserStyleSheets(extensionStyleSheets.injectedUserStyleSheets(), tempUserStyle.get(), mediaQueryEvaluator);
+        if (page && !extensionStyleSheets.injectedUserStyleSheets().isEmpty())
+            page->mainFrame().loader().client().notifyPageOfAppBoundBehavior();
+    }
     collectRulesFromUserStyleSheets(extensionStyleSheets.documentUserStyleSheets(), tempUserStyle.get(), mediaQueryEvaluator);
     if (tempUserStyle->ruleCount() > 0 || tempUserStyle->pageRules().size() > 0)
         m_userStyle = WTFMove(tempUserStyle);
index c0b995c..d0a999d 100644 (file)
@@ -1,3 +1,100 @@
+2020-05-11  Kate Cheney  <katherine_cheney@apple.com>
+
+        Fail navigations to non app-bound domains after use of app-bound APIs
+        https://bugs.webkit.org/show_bug.cgi?id=211647
+        <rdar://problem/62978159>
+
+        Reviewed by Brent Fulgham.
+
+        A lot of this patch is deleting the unnecessary variable/function
+        hasNavigatedAwayFromAppBoundDomain now that navigating away from an
+        app-bound domain is not possible.
+        
+        To address the bug, this sets the default isNavigatingToAppBoundDomain
+        value to be WTF::nullopt. This will allow app-bound behaviors until
+        a navigation has been attempted, in which case it will fail or will
+        update isNavigatingToAppBoundDomain to the correct value.
+
+
+        * Shared/LoadParameters.cpp:
+        (WebKit::LoadParameters::encode const):
+        (WebKit::LoadParameters::decode):
+        * Shared/LoadParameters.h:
+        * Shared/PolicyDecision.h:
+        (WebKit::PolicyDecision::encode const):
+        (WebKit::PolicyDecision::decode):
+        * UIProcess/ProvisionalPageProxy.cpp:
+        (WebKit::ProvisionalPageProxy::loadData):
+        (WebKit::ProvisionalPageProxy::loadRequest):
+        (WebKit::ProvisionalPageProxy::decidePolicyForNavigationActionSync):
+        * UIProcess/ProvisionalPageProxy.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::loadRequest):
+        (WebKit::WebPageProxy::loadRequestWithNavigationShared):
+        (WebKit::WebPageProxy::loadData):
+        (WebKit::WebPageProxy::loadDataWithNavigationShared):
+        (WebKit::WebPageProxy::receivedPolicyDecision):
+        (WebKit::WebPageProxy::continueNavigationInNewProcess):
+        (WebKit::WebPageProxy::decidePolicyForNavigationActionSyncShared):
+        (WebKit::WebPageProxy::hasNavigatedAwayFromAppBoundDomain const): Deleted.
+        Remove hasNavigatedAwayFromAppBoundDomain.
+
+        (WebKit::WebPageProxy::setIsNavigatingToAppBoundDomainAndCheckIfPermitted):
+        Check for new m_hasExecutedAppBoundBehaviorBeforeNavigation parameter
+        and fail the navigation if a WebView has used app-bound behavior then
+        tries to navigate to a non app-bound domain.
+
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        Update error message to be more general now that more than one error
+        can occur.
+
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::setHasExecutedAppBoundBehaviorBeforeNavigation):
+        * UIProcess/WebPageProxy.messages.in:
+        New parameter to indicate a WebView has used app-bound APIs before
+        navigating.
+
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForResponse):
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+        (WebKit::WebFrameLoaderClient::shouldEnableInAppBrowserPrivacyProtections):
+        (WebKit::WebFrameLoaderClient::hasNavigatedAwayFromAppBoundDomain): Deleted.
+        (WebKit::WebFrameLoaderClient::needsInAppBrowserPrivacyQuirks const): Deleted.
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
+        Combined two functions into a simpler function:
+        shouldEnableInAppBrowserPrivacyProtections().
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_limitsNavigationsToAppBoundDomains):
+        (WebKit::WebPage::updatePreferences):
+        Store the special app-bound domain flag to gate the service worker
+        API. This should be stored separately from
+        m_isNavigatingToAppBoundDomain, because in the WebPage constructor we
+        don't yet know whether the WKAppBoundDomains key exists.
+
+        (WebKit::WebPage::loadRequest):
+        (WebKit::WebPage::loadDataImpl):
+        (WebKit::WebPage::loadData):
+        (WebKit::WebPage::loadAlternateHTML):
+        (WebKit::WebPage::didReceivePolicyDecision):
+        Remove hasNavigatedAwayFromAppBoundDomain.
+
+        (WebKit::WebPage::runJavaScript):
+        (WebKit::WebPage::setIsNavigatingToAppBoundDomain):
+        (WebKit::WebPage::shouldEnableInAppBrowserPrivacyProtections):
+        If m_needsInAppBrowserPrivacyQuirks are on for testing, don't enable
+        protections. Only notify the WebPageProxy of app-bound behavior if
+        a navigation has not occured and we know the webView is not app-bound
+        (in order to limit IPC).
+
+        (WebKit::m_isNavigatingToAppBoundDomain): Deleted.
+        * WebProcess/WebPage/WebPage.h:
+        (WebKit::WebPage::isNavigatingToAppBoundDomain const):
+        (WebKit::WebPage::setIsNavigatingToAppBoundDomain): Deleted.
+        (WebKit::WebPage::hasNavigatedAwayFromAppBoundDomain const): Deleted.
+        (WebKit::WebPage::setHasNavigatedAwayFromAppBoundDomain): Deleted.
+        (WebKit::WebPage::needsInAppBrowserPrivacyQuirks const): Deleted.
+
 2020-05-11  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Remove some unnecessary indirection when getting Document’s Editor
index 61f10cc..0ebac05 100644 (file)
@@ -62,6 +62,7 @@
 #import <WebKitAdditions/NetworkSessionCocoaAdditions.h>
 #else
 #define NETWORK_SESSION_COCOA_ADDITIONS_1
+#define NETWORK_SESSION_COCOA_ADDITIONS_2 true
 #endif
 
 #import "DeviceManagementSoftLink.h"
@@ -1260,6 +1261,8 @@ void NetworkSessionCocoa::initializeEphemeralStatelessSession(NavigatingToAppBou
 SessionWrapper& NetworkSessionCocoa::sessionWrapperForTask(const WebCore::ResourceRequest& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
 {
     auto shouldBeConsideredAppBound = isNavigatingToAppBoundDomain ? *isNavigatingToAppBoundDomain : NavigatingToAppBoundDomain::Yes;
+    if (NETWORK_SESSION_COCOA_ADDITIONS_2)
+        shouldBeConsideredAppBound = NavigatingToAppBoundDomain::No;
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     if (auto* storageSession = networkStorageSession()) {
         auto firstParty = WebCore::RegistrableDomain(request.firstPartyForCookies());
index 6e5699a..28968ed 100644 (file)
@@ -57,7 +57,6 @@ void LoadParameters::encode(IPC::Encoder& encoder) const
     encoder.encodeEnum(lockBackForwardList);
     encoder << clientRedirectSourceForHistory;
     encoder << isNavigatingToAppBoundDomain;
-    encoder << hasNavigatedAwayFromAppBoundDomain;
 
     platformEncode(encoder);
 }
@@ -138,9 +137,6 @@ bool LoadParameters::decode(IPC::Decoder& decoder, LoadParameters& data)
     if (!decoder.decode(data.isNavigatingToAppBoundDomain))
         return false;
     
-    if (!decoder.decode(data.hasNavigatedAwayFromAppBoundDomain))
-        return false;
-    
     if (!platformDecode(decoder, data))
         return false;
 
index a7a49d0..4710d32 100644 (file)
@@ -70,8 +70,7 @@ struct LoadParameters {
     WebCore::LockHistory lockHistory { WebCore::LockHistory::No };
     WebCore::LockBackForwardList lockBackForwardList { WebCore::LockBackForwardList::No };
     String clientRedirectSourceForHistory;
-    Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain { NavigatingToAppBoundDomain::No };
-    NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain { NavigatedAwayFromAppBoundDomain::No };
+    Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain;
 
 #if PLATFORM(COCOA)
     RetainPtr<NSDictionary> dataDetectionContext;
index 445e32b..82911b6 100644 (file)
 
 namespace WebKit {
 
-enum class NavigatedAwayFromAppBoundDomain : bool { Yes, No};
-
 struct PolicyDecision {
     WebCore::PolicyCheckIdentifier identifier { };
-    Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain { NavigatingToAppBoundDomain::No };
-    NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain { NavigatedAwayFromAppBoundDomain::No };
+    Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain { WTF::nullopt };
     WebCore::PolicyAction policyAction { WebCore::PolicyAction::Ignore };
     uint64_t navigationID { 0 };
     DownloadID downloadID { 0 };
@@ -50,7 +47,6 @@ struct PolicyDecision {
     {
         encoder << identifier;
         encoder << isNavigatingToAppBoundDomain;
-        encoder << hasNavigatedAwayFromAppBoundDomain;
         encoder << policyAction;
         encoder << navigationID;
         encoder << downloadID;
@@ -70,11 +66,6 @@ struct PolicyDecision {
         decoder >> decodedIsNavigatingToAppBoundDomain;
         if (!decodedIsNavigatingToAppBoundDomain)
             return WTF::nullopt;
-        
-        Optional<NavigatedAwayFromAppBoundDomain> decodedHasNavigatedAwayFromAppBoundDomain;
-        decoder >> decodedHasNavigatedAwayFromAppBoundDomain;
-        if (!decodedHasNavigatedAwayFromAppBoundDomain)
-            return WTF::nullopt;
 
         Optional<WebCore::PolicyAction> decodedPolicyAction;
         decoder >> decodedPolicyAction;
@@ -101,7 +92,7 @@ struct PolicyDecision {
         if (!sandboxExtensionHandle)
             return WTF::nullopt;
 
-        return {{ WTFMove(*decodedIdentifier), WTFMove(*decodedIsNavigatingToAppBoundDomain), WTFMove(*decodedHasNavigatedAwayFromAppBoundDomain), WTFMove(*decodedPolicyAction), WTFMove(*decodedNavigationID), WTFMove(*decodedDownloadID), WTFMove(*decodedWebsitePoliciesData), WTFMove(*sandboxExtensionHandle)}};
+        return {{ WTFMove(*decodedIdentifier), WTFMove(*decodedIsNavigatingToAppBoundDomain), WTFMove(*decodedPolicyAction), WTFMove(*decodedNavigationID), WTFMove(*decodedDownloadID), WTFMove(*decodedWebsitePoliciesData), WTFMove(*sandboxExtensionHandle)}};
     }
 };
 
index 3ef727a..ad48bcd 100644 (file)
@@ -156,14 +156,14 @@ void ProvisionalPageProxy::initializeWebPage(RefPtr<API::WebsitePolicies>&& webs
         send(Messages::WebPage::FreezeLayerTreeDueToSwipeAnimation());
 }
 
-void ProvisionalPageProxy::loadData(API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
+void ProvisionalPageProxy::loadData(API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
 {
     RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "loadData: pageProxyID=%" PRIu64 " webPageID=%" PRIu64, m_page.identifier().toUInt64(), m_webPageID.toUInt64());
 
-    m_page.loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, isNavigatingToAppBoundDomain, hasNavigatedAwayFromAppBoundDomain, WTFMove(websitePolicies), navigation.lastNavigationAction().shouldOpenExternalURLsPolicy);
+    m_page.loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, isNavigatingToAppBoundDomain, WTFMove(websitePolicies), navigation.lastNavigationAction().shouldOpenExternalURLsPolicy);
 }
 
-void ProvisionalPageProxy::loadRequest(API::Navigation& navigation, WebCore::ResourceRequest&& request, API::Object* userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
+void ProvisionalPageProxy::loadRequest(API::Navigation& navigation, WebCore::ResourceRequest&& request, API::Object* userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
 {
     RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "loadRequest: pageProxyID=%" PRIu64 " webPageID=%" PRIu64, m_page.identifier().toUInt64(), m_webPageID.toUInt64());
 
@@ -173,7 +173,7 @@ void ProvisionalPageProxy::loadRequest(API::Navigation& navigation, WebCore::Res
     if (navigation.fromItem() && navigation.lockBackForwardList() == WebCore::LockBackForwardList::Yes)
         navigation.fromItem()->setLastProcessIdentifier(m_process->coreProcessIdentifier());
 
-    m_page.loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, WTFMove(request), navigation.lastNavigationAction().shouldOpenExternalURLsPolicy, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, isNavigatingToAppBoundDomain, hasNavigatedAwayFromAppBoundDomain, WTFMove(websitePolicies));
+    m_page.loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, WTFMove(request), navigation.lastNavigationAction().shouldOpenExternalURLsPolicy, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, isNavigatingToAppBoundDomain, WTFMove(websitePolicies));
 }
 
 void ProvisionalPageProxy::goToBackForwardItem(API::Navigation& navigation, WebBackForwardListItem& item, RefPtr<API::WebsitePolicies>&& websitePolicies)
@@ -357,7 +357,7 @@ void ProvisionalPageProxy::decidePolicyForNavigationActionSync(FrameIdentifier f
     const UserData& userData, Messages::WebPageProxy::DecidePolicyForNavigationActionSync::DelayedReply&& reply)
 {
     if (!isMainFrame || (m_mainFrame && m_mainFrame->frameID() != frameID) || navigationID != m_navigationID) {
-        reply(PolicyDecision { identifier, NavigatingToAppBoundDomain::No, NavigatedAwayFromAppBoundDomain::No, WebCore::PolicyAction::Ignore, navigationID, DownloadID(), WTF::nullopt });
+        reply(PolicyDecision { identifier, WTF::nullopt, WebCore::PolicyAction::Ignore, navigationID, DownloadID(), WTF::nullopt });
         return;
     }
 
index 44bfcbb..9d72131 100644 (file)
@@ -92,8 +92,8 @@ public:
     LayerHostingContextID contextIDForVisibilityPropagation() const { return m_contextIDForVisibilityPropagation; }
 #endif
 
-    void loadData(API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<NavigatingToAppBoundDomain>, NavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& = WTF::nullopt);
-    void loadRequest(API::Navigation&, WebCore::ResourceRequest&&, API::Object* userData, Optional<NavigatingToAppBoundDomain>, NavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& = WTF::nullopt);
+    void loadData(API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<NavigatingToAppBoundDomain>, Optional<WebsitePoliciesData>&& = WTF::nullopt);
+    void loadRequest(API::Navigation&, WebCore::ResourceRequest&&, API::Object* userData, Optional<NavigatingToAppBoundDomain>, Optional<WebsitePoliciesData>&& = WTF::nullopt);
     void goToBackForwardItem(API::Navigation&, WebBackForwardListItem&, RefPtr<API::WebsitePolicies>&&);
     void cancel();
 
index 4cf8099..680c55c 100644 (file)
@@ -1281,11 +1281,11 @@ RefPtr<API::Navigation> WebPageProxy::loadRequest(ResourceRequest&& request, Sho
     if (shouldForceForegroundPriorityForClientNavigation())
         navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
 
-    loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain());
+    loadRequestWithNavigationShared(m_process.copyRef(), m_webPageID, navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain());
     return navigation;
 }
 
-void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
+void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies)
 {
     ASSERT(!m_isClosed);
 
@@ -1308,7 +1308,6 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces
     loadParameters.lockBackForwardList = navigation.lockBackForwardList();
     loadParameters.clientRedirectSourceForHistory = navigation.clientRedirectSourceForHistory();
     loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
-    loadParameters.hasNavigatedAwayFromAppBoundDomain = hasNavigatedAwayFromAppBoundDomain;
     maybeInitializeSandboxExtensionHandle(process, url, m_pageLoadState.resourceDirectoryURL(), loadParameters.sandboxExtensionHandle);
 
     addPlatformLoadParameters(loadParameters);
@@ -1405,11 +1404,11 @@ RefPtr<API::Navigation> WebPageProxy::loadData(const IPC::DataReference& data, c
     if (shouldForceForegroundPriorityForClientNavigation())
         navigation->setClientNavigationActivity(process().throttler().foregroundActivity("Client navigation"_s));
 
-    loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTF::nullopt, shouldOpenExternalURLsPolicy);
+    loadDataWithNavigationShared(m_process.copyRef(), m_webPageID, navigation, data, MIMEType, encoding, baseURL, userData, ShouldTreatAsContinuingLoad::No, isNavigatingToAppBoundDomain(), WTF::nullopt, shouldOpenExternalURLsPolicy);
     return navigation;
 }
 
-void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process, WebCore::PageIdentifier webPageID, API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, ShouldTreatAsContinuingLoad shouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, Optional<WebsitePoliciesData>&& websitePolicies, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
 {
     RELEASE_LOG_IF_ALLOWED(Loading, "loadDataWithNavigation");
 
@@ -1430,7 +1429,6 @@ void WebPageProxy::loadDataWithNavigationShared(Ref<WebProcessProxy>&& process,
     loadParameters.websitePolicies = WTFMove(websitePolicies);
     loadParameters.shouldOpenExternalURLsPolicy = shouldOpenExternalURLsPolicy;
     loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
-    loadParameters.hasNavigatedAwayFromAppBoundDomain = hasNavigatedAwayFromAppBoundDomain;
     addPlatformLoadParameters(loadParameters);
 
     process->assumeReadAccessToBaseURL(*this, baseURL);
@@ -3131,9 +3129,10 @@ bool WebPageProxy::setIsNavigatingToAppBoundDomainAndCheckIfPermitted(bool isMai
             m_configuration->setWebViewCategory(WebViewCategory::AppBoundDomain);
             m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::Yes;
         } else {
+            if (m_hasExecutedAppBoundBehaviorBeforeNavigation)
+                return false;
             m_configuration->setWebViewCategory(WebViewCategory::InAppBrowser);
             m_isNavigatingToAppBoundDomain = NavigatingToAppBoundDomain::No;
-            m_hasNavigatedAwayFromAppBoundDomain = NavigatedAwayFromAppBoundDomain::Yes;
         }
     }
 #else
@@ -3275,7 +3274,7 @@ void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, A
 void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr<API::WebsitePolicies>&& websitePolicies, Ref<PolicyDecisionSender>&& sender, Optional<SandboxExtension::Handle> sandboxExtensionHandle, WillContinueLoadInNewProcess willContinueLoadInNewProcess)
 {
     if (!hasRunningProcess()) {
-        sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt });
+        sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt });
         return;
     }
 
@@ -3302,7 +3301,7 @@ void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation*
     if (websitePolicies)
         websitePoliciesData = websitePolicies->data();
 
-    sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePoliciesData), WTFMove(sandboxExtensionHandle) });
+    sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePoliciesData), WTFMove(sandboxExtensionHandle) });
 }
 
 void WebPageProxy::commitProvisionalPage(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool usedLegacyTLS, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData& userData)
@@ -3383,9 +3382,9 @@ void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, s
         // FIXME: Work out timing of responding with the last policy delegate, etc
         ASSERT(!navigation->currentRequest().isEmpty());
         if (auto& substituteData = navigation->substituteData())
-            m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTFMove(websitePoliciesData));
+            m_provisionalPage->loadData(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData));
         else
-            m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, nullptr, isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), WTFMove(websitePoliciesData));
+            m_provisionalPage->loadRequest(navigation, ResourceRequest { navigation->currentRequest() }, nullptr, isNavigatingToAppBoundDomain(), WTFMove(websitePoliciesData));
     };
     if (m_inspectorController->shouldPauseLoading(*m_provisionalPage))
         m_inspectorController->setContinueLoadingCallback(*m_provisionalPage, WTFMove(continuation));
@@ -5107,7 +5106,7 @@ void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& proces
 
     if (!checkURLReceivedFromCurrentOrPreviousWebProcess(process, request.url())) {
         RELEASE_LOG_ERROR_IF_ALLOWED(Process, "Ignoring request to load this main resource because it is outside the sandbox");
-        sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt });
+        sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt });
         return;
     }
 
@@ -5181,9 +5180,9 @@ void WebPageProxy::decidePolicyForNavigationAction(Ref<WebProcessProxy>&& proces
         
         if (policyAction != PolicyAction::Ignore) {
             if (!setIsNavigatingToAppBoundDomainAndCheckIfPermitted(frame->isMainFrame(), navigation->currentRequest().url(), isAppBoundDomain)) {
-                auto error = ResourceError { String { }, 0, navigation->currentRequest().url(), "Attempted navigation away from app-bound domain"_s };
+                auto error = ResourceError { String { }, 0, navigation->currentRequest().url(), "App-bound domain failure"_s };
                 m_navigationClient->didFailProvisionalNavigationWithError(*this, FrameInfoData { frameInfo }, navigation.get(), error, userDataObject);
-                RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "Ignoring request to load this main resource because it is attempting to navigate away from an app-bound domain");
+                RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "Ignoring request to load this main resource because it is attempting to navigate away from an app-bound domain or navigate after using restricted APIs");
                 completionHandler(PolicyAction::Ignore);
                 return;
             }
@@ -5355,7 +5354,7 @@ void WebPageProxy::decidePolicyForNavigationActionSyncShared(Ref<WebProcessProxy
     decidePolicyForNavigationAction(WTFMove(process), *frame, WTFMove(frameInfo), navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, sender.copyRef());
 
     // If the client did not respond synchronously, proceed with the load.
-    sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), PolicyAction::Use, navigationID, DownloadID(), WTF::nullopt });
+    sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Use, navigationID, DownloadID(), WTF::nullopt });
 }
 
 void WebPageProxy::decidePolicyForNewWindowAction(FrameIdentifier frameID, FrameInfoData&& frameInfo, PolicyCheckIdentifier identifier, NavigationActionData&& navigationActionData, ResourceRequest&& request, const String& frameName, uint64_t listenerID, const UserData& userData)
index 0178781..6a90d35 100644 (file)
@@ -1650,8 +1650,8 @@ public:
     void decidePolicyForNavigationActionAsyncShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, WebCore::FrameIdentifier, FrameInfoData&&, WebCore::PolicyCheckIdentifier, uint64_t navigationID, NavigationActionData&&, FrameInfoData&& originatingFrameInfo, Optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&&, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData&, uint64_t listenerID);
     void decidePolicyForResponseShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, WebCore::FrameIdentifier, FrameInfoData&&, WebCore::PolicyCheckIdentifier, uint64_t navigationID, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, const String& downloadAttribute, uint64_t listenerID, const UserData&);
     void startURLSchemeTaskShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, URLSchemeTaskParameters&&);
-    void loadDataWithNavigationShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain>, NavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& = WTF::nullopt, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
-    void loadRequestWithNavigationShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain>, NavigatedAwayFromAppBoundDomain, Optional<WebsitePoliciesData>&& = WTF::nullopt);
+    void loadDataWithNavigationShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain>, Optional<WebsitePoliciesData>&& = WTF::nullopt, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
+    void loadRequestWithNavigationShared(Ref<WebProcessProxy>&&, WebCore::PageIdentifier, API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<NavigatingToAppBoundDomain>, Optional<WebsitePoliciesData>&& = WTF::nullopt);
     void backForwardGoToItemShared(Ref<WebProcessProxy>&&, const WebCore::BackForwardItemIdentifier&, CompletionHandler<void(const WebBackForwardListCounts&)>&&);
     void decidePolicyForNavigationActionSyncShared(Ref<WebProcessProxy>&&, WebCore::FrameIdentifier, bool isMainFrame, FrameInfoData&&, WebCore::PolicyCheckIdentifier, uint64_t navigationID, NavigationActionData&&, FrameInfoData&& originatingFrameInfo, Optional<WebPageProxyIdentifier> originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&&, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData&, Messages::WebPageProxy::DecidePolicyForNavigationActionSyncDelayedReply&&);
 #if USE(QUICK_LOOK)
@@ -1763,6 +1763,8 @@ public:
     void removeMediaUsageManagerSession(WebCore::MediaSessionIdentifier);
 #endif
 
+    void setHasExecutedAppBoundBehaviorBeforeNavigation() { m_hasExecutedAppBoundBehaviorBeforeNavigation = true; }
+        
 private:
     WebPageProxy(PageClient&, WebProcessProxy&, Ref<API::PageConfiguration>&&);
     void platformInitialize();
@@ -2317,7 +2319,6 @@ private:
     void makeStorageSpaceRequest(WebCore::FrameIdentifier, const String& originIdentifier, const String& databaseName, const String& displayName, uint64_t currentQuota, uint64_t currentOriginUsage, uint64_t currentDatabaseUsage, uint64_t expectedUsage, CompletionHandler<void(uint64_t)>&&);
         
     bool setIsNavigatingToAppBoundDomainAndCheckIfPermitted(bool isMainFrame, const URL&, Optional<NavigatingToAppBoundDomain>);
-    NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain() const { return m_hasNavigatedAwayFromAppBoundDomain; }
         
     const Identifier m_identifier;
     WebCore::PageIdentifier m_webPageID;
@@ -2811,11 +2812,11 @@ private:
     MonotonicTime m_didFinishDocumentLoadForMainFrameTimestamp;
 #endif
         
-    Optional<NavigatingToAppBoundDomain> m_isNavigatingToAppBoundDomain { NavigatingToAppBoundDomain::No };
-    NavigatedAwayFromAppBoundDomain m_hasNavigatedAwayFromAppBoundDomain { NavigatedAwayFromAppBoundDomain::No };
+    Optional<NavigatingToAppBoundDomain> m_isNavigatingToAppBoundDomain;
     bool m_ignoresAppBoundDomains { false };
     bool m_userScriptsNotified { false };
     bool m_limitsNavigationsToAppBoundDomains { false };
+    bool m_hasExecutedAppBoundBehaviorBeforeNavigation { false };
 
 #if ENABLE(ROUTING_ARBITRATION)
     std::unique_ptr<AudioSessionRoutingArbitratorProxy> m_routingArbitrator;
index d120211..73f9321 100644 (file)
@@ -599,4 +599,5 @@ messages -> WebPageProxy {
     RemoveMediaUsageManagerSession(WebCore::MediaSessionIdentifier identifier);
 #endif
 
+    SetHasExecutedAppBoundBehaviorBeforeNavigation()
 }
index e46da0e..62858e9 100644 (file)
@@ -830,7 +830,7 @@ void WebFrameLoaderClient::dispatchDecidePolicyForResponse(const ResourceRespons
     uint64_t listenerID = m_frame->setUpPolicyListener(identifier, WTFMove(function), WebFrame::ForNavigationAction::No);
     if (!webPage->send(Messages::WebPageProxy::DecidePolicyForResponse(m_frame->frameID(), m_frame->info(), identifier, navigationID, response, request, canShowResponse, downloadAttribute, listenerID, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())))) {
         WEBFRAMELOADERCLIENT_RELEASE_LOG(Network, "dispatchDecidePolicyForResponse: ignoring because WebPageProxy::DecidePolicyForResponse failed");
-        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { identifier, NavigatingToAppBoundDomain::No, NavigatedAwayFromAppBoundDomain::No, PolicyAction::Ignore, 0, { }, { } });
+        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { identifier, WTF::nullopt, PolicyAction::Ignore, 0, { }, { } });
     }
 }
 
@@ -992,17 +992,17 @@ void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const Navigat
         PolicyDecision policyDecision;
 
         if (!webPage->sendSync(Messages::WebPageProxy::DecidePolicyForNavigationActionSync(m_frame->frameID(), m_frame->isMainFrame(), m_frame->info(), requestIdentifier, documentLoader->navigationID(), navigationActionData, originatingFrameInfoData, originatingPageID, navigationAction.resourceRequest(), request, IPC::FormDataReference { request.httpBody() }, redirectResponse, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())), Messages::WebPageProxy::DecidePolicyForNavigationActionSync::Reply(policyDecision))) {
-            m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { requestIdentifier, NavigatingToAppBoundDomain::No, NavigatedAwayFromAppBoundDomain::No, PolicyAction::Ignore, 0, { }, { } });
+            m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { requestIdentifier, WTF::nullopt, PolicyAction::Ignore, 0, { }, { } });
             return;
         }
 
-        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { policyDecision.identifier, policyDecision.isNavigatingToAppBoundDomain, policyDecision.hasNavigatedAwayFromAppBoundDomain, policyDecision.policyAction, 0, policyDecision.downloadID, { }});
+        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { policyDecision.identifier, policyDecision.isNavigatingToAppBoundDomain, policyDecision.policyAction, 0, policyDecision.downloadID, { }});
         return;
     }
 
     ASSERT(policyDecisionMode == PolicyDecisionMode::Asynchronous);
     if (!webPage->send(Messages::WebPageProxy::DecidePolicyForNavigationActionAsync(m_frame->frameID(), m_frame->info(), requestIdentifier, documentLoader->navigationID(), navigationActionData, originatingFrameInfoData, originatingPageID, navigationAction.resourceRequest(), request, IPC::FormDataReference { request.httpBody() }, redirectResponse, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get()), listenerID)))
-        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { requestIdentifier, NavigatingToAppBoundDomain::No, NavigatedAwayFromAppBoundDomain::No, PolicyAction::Ignore, 0, { }, { } });
+        m_frame->didReceivePolicyDecision(listenerID, PolicyDecision { requestIdentifier, WTF::nullopt, PolicyAction::Ignore, 0, { }, { } });
 }
 
 void WebFrameLoaderClient::cancelPolicyCheck()
@@ -1921,7 +1921,7 @@ void WebFrameLoaderClient::finishedLoadingApplicationManifest(uint64_t callbackI
 }
 #endif // ENABLE(APPLICATION_MANIFEST)
 
-bool WebFrameLoaderClient::hasNavigatedAwayFromAppBoundDomain()
+bool WebFrameLoaderClient::shouldEnableInAppBrowserPrivacyProtections() const
 {
     if (!m_frame->isMainFrame())
         return false;
@@ -1929,19 +1929,21 @@ bool WebFrameLoaderClient::hasNavigatedAwayFromAppBoundDomain()
     auto* webPage = m_frame->page();
     if (!webPage)
         return false;
-    
-    return webPage->hasNavigatedAwayFromAppBoundDomain() == NavigatedAwayFromAppBoundDomain::Yes;
+
+    return webPage->shouldEnableInAppBrowserPrivacyProtections();
 }
 
-bool WebFrameLoaderClient::needsInAppBrowserPrivacyQuirks() const
+void WebFrameLoaderClient::notifyPageOfAppBoundBehavior()
 {
+    if (!m_frame->isMainFrame())
+        return;
+
     auto* webPage = m_frame->page();
     if (!webPage)
-        return false;
-    
-    return webPage->needsInAppBrowserPrivacyQuirks();
-}
+        return;
 
+    webPage->notifyPageOfAppBoundBehavior();
+}
 
 } // namespace WebKit
 
index 0f8eb09..a0fda7c 100644 (file)
@@ -288,8 +288,8 @@ private:
     Optional<FrameSpecificStorageAccessIdentifier> m_frameSpecificStorageAccessIdentifier;
 #endif
 
-    bool hasNavigatedAwayFromAppBoundDomain() final;
-    bool needsInAppBrowserPrivacyQuirks() const final;
+    bool shouldEnableInAppBrowserPrivacyProtections() const final;
+    void notifyPageOfAppBoundBehavior() final;
 };
 
 // As long as EmptyFrameLoaderClient exists in WebCore, this can return 0.
index 17eac41..f89bf62 100644 (file)
@@ -475,7 +475,7 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters)
 #endif
     , m_overriddenMediaType(parameters.overriddenMediaType)
     , m_processDisplayName(parameters.processDisplayName)
-    , m_isNavigatingToAppBoundDomain(parameters.limitsNavigationsToAppBoundDomains ? NavigatingToAppBoundDomain::Yes : NavigatingToAppBoundDomain::No)
+    , m_limitsNavigationsToAppBoundDomains(parameters.limitsNavigationsToAppBoundDomains)
 {
     ASSERT(m_identifier);
 
@@ -1527,7 +1527,6 @@ void WebPage::platformDidReceiveLoadParameters(const LoadParameters& loadParamet
 void WebPage::loadRequest(LoadParameters&& loadParameters)
 {
     setIsNavigatingToAppBoundDomain(loadParameters.isNavigatingToAppBoundDomain);
-    setHasNavigatedAwayFromAppBoundDomain(loadParameters.hasNavigatedAwayFromAppBoundDomain);
 
     SendStopResponsivenessTimer stopper;
 
@@ -1563,10 +1562,9 @@ NO_RETURN void WebPage::loadRequestWaitingForProcessLaunch(LoadParameters&&, URL
     RELEASE_ASSERT_NOT_REACHED();
 }
 
-void WebPage::loadDataImpl(uint64_t navigationID, bool shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies, Ref<SharedBuffer>&& sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, const UserData& userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
+void WebPage::loadDataImpl(uint64_t navigationID, bool shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& websitePolicies, Ref<SharedBuffer>&& sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, const UserData& userData, Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy)
 {
     setIsNavigatingToAppBoundDomain(isNavigatingToAppBoundDomain);
-    setHasNavigatedAwayFromAppBoundDomain(hasNavigatedAwayFromAppBoundDomain);
 
     SendStopResponsivenessTimer stopper;
 
@@ -1595,7 +1593,7 @@ void WebPage::loadData(LoadParameters&& loadParameters)
 
     auto sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(loadParameters.data.data()), loadParameters.data.size());
     URL baseURL = loadParameters.baseURLString.isEmpty() ? aboutBlankURL() : URL(URL(), loadParameters.baseURLString);
-    loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, URL(), loadParameters.userData, loadParameters.isNavigatingToAppBoundDomain, loadParameters.hasNavigatedAwayFromAppBoundDomain, loadParameters.shouldOpenExternalURLsPolicy);
+    loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, URL(), loadParameters.userData, loadParameters.isNavigatingToAppBoundDomain, loadParameters.shouldOpenExternalURLsPolicy);
 }
 
 void WebPage::loadAlternateHTML(LoadParameters&& loadParameters)
@@ -1607,7 +1605,7 @@ void WebPage::loadAlternateHTML(LoadParameters&& loadParameters)
     URL provisionalLoadErrorURL = loadParameters.provisionalLoadErrorURLString.isEmpty() ? URL() : URL(URL(), loadParameters.provisionalLoadErrorURLString);
     auto sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(loadParameters.data.data()), loadParameters.data.size());
     m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL(provisionalLoadErrorURL);    
-    loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, unreachableURL, loadParameters.userData, loadParameters.isNavigatingToAppBoundDomain, loadParameters.hasNavigatedAwayFromAppBoundDomain);
+    loadDataImpl(loadParameters.navigationID, loadParameters.shouldTreatAsContinuingLoad, WTFMove(loadParameters.websitePolicies), WTFMove(sharedBuffer), loadParameters.MIMEType, loadParameters.encodingName, baseURL, unreachableURL, loadParameters.userData, loadParameters.isNavigatingToAppBoundDomain);
     m_mainFrame->coreFrame()->loader().setProvisionalLoadErrorBeingHandledURL({ });
 }
 
@@ -3253,7 +3251,6 @@ void WebPage::setLayerHostingMode(LayerHostingMode layerHostingMode)
 void WebPage::didReceivePolicyDecision(FrameIdentifier frameID, uint64_t listenerID, PolicyDecision&& policyDecision)
 {
     setIsNavigatingToAppBoundDomain(policyDecision.isNavigatingToAppBoundDomain);
-    setHasNavigatedAwayFromAppBoundDomain(policyDecision.hasNavigatedAwayFromAppBoundDomain);
 
     WebFrame* frame = WebProcess::singleton().webFrame(frameID);
     if (!frame)
@@ -3426,8 +3423,7 @@ void WebPage::runJavaScript(WebFrame* frame, RunJavaScriptParameters&& parameter
 
         send(Messages::WebPageProxy::ScriptValueCallback(dataReference, details, callbackID));
     };
-    
-    if (hasNavigatedAwayFromAppBoundDomain() == NavigatedAwayFromAppBoundDomain::Yes && !m_needsInAppBrowserPrivacyQuirks) {
+    if (shouldEnableInAppBrowserPrivacyProtections()) {
         send(Messages::WebPageProxy::ScriptValueCallback({ }, ExceptionDetails { "Unable to execute JavaScript"_s }, callbackID));
         if (auto* document = m_page->mainFrame().document())
             document->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, "Ignoring user script injection for non-app bound domain.");
@@ -3683,8 +3679,8 @@ void WebPage::updatePreferences(const WebPreferencesStore& store)
         disableServiceWorkerEntitlement();
 
     if (store.getBoolValueForKey(WebPreferencesKey::serviceWorkersEnabledKey())) {
-        ASSERT(parentProcessHasServiceWorkerEntitlement() || m_isNavigatingToAppBoundDomain);
-        if (!parentProcessHasServiceWorkerEntitlement() && !m_isNavigatingToAppBoundDomain)
+        ASSERT(parentProcessHasServiceWorkerEntitlement() || m_limitsNavigationsToAppBoundDomains);
+        if (!parentProcessHasServiceWorkerEntitlement() && !m_limitsNavigationsToAppBoundDomains)
             RuntimeEnabledFeatures::sharedFeatures().setServiceWorkerEnabled(false);
     }
 #endif
@@ -7102,6 +7098,27 @@ void WebPage::animationDidFinishForElement(const WebCore::Element&)
 
 #endif
 
+void WebPage::setIsNavigatingToAppBoundDomain(Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
+{
+    m_isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
+    
+    m_navigationHasOccured = true;
+}
+
+void WebPage::notifyPageOfAppBoundBehavior()
+{
+    if (!m_navigationHasOccured && !m_limitsNavigationsToAppBoundDomains)
+        send(Messages::WebPageProxy::SetHasExecutedAppBoundBehaviorBeforeNavigation());
+}
+
+bool WebPage::shouldEnableInAppBrowserPrivacyProtections()
+{
+    if (m_needsInAppBrowserPrivacyQuirks)
+        return false;
+
+    return isNavigatingToAppBoundDomain() && isNavigatingToAppBoundDomain() == NavigatingToAppBoundDomain::No;
+}
+
 } // namespace WebKit
 
 #undef RELEASE_LOG_IF_ALLOWED
index 3ddab9a..15f28cf 100644 (file)
@@ -1315,11 +1315,10 @@ public:
 
     void getAllFrames(CompletionHandler<void(FrameTreeNodeData&&)>&&);
 
-    void setIsNavigatingToAppBoundDomain(Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) { m_isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain; }
+    void notifyPageOfAppBoundBehavior();
+    bool shouldEnableInAppBrowserPrivacyProtections();
+    void setIsNavigatingToAppBoundDomain(Optional<NavigatingToAppBoundDomain>);
     Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain() const { return m_isNavigatingToAppBoundDomain; }
-    NavigatedAwayFromAppBoundDomain hasNavigatedAwayFromAppBoundDomain() const { return m_hasNavigatedAwayFromAppBoundDomain; }
-    void setHasNavigatedAwayFromAppBoundDomain(NavigatedAwayFromAppBoundDomain navigatedAwayFromAppBoundDomain) { m_hasNavigatedAwayFromAppBoundDomain = navigatedAwayFromAppBoundDomain; }
-    bool needsInAppBrowserPrivacyQuirks() const { return m_needsInAppBrowserPrivacyQuirks; }
     
     bool shouldUseRemoteRenderingFor(WebCore::RenderingPurpose);
 
@@ -1419,7 +1418,7 @@ private:
 
     String sourceForFrame(WebFrame*);
 
-    void loadDataImpl(uint64_t navigationID, bool shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&&, Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& failingURL, const UserData&, Optional<NavigatingToAppBoundDomain>, NavigatedAwayFromAppBoundDomain, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
+    void loadDataImpl(uint64_t navigationID, bool shouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&&, Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& failingURL, const UserData&, Optional<NavigatingToAppBoundDomain>, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
 
     // Actions
     void tryClose(CompletionHandler<void(bool)>&&);
@@ -2104,8 +2103,9 @@ private:
     String m_themeName;
 #endif
     
-    Optional<NavigatingToAppBoundDomain> m_isNavigatingToAppBoundDomain { NavigatingToAppBoundDomain::No };
-    NavigatedAwayFromAppBoundDomain m_hasNavigatedAwayFromAppBoundDomain { NavigatedAwayFromAppBoundDomain::No };
+    Optional<NavigatingToAppBoundDomain> m_isNavigatingToAppBoundDomain;
+    bool m_limitsNavigationsToAppBoundDomains { false };
+    bool m_navigationHasOccured { false };
 };
 
 #if !PLATFORM(IOS_FAMILY)
index d6462aa..5d756ae 100644 (file)
@@ -1,3 +1,29 @@
+2020-05-11  Kate Cheney  <katherine_cheney@apple.com>
+
+        Fail navigations to non app-bound domains after use of app-bound APIs
+        https://bugs.webkit.org/show_bug.cgi?id=211647
+        <rdar://problem/62978159>
+
+        Reviewed by Brent Fulgham.
+
+        Added a new test to confirm a non-app bound navigation fails after
+        using script injection.
+
+        This fix also required changing any test which uses a restricted API
+        to confirm behavior of another restricted API. Tests can set
+        _setNeedsInAppBrowserPrivacyQuirks in the configuration to indicate
+        APIs should not be blocked, then toggle it to test actual behavior.
+
+        Also, we can remove any calls to _setInAppBrowserPrivacyEnabled
+        now that this is just an internal test flag. 
+
+        * TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
+        (-[AppBoundDomainDelegate webView:didFinishNavigation:]):
+        (-[AppBoundDomainDelegate webView:didFailProvisionalNavigation:withError:]):
+        (-[AppBoundDomainDelegate waitForDidFinishNavigation]):
+        (-[AppBoundDomainDelegate waitForDidFailProvisionalNavigationError]):
+        (TEST):
+
 2020-05-11  Alex Christensen  <achristensen@webkit.org>
 
         Add some logs to diagnose why WebKitLegacy.CrossPartitionFileSchemeAccess API test times out in EWS
index 1f4b607..3dd5030 100644 (file)
 
 static bool isDone;
 
+@interface AppBoundDomainDelegate : NSObject <WKNavigationDelegate>
+- (void)waitForDidFinishNavigation;
+- (NSError *)waitForDidFailProvisionalNavigationError;
+@end
+
+@implementation AppBoundDomainDelegate {
+    bool _navigationFinished;
+    RetainPtr<NSError> _provisionalNavigationFailedError;
+}
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    _navigationFinished = true;
+}
+
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
+{
+    _provisionalNavigationFailedError = error;
+}
+
+- (void)waitForDidFinishNavigation
+{
+    TestWebKitAPI::Util::run(&_navigationFinished);
+}
+
+- (NSError *)waitForDidFailProvisionalNavigationError
+{
+    while (!_provisionalNavigationFailedError)
+        TestWebKitAPI::Util::spinRunLoop();
+    return _provisionalNavigationFailedError.autorelease();
+}
+
+@end
+
 static NSString * const userScriptSource = @"window.wkUserScriptInjected = true";
 
 @interface InAppBrowserSchemeHandler : NSObject <WKURLSchemeHandler>
@@ -103,8 +137,6 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtStart)
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
     [configuration.userContentController addUserScript:userScript.get()];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
@@ -121,8 +153,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtStart)
     isDone = false;
     TestWebKitAPI::Util::run(&isDone);
 
-    // Turn back on In-App Browser Privacy quirks to check that original attempt to set this variable was rejected.
-    isDone = false;
+    // Disable script injection blocking to check that original attempt to set this variable was rejected.
     [[[webView configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
     [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_EQ(NO, [result boolValue]);
@@ -145,8 +176,6 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtEnd)
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
     [configuration.userContentController addUserScript:userScript.get()];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-script"]];
@@ -163,8 +192,7 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtEnd)
     isDone = false;
     TestWebKitAPI::Util::run(&isDone);
 
-    // Turn back on In-App Browser Privacy quirks to check that original attempt to set this variable was rejected.
-    isDone = false;
+    // Disable script injection blocking to check that original attempt to set this variable was rejected.
     [[[webView configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
     [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
         EXPECT_EQ(NO, [result boolValue]);
@@ -179,9 +207,11 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserScriptAtEnd)
 
 TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserAgentScripts)
 {
+    initializeInAppBrowserPrivacyTestSettings();
+
     WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    // Disable blocking of restricted APIs for test setup.
     [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:NO];
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
@@ -198,13 +228,11 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainFailedUserAgentScripts)
 
     isDone = false;
     TestWebKitAPI::Util::run(&isDone);
-
-    initializeInAppBrowserPrivacyTestSettings();
+    
+    // Enable blocking of restricted APIs.
     [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
 
     auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
-
     isDone = false;
     [webView2 loadRequest:request];
     [webView2 _test_waitForDidFinishNavigation];
@@ -244,7 +272,6 @@ TEST(InAppBrowserPrivacy, LocalFilesAreAppBound)
 {
     initializeInAppBrowserPrivacyTestSettings();
     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
     [configuration setLimitsNavigationsToAppBoundDomains:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
@@ -265,7 +292,6 @@ TEST(InAppBrowserPrivacy, DataFilesAreAppBound)
 {
     initializeInAppBrowserPrivacyTestSettings();
     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
     [configuration setLimitsNavigationsToAppBoundDomains:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
@@ -285,7 +311,6 @@ TEST(InAppBrowserPrivacy, AboutFilesAreAppBound)
 {
     initializeInAppBrowserPrivacyTestSettings();
     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
     [configuration setLimitsNavigationsToAppBoundDomains:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
@@ -303,7 +328,6 @@ TEST(InAppBrowserPrivacy, AboutFilesAreAppBound)
 
 static NSString *styleSheetSource = @"body { background-color: green !important; }";
 static NSString *backgroundColorScript = @"window.getComputedStyle(document.body, null).getPropertyValue('background-color')";
-static NSString *frameBackgroundColorScript = @"window.getComputedStyle(document.getElementsByTagName('iframe')[0].contentDocument.body, null).getPropertyValue('background-color')";
 static const char* redInRGB = "rgb(255, 0, 0)";
 static const char* blackInRGB = "rgba(0, 0, 0, 0)";
 
@@ -329,19 +353,19 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForSpecificWebViewFails)
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
+    RetainPtr<_WKUserContentWorld> world = [_WKUserContentWorld worldWithName:@"TestWorld"];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
-    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
-    [webView loadRequest:request];
-    [webView _test_waitForDidFinishNavigation];
-
-    RetainPtr<_WKUserContentWorld> world = [_WKUserContentWorld worldWithName:@"TestWorld"];
     RetainPtr<_WKUserStyleSheet> styleSheet = adoptNS([[_WKUserStyleSheet alloc] initWithSource:styleSheetSource forWKWebView:webView.get() forMainFrameOnly:YES level:_WKUserStyleUserLevel userContentWorld:world.get()]);
     [[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
 
-    expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    auto delegate = adoptNS([AppBoundDomainDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
+    [webView loadRequest:request];
+    NSError *error = [delegate waitForDidFailProvisionalNavigationError];
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
     cleanUpInAppBrowserPrivacyTestSettings();
 }
 
@@ -353,18 +377,18 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetForAllWebViewsFails)
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
-
-    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
-    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
-    [webView loadRequest:request];
-    [webView _test_waitForDidFinishNavigation];
-
+    
     RetainPtr<_WKUserStyleSheet> styleSheet = adoptNS([[_WKUserStyleSheet alloc] initWithSource:styleSheetSource forMainFrameOnly:YES]);
     [[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
+    
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+    auto delegate = adoptNS([AppBoundDomainDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
 
-    expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
+    [webView loadRequest:request];
+    NSError *error = [delegate waitForDidFailProvisionalNavigationError];
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
     cleanUpInAppBrowserPrivacyTestSettings();
 }
 
@@ -376,22 +400,17 @@ TEST(InAppBrowserPrivacy, NonAppBoundUserStyleSheetAffectingAllFramesFails)
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
-
-    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
-    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets-iframe"]];
-    [webView loadRequest:request];
-    [webView _test_waitForDidFinishNavigation];
-
     RetainPtr<_WKUserStyleSheet> styleSheet = adoptNS([[_WKUserStyleSheet alloc] initWithSource:styleSheetSource forMainFrameOnly:NO]);
     [[configuration userContentController] _addUserStyleSheet:styleSheet.get()];
 
-    // The main frame should be affected.
-    expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, redInRGB);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+    auto delegate = adoptNS([AppBoundDomainDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
 
-    // The subframe should also be affected.
-    expectScriptEvaluatesToColor(webView.get(), frameBackgroundColorScript, redInRGB);
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets-iframe"]];
+    [webView loadRequest:request];
+    NSError *error = [delegate waitForDidFailProvisionalNavigationError];
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
     cleanUpInAppBrowserPrivacyTestSettings();
 }
 
@@ -404,8 +423,6 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
-    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
 
@@ -416,6 +433,10 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainCannotAccessMessageHandlers)
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-message-handler"]];
     [webView loadRequest:request];
     [webView _test_waitForDidFinishNavigation];
+    
+    // Disable script injection blocking to check that the request for message
+    // handlers returned null.
+    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
 
     // Set the background color to red if message handlers returned null so we can
     // check without needing a message handler.
@@ -432,7 +453,6 @@ TEST(InAppBrowserPrivacy, AppBoundDomainCanAccessMessageHandlers)
 
     auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
-    [[configuration preferences] _setInAppBrowserPrivacyEnabled:YES];
     [configuration setLimitsNavigationsToAppBoundDomains:YES];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
@@ -833,40 +853,6 @@ TEST(InAppBrowserPrivacy, NonAppBoundDomainDoesNotAllowServiceWorkers)
     isDone = false;
 }
 
-@interface AppBoundDomainDelegate : NSObject <WKNavigationDelegate>
-- (void)waitForDidFinishNavigation;
-- (NSError *)waitForDidFailProvisionalNavigationError;
-@end
-
-@implementation AppBoundDomainDelegate {
-    bool _navigationFinished;
-    RetainPtr<NSError> _provisionalNavigationFailedError;
-}
-
-- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
-{
-    _navigationFinished = true;
-}
-
-- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
-{
-    _provisionalNavigationFailedError = error;
-}
-
-- (void)waitForDidFinishNavigation
-{
-    TestWebKitAPI::Util::run(&_navigationFinished);
-}
-
-- (NSError *)waitForDidFailProvisionalNavigationError
-{
-    while (!_provisionalNavigationFailedError)
-        TestWebKitAPI::Util::spinRunLoop();
-    return _provisionalNavigationFailedError.autorelease();
-}
-
-@end
-
 TEST(InAppBrowserPrivacy, AppBoundFlagForNonAppBoundDomainFails)
 {
     initializeInAppBrowserPrivacyTestSettings();
@@ -885,7 +871,7 @@ TEST(InAppBrowserPrivacy, AppBoundFlagForNonAppBoundDomainFails)
     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
     [webView loadRequest:request];
     NSError *error = [delegate waitForDidFailProvisionalNavigationError];
-    EXPECT_WK_STREQ(error.localizedDescription, @"Attempted navigation away from app-bound domain");
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
 
     // Make sure the load didn't complete by checking the background color.
     // Red would indicate it finished loading.
@@ -916,7 +902,7 @@ TEST(InAppBrowserPrivacy, NavigateAwayFromAppBoundDomainWithAppBoundFlagFails)
     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
     [webView loadRequest:request];
     NSError *error = [delegate waitForDidFailProvisionalNavigationError];
-    EXPECT_WK_STREQ(error.localizedDescription, @"Attempted navigation away from app-bound domain");
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
 
     // Make sure the load didn't complete by checking the background color.
     // Red would indicate it finished loading.
@@ -991,11 +977,14 @@ TEST(InAppBrowserPrivacy, WebViewWithoutAppBoundFlagCanFreelyNavigate)
     TestWebKitAPI::Util::run(&isDone);
 
     // Navigation should be successful, but this WebView should not get app-bound domain
-    // privileges like user style sheets. Set quirks to true so we can evaluate script
-    // to check.
-    [[[webView configuration] preferences] _setNeedsInAppBrowserPrivacyQuirks:YES];
-    expectScriptEvaluatesToColor(webView.get(), backgroundColorScript, blackInRGB);
-    cleanUpInAppBrowserPrivacyTestSettings();
+    // privileges like script injection.
+    isDone = false;
+    [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+        EXPECT_TRUE(!!error);
+        isDone = true;
+    }];
+
+    TestWebKitAPI::Util::run(&isDone);
 }
 
 TEST(InAppBrowserPrivacy, WebViewCannotUpdateAppBoundFlagOnceSet)
@@ -1029,11 +1018,42 @@ TEST(InAppBrowserPrivacy, WebViewCannotUpdateAppBoundFlagOnceSet)
     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
     [webView loadRequest:request];
     NSError *error = [delegate waitForDidFailProvisionalNavigationError];
-    EXPECT_WK_STREQ(error.localizedDescription, @"Attempted navigation away from app-bound domain");
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
 
     cleanUpInAppBrowserPrivacyTestSettings();
 }
 
+TEST(InAppBrowserPrivacy, InjectScriptThenNavigateToNonAppBoundDomainFails)
+{
+    isDone = false;
+    initializeInAppBrowserPrivacyTestSettings();
+    auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
+
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
+    auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
+    [configuration.userContentController addUserScript:userScript.get()];
+    [[configuration preferences] _setNeedsInAppBrowserPrivacyQuirks:NO];
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
+    auto delegate = adoptNS([AppBoundDomainDelegate new]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    isDone = false;
+    [webView evaluateJavaScript:@"window.wkUserScriptInjected" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
+        EXPECT_FALSE(!!error);
+        isDone = true;
+    }];
+
+    TestWebKitAPI::Util::run(&isDone);
+    
+    // Load a non-app bound domain.
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-agent-script"]];
+    [webView loadRequest:request];
+    NSError *error = [delegate waitForDidFailProvisionalNavigationError];
+    EXPECT_WK_STREQ(error.localizedDescription, @"App-bound domain failure");
+}
+
 TEST(InAppBrowserPrivacy, WebViewCategory)
 {
     initializeInAppBrowserPrivacyTestSettings();