Title: [260330] trunk
Revision
260330
Author
beid...@apple.com
Date
2020-04-18 19:08:52 -0700 (Sat, 18 Apr 2020)

Log Message

Fix WebUserContentControllerProxy vs ContentWorld lifetime
https://bugs.webkit.org/show_bug.cgi?id=210700

Reviewed by Alex Christensen.

Source/WebKit:

Covered by API test.

WebUserContentControllerProxy currently keeps all of its associated API::ContentWorlds alive via RefPtrs.

This is despite the fact that all of the associated WebScriptMessageHandlers, UserScripts, and
UserStyleSheets already keep their associated API::ContentWorlds alive.

It then decideds to tell WebProcesses to forget a content world after all of its clients are removed.

Unfortunately, content worlds are used for more than just content controller stuff. They're used for direct
_javascript_ evaluation as well.

So a client could:
  - Add a script message handler in a content world.
  - Evaluate _javascript_ in that content world, setting up some persistent state.
  - Remove the script message handler.
  - Find that their persistent state from the _javascript_ evaluation is gone from that world, even though they
    still retain a usable handle to that world.

The only party who has any business managing the lifetime of an API::ContentWorld is the API::ContentWorld itself.

Making this change is:
  1 - Nice cleanup
  2 - Fixes the above mentioned bug

* UIProcess/API/APIContentWorld.cpp:
(API::ContentWorld::worldForIdentifier):
(API::ContentWorld::ContentWorld):
(API::ContentWorld::sharedWorldWithName):
(API::ContentWorld::~ContentWorld):
(API::ContentWorld::addAssociatedUserContentControllerProxy):
(API::ContentWorld::userContentControllerProxyDestroyed):
* UIProcess/API/APIContentWorld.h:

* UIProcess/UserContent/WebUserContentControllerProxy.cpp:
(WebKit::WebUserContentControllerProxy::parameters const):
(WebKit::WebUserContentControllerProxy::addContentWorld):
(WebKit::WebUserContentControllerProxy::contentWorldDestroyed):
(WebKit::WebUserContentControllerProxy::addUserScript):
(WebKit::WebUserContentControllerProxy::removeUserScript):
(WebKit::WebUserContentControllerProxy::removeAllUserScripts):
(WebKit::WebUserContentControllerProxy::addUserStyleSheet):
(WebKit::WebUserContentControllerProxy::removeUserStyleSheet):
(WebKit::WebUserContentControllerProxy::removeAllUserStyleSheets):
(WebKit::WebUserContentControllerProxy::addUserScriptMessageHandler):
(WebKit::WebUserContentControllerProxy::removeUserMessageHandlerForName):
(WebKit::WebUserContentControllerProxy::removeAllUserMessageHandlers):
(WebKit::WebUserContentControllerProxy::addContentWorldUse): Deleted.
(WebKit::WebUserContentControllerProxy::shouldSendRemoveContentWorldsMessage): Deleted.
(WebKit::WebUserContentControllerProxy::removeContentWorldUses): Deleted.
* UIProcess/UserContent/WebUserContentControllerProxy.h:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm:
(-[DummyMessageHandler userContentController:didReceiveScriptMessage:]):
(TEST): Make sure removing a script message handler from a particular world
  doesn't also destroy the other _javascript_ contents of that world.

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (260329 => 260330)


--- trunk/Source/WebKit/ChangeLog	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Source/WebKit/ChangeLog	2020-04-19 02:08:52 UTC (rev 260330)
@@ -1,3 +1,62 @@
+2020-04-18  Brady Eidson  <beid...@apple.com>
+
+        Fix WebUserContentControllerProxy vs ContentWorld lifetime
+        https://bugs.webkit.org/show_bug.cgi?id=210700
+
+        Reviewed by Alex Christensen.
+
+        Covered by API test.
+        
+        WebUserContentControllerProxy currently keeps all of its associated API::ContentWorlds alive via RefPtrs.
+        
+        This is despite the fact that all of the associated WebScriptMessageHandlers, UserScripts, and 
+        UserStyleSheets already keep their associated API::ContentWorlds alive.
+
+        It then decideds to tell WebProcesses to forget a content world after all of its clients are removed.
+        
+        Unfortunately, content worlds are used for more than just content controller stuff. They're used for direct
+        _javascript_ evaluation as well.
+        
+        So a client could:
+          - Add a script message handler in a content world.
+          - Evaluate _javascript_ in that content world, setting up some persistent state.
+          - Remove the script message handler.
+          - Find that their persistent state from the _javascript_ evaluation is gone from that world, even though they
+            still retain a usable handle to that world.
+        
+        The only party who has any business managing the lifetime of an API::ContentWorld is the API::ContentWorld itself.
+        
+        Making this change is:
+          1 - Nice cleanup
+          2 - Fixes the above mentioned bug
+        
+        * UIProcess/API/APIContentWorld.cpp:
+        (API::ContentWorld::worldForIdentifier):
+        (API::ContentWorld::ContentWorld):
+        (API::ContentWorld::sharedWorldWithName):
+        (API::ContentWorld::~ContentWorld):
+        (API::ContentWorld::addAssociatedUserContentControllerProxy):
+        (API::ContentWorld::userContentControllerProxyDestroyed):
+        * UIProcess/API/APIContentWorld.h:
+
+        * UIProcess/UserContent/WebUserContentControllerProxy.cpp:
+        (WebKit::WebUserContentControllerProxy::parameters const):
+        (WebKit::WebUserContentControllerProxy::addContentWorld):
+        (WebKit::WebUserContentControllerProxy::contentWorldDestroyed):
+        (WebKit::WebUserContentControllerProxy::addUserScript):
+        (WebKit::WebUserContentControllerProxy::removeUserScript):
+        (WebKit::WebUserContentControllerProxy::removeAllUserScripts):
+        (WebKit::WebUserContentControllerProxy::addUserStyleSheet):
+        (WebKit::WebUserContentControllerProxy::removeUserStyleSheet):
+        (WebKit::WebUserContentControllerProxy::removeAllUserStyleSheets):
+        (WebKit::WebUserContentControllerProxy::addUserScriptMessageHandler):
+        (WebKit::WebUserContentControllerProxy::removeUserMessageHandlerForName):
+        (WebKit::WebUserContentControllerProxy::removeAllUserMessageHandlers):
+        (WebKit::WebUserContentControllerProxy::addContentWorldUse): Deleted.
+        (WebKit::WebUserContentControllerProxy::shouldSendRemoveContentWorldsMessage): Deleted.
+        (WebKit::WebUserContentControllerProxy::removeContentWorldUses): Deleted.
+        * UIProcess/UserContent/WebUserContentControllerProxy.h:
+
 2020-04-18  David Kilzer  <ddkil...@apple.com>
 
         Attempt #4 to fix tvOS build

Modified: trunk/Source/WebKit/UIProcess/API/APIContentWorld.cpp (260329 => 260330)


--- trunk/Source/WebKit/UIProcess/API/APIContentWorld.cpp	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Source/WebKit/UIProcess/API/APIContentWorld.cpp	2020-04-19 02:08:52 UTC (rev 260330)
@@ -27,11 +27,29 @@
 #include "APIContentWorld.h"
 
 #include "ContentWorldShared.h"
+#include "WebUserContentControllerProxy.h"
 #include <wtf/HashMap.h>
 #include <wtf/text/StringHash.h>
 
 namespace API {
 
+static HashMap<WTF::String, ContentWorld*>& sharedWorldNameMap()
+{
+    static NeverDestroyed<HashMap<WTF::String, ContentWorld*>> sharedMap;
+    return sharedMap;
+}
+
+static HashMap<WebKit::ContentWorldIdentifier, ContentWorld*>& sharedWorldIdentifierMap()
+{
+    static NeverDestroyed<HashMap<WebKit::ContentWorldIdentifier, ContentWorld*>> sharedMap;
+    return sharedMap;
+}
+
+ContentWorld* ContentWorld::worldForIdentifier(WebKit::ContentWorldIdentifier identifer)
+{
+    return sharedWorldIdentifierMap().get(identifer);
+}
+
 ContentWorld::ContentWorld(const WTF::String& name)
     : m_name(name)
 {
@@ -44,17 +62,19 @@
     });
 
     m_identifier = WebKit::ContentWorldIdentifier::generate();
+    auto addResult = sharedWorldIdentifierMap().add(m_identifier, this);
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
 }
 
-static HashMap<WTF::String, ContentWorld*>& sharedWorldMap()
+ContentWorld::ContentWorld(WebKit::ContentWorldIdentifier identifier)
+    : m_identifier(identifier)
 {
-    static HashMap<WTF::String, ContentWorld*>* sharedMap = new HashMap<WTF::String, ContentWorld*>;
-    return *sharedMap;
+    ASSERT(m_identifier == WebKit::pageContentWorldIdentifier());
 }
 
 Ref<ContentWorld> ContentWorld::sharedWorldWithName(const WTF::String& name)
 {
-    auto result = sharedWorldMap().add(name, nullptr);
+    auto result = sharedWorldNameMap().add(name, nullptr);
     if (result.isNewEntry) {
         result.iterator->value = new ContentWorld(name);
         return adoptRef(*result.iterator->value);
@@ -77,11 +97,30 @@
 
 ContentWorld::~ContentWorld()
 {
-    if (name().isNull())
-        return;
+    ASSERT(m_identifier != WebKit::pageContentWorldIdentifier());
 
-    auto taken = sharedWorldMap().take(name());
-    ASSERT_UNUSED(taken, taken == this);
+    auto result = sharedWorldIdentifierMap().take(m_identifier);
+    ASSERT_UNUSED(result, result == this || m_identifier == WebKit::pageContentWorldIdentifier());
+
+    if (!name().isNull()) {
+        auto taken = sharedWorldNameMap().take(name());
+        ASSERT_UNUSED(taken, taken == this);
+    }
+
+    for (auto proxy : m_associatedContentControllerProxies)
+        proxy->contentWorldDestroyed(*this);
 }
 
+void ContentWorld::addAssociatedUserContentControllerProxy(WebKit::WebUserContentControllerProxy& proxy)
+{
+    auto addResult = m_associatedContentControllerProxies.add(&proxy);
+    ASSERT_UNUSED(addResult, addResult.isNewEntry);
+}
+
+void ContentWorld::userContentControllerProxyDestroyed(WebKit::WebUserContentControllerProxy& proxy)
+{
+    bool removed = m_associatedContentControllerProxies.remove(&proxy);
+    ASSERT_UNUSED(removed, removed);
+}
+
 } // namespace API

Modified: trunk/Source/WebKit/UIProcess/API/APIContentWorld.h (260329 => 260330)


--- trunk/Source/WebKit/UIProcess/API/APIContentWorld.h	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Source/WebKit/UIProcess/API/APIContentWorld.h	2020-04-19 02:08:52 UTC (rev 260330)
@@ -27,12 +27,18 @@
 
 #include "APIObject.h"
 #include "ContentWorldShared.h"
+#include <wtf/HashSet.h>
 #include <wtf/text/WTFString.h>
 
+namespace WebKit {
+class WebUserContentControllerProxy;
+}
+
 namespace API {
 
 class ContentWorld final : public API::ObjectImpl<API::Object::Type::ContentWorld> {
 public:
+    static ContentWorld* worldForIdentifier(WebKit::ContentWorldIdentifier);
     static Ref<ContentWorld> sharedWorldWithName(const WTF::String&);
     static ContentWorld& pageContentWorld();
     static ContentWorld& defaultClientWorld();
@@ -43,13 +49,16 @@
     const WTF::String& name() const { return m_name; }
     std::pair<WebKit::ContentWorldIdentifier, WTF::String> worldData() const { return { m_identifier, m_name }; }
 
+    void addAssociatedUserContentControllerProxy(WebKit::WebUserContentControllerProxy&);
+    void userContentControllerProxyDestroyed(WebKit::WebUserContentControllerProxy&);
+
 private:
     explicit ContentWorld(const WTF::String&);
-    explicit ContentWorld(WebKit::ContentWorldIdentifier identifier)
-        : m_identifier(identifier) { }
+    explicit ContentWorld(WebKit::ContentWorldIdentifier);
 
     WebKit::ContentWorldIdentifier m_identifier;
     WTF::String m_name;
+    HashSet<WebKit::WebUserContentControllerProxy*> m_associatedContentControllerProxies;
 };
 
 } // namespace API

Modified: trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp (260329 => 260330)


--- trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.cpp	2020-04-19 02:08:52 UTC (rev 260330)
@@ -73,6 +73,12 @@
 
 WebUserContentControllerProxy::~WebUserContentControllerProxy()
 {
+    for (const auto& identifier : m_associatedContentWorlds) {
+        auto* world = API::ContentWorld::worldForIdentifier(identifier);
+        RELEASE_ASSERT(world);
+        world->userContentControllerProxyDestroyed(*this);
+    }
+    
     webUserContentControllerProxies().remove(m_identifier);
     for (auto& process : m_processes) {
         process.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier());
@@ -110,8 +116,12 @@
 
     parameters.identifier = identifier();
     
-    for (const auto& world : m_contentWorlds)
-        parameters.userContentWorlds.append(world.key->worldData());
+    ASSERT(parameters.userContentWorlds.isEmpty());
+    for (const auto& identifier : m_associatedContentWorlds) {
+        auto* world = API::ContentWorld::worldForIdentifier(identifier);
+        RELEASE_ASSERT(world);
+        parameters.userContentWorlds.append(world->worldData());
+    }
 
     for (auto userScript : m_userScripts->elementsOfType<API::UserScript>())
         parameters.userScripts.append({ userScript->identifier(), userScript->contentWorld().identifier(), userScript->userScript() });
@@ -149,52 +159,27 @@
     webProcessProxy.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), identifier());
 }
 
-void WebUserContentControllerProxy::addContentWorldUse(API::ContentWorld& world)
+void WebUserContentControllerProxy::addContentWorld(API::ContentWorld& world)
 {
-    if (&world == &API::ContentWorld::pageContentWorld())
+    if (world.identifier() == pageContentWorldIdentifier())
         return;
 
-    auto addResult = m_contentWorlds.add(&world);
-    if (addResult.isNewEntry) {
-        for (auto& process : m_processes)
-            process.send(Messages::WebUserContentController::AddContentWorlds({ world.worldData() }), identifier());
-    }
-}
+    auto addResult = m_associatedContentWorlds.add(world.identifier());
+    if (!addResult.isNewEntry)
+        return;
 
-bool WebUserContentControllerProxy::shouldSendRemoveContentWorldsMessage(API::ContentWorld& world, unsigned numberOfUsesToRemove)
-{
-    if (&world == &API::ContentWorld::pageContentWorld())
-        return false;
-
-    auto it = m_contentWorlds.find(&world);
-    for (unsigned i = 0; i < numberOfUsesToRemove; ++i) {
-        if (m_contentWorlds.remove(it)) {
-            ASSERT(i == (numberOfUsesToRemove - 1));
-            return true;
-        }
-    }
-    
-    return false;
+    world.addAssociatedUserContentControllerProxy(*this);
+    for (auto& process : m_processes)
+        process.send(Messages::WebUserContentController::AddContentWorlds({ world.worldData() }), identifier());
 }
 
-void WebUserContentControllerProxy::removeContentWorldUses(API::ContentWorld& world, unsigned numberOfUsesToRemove)
+void WebUserContentControllerProxy::contentWorldDestroyed(API::ContentWorld& world)
 {
-    if (shouldSendRemoveContentWorldsMessage(world, numberOfUsesToRemove)) {
-        for (auto& process : m_processes)
-            process.send(Messages::WebUserContentController::RemoveContentWorlds({ world.identifier() }), identifier());
-    }
-}
+    bool result = m_associatedContentWorlds.remove(world.identifier());
+    ASSERT_UNUSED(result, result);
 
-void WebUserContentControllerProxy::removeContentWorldUses(HashCountedSet<RefPtr<API::ContentWorld>>& worlds)
-{
-    Vector<ContentWorldIdentifier> worldsToRemove;
-    for (auto& worldUsePair : worlds) {
-        if (shouldSendRemoveContentWorldsMessage(*worldUsePair.key.get(), worldUsePair.value))
-            worldsToRemove.append(worldUsePair.key->identifier());
-    }
-
     for (auto& process : m_processes)
-        process.send(Messages::WebUserContentController::RemoveContentWorlds(worldsToRemove), identifier());
+        process.send(Messages::WebUserContentController::RemoveContentWorlds({ world.identifier() }), identifier());
 }
 
 void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript, InjectUserScriptImmediately immediately)
@@ -201,7 +186,7 @@
 {
     Ref<API::ContentWorld> world = userScript.contentWorld();
 
-    addContentWorldUse(world.get());
+    addContentWorld(world.get());
 
     m_userScripts->elements().append(&userScript);
 
@@ -217,8 +202,6 @@
         process.send(Messages::WebUserContentController::RemoveUserScript(world->identifier(), userScript.identifier()), identifier());
 
     m_userScripts->elements().removeAll(&userScript);
-
-    removeContentWorldUses(world.get(), 1);
 }
 
 void WebUserContentControllerProxy::removeAllUserScripts(API::ContentWorld& world)
@@ -226,11 +209,9 @@
     for (auto& process : m_processes)
         process.send(Messages::WebUserContentController::RemoveAllUserScripts({ world.identifier() }), identifier());
 
-    unsigned userScriptsRemoved = m_userScripts->removeAllOfTypeMatching<API::UserScript>([&](const auto& userScript) {
+    m_userScripts->removeAllOfTypeMatching<API::UserScript>([&](const auto& userScript) {
         return &userScript->contentWorld() == &world;
     });
-
-    removeContentWorldUses(world, userScriptsRemoved);
 }
 
 void WebUserContentControllerProxy::removeAllUserScripts()
@@ -248,8 +229,6 @@
         process.send(Messages::WebUserContentController::RemoveAllUserScripts(worldIdentifiers), identifier());
 
     m_userScripts->elements().clear();
-
-    removeContentWorldUses(worlds);
 }
 
 void WebUserContentControllerProxy::addUserStyleSheet(API::UserStyleSheet& userStyleSheet)
@@ -256,7 +235,7 @@
 {
     Ref<API::ContentWorld> world = userStyleSheet.contentWorld();
 
-    addContentWorldUse(world.get());
+    addContentWorld(world.get());
 
     m_userStyleSheets->elements().append(&userStyleSheet);
 
@@ -272,8 +251,6 @@
         process.send(Messages::WebUserContentController::RemoveUserStyleSheet(world->identifier(), userStyleSheet.identifier()), identifier());
 
     m_userStyleSheets->elements().removeAll(&userStyleSheet);
-
-    removeContentWorldUses(world.get(), 1);
 }
 
 void WebUserContentControllerProxy::removeAllUserStyleSheets(API::ContentWorld& world)
@@ -281,11 +258,9 @@
     for (auto& process : m_processes)
         process.send(Messages::WebUserContentController::RemoveAllUserStyleSheets({ world.identifier() }), identifier());
 
-    unsigned userStyleSheetsRemoved = m_userStyleSheets->removeAllOfTypeMatching<API::UserStyleSheet>([&](const auto& userStyleSheet) {
+    m_userStyleSheets->removeAllOfTypeMatching<API::UserStyleSheet>([&](const auto& userStyleSheet) {
         return &userStyleSheet->contentWorld() == &world;
     });
-
-    removeContentWorldUses(world, userStyleSheetsRemoved);
 }
 
 void WebUserContentControllerProxy::removeAllUserStyleSheets()
@@ -303,8 +278,6 @@
         process.send(Messages::WebUserContentController::RemoveAllUserStyleSheets(worldIdentifiers), identifier());
 
     m_userStyleSheets->elements().clear();
-
-    removeContentWorldUses(worlds);
 }
 
 bool WebUserContentControllerProxy::addUserScriptMessageHandler(WebScriptMessageHandler& handler)
@@ -316,7 +289,7 @@
             return false;
     }
 
-    addContentWorldUse(world);
+    addContentWorld(world);
 
     m_scriptMessageHandlers.add(handler.identifier(), &handler);
 
@@ -335,7 +308,6 @@
 
             m_scriptMessageHandlers.remove(it);
 
-            removeContentWorldUses(world, 1);
             return;
         }
     }
@@ -354,8 +326,6 @@
         }
         return false;
     });
-
-    removeContentWorldUses(world, numberRemoved);
 }
 
 void WebUserContentControllerProxy::didPostMessage(IPC::Connection& connection, WebPageProxyIdentifier pageProxyID, FrameInfoData&& frameInfoData, uint64_t messageHandlerID, const IPC::DataReference& dataReference)

Modified: trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h (260329 => 260330)


--- trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Source/WebKit/UIProcess/UserContent/WebUserContentControllerProxy.h	2020-04-19 02:08:52 UTC (rev 260330)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "APIObject.h"
+#include "ContentWorldShared.h"
 #include "MessageReceiver.h"
 #include "UserContentControllerIdentifier.h"
 #include "WebPageProxyIdentifier.h"
@@ -93,8 +94,6 @@
     void removeAllUserStyleSheets(API::ContentWorld&);
     void removeAllUserStyleSheets();
 
-    void removeAllUserContent(API::ContentWorld&);
-
     // Returns false if there was a name conflict.
     bool addUserScriptMessageHandler(WebScriptMessageHandler&);
     void removeUserMessageHandlerForName(const String&, API::ContentWorld&);
@@ -113,6 +112,8 @@
 
     UserContentControllerIdentifier identifier() const { return m_identifier; }
 
+    void contentWorldDestroyed(API::ContentWorld&);
+
 private:
     // IPC::MessageReceiver.
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
@@ -119,10 +120,7 @@
 
     void didPostMessage(IPC::Connection&, WebPageProxyIdentifier, FrameInfoData&&, uint64_t messageHandlerID, const IPC::DataReference&);
 
-    void addContentWorldUse(API::ContentWorld&);
-    void removeContentWorldUses(API::ContentWorld&, unsigned numberOfUsesToRemove);
-    void removeContentWorldUses(HashCountedSet<RefPtr<API::ContentWorld>>&);
-    bool shouldSendRemoveContentWorldsMessage(API::ContentWorld&, unsigned numberOfUsesToRemove);
+    void addContentWorld(API::ContentWorld&);
 
     UserContentControllerIdentifier m_identifier;
     WeakHashSet<WebProcessProxy> m_processes;
@@ -129,7 +127,7 @@
     Ref<API::Array> m_userScripts;
     Ref<API::Array> m_userStyleSheets;
     HashMap<uint64_t, RefPtr<WebScriptMessageHandler>> m_scriptMessageHandlers;
-    HashCountedSet<RefPtr<API::ContentWorld>> m_contentWorlds;
+    HashSet<ContentWorldIdentifier> m_associatedContentWorlds;
 
 #if ENABLE(CONTENT_EXTENSIONS)
     WeakHashSet<NetworkProcessProxy> m_networkProcesses;

Modified: trunk/Tools/ChangeLog (260329 => 260330)


--- trunk/Tools/ChangeLog	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Tools/ChangeLog	2020-04-19 02:08:52 UTC (rev 260330)
@@ -1,3 +1,15 @@
+2020-04-18  Brady Eidson  <beid...@apple.com>
+
+        Fix WebUserContentControllerProxy vs ContentWorld lifetime
+        https://bugs.webkit.org/show_bug.cgi?id=210700
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm:
+        (-[DummyMessageHandler userContentController:didReceiveScriptMessage:]):
+        (TEST): Make sure removing a script message handler from a particular world
+          doesn't also destroy the other _javascript_ contents of that world.
+
 2020-04-18  Daniel Bates  <daba...@apple.com>
 
         Add some more tests for -focusTextInputContext:placeCaretAt:completionHandler:

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm (260329 => 260330)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm	2020-04-18 23:32:19 UTC (rev 260329)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm	2020-04-19 02:08:52 UTC (rev 260330)
@@ -34,11 +34,12 @@
 #import "TestURLSchemeHandler.h"
 #import "TestWKWebView.h"
 #import "WKWebViewConfigurationExtras.h"
-#import <WebKit/WKWebViewConfigurationPrivate.h>
-#import <WebKit/WKContentWorld.h>
+#import <WebKit/WKContentWorldPrivate.h>
 #import <WebKit/WKErrorPrivate.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKPreferencesRef.h>
+#import <WebKit/WKUserContentControllerPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/_WKFrameTreeNode.h>
 #import <wtf/RetainPtr.h>
@@ -133,6 +134,15 @@
     EXPECT_EQ(namedWorld, [WKContentWorld worldWithName:@"Name"]);
 }
 
+@interface DummyMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation DummyMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+}
+@end
+
 TEST(WKWebView, EvaluateJavaScriptInWorlds)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
@@ -185,8 +195,12 @@
     TestWebKitAPI::Util::run(&isDone);
     isDone = false;
 
-    // Set a varibale value in a named world.
+    // Add a scriptMessageHandler in a named world.
     RetainPtr<WKContentWorld> namedWorld = [WKContentWorld worldWithName:@"NamedWorld"];
+    id handler = [[[DummyMessageHandler alloc] init] autorelease];
+    [webView.get().configuration.userContentController _addScriptMessageHandler:handler name:@"testHandlerName" userContentWorld:namedWorld.get()._userContentWorld];
+
+    // Set a variable value in that named world.
     [webView evaluateJavaScript:@"var bar = 'baz'" inContentWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
         EXPECT_NULL(result);
         isDone = true;
@@ -195,7 +209,7 @@
     TestWebKitAPI::Util::run(&isDone);
     isDone = false;
 
-    // Set a global variable value in a named world via a function call.
+    // Set a global variable value in that named world via a function call.
     [webView callAsyncJavaScript:@"window.baz = 'bat'" arguments:nil inContentWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
         EXPECT_NULL(result);
         EXPECT_NULL(error);
@@ -205,7 +219,10 @@
     TestWebKitAPI::Util::run(&isDone);
     isDone = false;
 
-    // Verify they are there in that named world.
+    // Remove the dummy message handler
+    [webView.get().configuration.userContentController _removeScriptMessageHandlerForName:@"testHandlerName" userContentWorld:namedWorld.get()._userContentWorld];
+
+    // Verify the variables we set are there in that named world.
     [webView evaluateJavaScript:@"bar" inContentWorld:namedWorld.get() completionHandler:^(id result, NSError *error) {
         EXPECT_TRUE([result isKindOfClass:[NSString class]]);
         EXPECT_TRUE([result isEqualToString:@"baz"]);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to