Title: [232419] trunk
Revision
232419
Author
[email protected]
Date
2018-06-01 15:30:02 -0700 (Fri, 01 Jun 2018)

Log Message

ResourceLoader::cancel() shouldn't synchronously fire load event on document
https://bugs.webkit.org/show_bug.cgi?id=185284
Source/WebCore:

Reviewed by Antti Koivisto.

Because a resource loading can be canceled as a node is removed a document or CachedResource is destructed,
it's not safe to synchronously fire load event on document upon cancelation. This patch makes the cancellation
of a resource load schedule m_checkTimer in FrameLoader to fire a load event asynchronously instead.

Specifically, this patch makes FrameLoader::loadDone call FrameLoader::scheduleCheckCompleted when the load
had failed or cancled instead of calling FrameLoader::checkCompleted which can synchronously fire load event.
To differentiate the two cases, new enum LoadCompletionType has been added to FrameLoader::loadDone and related
functions. To avoid calling the navigation delegate too early, the same abstraction for checkLoadComplete()
has been added in the form of FrameLoader::subresourceLoadDone.

Unfortunately, delaying calls to checkCompleted() and checkLoadComplete() by a timer can result in client
callbacks such as didFinishLoadForFrame and didFailLoadWithError to never get called when the frame gets
detached from the parent after the last resource had stopped loading but before the timer fires. To preserve
these deleagte callbacks, this patch expedites the timer in FrameLoader::frameDetached and Page::goToItem by
by invoking newly added stopAllLoadersAndCheckCompleteness, which stops all loading and then immediately invokes
checkCompleted() and checkLoadComplete() synchronously if m_checkTimer had been started.

Tests: http/tests/preload/dynamic_removing_preload.html

* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::beginLoadTimerFired): Removed superfluous call to checkLoadComplete since
cachedResourceLoader's loadDone would call checkLoadComplete anyway.
* html/HTMLFrameOwnerElement.cpp:
(WebCore::HTMLFrameOwnerElement::disconnectContentFrame): Removed the misleading comment added in r140090.
Firefox DOES indeed fire unload event in the content document of a removed frame. While this comment made
it sound like this function isn't called when a frame is removed from the tree when in reality we simply
remove a frame prior to removing the node via disconnectSubframesIfNeeded.
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::removeSubresourceLoader):
* loader/DocumentLoader.h:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::FrameLoader):
(WebCore::FrameLoader::loadDone):
(WebCore::FrameLoader::subresourceLoadDone):
(WebCore::FrameLoader::checkCompleted): Added a release assert that this function is only called when it's safe
to execute scripts.
(WebCore::FrameLoader::checkTimerFired):
(WebCore::FrameLoader::checkCompletenessNow):Extracted from checkTimerFired.
(WebCore::FrameLoader::stopAllLoaders): Removed the code to stop m_checkTimer introduced in r53655.
Stopping the timer here would prevent FrameLoader::frameDetached to detect the case when stopping the loader
scheduled a load completion check. Also stopping this timer without clearing the corresponding booleans:
m_checkingLoadCompleteForDetachment and m_checkingLoadCompleteForDetachment is problematic. The assertion
r53655 addressed is now addressed by explicitly checking & clearing the timer in frameDetached.
(WebCore::FrameLoader::stopAllLoadersAndCheckCompleteness): Added.
(WebCore::FrameLoader::checkLoadCompleteForThisFrame): Avoid an early exit when the newly added boolean
m_checkingLoadCompleteForDetachment is set since m_isStopping is no longer set in frameDetached in order
to invoke didFailLoadWithError when detaching a frame.
(WebCore::FrameLoader::frameDetached): Call checkCompletenessNow in the case the frame had already been
completed loading. Also call stopAllLoadersAndCheckCompleteness in the case stopping loading would complete
the loading before stopping active DOM objects.
* loader/FrameLoader.h:
(WebCore::FrameLoader::m_checkingLoadCompleteForDetachment): Added.
* loader/FrameLoaderTypes.h:
(WebCore::LoadCompletionType): Added.
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::didFinishLoading):
(WebCore::SubresourceLoader::didFail):
(WebCore::SubresourceLoader::didCancel):
(WebCore::SubresourceLoader::notifyDone):
* loader/SubresourceLoader.h:
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::loadDone):
* loader/cache/CachedResourceLoader.h:
* page/Page.cpp:
(WebCore::Page::goToItem): Call stopAllLoadersAndCheckCompleteness instead of stopAllLoaders since stopping
loading here may complete loading.

LayoutTests:

<rdar://problem/39994507>

Reviewed by Antti Koivisto.

Fixed the tests as needed, and skipped more drag & drop tests in WebKitTestRunner as drag & drop isn't supported.

* editing/pasteboard/drag-image-to-contenteditable-in-iframe.html: Fixed the test. Explicitly invoke
testRunner.waitUntilDone() to wait until the iframe is loaded. Because "load" event in DOM only fires after
all subframes are loaded but the load delegate callback fires as long as subresources in the main frame
had finished loading, DumpRenderTree would finish the test prematurely otherwise. The old code happens to
work before this patch because we happen to not invoke FrameLoader::checkComplete at the "right" moment.
The WebCore change now triggers such a check and prematurely end the test without this fix to the test.
* http/tests/xmlhttprequest/reentrant-cancel-expected.txt:
* http/tests/xmlhttprequest/reentrant-cancel.html: Canceling XHR inside addElement is no longer
firing load event synchronously as expected. Added a code to end the test after the load event.
* http/wpt/service-workers/clone-opaque-being-loaded-response.html:
* platform/mac-wk2/TestExpectations:
* platform/wk2/TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (232418 => 232419)


--- trunk/LayoutTests/ChangeLog	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/ChangeLog	2018-06-01 22:30:02 UTC (rev 232419)
@@ -1,3 +1,26 @@
+2018-06-01  Ryosuke Niwa  <[email protected]>
+
+        ResourceLoader::cancel() shouldn't synchronously fire load event on document
+        https://bugs.webkit.org/show_bug.cgi?id=185284
+        <rdar://problem/39994507>
+
+        Reviewed by Antti Koivisto.
+
+        Fixed the tests as needed, and skipped more drag & drop tests in WebKitTestRunner as drag & drop isn't supported.
+
+        * editing/pasteboard/drag-image-to-contenteditable-in-iframe.html: Fixed the test. Explicitly invoke
+        testRunner.waitUntilDone() to wait until the iframe is loaded. Because "load" event in DOM only fires after
+        all subframes are loaded but the load delegate callback fires as long as subresources in the main frame
+        had finished loading, DumpRenderTree would finish the test prematurely otherwise. The old code happens to
+        work before this patch because we happen to not invoke FrameLoader::checkComplete at the "right" moment.
+        The WebCore change now triggers such a check and prematurely end the test without this fix to the test.
+        * http/tests/xmlhttprequest/reentrant-cancel-expected.txt:
+        * http/tests/xmlhttprequest/reentrant-cancel.html: Canceling XHR inside addElement is no longer
+        firing load event synchronously as expected. Added a code to end the test after the load event.
+        * http/wpt/service-workers/clone-opaque-being-loaded-response.html:
+        * platform/mac-wk2/TestExpectations:
+        * platform/wk2/TestExpectations:
+
 2018-05-31  Ryosuke Niwa  <[email protected]>
 
         Some tests for webkitdirectory API fail when tests are in an APFS file system

Modified: trunk/LayoutTests/editing/pasteboard/drag-image-to-contenteditable-in-iframe.html (232418 => 232419)


--- trunk/LayoutTests/editing/pasteboard/drag-image-to-contenteditable-in-iframe.html	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/editing/pasteboard/drag-image-to-contenteditable-in-iframe.html	2018-06-01 22:30:02 UTC (rev 232419)
@@ -10,14 +10,15 @@
     li.appendChild(text);
 }
 
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
 function runTest() {
     if (!window.testRunner) {
         log("To run this test manually attempt to drag and drop Abe after the broken image in the editable div");
         return;
     }
-
-    testRunner.waitUntilDone();
-
+    
     //find abe
     var dragme = document.getElementById("dragme");
     x1 = dragme.offsetLeft + 20;
@@ -34,8 +35,14 @@
     eventSender.leapForward(500);
     eventSender.mouseMoveTo(x2, y2);
     eventSender.mouseUp();
-    
-    testRunner.notifyDone();
+
+    if (window.testRunner) {
+        var pasted_image = drag_target.contentDocument.querySelector('.target');
+        if (pasted_image.complete)
+            testRunner.notifyDone();
+        else
+            pasted_image._onload_ = function () { testRunner.notifyDone(); }
+    }
 }
 
 </script>
@@ -44,7 +51,7 @@
 <body _onload_="runTest()">
     <p>This tests that we can drag an image into the last position of a content editable div in an iframe that already contains an image, without crashing.</p>
     
-    <img id="dragme" src=""
+    <img id="dragme" class="target" src=""
     <iframe id="drag_target" src=""
     <ul id="console"></ul>
 </body>

Modified: trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel-expected.txt (232418 => 232419)


--- trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel-expected.txt	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel-expected.txt	2018-06-01 22:30:02 UTC (rev 232419)
@@ -1 +1,4 @@
+CONSOLE MESSAGE: line 16: Sending XHR
+CONSOLE MESSAGE: line 16: Sending XHR
+CONSOLE MESSAGE: line 16: Sending XHR
 XThis tests that when we re-entrantly create and cancel XHRs, we don't try to disconnect the same CachedResourceClient multiple times from its CachedResource. We pass if we don't crash. XX

Modified: trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel.html (232418 => 232419)


--- trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel.html	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/reentrant-cancel.html	2018-06-01 22:30:02 UTC (rev 232419)
@@ -13,6 +13,7 @@
 var xhr = new XMLHttpRequest;
 function sendXHR()
 {
+    console.log('Sending XHR');
     xhr.open("GET", "", true);
     try {
         xhr.send();
@@ -28,6 +29,10 @@
 }
 window.addEventListener("DOMSubtreeModified", sendXHR);
 addElement();
+window.addEventListener('load', () => setTimeout(() => {
+    if (window.testRunner)
+        testRunner.notifyDone();
+}, 0));
 </script>
 This tests that when we re-entrantly create and cancel XHRs, we don't try to disconnect the same CachedResourceClient
 multiple times from its CachedResource. We pass if we don't crash.

Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (232418 => 232419)


--- trunk/LayoutTests/platform/mac-wk2/TestExpectations	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations	2018-06-01 22:30:02 UTC (rev 232419)
@@ -84,24 +84,6 @@
 editing/pasteboard/4947130.html
 editing/pasteboard/cleanup-on-move.html
 editing/pasteboard/copy-standalone-image-crash.html
-editing/pasteboard/drag-and-drop-image-contenteditable.html
-editing/pasteboard/drag-and-drop-inputimage-contenteditable.html
-editing/pasteboard/drag-and-drop-objectimage-contenteditable.html
-editing/pasteboard/drag-drop-copy-content.html
-editing/pasteboard/drag-drop-dead-frame.html
-editing/pasteboard/drag-drop-input-textarea.html
-editing/pasteboard/drag-drop-list.html
-editing/pasteboard/drag-drop-modifies-page.html
-editing/pasteboard/drag-drop-url-text.html
-editing/pasteboard/drag-image-in-about-blank-frame.html
-editing/pasteboard/drag-image-to-contenteditable-in-iframe.html
-editing/pasteboard/drag-list-item.html
-editing/pasteboard/drag-selected-image-to-contenteditable.html
-editing/pasteboard/drop-file-svg.html
-editing/pasteboard/drop-inputtext-acquires-style.html
-editing/pasteboard/drop-link.html
-editing/pasteboard/drop-text-events.html
-editing/pasteboard/drop-text-without-selection.html
 editing/pasteboard/emacs-cntl-y-001.html
 editing/pasteboard/emacs-ctrl-k-y-001.html
 editing/pasteboard/files-during-page-drags.html

Modified: trunk/LayoutTests/platform/wk2/TestExpectations (232418 => 232419)


--- trunk/LayoutTests/platform/wk2/TestExpectations	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/LayoutTests/platform/wk2/TestExpectations	2018-06-01 22:30:02 UTC (rev 232419)
@@ -565,6 +565,24 @@
 # https://bugs.webkit.org/show_bug.cgi?id=64285
 editing/pasteboard/datatransfer-items-drop-plaintext-file.html
 editing/pasteboard/datatransfer-types-dropping-text-file.html
+editing/pasteboard/drag-and-drop-image-contenteditable.html
+editing/pasteboard/drag-and-drop-inputimage-contenteditable.html
+editing/pasteboard/drag-and-drop-objectimage-contenteditable.html
+editing/pasteboard/drag-drop-copy-content.html
+editing/pasteboard/drag-drop-dead-frame.html
+editing/pasteboard/drag-drop-input-textarea.html
+editing/pasteboard/drag-drop-list.html
+editing/pasteboard/drag-drop-modifies-page.html
+editing/pasteboard/drag-drop-url-text.html
+editing/pasteboard/drag-image-in-about-blank-frame.html
+editing/pasteboard/drag-image-to-contenteditable-in-iframe.html
+editing/pasteboard/drag-list-item.html
+editing/pasteboard/drag-selected-image-to-contenteditable.html
+editing/pasteboard/drop-file-svg.html
+editing/pasteboard/drop-inputtext-acquires-style.html
+editing/pasteboard/drop-link.html
+editing/pasteboard/drop-text-events.html
+editing/pasteboard/drop-text-without-selection.html
 editing/pasteboard/entries-api
 editing/pasteboard/file-drag-to-editable.html [ Skip ]
 editing/pasteboard/file-input-files-access.html

Modified: trunk/Source/WebCore/ChangeLog (232418 => 232419)


--- trunk/Source/WebCore/ChangeLog	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/ChangeLog	2018-06-01 22:30:02 UTC (rev 232419)
@@ -1,3 +1,77 @@
+2018-06-01  Ryosuke Niwa  <[email protected]>
+
+        ResourceLoader::cancel() shouldn't synchronously fire load event on document
+        https://bugs.webkit.org/show_bug.cgi?id=185284
+
+        Reviewed by Antti Koivisto.
+
+        Because a resource loading can be canceled as a node is removed a document or CachedResource is destructed,
+        it's not safe to synchronously fire load event on document upon cancelation. This patch makes the cancellation
+        of a resource load schedule m_checkTimer in FrameLoader to fire a load event asynchronously instead.
+
+        Specifically, this patch makes FrameLoader::loadDone call FrameLoader::scheduleCheckCompleted when the load
+        had failed or cancled instead of calling FrameLoader::checkCompleted which can synchronously fire load event.
+        To differentiate the two cases, new enum LoadCompletionType has been added to FrameLoader::loadDone and related
+        functions. To avoid calling the navigation delegate too early, the same abstraction for checkLoadComplete()
+        has been added in the form of FrameLoader::subresourceLoadDone.
+
+        Unfortunately, delaying calls to checkCompleted() and checkLoadComplete() by a timer can result in client
+        callbacks such as didFinishLoadForFrame and didFailLoadWithError to never get called when the frame gets
+        detached from the parent after the last resource had stopped loading but before the timer fires. To preserve
+        these deleagte callbacks, this patch expedites the timer in FrameLoader::frameDetached and Page::goToItem by
+        by invoking newly added stopAllLoadersAndCheckCompleteness, which stops all loading and then immediately invokes
+        checkCompleted() and checkLoadComplete() synchronously if m_checkTimer had been started.
+
+        Tests: http/tests/preload/dynamic_removing_preload.html
+
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::beginLoadTimerFired): Removed superfluous call to checkLoadComplete since
+        cachedResourceLoader's loadDone would call checkLoadComplete anyway.
+        * html/HTMLFrameOwnerElement.cpp:
+        (WebCore::HTMLFrameOwnerElement::disconnectContentFrame): Removed the misleading comment added in r140090.
+        Firefox DOES indeed fire unload event in the content document of a removed frame. While this comment made
+        it sound like this function isn't called when a frame is removed from the tree when in reality we simply
+        remove a frame prior to removing the node via disconnectSubframesIfNeeded.
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::removeSubresourceLoader):
+        * loader/DocumentLoader.h:
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::FrameLoader):
+        (WebCore::FrameLoader::loadDone):
+        (WebCore::FrameLoader::subresourceLoadDone):
+        (WebCore::FrameLoader::checkCompleted): Added a release assert that this function is only called when it's safe
+        to execute scripts.
+        (WebCore::FrameLoader::checkTimerFired):
+        (WebCore::FrameLoader::checkCompletenessNow):Extracted from checkTimerFired.
+        (WebCore::FrameLoader::stopAllLoaders): Removed the code to stop m_checkTimer introduced in r53655.
+        Stopping the timer here would prevent FrameLoader::frameDetached to detect the case when stopping the loader
+        scheduled a load completion check. Also stopping this timer without clearing the corresponding booleans:
+        m_checkingLoadCompleteForDetachment and m_checkingLoadCompleteForDetachment is problematic. The assertion
+        r53655 addressed is now addressed by explicitly checking & clearing the timer in frameDetached.
+        (WebCore::FrameLoader::stopAllLoadersAndCheckCompleteness): Added.
+        (WebCore::FrameLoader::checkLoadCompleteForThisFrame): Avoid an early exit when the newly added boolean
+        m_checkingLoadCompleteForDetachment is set since m_isStopping is no longer set in frameDetached in order
+        to invoke didFailLoadWithError when detaching a frame.
+        (WebCore::FrameLoader::frameDetached): Call checkCompletenessNow in the case the frame had already been
+        completed loading. Also call stopAllLoadersAndCheckCompleteness in the case stopping loading would complete
+        the loading before stopping active DOM objects.
+        * loader/FrameLoader.h:
+        (WebCore::FrameLoader::m_checkingLoadCompleteForDetachment): Added.
+        * loader/FrameLoaderTypes.h:
+        (WebCore::LoadCompletionType): Added.
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::didFinishLoading):
+        (WebCore::SubresourceLoader::didFail):
+        (WebCore::SubresourceLoader::didCancel):
+        (WebCore::SubresourceLoader::notifyDone):
+        * loader/SubresourceLoader.h:
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::loadDone):
+        * loader/cache/CachedResourceLoader.h:
+        * page/Page.cpp:
+        (WebCore::Page::goToItem): Call stopAllLoadersAndCheckCompleteness instead of stopAllLoaders since stopping
+        loading here may complete loading.
+
 2018-06-01  Sihui Liu  <[email protected]>
 
         Stop using StorageTracker.db in LocalStorageDatabaseTracker

Modified: trunk/Source/WebCore/css/CSSFontSelector.cpp (232418 => 232419)


--- trunk/Source/WebCore/css/CSSFontSelector.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/css/CSSFontSelector.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -365,11 +365,7 @@
         cachedResourceLoader.decrementRequestCount(*fontHandle);
     }
     // Ensure that if the request count reaches zero, the frame loader will know about it.
-    cachedResourceLoader.loadDone();
-    // New font loads may be triggered by layout after the document load is complete but before we have dispatched
-    // didFinishLoading for the frame. Make sure the delegate is always dispatched by checking explicitly.
-    if (m_document && m_document->frame())
-        m_document->frame()->loader().checkLoadComplete();
+    cachedResourceLoader.loadDone(LoadCompletionType::Finish);
 }
 
 

Modified: trunk/Source/WebCore/html/HTMLFrameOwnerElement.cpp (232418 => 232419)


--- trunk/Source/WebCore/html/HTMLFrameOwnerElement.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/html/HTMLFrameOwnerElement.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -77,10 +77,6 @@
 
 void HTMLFrameOwnerElement::disconnectContentFrame()
 {
-    // FIXME: Currently we don't do this in removedFrom because this causes an
-    // unload event in the subframe which could execute script that could then
-    // reach up into this document and then attempt to look back down. We should
-    // see if this behavior is really needed as Gecko does not allow this.
     if (RefPtr<Frame> frame = contentFrame()) {
         Ref<Frame> protect(*frame);
         frame->loader().frameDetached();

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (232418 => 232419)


--- trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -1625,7 +1625,7 @@
     m_subresourceLoaders.add(loader->identifier(), loader);
 }
 
-void DocumentLoader::removeSubresourceLoader(ResourceLoader* loader)
+void DocumentLoader::removeSubresourceLoader(LoadCompletionType type, ResourceLoader* loader)
 {
     ASSERT(loader->identifier());
 
@@ -1633,7 +1633,7 @@
         return;
     checkLoadComplete();
     if (Frame* frame = m_frame)
-        frame->loader().checkLoadComplete();
+        frame->loader().subresourceLoadDone(type);
 }
 
 void DocumentLoader::addPlugInStreamLoader(ResourceLoader& loader)

Modified: trunk/Source/WebCore/loader/DocumentLoader.h (232418 => 232419)


--- trunk/Source/WebCore/loader/DocumentLoader.h	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/DocumentLoader.h	2018-06-01 22:30:02 UTC (rev 232419)
@@ -269,7 +269,7 @@
     void setPopUpPolicy(PopUpPolicy popUpPolicy) { m_popUpPolicy = popUpPolicy; }
 
     void addSubresourceLoader(ResourceLoader*);
-    void removeSubresourceLoader(ResourceLoader*);
+    void removeSubresourceLoader(LoadCompletionType, ResourceLoader*);
     void addPlugInStreamLoader(ResourceLoader&);
     void removePlugInStreamLoader(ResourceLoader&);
 

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (232418 => 232419)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -787,11 +787,22 @@
     m_frame.view()->restoreScrollbar();
 }
 
-void FrameLoader::loadDone()
+void FrameLoader::loadDone(LoadCompletionType type)
 {
-    checkCompleted();
+    if (type == LoadCompletionType::Finish)
+        checkCompleted();
+    else
+        scheduleCheckCompleted();
 }
 
+void FrameLoader::subresourceLoadDone(LoadCompletionType type)
+{
+    if (type == LoadCompletionType::Finish)
+        checkLoadComplete();
+    else
+        scheduleCheckLoadComplete();
+}
+
 bool FrameLoader::allChildrenAreComplete() const
 {
     for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) {
@@ -812,6 +823,7 @@
 
 void FrameLoader::checkCompleted()
 {
+    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
     m_shouldCallCheckCompleted = false;
 
     // Have we completed before?
@@ -887,6 +899,11 @@
 
 void FrameLoader::checkTimerFired()
 {
+    checkCompletenessNow();
+}
+
+void FrameLoader::checkCompletenessNow()
+{
     Ref<Frame> protect(m_frame);
 
     if (Page* page = m_frame.page()) {
@@ -1765,11 +1782,22 @@
 
     setProvisionalDocumentLoader(nullptr);
 
-    m_checkTimer.stop();
-
     m_inStopAllLoaders = false;    
 }
 
+void FrameLoader::stopAllLoadersAndCheckCompleteness()
+{
+    stopAllLoaders();
+
+    if (!m_checkTimer.isActive())
+        return;
+
+    m_checkTimer.stop();
+    m_checkingLoadCompleteForDetachment = true;
+    checkCompletenessNow();
+    m_checkingLoadCompleteForDetachment = false;
+}
+
 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
 {
     // Calling stopAllLoaders can cause the frame to be deallocated, including the frame loader.
@@ -2395,9 +2423,10 @@
         }
         
         case FrameStateCommittedPage: {
-            DocumentLoader* dl = m_documentLoader.get();            
-            if (!dl || (dl->isLoadingInAPISense() && !dl->isStopping()))
+            if (!m_documentLoader)
                 return;
+            if (m_documentLoader->isLoadingInAPISense() && !m_documentLoader->isStopping() && !m_checkingLoadCompleteForDetachment)
+                return;
 
             setState(FrameStateComplete);
 
@@ -2425,7 +2454,7 @@
                 }
             }
 
-            const ResourceError& error = dl->mainDocumentError();
+            const ResourceError& error = m_documentLoader->mainDocumentError();
 
             AXObjectCache::AXLoadingEvent loadingEvent;
             if (!error.isNull()) {
@@ -2619,11 +2648,16 @@
 
 void FrameLoader::frameDetached()
 {
-    // Calling stopAllLoaders() can cause the frame to be deallocated, including the frame loader.
+    // Calling stopAllLoadersAndCheckCompleteness() can cause the frame to be deallocated, including the frame loader.
     Ref<Frame> protectedFrame(m_frame);
 
+    if (m_checkTimer.isActive()) {
+        m_checkTimer.stop();
+        checkCompletenessNow();
+    }
+
     if (m_frame.document()->pageCacheState() != Document::InPageCache) {
-        stopAllLoaders();
+        stopAllLoadersAndCheckCompleteness();
         m_frame.document()->stopActiveDOMObjects();
     }
 

Modified: trunk/Source/WebCore/loader/FrameLoader.h (232418 => 232419)


--- trunk/Source/WebCore/loader/FrameLoader.h	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/FrameLoader.h	2018-06-01 22:30:02 UTC (rev 232419)
@@ -138,6 +138,7 @@
     static void reportAuthenticationChallengeBlocked(Frame*, const URL&, const String& reason);
 
     // FIXME: These are all functions which stop loads. We have too many.
+    void stopAllLoadersAndCheckCompleteness();
     WEBCORE_EXPORT void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem);
     WEBCORE_EXPORT void stopForUserCancel(bool deferCheckLoadComplete = false);
     void stop();
@@ -253,7 +254,8 @@
 
     void setOutgoingReferrer(const URL&);
 
-    void loadDone();
+    void loadDone(LoadCompletionType);
+    void subresourceLoadDone(LoadCompletionType);
     void finishedParsing();
     void checkCompleted();
 
@@ -319,6 +321,7 @@
     bool allChildrenAreComplete() const; // immediate children, not all descendants
 
     void checkTimerFired();
+    void checkCompletenessNow();
 
     void loadSameDocumentItem(HistoryItem&);
     void loadDifferentDocumentItem(HistoryItem&, FrameLoadType, FormSubmissionCacheLoadPolicy, NavigationPolicyCheck);
@@ -467,6 +470,8 @@
     bool m_isStrictRawResourceValidationPolicyDisabledForTesting { false };
     bool m_currentLoadShouldCheckNavigationPolicy { true };
 
+    bool m_checkingLoadCompleteForDetachment { false };
+
     URL m_previousURL;
     RefPtr<HistoryItem> m_requestedHistoryItem;
 };

Modified: trunk/Source/WebCore/loader/FrameLoaderTypes.h (232418 => 232419)


--- trunk/Source/WebCore/loader/FrameLoaderTypes.h	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/FrameLoaderTypes.h	2018-06-01 22:30:02 UTC (rev 232419)
@@ -155,6 +155,11 @@
     bool isSystemPreview { false };
 };
 
+enum class LoadCompletionType {
+    Finish,
+    Cancel
+};
+
 } // namespace WebCore
 
 namespace WTF {

Modified: trunk/Source/WebCore/loader/SubresourceLoader.cpp (232418 => 232419)


--- trunk/Source/WebCore/loader/SubresourceLoader.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/SubresourceLoader.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -639,7 +639,7 @@
     m_resource->finish();
     ASSERT(!reachedTerminalState());
     didFinishLoadingOnePart(networkLoadMetrics);
-    notifyDone();
+    notifyDone(LoadCompletionType::Finish);
 
     if (reachedTerminalState())
         return;
@@ -675,7 +675,7 @@
         MemoryCache::singleton().remove(*m_resource);
     m_resource->error(CachedResource::LoadError);
     cleanupForError(error);
-    notifyDone();
+    notifyDone(LoadCompletionType::Cancel);
     if (reachedTerminalState())
         return;
     releaseResources();
@@ -717,7 +717,7 @@
         tracePoint(SubresourceLoadDidEnd);
 
     m_resource->cancelLoad();
-    notifyDone();
+    notifyDone(LoadCompletionType::Cancel);
 }
 
 void SubresourceLoader::didRetrieveDerivedDataFromCache(const String& type, SharedBuffer& buffer)
@@ -727,20 +727,21 @@
     m_resource->didRetrieveDerivedDataFromCache(type, buffer);
 }
 
-void SubresourceLoader::notifyDone()
+void SubresourceLoader::notifyDone(LoadCompletionType type)
 {
     if (reachedTerminalState())
         return;
 
     m_requestCountTracker = std::nullopt;
+    bool shouldPerformPostLoadActions = true;
 #if PLATFORM(IOS)
-    m_documentLoader->cachedResourceLoader().loadDone(m_state != CancelledWhileInitializing);
-#else
-    m_documentLoader->cachedResourceLoader().loadDone();
+    if (m_state == CancelledWhileInitializing)
+        shouldPerformPostLoadActions = false;
 #endif
+    m_documentLoader->cachedResourceLoader().loadDone(type, shouldPerformPostLoadActions);
     if (reachedTerminalState())
         return;
-    m_documentLoader->removeSubresourceLoader(this);
+    m_documentLoader->removeSubresourceLoader(type, this);
 }
 
 void SubresourceLoader::releaseResources()

Modified: trunk/Source/WebCore/loader/SubresourceLoader.h (232418 => 232419)


--- trunk/Source/WebCore/loader/SubresourceLoader.h	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/SubresourceLoader.h	2018-06-01 22:30:02 UTC (rev 232419)
@@ -95,7 +95,7 @@
 
     void didReceiveDataOrBuffer(const char*, int, RefPtr<SharedBuffer>&&, long long encodedDataLength, DataPayloadType);
 
-    void notifyDone();
+    void notifyDone(LoadCompletionType);
 
     void reportResourceTiming(const NetworkLoadMetrics&);
 

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp (232418 => 232419)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -1299,13 +1299,15 @@
     m_documentResources.remove(resource.url());
 }
 
-void CachedResourceLoader::loadDone(bool shouldPerformPostLoadActions)
+void CachedResourceLoader::loadDone(LoadCompletionType type, bool shouldPerformPostLoadActions)
 {
     RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
     RefPtr<Document> protectDocument(m_document);
 
+    ASSERT(shouldPerformPostLoadActions || type == LoadCompletionType::Cancel);
+
     if (frame())
-        frame()->loader().loadDone();
+        frame()->loader().loadDone(type);
 
     if (shouldPerformPostLoadActions)
         performPostLoadActions();

Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.h (232418 => 232419)


--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.h	2018-06-01 22:30:02 UTC (rev 232419)
@@ -132,7 +132,7 @@
 
     void removeCachedResource(CachedResource&);
 
-    void loadDone(bool shouldPerformPostLoadActions = true);
+    void loadDone(LoadCompletionType, bool shouldPerformPostLoadActions = true);
 
     WEBCORE_EXPORT void garbageCollectDocumentResources();
 

Modified: trunk/Source/WebCore/page/Page.cpp (232418 => 232419)


--- trunk/Source/WebCore/page/Page.cpp	2018-06-01 21:40:58 UTC (rev 232418)
+++ trunk/Source/WebCore/page/Page.cpp	2018-06-01 22:30:02 UTC (rev 232419)
@@ -482,8 +482,9 @@
     // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
     Ref<HistoryItem> protector(item);
 
-    if (m_mainFrame->loader().history().shouldStopLoadingForHistoryItem(item))
-        m_mainFrame->loader().stopAllLoaders();
+    auto& frameLoader = m_mainFrame->loader();
+    if (frameLoader.history().shouldStopLoadingForHistoryItem(item))
+        m_mainFrame->loader().stopAllLoadersAndCheckCompleteness();
 
     m_mainFrame->loader().history().goToItem(item, type, navigationPolicyCheck);
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to