<!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>[181480] trunk</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/181480">181480</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2015-03-13 10:58:50 -0700 (Fri, 13 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>XMLHttpRequests should not prevent a page from entering PageCache
https://bugs.webkit.org/show_bug.cgi?id=142612
&lt;rdar://problem/19923085&gt;

Reviewed by Alexey Proskuryakov.

Source/WebCore:

Make XMLHttpRequest ActiveDOMObjects suspendable in most cases to
drastically improve the likelihood of pages using them to enter
PageCache. XMLHttpRequest used to be only suspendable when not
loading. After this patch, if the XMLHttpRequest is loading when
navigating away from the page, it will be aborted and the page
will enter the PageCache. Upon restoring the page from PageCache,
the XMLHttpRequests' error handlers will be executed to give them
a chance to reload if they want to.

Test: http/tests/navigation/page-cache-xhr.html

* history/PageCache.cpp:
(WebCore::logCanCacheFrameDecision):
(WebCore::PageCache::canCachePageContainingThisFrame):
Do not prevent a page to enter the page cache ff the main document has
an error that is a cancellation and all remaining subresource loaders
are for XHR. We extend the pre-existing mechanism used on iOS, which
allowed PageCaching if the remaining resource loads are for images.

* loader/DocumentLoader.cpp:
(WebCore::areAllLoadersPageCacheAcceptable):
Mark XHR loaders as PageCache acceptable.

* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::isXMLHttpRequest):
* loader/DocumentThreadableLoader.h:
* loader/ThreadableLoader.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::areAllClientsXMLHttpRequests):
* loader/cache/CachedResource.h:
* loader/cache/CachedResourceClient.h:
(WebCore::CachedResourceClient::isXMLHttpRequest):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::XMLHttpRequest):
(WebCore::XMLHttpRequest::createRequest):
(WebCore::XMLHttpRequest::canSuspend):
Report that we can suspend XMLHttpRequests as long as the window load
event has already fired. If the window load event has not fired yet,
it would be unsafe to cancel the load in suspend() as it would
potentially cause arbitrary JS execution while suspending.

(WebCore::XMLHttpRequest::suspend):
If suspending for PageCache and the request is currently loading, abort
the load and mark that we should fire the error event upon restoring
from PageCache.

(WebCore::XMLHttpRequest::resume):
(WebCore::XMLHttpRequest::resumeTimerFired):
Upon resuming, fire the error event in a timer if the load was aborted
for suspending. We need to do this in a timer because we are not allowed
to execute arbitrary JS inside resume().

(WebCore::XMLHttpRequest::stop):
Add a assertion to make sure we are not firing event inside stop() as
this would potentially cause arbitrary JS execution and it would be
unsafe. It seems to me that our code is currently unsafe but the
assertion does not seem to be hit by our current layout tests. I am
adding the assertion as it would make it clear we have a bug and we
need to fix it.

* xml/XMLHttpRequest.h:

LayoutTests:

Add a tests to make sure that loading XMLHttpRequests do not prevent a
page from entering PageCache.

* http/tests/navigation/page-cache-xhr-expected.txt: Added.
* http/tests/navigation/page-cache-xhr.html: Added.
* http/tests/navigation/resources/page-cache-helper.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehistoryPageCachecpp">trunk/Source/WebCore/history/PageCache.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderDocumentLoadercpp">trunk/Source/WebCore/loader/DocumentLoader.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderDocumentThreadableLoadercpp">trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp</a></li>
<li><a href="#trunkSourceWebCoreloaderDocumentThreadableLoaderh">trunk/Source/WebCore/loader/DocumentThreadableLoader.h</a></li>
<li><a href="#trunkSourceWebCoreloaderThreadableLoaderh">trunk/Source/WebCore/loader/ThreadableLoader.h</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourcecpp">trunk/Source/WebCore/loader/cache/CachedResource.cpp</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourceh">trunk/Source/WebCore/loader/cache/CachedResource.h</a></li>
<li><a href="#trunkSourceWebCoreloadercacheCachedResourceClienth">trunk/Source/WebCore/loader/cache/CachedResourceClient.h</a></li>
<li><a href="#trunkSourceWebCorexmlXMLHttpRequestcpp">trunk/Source/WebCore/xml/XMLHttpRequest.cpp</a></li>
<li><a href="#trunkSourceWebCorexmlXMLHttpRequesth">trunk/Source/WebCore/xml/XMLHttpRequest.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestsnavigationpagecachexhrexpectedtxt">trunk/LayoutTests/http/tests/navigation/page-cache-xhr-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsnavigationpagecachexhrhtml">trunk/LayoutTests/http/tests/navigation/page-cache-xhr.html</a></li>
<li><a href="#trunkLayoutTestshttptestsnavigationresourcespagecachehelperhtml">trunk/LayoutTests/http/tests/navigation/resources/page-cache-helper.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/LayoutTests/ChangeLog        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-03-13  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        XMLHttpRequests should not prevent a page from entering PageCache
+        https://bugs.webkit.org/show_bug.cgi?id=142612
+        &lt;rdar://problem/19923085&gt;
+
+        Reviewed by Alexey Proskuryakov.
+
+        Add a tests to make sure that loading XMLHttpRequests do not prevent a
+        page from entering PageCache.
+
+        * http/tests/navigation/page-cache-xhr-expected.txt: Added.
+        * http/tests/navigation/page-cache-xhr.html: Added.
+        * http/tests/navigation/resources/page-cache-helper.html: Added.
+
</ins><span class="cx"> 2015-03-13  Marcos Chavarría Teijeiro  &lt;chavarria1991@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed Gardening 13th March.
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsnavigationpagecachexhrexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/navigation/page-cache-xhr-expected.txt (0 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/navigation/page-cache-xhr-expected.txt                                (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/page-cache-xhr-expected.txt        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+Tests that a page with a loading XMLHttpRequest goes into the page cache.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the page cache
+PASS Executed the XHR error handler after restoring from page cache
+PASS xhr.status is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestsnavigationpagecachexhrhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/navigation/page-cache-xhr.html (0 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/navigation/page-cache-xhr.html                                (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/page-cache-xhr.html        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -0,0 +1,66 @@
</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('Tests that a page with a loading XMLHttpRequest goes into the page cache.');
+window.jsTestIsAsync = true;
+
+var restoredFromPageCache = false;
+
+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 (event.persisted) {
+        testPassed(&quot;Page did enter and was restored from the page cache&quot;);
+        restoredFromPageCache = true;
+    }
+}, false);
+
+window.addEventListener(&quot;pagehide&quot;, function(event) {
+    debug(&quot;pagehide - &quot; + (event.persisted ? &quot;&quot; : &quot;not &quot;) + &quot;entering cache&quot;);
+    if (!event.persisted) {
+        testFailed(&quot;Page did not enter the page cache.&quot;);
+        finishJSTest();
+    }
+}, false);
+
+function xhrLoaded()
+{
+    testFailed(&quot;The XMLHttpRequest should not haved loaded&quot;);
+    finishJSTest();
+}
+
+function xhrError() {
+    if (restoredFromPageCache)
+        testPassed(&quot;Executed the XHR error handler after restoring from page cache&quot;);
+    else
+        testFailed(&quot;Executed the XHR error handler before restoring from page cache&quot;);
+
+    shouldBe(&quot;xhr.status&quot;, &quot;0&quot;);
+    finishJSTest();
+}
+
+window.addEventListener('load', function() {
+    xhr = new XMLHttpRequest();
+    xhr.onload = xhrLoaded;
+    xhr.onerror = xhrError;
+    // Slow loading XHR (3-second stall).
+    xhr.open(&quot;GET&quot;, &quot;/resources/load-and-stall.cgi?name=../../../http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout.js&amp;stallFor=3&amp;stallAt=0&amp;mimeType=text/plain&quot;, true);
+    xhr.send();
+
+    // This needs to happen in a setTimeout because a navigation inside the onload handler would
+    // not create a history entry.
+    setTimeout(function() {
+      // Force a back navigation back to this page.
+      window.location.href = &quot;resources/page-cache-helper.html&quot;;
+    }, 0);
+}, false);
+
+&lt;/script&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="trunkLayoutTestshttptestsnavigationresourcespagecachehelperhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/navigation/resources/page-cache-helper.html (0 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/navigation/resources/page-cache-helper.html                                (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/resources/page-cache-helper.html        2015-03-13 17:58:50 UTC (rev 181480)
</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();
+    }, 0);
+  }, false);
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/ChangeLog        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2015-03-13  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        XMLHttpRequests should not prevent a page from entering PageCache
+        https://bugs.webkit.org/show_bug.cgi?id=142612
+        &lt;rdar://problem/19923085&gt;
+
+        Reviewed by Alexey Proskuryakov.
+
+        Make XMLHttpRequest ActiveDOMObjects suspendable in most cases to
+        drastically improve the likelihood of pages using them to enter
+        PageCache. XMLHttpRequest used to be only suspendable when not
+        loading. After this patch, if the XMLHttpRequest is loading when
+        navigating away from the page, it will be aborted and the page
+        will enter the PageCache. Upon restoring the page from PageCache,
+        the XMLHttpRequests' error handlers will be executed to give them
+        a chance to reload if they want to.
+
+        Test: http/tests/navigation/page-cache-xhr.html
+
+        * history/PageCache.cpp:
+        (WebCore::logCanCacheFrameDecision):
+        (WebCore::PageCache::canCachePageContainingThisFrame):
+        Do not prevent a page to enter the page cache ff the main document has
+        an error that is a cancellation and all remaining subresource loaders
+        are for XHR. We extend the pre-existing mechanism used on iOS, which
+        allowed PageCaching if the remaining resource loads are for images.
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::areAllLoadersPageCacheAcceptable):
+        Mark XHR loaders as PageCache acceptable.
+
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::isXMLHttpRequest):
+        * loader/DocumentThreadableLoader.h:
+        * loader/ThreadableLoader.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::areAllClientsXMLHttpRequests):
+        * loader/cache/CachedResource.h:
+        * loader/cache/CachedResourceClient.h:
+        (WebCore::CachedResourceClient::isXMLHttpRequest):
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::XMLHttpRequest):
+        (WebCore::XMLHttpRequest::createRequest):
+        (WebCore::XMLHttpRequest::canSuspend):
+        Report that we can suspend XMLHttpRequests as long as the window load
+        event has already fired. If the window load event has not fired yet,
+        it would be unsafe to cancel the load in suspend() as it would
+        potentially cause arbitrary JS execution while suspending.
+
+        (WebCore::XMLHttpRequest::suspend):
+        If suspending for PageCache and the request is currently loading, abort
+        the load and mark that we should fire the error event upon restoring
+        from PageCache.
+
+        (WebCore::XMLHttpRequest::resume):
+        (WebCore::XMLHttpRequest::resumeTimerFired):
+        Upon resuming, fire the error event in a timer if the load was aborted
+        for suspending. We need to do this in a timer because we are not allowed
+        to execute arbitrary JS inside resume().
+
+        (WebCore::XMLHttpRequest::stop):
+        Add a assertion to make sure we are not firing event inside stop() as
+        this would potentially cause arbitrary JS execution and it would be
+        unsafe. It seems to me that our code is currently unsafe but the
+        assertion does not seem to be hit by our current layout tests. I am
+        adding the assertion as it would make it clear we have a bug and we
+        need to fix it.
+
+        * xml/XMLHttpRequest.h:
+
</ins><span class="cx"> 2015-03-13  Joonghun Park  &lt;jh718.park@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix Debug build error 'comparison is always true due to limited range of data type [-Werror=type-limits]'
</span></span></pre></div>
<a id="trunkSourceWebCorehistoryPageCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/history/PageCache.cpp (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/history/PageCache.cpp        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/history/PageCache.cpp        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -128,14 +128,11 @@
</span><span class="cx">     if (!frame.loader().documentLoader()-&gt;mainDocumentError().isNull()) {
</span><span class="cx">         PCLOG(&quot;   -Main document has an error&quot;);
</span><span class="cx">         logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::mainDocumentErrorKey());
</span><del>-#if !PLATFORM(IOS)
-        rejectReasons |= 1 &lt;&lt; MainDocumentError;
-#else
</del><ins>+
</ins><span class="cx">         if (frame.loader().documentLoader()-&gt;mainDocumentError().isCancellation() &amp;&amp; frame.loader().documentLoader()-&gt;subresourceLoadersArePageCacheAcceptable())
</span><del>-            PCLOG(&quot;    -But, it was a cancellation and all loaders during the cancel were loading images.&quot;);
</del><ins>+            PCLOG(&quot;    -But, it was a cancellation and all loaders during the cancelation were loading images or XHR.&quot;);
</ins><span class="cx">         else
</span><span class="cx">             rejectReasons |= 1 &lt;&lt; MainDocumentError;
</span><del>-#endif
</del><span class="cx">     }
</span><span class="cx">     if (frame.loader().documentLoader()-&gt;substituteData().isValid() &amp;&amp; frame.loader().documentLoader()-&gt;substituteData().failingURL().isEmpty()) {
</span><span class="cx">         PCLOG(&quot;   -Frame is an error page&quot;);
</span><span class="lines">@@ -304,11 +301,7 @@
</span><span class="cx">     Document* document = frame.document();
</span><span class="cx">     
</span><span class="cx">     return documentLoader
</span><del>-#if !PLATFORM(IOS)
-        &amp;&amp; documentLoader-&gt;mainDocumentError().isNull()
-#else
</del><span class="cx">         &amp;&amp; (documentLoader-&gt;mainDocumentError().isNull() || (documentLoader-&gt;mainDocumentError().isCancellation() &amp;&amp; documentLoader-&gt;subresourceLoadersArePageCacheAcceptable()))
</span><del>-#endif
</del><span class="cx">         // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs).
</span><span class="cx">         &amp;&amp; !(documentLoader-&gt;substituteData().isValid() &amp;&amp; !documentLoader-&gt;substituteData().failingURL().isEmpty())
</span><span class="cx">         &amp;&amp; (!frameLoader.subframeLoader().containsPlugins() || frame.page()-&gt;settings().pageCacheSupportsPlugins())
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentLoader.cpp        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -99,19 +99,16 @@
</span><span class="cx">     Vector&lt;RefPtr&lt;ResourceLoader&gt;&gt; loadersCopy;
</span><span class="cx">     copyValuesToVector(loaders, loadersCopy);
</span><span class="cx">     for (auto&amp; loader : loadersCopy) {
</span><del>-        ResourceHandle* handle = loader-&gt;handle();
-        if (!handle)
-            return false;
-
</del><span class="cx">         if (!loader-&gt;frameLoader())
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><del>-        CachedResource* cachedResource = MemoryCache::singleton().resourceForURL(handle-&gt;firstRequest().url(), loader-&gt;frameLoader()-&gt;frame().page()-&gt;sessionID());
</del><ins>+        CachedResource* cachedResource = MemoryCache::singleton().resourceForURL(loader-&gt;request().url(), loader-&gt;frameLoader()-&gt;frame().page()-&gt;sessionID());
</ins><span class="cx">         if (!cachedResource)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><ins>+        // Only image and XHR loads do prevent the page from entering the PageCache.
</ins><span class="cx">         // All non-image loads will prevent the page from entering the PageCache.
</span><del>-        if (!cachedResource-&gt;isImage())
</del><ins>+        if (!cachedResource-&gt;isImage() &amp;&amp; !cachedResource-&gt;areAllClientsXMLHttpRequests())
</ins><span class="cx">             return false;
</span><span class="cx">     }
</span><span class="cx">     return true;
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentThreadableLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/DocumentThreadableLoader.cpp        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include &quot;CachedRawResource.h&quot;
</span><span class="cx"> #include &quot;CachedResourceLoader.h&quot;
</span><span class="cx"> #include &quot;CachedResourceRequest.h&quot;
</span><ins>+#include &quot;CachedResourceRequestInitiators.h&quot;
</ins><span class="cx"> #include &quot;CrossOriginAccessControl.h&quot;
</span><span class="cx"> #include &quot;CrossOriginPreflightResultCache.h&quot;
</span><span class="cx"> #include &quot;Document.h&quot;
</span><span class="lines">@@ -418,6 +419,11 @@
</span><span class="cx">     return m_sameOriginRequest &amp;&amp; securityOrigin()-&gt;canRequest(url);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool DocumentThreadableLoader::isXMLHttpRequest() const
+{
+    return m_options.initiator == cachedResourceRequestInitiators().xmlhttprequest;
+}
+
</ins><span class="cx"> SecurityOrigin* DocumentThreadableLoader::securityOrigin() const
</span><span class="cx"> {
</span><span class="cx">     return m_options.securityOrigin ? m_options.securityOrigin.get() : m_document.securityOrigin();
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderDocumentThreadableLoaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/DocumentThreadableLoader.h (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/DocumentThreadableLoader.h        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/DocumentThreadableLoader.h        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -96,6 +96,8 @@
</span><span class="cx">         void loadRequest(const ResourceRequest&amp;, SecurityCheckPolicy);
</span><span class="cx">         bool isAllowedRedirect(const URL&amp;);
</span><span class="cx"> 
</span><ins>+        bool isXMLHttpRequest() const override final;
+
</ins><span class="cx">         SecurityOrigin* securityOrigin() const;
</span><span class="cx"> 
</span><span class="cx">         CachedResourceHandle&lt;CachedRawResource&gt; m_resource;
</span></span></pre></div>
<a id="trunkSourceWebCoreloaderThreadableLoaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/ThreadableLoader.h (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/ThreadableLoader.h        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/ThreadableLoader.h        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -36,10 +36,7 @@
</span><span class="cx"> #include &lt;wtf/PassRefPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><del>-
-#if ENABLE(RESOURCE_TIMING)
</del><span class="cx"> #include &lt;wtf/text/AtomicString.h&gt;
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -69,9 +66,7 @@
</span><span class="cx">         PreflightPolicy preflightPolicy; // If AccessControl is used, how to determine if a preflight is needed.
</span><span class="cx">         CrossOriginRequestPolicy crossOriginRequestPolicy;
</span><span class="cx">         RefPtr&lt;SecurityOrigin&gt; securityOrigin;
</span><del>-#if ENABLE(RESOURCE_TIMING)
</del><span class="cx">         AtomicString initiator;
</span><del>-#endif
</del><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     // Useful for doing loader operations from any thread (not threadsafe, 
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourcecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResource.cpp (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResource.cpp        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/cache/CachedResource.cpp        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -735,6 +735,18 @@
</span><span class="cx">     return sizeof(CachedResource) + m_response.memoryUsage() + kAverageClientsHashMapSize + m_resourceRequest.url().string().length() * 2;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool CachedResource::areAllClientsXMLHttpRequests() const
+{
+    if (type() != RawResource)
+        return false;
+
+    for (auto&amp; client : m_clients) {
+        if (!client.key-&gt;isXMLHttpRequest())
+            return false;
+    }
+    return true;
+}
+
</ins><span class="cx"> void CachedResource::setLoadPriority(const Optional&lt;ResourceLoadPriority&gt;&amp; loadPriority)
</span><span class="cx"> {
</span><span class="cx">     if (loadPriority)
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResource.h (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResource.h        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/cache/CachedResource.h        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -158,6 +158,8 @@
</span><span class="cx"> 
</span><span class="cx">     SubresourceLoader* loader() { return m_loader.get(); }
</span><span class="cx"> 
</span><ins>+    bool areAllClientsXMLHttpRequests() const;
+
</ins><span class="cx">     bool isImage() const { return type() == ImageResource; }
</span><span class="cx">     // FIXME: CachedRawResource could be either a main resource or a raw XHR resource.
</span><span class="cx">     bool isMainOrRawResource() const { return type() == MainResource || type() == RawResource; }
</span></span></pre></div>
<a id="trunkSourceWebCoreloadercacheCachedResourceClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/loader/cache/CachedResourceClient.h (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/loader/cache/CachedResourceClient.h        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/loader/cache/CachedResourceClient.h        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx">     virtual ~CachedResourceClient() { }
</span><span class="cx">     virtual void notifyFinished(CachedResource*) { }
</span><span class="cx">     virtual void deprecatedDidReceiveCachedResource(CachedResource*) { }
</span><ins>+    virtual bool isXMLHttpRequest() const { return false; }
</ins><span class="cx"> 
</span><span class="cx">     static CachedResourceClientType expectedType() { return BaseResourceType; }
</span><span class="cx">     virtual CachedResourceClientType resourceClientType() const { return expectedType(); }
</span></span></pre></div>
<a id="trunkSourceWebCorexmlXMLHttpRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -24,6 +24,7 @@
</span><span class="cx"> #include &quot;XMLHttpRequest.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Blob.h&quot;
</span><ins>+#include &quot;CachedResourceRequestInitiators.h&quot;
</ins><span class="cx"> #include &quot;ContentSecurityPolicy.h&quot;
</span><span class="cx"> #include &quot;CrossOriginAccessControl.h&quot;
</span><span class="cx"> #include &quot;DOMFormData.h&quot;
</span><span class="lines">@@ -64,10 +65,6 @@
</span><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> #include &lt;wtf/text/CString.h&gt;
</span><span class="cx"> 
</span><del>-#if ENABLE(RESOURCE_TIMING)
-#include &quot;CachedResourceRequestInitiators.h&quot;
-#endif
-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, (&quot;XMLHttpRequest&quot;));
</span><span class="lines">@@ -139,6 +136,8 @@
</span><span class="cx">     , m_progressEventThrottle(this)
</span><span class="cx">     , m_responseTypeCode(ResponseTypeDefault)
</span><span class="cx">     , m_responseCacheIsValid(false)
</span><ins>+    , m_resumeTimer(*this, &amp;XMLHttpRequest::resumeTimerFired)
+    , m_dispatchErrorOnResuming(false)
</ins><span class="cx"> {
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     xmlHttpRequestCounter.increment();
</span><span class="lines">@@ -764,9 +763,7 @@
</span><span class="cx">     options.setAllowCredentials((m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials);
</span><span class="cx">     options.crossOriginRequestPolicy = UseAccessControl;
</span><span class="cx">     options.securityOrigin = securityOrigin();
</span><del>-#if ENABLE(RESOURCE_TIMING)
</del><span class="cx">     options.initiator = cachedResourceRequestInitiators().xmlhttprequest;
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx"> #if ENABLE(XHR_TIMEOUT)
</span><span class="cx">     if (m_timeoutMilliseconds)
</span><span class="lines">@@ -1255,7 +1252,10 @@
</span><span class="cx"> 
</span><span class="cx"> bool XMLHttpRequest::canSuspend() const
</span><span class="cx"> {
</span><del>-    return !m_loader;
</del><ins>+    // If the load event has not fired yet, cancelling the load in suspend() may cause
+    // the load event to be fired and arbitrary JS execution, which would be unsafe.
+    // Therefore, we prevent suspending in this case.
+    return document()-&gt;loadEventFinished();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> const char* XMLHttpRequest::activeDOMObjectName() const
</span><span class="lines">@@ -1263,18 +1263,50 @@
</span><span class="cx">     return &quot;XMLHttpRequest&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void XMLHttpRequest::suspend(ReasonForSuspension)
</del><ins>+void XMLHttpRequest::suspend(ReasonForSuspension reason)
</ins><span class="cx"> {
</span><ins>+    NoEventDispatchAssertion assertNoEventDispatch;
+
</ins><span class="cx">     m_progressEventThrottle.suspend();
</span><ins>+
+    if (m_resumeTimer.isActive()) {
+        m_resumeTimer.stop();
+        m_dispatchErrorOnResuming = true;
+    }
+
+    if (reason == ActiveDOMObject::DocumentWillBecomeInactive &amp;&amp; m_loader) {
+        // Going into PageCache, abort the request and dispatch a network error on resuming.
+        genericError();
+        m_dispatchErrorOnResuming = true;
+        bool aborted = internalAbort();
+        // It should not be possible to restart the load when aborting in suspend() because
+        // we are not allowed to execute in JS in suspend().
+        ASSERT_UNUSED(aborted, aborted);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void XMLHttpRequest::resume()
</span><span class="cx"> {
</span><ins>+    NoEventDispatchAssertion assertNoEventDispatch;
+
</ins><span class="cx">     m_progressEventThrottle.resume();
</span><ins>+
+    // We are not allowed to execute arbitrary JS in resume() so dispatch
+    // the error event in a timer.
+    if (m_dispatchErrorOnResuming &amp;&amp; !m_resumeTimer.isActive())
+        m_resumeTimer.startOneShot(0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void XMLHttpRequest::resumeTimerFired()
+{
+    ASSERT(m_dispatchErrorOnResuming);
+    m_dispatchErrorOnResuming = false;
+    dispatchErrorEvents(eventNames().errorEvent);
+}
+
</ins><span class="cx"> void XMLHttpRequest::stop()
</span><span class="cx"> {
</span><ins>+    NoEventDispatchAssertion assertNoEventDispatch;
</ins><span class="cx">     internalAbort();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorexmlXMLHttpRequesth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/xml/XMLHttpRequest.h (181479 => 181480)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/xml/XMLHttpRequest.h        2015-03-13 16:00:03 UTC (rev 181479)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.h        2015-03-13 17:58:50 UTC (rev 181480)
</span><span class="lines">@@ -205,6 +205,8 @@
</span><span class="cx"> 
</span><span class="cx">     void dispatchErrorEvents(const AtomicString&amp;);
</span><span class="cx"> 
</span><ins>+    void resumeTimerFired();
+
</ins><span class="cx">     std::unique_ptr&lt;XMLHttpRequestUpload&gt; m_upload;
</span><span class="cx"> 
</span><span class="cx">     URL m_url;
</span><span class="lines">@@ -254,6 +256,9 @@
</span><span class="cx">     // An enum corresponding to the allowed string values for the responseType attribute.
</span><span class="cx">     ResponseTypeCode m_responseTypeCode;
</span><span class="cx">     bool m_responseCacheIsValid;
</span><ins>+
+    Timer m_resumeTimer;
+    bool m_dispatchErrorOnResuming;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre>
</div>
</div>

</body>
</html>