Title: [251049] trunk
Revision
251049
Author
[email protected]
Date
2019-10-12 12:17:37 -0700 (Sat, 12 Oct 2019)

Log Message

Back/Forward cache does not work after doing a favorite navigation
https://bugs.webkit.org/show_bug.cgi?id=202762
<rdar://problem/56126911>

Reviewed by Antti Koivisto.

Source/WebCore:

When a subframe goes into the page cache, make sure we null out the opener
link of any windows that were opened by this frame. This matches what would
happened if this frame were closed.

Covered by the following API tests:
ProcessSwap.PageCacheAfterProcessSwapByClient
ProcessSwap.OpenerLinkAfterAPIControlledProcessSwappingOfOpener

* history/CachedFrame.cpp:
(WebCore::CachedFrame::CachedFrame):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::~FrameLoader):
(WebCore::FrameLoader::detachFromAllOpenedFrames):
* loader/FrameLoader.h:

Source/WebKit:

When a process-swap was forced by the client, we would always close the page in the previous
process after navigating. This would prevent leveraging the back/forward cache when navigating
back after such a process-swap. The reason we were doing this is that other pages may have
opener link to this page and closing the page was an easy way to break this opener link.

To address the issue, we no longer close the previous page when a process-swap is forced by the
client. Instead, we make sure to disconnect the frames' openees from their opener then the opener
enters the page cache.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::suspendCurrentPageIfPossible):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::suspendForProcessSwap):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (251048 => 251049)


--- trunk/Source/WebCore/ChangeLog	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebCore/ChangeLog	2019-10-12 19:17:37 UTC (rev 251049)
@@ -1,3 +1,26 @@
+2019-10-12  Chris Dumez  <[email protected]>
+
+        Back/Forward cache does not work after doing a favorite navigation
+        https://bugs.webkit.org/show_bug.cgi?id=202762
+        <rdar://problem/56126911>
+
+        Reviewed by Antti Koivisto.
+
+        When a subframe goes into the page cache, make sure we null out the opener
+        link of any windows that were opened by this frame. This matches what would
+        happened if this frame were closed.
+
+        Covered by the following API tests:
+        ProcessSwap.PageCacheAfterProcessSwapByClient
+        ProcessSwap.OpenerLinkAfterAPIControlledProcessSwappingOfOpener
+
+        * history/CachedFrame.cpp:
+        (WebCore::CachedFrame::CachedFrame):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::~FrameLoader):
+        (WebCore::FrameLoader::detachFromAllOpenedFrames):
+        * loader/FrameLoader.h:
+
 2019-10-12  Chris Fleizach  <[email protected]>
 
         AX: Make AXIsolatedTree compile again

Modified: trunk/Source/WebCore/history/CachedFrame.cpp (251048 => 251049)


--- trunk/Source/WebCore/history/CachedFrame.cpp	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebCore/history/CachedFrame.cpp	2019-10-12 19:17:37 UTC (rev 251049)
@@ -179,6 +179,10 @@
     // 'DidFirstVisuallyNonEmptyLayout' callback gets called against when restoring from PageCache.
     m_view->resetLayoutMilestones();
 
+    // The main frame is reused for the navigation and the opener link to its should thus persist.
+    if (!frame.isMainFrame())
+        frame.loader().detachFromAllOpenedFrames();
+
     frame.loader().client().savePlatformDataToCachedFrame(this);
 
     // documentWillSuspendForPageCache() can set up a layout timer on the FrameView, so clear timers after that.

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (251048 => 251049)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2019-10-12 19:17:37 UTC (rev 251049)
@@ -297,10 +297,8 @@
 FrameLoader::~FrameLoader()
 {
     setOpener(nullptr);
+    detachFromAllOpenedFrames();
 
-    for (auto& frame : m_openedFrames)
-        frame->loader().m_opener = nullptr;
-
     m_client.frameLoaderDestroyed();
 
     if (m_networkingContext)
@@ -307,6 +305,13 @@
         m_networkingContext->invalidate();
 }
 
+void FrameLoader::detachFromAllOpenedFrames()
+{
+    for (auto& frame : m_openedFrames)
+        frame->loader().m_opener = nullptr;
+    m_openedFrames.clear();
+}
+
 void FrameLoader::init()
 {
     // This somewhat odd set of steps gives the frame an initial empty document.

Modified: trunk/Source/WebCore/loader/FrameLoader.h (251048 => 251049)


--- trunk/Source/WebCore/loader/FrameLoader.h	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebCore/loader/FrameLoader.h	2019-10-12 19:17:37 UTC (rev 251049)
@@ -253,6 +253,7 @@
 
     WEBCORE_EXPORT Frame* opener();
     WEBCORE_EXPORT void setOpener(Frame*);
+    WEBCORE_EXPORT void detachFromAllOpenedFrames();
     bool hasOpenedFrames() const { return !m_openedFrames.isEmpty(); }
 
     void resetMultipleFormSubmissionProtection();

Modified: trunk/Source/WebKit/ChangeLog (251048 => 251049)


--- trunk/Source/WebKit/ChangeLog	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebKit/ChangeLog	2019-10-12 19:17:37 UTC (rev 251049)
@@ -1,5 +1,27 @@
 2019-10-12  Chris Dumez  <[email protected]>
 
+        Back/Forward cache does not work after doing a favorite navigation
+        https://bugs.webkit.org/show_bug.cgi?id=202762
+        <rdar://problem/56126911>
+
+        Reviewed by Antti Koivisto.
+
+        When a process-swap was forced by the client, we would always close the page in the previous
+        process after navigating. This would prevent leveraging the back/forward cache when navigating
+        back after such a process-swap. The reason we were doing this is that other pages may have
+        opener link to this page and closing the page was an easy way to break this opener link.
+
+        To address the issue, we no longer close the previous page when a process-swap is forced by the
+        client. Instead, we make sure to disconnect the frames' openees from their opener then the opener
+        enters the page cache.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::suspendCurrentPageIfPossible):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::suspendForProcessSwap):
+
+2019-10-12  Chris Dumez  <[email protected]>
+
         Clearing Website data for a given session should not shut down cached processes for other sessions
         https://bugs.webkit.org/show_bug.cgi?id=202865
         <rdar://problem/56202912>

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (251048 => 251049)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2019-10-12 19:17:37 UTC (rev 251049)
@@ -796,11 +796,6 @@
 
     LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, identifier().toUInt64(), suspendedPage->loggingString(), m_process->processIdentifier(), fromItem ? fromItem->itemID().logString() : 0);
 
-    // If the client forced a swap then it may not be web-compatible to keep the previous page because other windows may have an opener link to it. We thus close it as soon as we
-    // can do so without flashing.
-    if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
-        suspendedPage->closeWithoutFlashing();
-
     m_lastSuspendedPage = makeWeakPtr(*suspendedPage);
 
     if (fromItem && shouldUseBackForwardCache())

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (251048 => 251049)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-10-12 19:17:37 UTC (rev 251049)
@@ -1491,6 +1491,12 @@
         return;
     }
 
+    // Page cache does not break the opener link for the main frame (only does so for the subframes) because the
+    // main frame is normally re-used for the navigation. However, in the case of process-swapping, the main frame
+    // is now hosted in another process and the one in this process is in the cache.
+    if (m_mainFrame && m_mainFrame->coreFrame())
+        m_mainFrame->coreFrame()->loader().detachFromAllOpenedFrames();
+
     send(Messages::WebPageProxy::DidSuspendAfterProcessSwap());
 }
 

Modified: trunk/Tools/ChangeLog (251048 => 251049)


--- trunk/Tools/ChangeLog	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Tools/ChangeLog	2019-10-12 19:17:37 UTC (rev 251049)
@@ -1,3 +1,15 @@
+2019-10-12  Chris Dumez  <[email protected]>
+
+        Back/Forward cache does not work after doing a favorite navigation
+        https://bugs.webkit.org/show_bug.cgi?id=202762
+        <rdar://problem/56126911>
+
+        Reviewed by Antti Koivisto.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2019-10-12  Ryosuke Niwa  <[email protected]>
 
         requestIdleCallback cannot be enabled in DumpRenderTree on Windows

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (251048 => 251049)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2019-10-12 16:17:52 UTC (rev 251048)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2019-10-12 19:17:37 UTC (rev 251049)
@@ -3224,6 +3224,82 @@
     EXPECT_EQ(2u, seenPIDs.size());
 }
 
+TEST(ProcessSwap, PageCacheAfterProcessSwapByClient)
+{
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
+    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+
+    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [webViewConfiguration setProcessPool:processPool.get()];
+    auto handler = adoptNS([[PSONScheme alloc] init]);
+    [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:pageCache1Bytes];
+    [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:pageCache1Bytes];
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
+
+    auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
+    [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
+
+    [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterLoad1 = [webView _webProcessIdentifier];
+
+    EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
+
+    // We force a proces-swap via client API.
+    delegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) {
+        decisionHandler(_WKNavigationActionPolicyAllowInNewProcess);
+    };
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
+
+    [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterLoad2 = [webView _webProcessIdentifier];
+
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
+    EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
+
+    delegate->decidePolicyForNavigationAction = nil;
+
+    [webView goBack];
+    TestWebKitAPI::Util::run(&receivedMessage);
+    receivedMessage = false;
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterLoad3 = [webView _webProcessIdentifier];
+
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
+    EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
+    EXPECT_EQ(1u, [receivedMessages count]);
+    EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
+    EXPECT_EQ(2u, seenPIDs.size());
+
+    [webView goForward];
+    TestWebKitAPI::Util::run(&receivedMessage);
+    receivedMessage = false;
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterLoad4 = [webView _webProcessIdentifier];
+
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
+    EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
+    EXPECT_EQ(2u, [receivedMessages count]);
+    EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
+    EXPECT_EQ(2u, seenPIDs.size());
+}
+
 TEST(ProcessSwap, PageCacheWhenNavigatingFromJS)
 {
     auto processPoolConfiguration = psonProcessPoolConfiguration();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to