<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[186434] releases/WebKitGTK/webkit-2.8</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/186434">186434</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2015-07-07 03:33:34 -0700 (Tue, 07 Jul 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/186049">r186049</a> - Crash: com.apple.WebKit.WebContent at com.apple.WebCore: WebCore::CachedFrameBase::restore + 333
https://bugs.webkit.org/show_bug.cgi?id=146388
&lt;rdar://problem/21567343&gt;

Reviewed by Darin Adler.

Source/WebCore:

Pages that are currently loading are not supposed to go into the
PageCache. However, PageCache::canCache() only checks if the
FrameLoader's documentLoader is loading. If the subframe is in
provisional load stage, we would fail to detect that the frame is
actually loading because the FrameLoader active documentLoader would
be the provisional documentLoader, not the regular documentLoader.
Therefore, the page would get added to the PageCache and the frame
would keep loading while in the PageCache.

On http://www.audiusa.com/models, this is what was happening. It was
crashing because the subframe would finish loading while in the
PageCache, in which case we would fire the 'load' event and the
content 'load' event handler would then proceed to remove the iframe.
Upon restoring the PageCache entry, we would run into trouble as we
would have a CachedFrame whose Frame has been removed.

The solution proposed is to prevent page-caching if a subframe is in
provisional load stage.

Test: http/tests/navigation/page-cache-iframe-provisional-load.html

* history/PageCache.cpp:
(WebCore::logCanCacheFrameDecision):
(WebCore::PageCache::canCachePageContainingThisFrame):
* page/DiagnosticLoggingKeys.cpp:
(WebCore::DiagnosticLoggingKeys::provisionalLoadKey):
* page/DiagnosticLoggingKeys.h:

LayoutTests:

Add layout test to cover the case where a subframe is currently in
provisional load stage when checking if the page if page-cacheable.

The test also removes the iframe once loaded in order to cause a crash
if the frame were to finish loading while in the page cache.

* http/tests/navigation/page-cache-iframe-provisional-load-expected.txt: Added.
* http/tests/navigation/page-cache-iframe-provisional-load.html: Added.
* http/tests/navigation/resources/page-cache-helper-slow.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsChangeLog">releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCoreChangeLog">releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCorehistoryPageCachecpp">releases/WebKitGTK/webkit-2.8/Source/WebCore/history/PageCache.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCorepageDiagnosticLoggingKeyscpp">releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCorepageDiagnosticLoggingKeysh">releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationpagecacheiframeprovisionalloadexpectedtxt">releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load-expected.txt</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationpagecacheiframeprovisionalloadhtml">releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load.html</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationresourcespagecachehelperslowhtml">releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/resources/page-cache-helper-slow.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit28LayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog (186433 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog        2015-07-07 10:22:13 UTC (rev 186433)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2015-06-28  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Crash: com.apple.WebKit.WebContent at com.apple.WebCore: WebCore::CachedFrameBase::restore + 333
+        https://bugs.webkit.org/show_bug.cgi?id=146388
+        &lt;rdar://problem/21567343&gt;
+
+        Reviewed by Darin Adler.
+
+        Add layout test to cover the case where a subframe is currently in
+        provisional load stage when checking if the page if page-cacheable.
+
+        The test also removes the iframe once loaded in order to cause a crash
+        if the frame were to finish loading while in the page cache.
+
+        * http/tests/navigation/page-cache-iframe-provisional-load-expected.txt: Added.
+        * http/tests/navigation/page-cache-iframe-provisional-load.html: Added.
+        * http/tests/navigation/resources/page-cache-helper-slow.html: Added.
+
</ins><span class="cx"> 2015-06-25  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Do not send touch events to the slider's thumb when it does not have a renderer.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationpagecacheiframeprovisionalloadexpectedtxt"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load-expected.txt (0 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load-expected.txt                                (rev 0)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load-expected.txt        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+A frame in provisional load stage should prevent page caching.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+pageshow - not from cache
+PASS Page was not restored from PageCache
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationpagecacheiframeprovisionalloadhtml"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load.html (0 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load.html                                (rev 0)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/page-cache-iframe-provisional-load.html        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;/resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+description(&quot;A frame in provisional load stage should prevent page caching.&quot;);
+window.jsTestIsAsync = true;
+
+if (window.testRunner)
+    testRunner.overridePreference(&quot;WebKitUsesPageCachePreferenceKey&quot;, 1);
+
+window.addEventListener(&quot;pageshow&quot;, function(event) {
+    debug(&quot;pageshow - &quot; + (event.persisted ? &quot;&quot; : &quot;not &quot;) + &quot;from cache&quot;);
+
+    if (!window.sessionStorage.page_cache_provisional_load_test_started)
+        return;
+
+    delete window.sessionStorage.page_cache_provisional_load_test_started;
+
+    if (event.persisted)
+        testFailed(&quot;Page was restored from PageCache&quot;);
+    else
+        testPassed(&quot;Page was not restored from PageCache&quot;);
+
+    finishJSTest();
+}, false);
+
+window.addEventListener(&quot;pagehide&quot;, function(event) {
+    debug(&quot;pagehide&quot;);
+}, false);
+
+function loadSubframeAndNavigateAway()
+{
+    // Force a back navigation back to this page.
+    window.sessionStorage.page_cache_provisional_load_test_started = true;
+    window.location.href = &quot;resources/page-cache-helper-slow.html&quot;;
+
+    var testFrame = document.getElementById(&quot;testFrame&quot;);
+    testFrame.src = &quot;http://127.0.0.1:8000/navigation/resources/slow-resource.pl?delay=100&quot;;
+
+    // If the page goes into the page cache and the frame keeps loading while in the cache,
+    // the following will cause crashes.
+    testFrame.onload = function() { document.getElementById(&quot;testFrame&quot;).remove(); };
+}
+
+window.addEventListener('load', function() {
+    setTimeout(function() {
+        loadSubframeAndNavigateAway();
+    }, 0);
+}, false);
+
+&lt;/script&gt;
+&lt;iframe id=&quot;testFrame&quot; src=&quot;about:blank&quot;&gt;&lt;/iframe&gt;
+&lt;script src=&quot;/resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestshttptestsnavigationresourcespagecachehelperslowhtml"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/resources/page-cache-helper-slow.html (0 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/resources/page-cache-helper-slow.html                                (rev 0)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/http/tests/navigation/resources/page-cache-helper-slow.html        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+This page should go back. If a test outputs the contents of this
+page, then the test page failed to enter the page cache.
+&lt;script&gt;
+  window.addEventListener(&quot;load&quot;, function() {
+    setTimeout(function() {
+      history.back();
+    }, 500);
+  }, false);
+&lt;/script&gt;
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog (186433 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog        2015-07-07 10:22:13 UTC (rev 186433)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2015-06-28  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Crash: com.apple.WebKit.WebContent at com.apple.WebCore: WebCore::CachedFrameBase::restore + 333
+        https://bugs.webkit.org/show_bug.cgi?id=146388
+        &lt;rdar://problem/21567343&gt;
+
+        Reviewed by Darin Adler.
+
+        Pages that are currently loading are not supposed to go into the
+        PageCache. However, PageCache::canCache() only checks if the
+        FrameLoader's documentLoader is loading. If the subframe is in
+        provisional load stage, we would fail to detect that the frame is
+        actually loading because the FrameLoader active documentLoader would
+        be the provisional documentLoader, not the regular documentLoader.
+        Therefore, the page would get added to the PageCache and the frame
+        would keep loading while in the PageCache.
+
+        On http://www.audiusa.com/models, this is what was happening. It was
+        crashing because the subframe would finish loading while in the
+        PageCache, in which case we would fire the 'load' event and the
+        content 'load' event handler would then proceed to remove the iframe.
+        Upon restoring the PageCache entry, we would run into trouble as we
+        would have a CachedFrame whose Frame has been removed.
+
+        The solution proposed is to prevent page-caching if a subframe is in
+        provisional load stage.
+
+        Test: http/tests/navigation/page-cache-iframe-provisional-load.html
+
+        * history/PageCache.cpp:
+        (WebCore::logCanCacheFrameDecision):
+        (WebCore::PageCache::canCachePageContainingThisFrame):
+        * page/DiagnosticLoggingKeys.cpp:
+        (WebCore::DiagnosticLoggingKeys::provisionalLoadKey):
+        * page/DiagnosticLoggingKeys.h:
+
</ins><span class="cx"> 2015-06-25  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Do not send touch events to the slider's thumb when it does not have a renderer.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCorehistoryPageCachecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/history/PageCache.cpp (186433 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/history/PageCache.cpp        2015-07-07 10:22:13 UTC (rev 186433)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/history/PageCache.cpp        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -93,6 +93,7 @@
</span><span class="cx">     DocumentLoaderUsesApplicationCache,
</span><span class="cx">     ClientDeniesCaching,
</span><span class="cx">     NumberOfReasonsFramesCannotBeInPageCache,
</span><ins>+    IsInProvisionalLoadStage,
</ins><span class="cx"> };
</span><span class="cx"> COMPILE_ASSERT(NumberOfReasonsFramesCannotBeInPageCache &lt;= sizeof(unsigned)*8, ReasonFrameCannotBeInPageCacheDoesNotFitInBitmap);
</span><span class="cx"> 
</span><span class="lines">@@ -112,6 +113,11 @@
</span><span class="cx"> static unsigned logCanCacheFrameDecision(Frame&amp; frame, DiagnosticLoggingClient&amp; diagnosticLoggingClient, unsigned indentLevel)
</span><span class="cx"> {
</span><span class="cx">     PCLOG(&quot;+---&quot;);
</span><ins>+    if (!frame.isMainFrame() &amp;&amp; frame.loader().state() == FrameStateProvisional) {
+        PCLOG(&quot;   -Frame is in provisional load stage&quot;);
+        logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::provisionalLoadKey());
+        return 1 &lt;&lt; IsInProvisionalLoadStage;
+    }
</ins><span class="cx">     if (!frame.loader().documentLoader()) {
</span><span class="cx">         PCLOG(&quot;   -There is no DocumentLoader object&quot;);
</span><span class="cx">         logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noDocumentLoaderKey());
</span><span class="lines">@@ -305,6 +311,12 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     FrameLoader&amp; frameLoader = frame.loader();
</span><ins>+
+    // Prevent page caching if a subframe is still in provisional load stage.
+    // We only do this check for subframes because the main frame is reused when navigating to a new page.
+    if (!frame.isMainFrame() &amp;&amp; frameLoader.state() == FrameStateProvisional)
+        return false;
+
</ins><span class="cx">     DocumentLoader* documentLoader = frameLoader.documentLoader();
</span><span class="cx">     Document* document = frame.document();
</span><span class="cx">     
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCorepageDiagnosticLoggingKeyscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.cpp (186433 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.cpp        2015-07-07 10:22:13 UTC (rev 186433)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.cpp        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -53,6 +53,11 @@
</span><span class="cx">     return ASCIILiteral(&quot;pluginFailedLoading&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+String DiagnosticLoggingKeys::provisionalLoadKey()
+{
+    return ASCIILiteral(&quot;provisionalLoad&quot;);
+}
+
</ins><span class="cx"> String DiagnosticLoggingKeys::pageContainsPluginKey()
</span><span class="cx"> {
</span><span class="cx">     return ASCIILiteral(&quot;pageContainsPlugin&quot;);
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCorepageDiagnosticLoggingKeysh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.h (186433 => 186434)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.h        2015-07-07 10:22:13 UTC (rev 186433)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/page/DiagnosticLoggingKeys.h        2015-07-07 10:33:34 UTC (rev 186434)
</span><span class="lines">@@ -81,6 +81,7 @@
</span><span class="cx">     static String playedKey();
</span><span class="cx">     static String pluginLoadedKey();
</span><span class="cx">     static String pluginLoadingFailedKey();
</span><ins>+    static String provisionalLoadKey();
</ins><span class="cx">     static String prunedDueToMaxSizeReached();
</span><span class="cx">     static String prunedDueToMemoryPressureKey();
</span><span class="cx">     static String prunedDueToProcessSuspended();
</span></span></pre>
</div>
</div>

</body>
</html>