Title: [265510] trunk
Revision
265510
Author
[email protected]
Date
2020-08-11 12:52:31 -0700 (Tue, 11 Aug 2020)

Log Message

Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
https://bugs.webkit.org/show_bug.cgi?id=215382
rdar://problem/66837802

Reviewed by Sam Weinig.

Source/WebCore:

When defering a script in a frame it was previously added to a vector per-page.
Later when notified to inject the defered scripts, the page would iterate over all
the frames and evaluate the scripts on each frame. Since this vector had all the
frame's scripts the evaluations would be multiplied by the number of frames.

Now the defered scripts are stored per-frame and the page asks each frame to
inject the defered scripts.

* page/Frame.cpp:
(WebCore::Frame::injectUserScripts):
(WebCore::Frame::addUserScriptAwaitingNotification):
(WebCore::Frame::injectUserScriptsAwaitingNotification):
* page/Frame.h:
* page/Page.cpp:
(WebCore::Page::notifyToInjectUserScripts):
(WebCore::Page::addUserScriptAwaitingNotification): Deleted.
* page/Page.h:
* page/Quirks.cpp:
(WebCore::Quirks::triggerOptionalStorageAccessQuirk const):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm:
(TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (265509 => 265510)


--- trunk/Source/WebCore/ChangeLog	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/ChangeLog	2020-08-11 19:52:31 UTC (rev 265510)
@@ -1,3 +1,31 @@
+2020-08-11  Timothy Hatcher  <[email protected]>
+
+        Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
+        https://bugs.webkit.org/show_bug.cgi?id=215382
+        rdar://problem/66837802
+
+        Reviewed by Sam Weinig.
+
+        When defering a script in a frame it was previously added to a vector per-page.
+        Later when notified to inject the defered scripts, the page would iterate over all
+        the frames and evaluate the scripts on each frame. Since this vector had all the
+        frame's scripts the evaluations would be multiplied by the number of frames.
+
+        Now the defered scripts are stored per-frame and the page asks each frame to
+        inject the defered scripts.
+
+        * page/Frame.cpp:
+        (WebCore::Frame::injectUserScripts):
+        (WebCore::Frame::addUserScriptAwaitingNotification):
+        (WebCore::Frame::injectUserScriptsAwaitingNotification):
+        * page/Frame.h:
+        * page/Page.cpp:
+        (WebCore::Page::notifyToInjectUserScripts):
+        (WebCore::Page::addUserScriptAwaitingNotification): Deleted.
+        * page/Page.h:
+        * page/Quirks.cpp:
+        (WebCore::Quirks::triggerOptionalStorageAccessQuirk const):
+
 2020-08-11  Wenson Hsieh  <[email protected]>
 
         Text input autocorrect="off" attribute ignored on Mac

Modified: trunk/Source/WebCore/page/Frame.cpp (265509 => 265510)


--- trunk/Source/WebCore/page/Frame.cpp	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Frame.cpp	2020-08-11 19:52:31 UTC (rev 265510)
@@ -648,7 +648,7 @@
     m_page->userContentProvider().forEachUserScript([this, protectedThis = makeRef(*this), injectionTime, pageWasNotified] (DOMWrapperWorld& world, const UserScript& script) {
         if (script.injectionTime() == injectionTime) {
             if (script.waitForNotificationBeforeInjecting() == WaitForNotificationBeforeInjecting::Yes && !pageWasNotified)
-                m_page->addUserScriptAwaitingNotification(world, script);
+                addUserScriptAwaitingNotification(world, script);
             else
                 injectUserScriptImmediately(world, script);
         }
@@ -680,6 +680,17 @@
     m_script->evaluateInWorldIgnoringException(ScriptSourceCode(script.source(), URL(script.url())), world);
 }
 
+void Frame::addUserScriptAwaitingNotification(DOMWrapperWorld& world, const UserScript& script)
+{
+    m_userScriptsAwaitingNotification.append({ makeRef(world), makeUniqueRef<UserScript>(script) });
+}
+
+void Frame::injectUserScriptsAwaitingNotification()
+{
+    for (const auto& [world, script] : std::exchange(m_userScriptsAwaitingNotification, { }))
+        injectUserScriptImmediately(world, script.get());
+}
+
 Optional<PageIdentifier> Frame::pageID() const
 {
     return loader().pageID();

Modified: trunk/Source/WebCore/page/Frame.h (265509 => 265510)


--- trunk/Source/WebCore/page/Frame.h	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Frame.h	2020-08-11 19:52:31 UTC (rev 265510)
@@ -198,7 +198,10 @@
 
     WEBCORE_EXPORT void injectUserScripts(UserScriptInjectionTime);
     WEBCORE_EXPORT void injectUserScriptImmediately(DOMWrapperWorld&, const UserScript&);
-    
+
+    void injectUserScriptsAwaitingNotification();
+    void addUserScriptAwaitingNotification(DOMWrapperWorld&, const UserScript&);
+
     WEBCORE_EXPORT String layerTreeAsText(LayerTreeFlags = 0) const;
     WEBCORE_EXPORT String trackedRepaintRectsAsText() const;
 
@@ -328,6 +331,8 @@
 
     HashSet<FrameDestructionObserver*> m_destructionObservers;
 
+    Vector<std::pair<Ref<DOMWrapperWorld>, UniqueRef<UserScript>>> m_userScriptsAwaitingNotification;
+
     Frame& m_mainFrame;
     Page* m_page;
     const RefPtr<Settings> m_settings;

Modified: trunk/Source/WebCore/page/Page.cpp (265509 => 265510)


--- trunk/Source/WebCore/page/Page.cpp	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Page.cpp	2020-08-11 19:52:31 UTC (rev 265510)
@@ -2673,19 +2673,10 @@
 {
     m_hasBeenNotifiedToInjectUserScripts = true;
 
-    for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        for (const auto& pair : m_userScriptsAwaitingNotification)
-            frame->injectUserScriptImmediately(pair.first, pair.second.get());
-    }
-
-    m_userScriptsAwaitingNotification.clear();
+    for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
+        frame->injectUserScriptsAwaitingNotification();
 }
 
-void Page::addUserScriptAwaitingNotification(DOMWrapperWorld& world, const UserScript& script)
-{
-    m_userScriptsAwaitingNotification.append({ makeRef(world), makeUniqueRef<UserScript>(script) });
-}
-
 void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider)
 {
     m_userContentProvider->removePage(*this);

Modified: trunk/Source/WebCore/page/Page.h (265509 => 265510)


--- trunk/Source/WebCore/page/Page.h	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Page.h	2020-08-11 19:52:31 UTC (rev 265510)
@@ -775,7 +775,6 @@
 
     bool hasBeenNotifiedToInjectUserScripts() const { return m_hasBeenNotifiedToInjectUserScripts; }
     WEBCORE_EXPORT void notifyToInjectUserScripts();
-    void addUserScriptAwaitingNotification(DOMWrapperWorld&, const UserScript&);
 
 private:
     struct Navigation {
@@ -1070,7 +1069,6 @@
     bool m_loadsFromNetwork { true };
     ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
     bool m_hasBeenNotifiedToInjectUserScripts { false };
-    Vector<std::pair<Ref<DOMWrapperWorld>, UniqueRef<UserScript>>> m_userScriptsAwaitingNotification;
 };
 
 inline PageGroup& Page::group()

Modified: trunk/Source/WebCore/page/Quirks.cpp (265509 => 265510)


--- trunk/Source/WebCore/page/Quirks.cpp	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Quirks.cpp	2020-08-11 19:52:31 UTC (rev 265510)
@@ -965,11 +965,9 @@
             auto* abstractFrame = proxy->frame();
             if (abstractFrame && is<Frame>(*abstractFrame)) {
                 auto& frame = downcast<Frame>(*abstractFrame);
-                if (auto* page = frame.page()) {
-                    auto world = ScriptController::createWorld("kinjaComQuirkWorld", ScriptController::WorldType::User);
-                    page->addUserScriptAwaitingNotification(world.get(), kinjaLoginUserScript);
-                    return Quirks::StorageAccessResult::ShouldCancelEvent;
-                }
+                auto world = ScriptController::createWorld("kinjaComQuirkWorld", ScriptController::WorldType::User);
+                frame.addUserScriptAwaitingNotification(world.get(), kinjaLoginUserScript);
+                return Quirks::StorageAccessResult::ShouldCancelEvent;
             }
         }
     }

Modified: trunk/Tools/ChangeLog (265509 => 265510)


--- trunk/Tools/ChangeLog	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Tools/ChangeLog	2020-08-11 19:52:31 UTC (rev 265510)
@@ -1,3 +1,14 @@
+2020-08-11  Timothy Hatcher  <[email protected]>
+
+        Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
+        https://bugs.webkit.org/show_bug.cgi?id=215382
+        rdar://problem/66837802
+
+        Reviewed by Sam Weinig.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm:
+        (TEST):
+
 2020-08-11  Sihui Liu  <[email protected]>
 
         Text manipulation crashes when replacing element with img role

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm (265509 => 265510)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm	2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm	2020-08-11 19:52:31 UTC (rev 265510)
@@ -945,6 +945,18 @@
     EXPECT_FALSE(webView3._deferrableUserScriptsNeedNotification);
     EXPECT_WK_STREQ([delegate waitForAlert], "waited for notification");
     EXPECT_WK_STREQ([delegate waitForAlert], "document parsing ended");
+
+    TestWKWebView *webView4 = [[TestWKWebView new] autorelease];
+    EXPECT_TRUE(webView4._deferrableUserScriptsNeedNotification);
+    [webView4.configuration.userContentController addUserScript:waitsForNotification];
+    [webView4.configuration.userContentController addUserScript:documentEnd];
+    webView4.UIDelegate = delegate;
+    [webView4 loadTestPageNamed:@"simple-iframe"];
+    [webView4 _notifyUserScripts];
+
+    // If this is broken, two alerts would appear back-to-back with the same text due to the frame.
+    EXPECT_WK_STREQ([delegate waitForAlert], "waited for notification");
+    EXPECT_WK_STREQ([delegate waitForAlert], "document parsing ended");
 }
 
 @interface AsyncScriptMessageHandler : NSObject <WKScriptMessageHandlerWithReply>
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to