Title: [251495] trunk
Revision
251495
Author
cdu...@apple.com
Date
2019-10-23 13:38:22 -0700 (Wed, 23 Oct 2019)

Log Message

FetchRequest should not prevent entering the back/forward cache
https://bugs.webkit.org/show_bug.cgi?id=203091
<rdar://problem/56525333>

Reviewed by Youenn Fablet.

Source/WebCore:

FetchRequest used to prevent the page from entering the back/forward cache while it had a blob
load in progress. We no longer prevent suspension in such case. Instead, if the document is
suspended when the blob load finishes, we post a task to the Window event loop to do the work
and resolve / reject the promise. The Window event loop makes sure not to delays tasks that
are associated with a document that is suspended.

Tests: fast/history/page-cache-active-fetch-request-blobReadAsBlob.html
       fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html
       fast/history/page-cache-active-fetch-request-blobReadAsText.html

* Modules/fetch/FetchBodyOwner.cpp:
(WebCore::FetchBodyOwner::runNetworkTaskWhenPossible):
(WebCore::FetchBodyOwner::blobLoadingSucceeded):
(WebCore::FetchBodyOwner::blobLoadingFailed):
(WebCore::FetchBodyOwner::blobChunk):
(WebCore::FetchBodyOwner::postSuspendableNetworkTask): Deleted.
* Modules/fetch/FetchBodyOwner.h:
* Modules/fetch/FetchRequest.cpp:
* Modules/fetch/FetchRequest.h:
* dom/AbstractEventLoop.h:

LayoutTests:

Add layout test coverage.

* TestExpectations:
* fast/history/page-cache-active-fetch-request-blobReadAsBlob-expected.txt: Added.
* fast/history/page-cache-active-fetch-request-blobReadAsBlob.html: Added.
* fast/history/page-cache-active-fetch-request-blobReadAsReadableStream-expected.txt: Added.
* fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html: Added.
* fast/history/page-cache-active-fetch-request-blobReadAsText-expected.txt: Added.
* fast/history/page-cache-active-fetch-request-blobReadAsText.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (251494 => 251495)


--- trunk/LayoutTests/ChangeLog	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/LayoutTests/ChangeLog	2019-10-23 20:38:22 UTC (rev 251495)
@@ -1,3 +1,21 @@
+2019-10-23  Chris Dumez  <cdu...@apple.com>
+
+        FetchRequest should not prevent entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=203091
+        <rdar://problem/56525333>
+
+        Reviewed by Youenn Fablet.
+
+        Add layout test coverage.
+
+        * TestExpectations:
+        * fast/history/page-cache-active-fetch-request-blobReadAsBlob-expected.txt: Added.
+        * fast/history/page-cache-active-fetch-request-blobReadAsBlob.html: Added.
+        * fast/history/page-cache-active-fetch-request-blobReadAsReadableStream-expected.txt: Added.
+        * fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html: Added.
+        * fast/history/page-cache-active-fetch-request-blobReadAsText-expected.txt: Added.
+        * fast/history/page-cache-active-fetch-request-blobReadAsText.html: Added.
+
 2019-10-23  Yury Semikhatsky  <yu...@chromium.org>
 
         Web Inspector: notify inspector when provisional page is created, committed and destroyed

Modified: trunk/LayoutTests/TestExpectations (251494 => 251495)


--- trunk/LayoutTests/TestExpectations	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/LayoutTests/TestExpectations	2019-10-23 20:38:22 UTC (rev 251495)
@@ -266,6 +266,9 @@
 fast/files/file-reader-back-forward-cache.html [ DumpJSConsoleLogInStdErr ]
 fast/history/page-cache-createImageBitmap.html [ DumpJSConsoleLogInStdErr ]
 http/tests/navigation/page-cache-xhr-in-loading-iframe.html [ DumpJSConsoleLogInStdErr ]
+fast/history/page-cache-active-fetch-request-blobReadAsBlob.html [ DumpJSConsoleLogInStdErr ]
+fast/history/page-cache-active-fetch-request-blobReadAsText.html [ DumpJSConsoleLogInStdErr ]
+fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html [ DumpJSConsoleLogInStdErr ]
 
 webkit.org/b/202495 imported/w3c/web-platform-tests/shadow-dom/directionality-002.tentative.html [ ImageOnlyFailure ]
 

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob-expected.txt (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob-expected.txt	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,14 @@
+Tests that a page with an active fetch request is able to enter the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+PASS Promise resolved after restoring from the back/forward cache.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob.html (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob.html	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsBlob.html	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,55 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description('Tests that a page with an active fetch request is able to enter the back/forward cache.');
+window.jsTestIsAsync = true;
+let restoredFromCache = false;
+
+window.addEventListener("pageshow", function(event) {
+    debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+
+    if (event.persisted) {
+        testPassed("Page did enter and was restored from the back/forward cache");
+        restoredFromCache = true;
+    }
+}, false);
+
+window.addEventListener("pagehide", function(event) {
+    debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+    if (!event.persisted) {
+        testFailed("Page did not enter the back/forward cache.");
+        finishJSTest();
+    }
+}, false);
+
+var textData = JSON.stringify("This is the body");
+
+function tryGetRequestBlob()
+{
+    blob = new Blob([textData], { "type" : "text/plain" });
+    request = new Request("", {"method": "POST", "body": blob });
+    request.blob().then(() => {
+        if (restoredFromCache) {
+            testPassed("Promise resolved after restoring from the back/forward cache.");
+            finishJSTest();
+            return;
+        }
+        setTimeout(tryGetRequestBlob, 0);
+    }, (e) => {
+        setTimeout(tryGetRequestBlob, 0);
+    });
+}
+
+window.addEventListener('load', function() {
+    setTimeout(() => {
+      tryGetRequestBlob();
+      window.location.href = ""
+    }, 0);
+}, false);
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream-expected.txt (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream-expected.txt	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,13 @@
+Tests that a page with an active fetch request is able to enter the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,55 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description('Tests that a page with an active fetch request is able to enter the back/forward cache.');
+window.jsTestIsAsync = true;
+let restoredFromCache = false;
+
+window.addEventListener("pageshow", function(event) {
+    debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+
+    if (event.persisted) {
+        testPassed("Page did enter and was restored from the back/forward cache");
+        restoredFromCache = true;
+        finishJSTest();
+    }
+}, false);
+
+window.addEventListener("pagehide", function(event) {
+    debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+    if (!event.persisted) {
+        testFailed("Page did not enter the back/forward cache.");
+        finishJSTest();
+    }
+}, false);
+
+var textData = JSON.stringify("This is the body");
+
+function tryGetRequestBlob()
+{
+    blob = new Blob([textData], { "type" : "text/plain" });
+    request = new Request("", {"method": "POST", "body": blob });
+    readableStream = request.body;
+    readableStream.getReader().read().then(() => {
+        if (restoredFromCache) {
+            return;
+        }
+        setTimeout(tryGetRequestBlob, 0);
+    }, (e) => {
+        setTimeout(tryGetRequestBlob, 0);
+    });
+}
+
+window.addEventListener('load', function() {
+    setTimeout(() => {
+      tryGetRequestBlob();
+      window.location.href = ""
+    }, 0);
+}, false);
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText-expected.txt (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText-expected.txt	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,15 @@
+Tests that a page with an active fetch request is able to enter the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+PASS Promise resolved after restoring from the back/forward cache.
+PASS text is "\"This is the body\""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText.html (0 => 251495)


--- trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText.html	                        (rev 0)
+++ trunk/LayoutTests/fast/history/page-cache-active-fetch-request-blobReadAsText.html	2019-10-23 20:38:22 UTC (rev 251495)
@@ -0,0 +1,57 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description('Tests that a page with an active fetch request is able to enter the back/forward cache.');
+window.jsTestIsAsync = true;
+let restoredFromCache = false;
+
+window.addEventListener("pageshow", function(event) {
+    debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+
+    if (event.persisted) {
+        testPassed("Page did enter and was restored from the back/forward cache");
+        restoredFromCache = true;
+    }
+}, false);
+
+window.addEventListener("pagehide", function(event) {
+    debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+    if (!event.persisted) {
+        testFailed("Page did not enter the back/forward cache.");
+        finishJSTest();
+    }
+}, false);
+
+var textData = JSON.stringify("This is the body");
+
+function tryGetRequestBlob()
+{
+    blob = new Blob([textData], { "type" : "text/plain" });
+    request = new Request("", {"method": "POST", "body": blob });
+    request.text().then((_text) => {
+        if (restoredFromCache) {
+            testPassed("Promise resolved after restoring from the back/forward cache.");
+            text = _text;
+            shouldBeEqualToString("text", "" + textData);
+            finishJSTest();
+            return;
+        }
+        setTimeout(tryGetRequestBlob, 0);
+    }, (e) => {
+        setTimeout(tryGetRequestBlob, 0);
+    });
+}
+
+window.addEventListener('load', function() {
+    setTimeout(() => {
+      tryGetRequestBlob();
+      window.location.href = ""
+    }, 0);
+}, false);
+
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (251494 => 251495)


--- trunk/Source/WebCore/ChangeLog	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/ChangeLog	2019-10-23 20:38:22 UTC (rev 251495)
@@ -1,3 +1,32 @@
+2019-10-23  Chris Dumez  <cdu...@apple.com>
+
+        FetchRequest should not prevent entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=203091
+        <rdar://problem/56525333>
+
+        Reviewed by Youenn Fablet.
+
+        FetchRequest used to prevent the page from entering the back/forward cache while it had a blob
+        load in progress. We no longer prevent suspension in such case. Instead, if the document is
+        suspended when the blob load finishes, we post a task to the Window event loop to do the work
+        and resolve / reject the promise. The Window event loop makes sure not to delays tasks that
+        are associated with a document that is suspended.
+
+        Tests: fast/history/page-cache-active-fetch-request-blobReadAsBlob.html
+               fast/history/page-cache-active-fetch-request-blobReadAsReadableStream.html
+               fast/history/page-cache-active-fetch-request-blobReadAsText.html
+
+        * Modules/fetch/FetchBodyOwner.cpp:
+        (WebCore::FetchBodyOwner::runNetworkTaskWhenPossible):
+        (WebCore::FetchBodyOwner::blobLoadingSucceeded):
+        (WebCore::FetchBodyOwner::blobLoadingFailed):
+        (WebCore::FetchBodyOwner::blobChunk):
+        (WebCore::FetchBodyOwner::postSuspendableNetworkTask): Deleted.
+        * Modules/fetch/FetchBodyOwner.h:
+        * Modules/fetch/FetchRequest.cpp:
+        * Modules/fetch/FetchRequest.h:
+        * dom/AbstractEventLoop.h:
+
 2019-10-23  Yury Semikhatsky  <yu...@chromium.org>
 
         Web Inspector: notify inspector when provisional page is created, committed and destroyed

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp (251494 => 251495)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp	2019-10-23 20:38:22 UTC (rev 251495)
@@ -34,9 +34,27 @@
 #include "JSBlob.h"
 #include "ResourceError.h"
 #include "ResourceResponse.h"
+#include "WindowEventLoop.h"
 
 namespace WebCore {
 
+void FetchBodyOwner::runNetworkTaskWhenPossible(Function<void()>&& task)
+{
+    auto* context = scriptExecutionContext();
+    if (!context || !scriptExecutionContext()->activeDOMObjectsAreSuspended())
+        return task();
+
+    if (is<Document>(*context)) {
+        downcast<Document>(*context).eventLoop().queueTask(TaskSource::Networking, *context, [pendingActivity = makePendingActivity(*this), task = WTFMove(task)] {
+            task();
+        });
+    } else {
+        context->postTask([pendingActivity = makePendingActivity(*this), task = WTFMove(task)](ScriptExecutionContext&) {
+            task();
+        });
+    }
+}
+
 FetchBodyOwner::FetchBodyOwner(ScriptExecutionContext& context, Optional<FetchBody>&& body, Ref<FetchHeaders>&& headers)
     : ActiveDOMObject(&context)
     , m_body(WTFMove(body))
@@ -268,13 +286,15 @@
 void FetchBodyOwner::blobLoadingSucceeded()
 {
     ASSERT(!isBodyNull());
+    runNetworkTaskWhenPossible([this]() mutable {
 #if ENABLE(STREAMS_API)
-    if (m_readableStreamSource) {
-        m_readableStreamSource->close();
-        m_readableStreamSource = nullptr;
-    }
+        if (m_readableStreamSource) {
+            m_readableStreamSource->close();
+            m_readableStreamSource = nullptr;
+        }
 #endif
-    m_body->loadingSucceeded();
+        m_body->loadingSucceeded();
+    });
     finishBlobLoading();
 }
 
@@ -281,15 +301,16 @@
 void FetchBodyOwner::blobLoadingFailed()
 {
     ASSERT(!isBodyNull());
+    runNetworkTaskWhenPossible([this]() mutable {
 #if ENABLE(STREAMS_API)
-    if (m_readableStreamSource) {
-        if (!m_readableStreamSource->isCancelling())
-            m_readableStreamSource->error(Exception { TypeError, "Blob loading failed"_s});
-        m_readableStreamSource = nullptr;
-    } else
+        if (m_readableStreamSource) {
+            if (!m_readableStreamSource->isCancelling())
+                m_readableStreamSource->error(Exception { TypeError, "Blob loading failed"_s});
+            m_readableStreamSource = nullptr;
+        } else
 #endif
-        m_body->loadingFailed(Exception { TypeError, "Blob loading failed"_s});
-
+            m_body->loadingFailed(Exception { TypeError, "Blob loading failed"_s});
+    });
     finishBlobLoading();
 }
 
@@ -298,8 +319,10 @@
     ASSERT(data);
 #if ENABLE(STREAMS_API)
     ASSERT(m_readableStreamSource);
-    if (!m_readableStreamSource->enqueue(ArrayBuffer::tryCreate(data, size)))
-        stop();
+    runNetworkTaskWhenPossible([this, arrayBuffer = ArrayBuffer::tryCreate(data, size)]() mutable {
+        if (!m_readableStreamSource->enqueue(WTFMove(arrayBuffer)))
+            stop();
+    });
 #else
     UNUSED_PARAM(data);
     UNUSED_PARAM(size);

Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h (251494 => 251495)


--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h	2019-10-23 20:38:22 UTC (rev 251495)
@@ -125,6 +125,8 @@
     Ref<FetchHeaders> m_headers;
 
 private:
+    void runNetworkTaskWhenPossible(Function<void()>&&);
+
     Optional<BlobLoader> m_blobLoader;
     bool m_isBodyOpaque { false };
 

Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp (251494 => 251495)


--- trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp	2019-10-23 20:38:22 UTC (rev 251495)
@@ -329,11 +329,5 @@
     return "Request";
 }
 
-bool FetchRequest::shouldPreventEnteringBackForwardCache_DEPRECATED() const
-{
-    // FIXME: This should never prevent entering the back/forward cache.
-    return isActive();
-}
-
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.h (251494 => 251495)


--- trunk/Source/WebCore/Modules/fetch/FetchRequest.h	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.h	2019-10-23 20:38:22 UTC (rev 251495)
@@ -92,7 +92,6 @@
     ExceptionOr<void> setBody(FetchRequest&);
 
     const char* activeDOMObjectName() const final;
-    bool shouldPreventEnteringBackForwardCache_DEPRECATED() const final;
 
     ResourceRequest m_request;
     FetchOptions m_options;

Modified: trunk/Source/WebCore/dom/AbstractEventLoop.h (251494 => 251495)


--- trunk/Source/WebCore/dom/AbstractEventLoop.h	2019-10-23 20:16:00 UTC (rev 251494)
+++ trunk/Source/WebCore/dom/AbstractEventLoop.h	2019-10-23 20:38:22 UTC (rev 251495)
@@ -34,6 +34,7 @@
 
 enum class TaskSource : uint8_t {
     IdleTask,
+    Networking,
 };
 
 // https://html.spec.whatwg.org/multipage/webappapis.html#event-loop
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to