<!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>[194337] 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/194337">194337</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2015-12-21 11:54:46 -0800 (Mon, 21 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Limit cached redirect chain length
https://bugs.webkit.org/show_bug.cgi?id=152477

Reviewed by Andreas Kling.

Source/WebKit2:

Networking layer prevents cycles and limits the redirect chain length so creating cache cycles is difficult.
For robustness the network cache should still limit the maximum redirect chain length.

This patch adds a limit of five redirects both when storing and retrieving cache entries.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::canUseCache):
(WebKit::NetworkResourceLoader::canUseCachedRedirect):
(WebKit::NetworkResourceLoader::willSendRedirectedRequest):
(WebKit::NetworkResourceLoader::continueWillSendRequest):
(WebKit::NetworkResourceLoader::dispatchWillSendRequestForCacheEntry):
* NetworkProcess/NetworkResourceLoader.h:

LayoutTests:

* http/tests/cache/disk-cache/redirect-chain-limits-expected.txt: Added.
* http/tests/cache/disk-cache/redirect-chain-limits.html: Added.
* http/tests/cache/disk-cache/resources/redirect-chain.phpl: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcessNetworkResourceLoadercpp">trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcessNetworkResourceLoaderh">trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestscachediskcacheredirectchainlimitsexpectedtxt">trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestscachediskcacheredirectchainlimitshtml">trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits.html</a></li>
<li><a href="#trunkLayoutTestshttptestscachediskcacheresourcesredirectchainphp">trunk/LayoutTests/http/tests/cache/disk-cache/resources/redirect-chain.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (194336 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-12-21 19:49:45 UTC (rev 194336)
+++ trunk/LayoutTests/ChangeLog        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2015-12-21  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        Limit cached redirect chain length
+        https://bugs.webkit.org/show_bug.cgi?id=152477
+
+        Reviewed by Andreas Kling.
+
+        * http/tests/cache/disk-cache/redirect-chain-limits-expected.txt: Added.
+        * http/tests/cache/disk-cache/redirect-chain-limits.html: Added.
+        * http/tests/cache/disk-cache/resources/redirect-chain.phpl: Added.
+
</ins><span class="cx"> 2015-12-21  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Marking webaudio/audiocontext-state-interrupted.html  as a flaky crasher on mac-wk1
</span></span></pre></div>
<a id="trunkLayoutTestshttptestscachediskcacheredirectchainlimitsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits-expected.txt (0 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits-expected.txt                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits-expected.txt        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+Test the limits of redirect chain length.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Redirect chain length: 1
+Response status code: 200
+Response source: Disk cache
+
+Redirect chain length: 5
+Response status code: 200
+Response source: Disk cache
+
+Redirect chain length: 6
+Response status code: 200
+Response source: Network
+
+Redirect chain length: 20
+Response status code: 200
+Response source: Network
+
+Redirect chain length: 40
+Response status code: 0
+Response source: Null response
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscachediskcacheredirectchainlimitshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits.html (0 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits.html                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/disk-cache/redirect-chain-limits.html        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -0,0 +1,48 @@
</span><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+window.jsTestIsAsync = true;
+
+description(&quot;Test the limits of redirect chain length.&quot;);
+
+function redirectChain(length, uniqueId, onload)
+{
+    internals.clearMemoryCache()
+
+    var url = &quot;resources/redirect-chain.php?length=&quot; + length + &quot;&amp;uniqueId=&quot; + uniqueId;
+
+    xhr = new XMLHttpRequest();
+    xhr.onload = onload;
+    xhr.onerror = onload;
+    xhr.onabort = onload;
+    xhr.open(&quot;get&quot;, url, true);
+
+    xhr.send();
+}
+
+function testRedirectChain(length, completionHandler)
+{
+    var uniqueId = Math.floor(Math.random() * 1000000000000);
+    redirectChain(length, uniqueId, (ev) =&gt; {
+        redirectChain(length, uniqueId, (ev) =&gt; {
+            debug(&quot;Redirect chain length: &quot; + length)
+            debug(&quot;Response status code: &quot; + ev.target.status);
+            debug(&quot;Response source: &quot; + internals.xhrResponseSource(ev.target));
+            debug(&quot;&quot;);
+            completionHandler();
+        });
+    });
+}
+
+testRedirectChain(1, () =&gt; {
+    testRedirectChain(5, () =&gt; {
+        testRedirectChain(6, () =&gt; {
+            testRedirectChain(20, () =&gt; {
+                testRedirectChain(40, () =&gt; {
+                    finishJSTest();
+                });
+            });
+        });
+    });
+});
+&lt;/script&gt;
+&lt;script src=&quot;/js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscachediskcacheresourcesredirectchainphp"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/disk-cache/resources/redirect-chain.php (0 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/disk-cache/resources/redirect-chain.php                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/disk-cache/resources/redirect-chain.php        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+&lt;?
+$length = $_GET['length'];
+if ($length == 0) {
+    header('Status: 200');
+    header('Cache-Control: max-age=100');
+    exit();
+}
+$length = $length - 1;
+
+header('Status: 302');
+header('Cache-Control: max-age=100');
+header('Location: redirect-chain.php?length=' . $length . '&amp;uniqueId=' . $_GET['uniqueId'] . '&amp;random=' . rand());
+?&gt;
</ins></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (194336 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-12-21 19:49:45 UTC (rev 194336)
+++ trunk/Source/WebKit2/ChangeLog        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2015-12-21  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        Limit cached redirect chain length
+        https://bugs.webkit.org/show_bug.cgi?id=152477
+
+        Reviewed by Andreas Kling.
+
+        Networking layer prevents cycles and limits the redirect chain length so creating cache cycles is difficult.
+        For robustness the network cache should still limit the maximum redirect chain length.
+
+        This patch adds a limit of five redirects both when storing and retrieving cache entries.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::canUseCache):
+        (WebKit::NetworkResourceLoader::canUseCachedRedirect):
+        (WebKit::NetworkResourceLoader::willSendRedirectedRequest):
+        (WebKit::NetworkResourceLoader::continueWillSendRequest):
+        (WebKit::NetworkResourceLoader::dispatchWillSendRequestForCacheEntry):
+        * NetworkProcess/NetworkResourceLoader.h:
+
</ins><span class="cx"> 2015-12-21  Dan Bernstein  &lt;mitz@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Different and incorrect flags are passed to sendSync when accessibility is enabled, SpinRunLoopWhileWaitingForReply
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessNetworkResourceLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp (194336 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2015-12-21 19:49:45 UTC (rev 194336)
+++ trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -116,8 +116,22 @@
</span><span class="cx">         return false;
</span><span class="cx">     if (!request.url().protocolIsInHTTPFamily())
</span><span class="cx">         return false;
</span><ins>+
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><ins>+
+bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest&amp; request) const
+{
+    if (!canUseCache(request))
+        return false;
+    // Limit cached redirects to avoid cycles and other trouble.
+    // Networking layer follows over 30 redirects but caching that many seems unnecessary.
+    static const unsigned maximumCachedRedirectCount { 5 };
+    if (m_redirectCount &gt; maximumCachedRedirectCount)
+        return false;
+
+    return true;
+}
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> bool NetworkResourceLoader::isSynchronous() const
</span><span class="lines">@@ -384,6 +398,8 @@
</span><span class="cx"> 
</span><span class="cx"> void NetworkResourceLoader::willSendRedirectedRequest(const ResourceRequest&amp; request, const WebCore::ResourceRequest&amp; redirectRequest, const ResourceResponse&amp; redirectResponse)
</span><span class="cx"> {
</span><ins>+    ++m_redirectCount;
+
</ins><span class="cx">     if (isSynchronous()) {
</span><span class="cx">         ResourceRequest overridenRequest = redirectRequest;
</span><span class="cx">         // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
</span><span class="lines">@@ -400,7 +416,7 @@
</span><span class="cx">     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(redirectRequest, redirectResponse));
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETWORK_CACHE)
</span><del>-    if (canUseCache(request))
</del><ins>+    if (canUseCachedRedirect(request))
</ins><span class="cx">         NetworkCache::singleton().storeRedirect(request, redirectResponse, redirectRequest);
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(request);
</span><span class="lines">@@ -412,7 +428,8 @@
</span><span class="cx"> #if ENABLE(NETWORK_CACHE)
</span><span class="cx">     if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
</span><span class="cx">         LOG(NetworkCache, &quot;(NetworkProcess) Retrieving cached redirect&quot;);
</span><del>-        if (canUseCache(newRequest))
</del><ins>+
+        if (canUseCachedRedirect(newRequest))
</ins><span class="cx">             retrieveCacheEntry(newRequest);
</span><span class="cx">         else
</span><span class="cx">             startNetworkLoad(newRequest);
</span><span class="lines">@@ -535,6 +552,7 @@
</span><span class="cx">     ASSERT(entry-&gt;redirectRequest());
</span><span class="cx">     LOG(NetworkCache, &quot;(NetworkProcess) Executing cached redirect&quot;);
</span><span class="cx"> 
</span><ins>+    ++m_redirectCount;
</ins><span class="cx">     sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(*entry-&gt;redirectRequest(), entry-&gt;response()));
</span><span class="cx">     m_isWaitingContinueWillSendRequestForCachedRedirect = true;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessNetworkResourceLoaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h (194336 => 194337)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h        2015-12-21 19:49:45 UTC (rev 194336)
+++ trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h        2015-12-21 19:54:46 UTC (rev 194337)
</span><span class="lines">@@ -61,10 +61,6 @@
</span><span class="cx"> 
</span><span class="cx">     NetworkLoad* networkLoad() const { return m_networkLoad.get(); }
</span><span class="cx"> 
</span><del>-#if ENABLE(NETWORK_CACHE)
-    bool canUseCache(const WebCore::ResourceRequest&amp;) const;
-#endif
-
</del><span class="cx">     void start();
</span><span class="cx">     void abort();
</span><span class="cx"> 
</span><span class="lines">@@ -116,6 +112,9 @@
</span><span class="cx">     virtual uint64_t messageSenderDestinationID() override { return m_parameters.identifier; }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETWORK_CACHE)
</span><ins>+    bool canUseCache(const WebCore::ResourceRequest&amp;) const;
+    bool canUseCachedRedirect(const WebCore::ResourceRequest&amp;) const;
+
</ins><span class="cx">     void retrieveCacheEntry(const WebCore::ResourceRequest&amp;);
</span><span class="cx">     void didRetrieveCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt;);
</span><span class="cx">     void validateCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt;);
</span><span class="lines">@@ -149,6 +148,7 @@
</span><span class="cx">     size_t m_bytesReceived { 0 };
</span><span class="cx">     size_t m_bufferedDataEncodedDataLength { 0 };
</span><span class="cx">     RefPtr&lt;WebCore::SharedBuffer&gt; m_bufferedData;
</span><ins>+    unsigned m_redirectCount { 0 };
</ins><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;SynchronousLoadData&gt; m_synchronousLoadData;
</span><span class="cx">     Vector&lt;RefPtr&lt;WebCore::BlobDataFileReference&gt;&gt; m_fileReferences;
</span></span></pre>
</div>
</div>

</body>
</html>