<!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>[192328] trunk/Source/WebKit2</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/192328">192328</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2015-11-11 15:01:30 -0800 (Wed, 11 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WK2] Add initial support for speculative resource revalidation to the WebKit disk cache
https://bugs.webkit.org/show_bug.cgi?id=150856
&lt;rdar://problem/23092196&gt;

Reviewed by Antti Koivisto.

Add initial support for speculative resource revalidation to the WebKit
disk cache. When a main resource is requested by WebCore, we look up its
list of subresources in the cache and speculatively warm them up before
WebCore asks for them, in order to improve page load time. In this
context, warming it up means:
1. If the cached resource is usable (has not expired), keep it around
   in a memory for a limited amount of time (10 seconds).
2. If the resource has expired, do a speculative revalidation of the
   resource and then keep it in memory for a while as well (10 seconds).

The feature is currently behind a compile-time flag that is only enabled
on COCOA. Also, it is currently disabled at run-time until it is mature
enough.

Initial results show that speculative revalidation gives a ~5%
progression on throttled warm PLT on iPhone 5s.

* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::start):
* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::Cache::retrieve):
(WebKit::NetworkCache::Cache::store):
(WebKit::NetworkCache::Cache::update):
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheEntry.cpp:
(WebKit::NetworkCache::Entry::Entry):
* NetworkProcess/cache/NetworkCacheEntry.h:
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp: Added.
(WebKit::NetworkCache::SpeculativeLoad::SpeculativeLoad):
(WebKit::NetworkCache::SpeculativeLoad::~SpeculativeLoad):
(WebKit::NetworkCache::SpeculativeLoad::willSendRedirectedRequest):
(WebKit::NetworkCache::SpeculativeLoad::didReceiveBuffer):
(WebKit::NetworkCache::SpeculativeLoad::didFinishLoading):
(WebKit::NetworkCache::SpeculativeLoad::didFailLoading):
(WebKit::NetworkCache::SpeculativeLoad::didComplete):
* NetworkProcess/cache/NetworkCacheSpeculativeLoad.h: Added.
* NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:
(WebKit::NetworkCache::constructRevalidationRequest):
(WebKit::NetworkCache::responseNeedsRevalidation):
(WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::PreloadedEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::takeCacheEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::lifetimeTimerFired):
(WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::PendingFrameLoad):
(WebKit::NetworkCache::SpeculativeLoadManager::retrieve):
(WebKit::NetworkCache::SpeculativeLoadManager::registerLoad):
(WebKit::NetworkCache::SpeculativeLoadManager::addPreloadedEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::retrieveEntryFromStorage):
(WebKit::NetworkCache::SpeculativeLoadManager::satisfyPendingRequests):
(WebKit::NetworkCache::SpeculativeLoadManager::revalidateEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::preloadEntry):
(WebKit::NetworkCache::SpeculativeLoadManager::startSpeculativeRevalidation):
(WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::registerSubresource): Deleted.
(WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::encodeAsSubresourcesRecord): Deleted.
* NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h:
* WebKit2.xcodeproj/project.pbxproj:</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceWebKit2NetworkProcesscacheNetworkCachecpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheEntrycpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheEntryh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadManagercpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadManagerh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h</a></li>
<li><a href="#trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj">trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadcpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/ChangeLog        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -1,3 +1,67 @@
</span><ins>+2015-11-11  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        [WK2] Add initial support for speculative resource revalidation to the WebKit disk cache
+        https://bugs.webkit.org/show_bug.cgi?id=150856
+        &lt;rdar://problem/23092196&gt;
+
+        Reviewed by Antti Koivisto.
+
+        Add initial support for speculative resource revalidation to the WebKit
+        disk cache. When a main resource is requested by WebCore, we look up its
+        list of subresources in the cache and speculatively warm them up before
+        WebCore asks for them, in order to improve page load time. In this
+        context, warming it up means:
+        1. If the cached resource is usable (has not expired), keep it around
+           in a memory for a limited amount of time (10 seconds).
+        2. If the resource has expired, do a speculative revalidation of the
+           resource and then keep it in memory for a while as well (10 seconds).
+
+        The feature is currently behind a compile-time flag that is only enabled
+        on COCOA. Also, it is currently disabled at run-time until it is mature
+        enough.
+
+        Initial results show that speculative revalidation gives a ~5%
+        progression on throttled warm PLT on iPhone 5s.
+
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::start):
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::Cache::retrieve):
+        (WebKit::NetworkCache::Cache::store):
+        (WebKit::NetworkCache::Cache::update):
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheEntry.cpp:
+        (WebKit::NetworkCache::Entry::Entry):
+        * NetworkProcess/cache/NetworkCacheEntry.h:
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp: Added.
+        (WebKit::NetworkCache::SpeculativeLoad::SpeculativeLoad):
+        (WebKit::NetworkCache::SpeculativeLoad::~SpeculativeLoad):
+        (WebKit::NetworkCache::SpeculativeLoad::willSendRedirectedRequest):
+        (WebKit::NetworkCache::SpeculativeLoad::didReceiveBuffer):
+        (WebKit::NetworkCache::SpeculativeLoad::didFinishLoading):
+        (WebKit::NetworkCache::SpeculativeLoad::didFailLoading):
+        (WebKit::NetworkCache::SpeculativeLoad::didComplete):
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoad.h: Added.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp:
+        (WebKit::NetworkCache::constructRevalidationRequest):
+        (WebKit::NetworkCache::responseNeedsRevalidation):
+        (WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::PreloadedEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::takeCacheEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::PreloadedEntry::lifetimeTimerFired):
+        (WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::PendingFrameLoad):
+        (WebKit::NetworkCache::SpeculativeLoadManager::retrieve):
+        (WebKit::NetworkCache::SpeculativeLoadManager::registerLoad):
+        (WebKit::NetworkCache::SpeculativeLoadManager::addPreloadedEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::retrieveEntryFromStorage):
+        (WebKit::NetworkCache::SpeculativeLoadManager::satisfyPendingRequests):
+        (WebKit::NetworkCache::SpeculativeLoadManager::revalidateEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::preloadEntry):
+        (WebKit::NetworkCache::SpeculativeLoadManager::startSpeculativeRevalidation):
+        (WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::registerSubresource): Deleted.
+        (WebKit::NetworkCache::SpeculativeLoadManager::PendingFrameLoad::encodeAsSubresourcesRecord): Deleted.
+        * NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h:
+        * WebKit2.xcodeproj/project.pbxproj:
+
</ins><span class="cx"> 2015-11-11  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         _WKRemoteObjectInterface should handle specifying allowed classes for reply block arguments
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessNetworkResourceLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -128,7 +128,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;NetworkResourceLoader&gt; loader(this);
</span><del>-    NetworkCache::singleton().retrieve(originalRequest(), m_parameters.webPageID, m_parameters.webFrameID, [loader](std::unique_ptr&lt;NetworkCache::Entry&gt; entry) {
</del><ins>+    NetworkCache::singleton().retrieve(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, [loader](std::unique_ptr&lt;NetworkCache::Entry&gt; entry) {
</ins><span class="cx">         if (loader-&gt;hasOneRef()) {
</span><span class="cx">             // The loader has been aborted and is only held alive by this lambda.
</span><span class="cx">             return;
</span><span class="lines">@@ -241,7 +241,7 @@
</span><span class="cx">     if (m_cacheEntryForValidation) {
</span><span class="cx">         bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
</span><span class="cx">         if (validationSucceeded) {
</span><del>-            NetworkCache::singleton().update(originalRequest(), m_parameters.webPageID, *m_cacheEntryForValidation, m_response);
</del><ins>+            NetworkCache::singleton().update(originalRequest(), { m_parameters.webPageID, m_parameters.webFrameID }, *m_cacheEntryForValidation, m_response);
</ins><span class="cx">             // If the request was conditional then this revalidation was not triggered by the network cache and we pass the
</span><span class="cx">             // 304 response to WebCore.
</span><span class="cx">             if (originalRequest().isConditional())
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCachecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -343,7 +343,7 @@
</span><span class="cx">     return StoreDecision::Yes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Cache::retrieve(const WebCore::ResourceRequest&amp; originalRequest, uint64_t webPageID, uint64_t webFrameID, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler)
</del><ins>+void Cache::retrieve(const WebCore::ResourceRequest&amp; originalRequest, const GlobalFrameID&amp; frameID, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isEnabled());
</span><span class="cx">     ASSERT(originalRequest.url().protocolIsInHTTPFamily());
</span><span class="lines">@@ -351,35 +351,47 @@
</span><span class="cx">     LOG(NetworkCache, &quot;(NetworkProcess) retrieving %s priority %d&quot;, originalRequest.url().string().ascii().data(), static_cast&lt;int&gt;(originalRequest.priority()));
</span><span class="cx"> 
</span><span class="cx">     if (m_statistics)
</span><del>-        m_statistics-&gt;recordRetrievalRequest(webPageID);
</del><ins>+        m_statistics-&gt;recordRetrievalRequest(frameID.first);
</ins><span class="cx"> 
</span><span class="cx">     Key storageKey = makeCacheKey(originalRequest);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
</span><del>-    if (m_speculativeLoadManager)
-        m_speculativeLoadManager-&gt;registerLoad(webPageID, webFrameID, originalRequest, storageKey);
-#else
-    UNUSED_PARAM(webFrameID);
</del><ins>+    if (m_speculativeLoadManager) {
+        m_speculativeLoadManager-&gt;registerLoad(frameID, originalRequest, storageKey);
+        RunLoop::main().dispatch([this, originalRequest, frameID, storageKey] {
+            m_speculativeLoadManager-&gt;startSpeculativeRevalidation(originalRequest, frameID, storageKey);
+        });
+    }
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     auto retrieveDecision = makeRetrieveDecision(originalRequest);
</span><span class="cx">     if (retrieveDecision != RetrieveDecision::Yes) {
</span><span class="cx">         if (m_statistics)
</span><del>-            m_statistics-&gt;recordNotUsingCacheForRequest(webPageID, storageKey, originalRequest, retrieveDecision);
</del><ins>+            m_statistics-&gt;recordNotUsingCacheForRequest(frameID.first, storageKey, originalRequest, retrieveDecision);
</ins><span class="cx"> 
</span><span class="cx">         completionHandler(nullptr);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+    if (m_speculativeLoadManager &amp;&amp; m_speculativeLoadManager-&gt;retrieve(storageKey, [originalRequest, completionHandler](std::unique_ptr&lt;Entry&gt; entry) {
+        if (entry &amp;&amp; verifyVaryingRequestHeaders(entry-&gt;varyingRequestHeaders(), originalRequest))
+            completionHandler(WTF::move(entry));
+        else
+            completionHandler(nullptr);
+    }))
+        return;
+#endif
+
</ins><span class="cx">     auto startTime = std::chrono::system_clock::now();
</span><span class="cx">     auto priority = static_cast&lt;unsigned&gt;(originalRequest.priority());
</span><span class="cx"> 
</span><del>-    m_storage-&gt;retrieve(storageKey, priority, [this, originalRequest, completionHandler, startTime, storageKey, webPageID](std::unique_ptr&lt;Storage::Record&gt; record) {
</del><ins>+    m_storage-&gt;retrieve(storageKey, priority, [this, originalRequest, completionHandler, startTime, storageKey, frameID](std::unique_ptr&lt;Storage::Record&gt; record) {
</ins><span class="cx">         if (!record) {
</span><span class="cx">             LOG(NetworkCache, &quot;(NetworkProcess) not found in storage&quot;);
</span><span class="cx"> 
</span><span class="cx">             if (m_statistics)
</span><del>-                m_statistics-&gt;recordRetrievalFailure(webPageID, storageKey, originalRequest);
</del><ins>+                m_statistics-&gt;recordRetrievalFailure(frameID.first, storageKey, originalRequest);
</ins><span class="cx"> 
</span><span class="cx">             completionHandler(nullptr);
</span><span class="cx">             return false;
</span><span class="lines">@@ -407,12 +419,12 @@
</span><span class="cx">         completionHandler(WTF::move(entry));
</span><span class="cx"> 
</span><span class="cx">         if (m_statistics)
</span><del>-            m_statistics-&gt;recordRetrievedCachedEntry(webPageID, storageKey, originalRequest, useDecision);
</del><ins>+            m_statistics-&gt;recordRetrievedCachedEntry(frameID.first, storageKey, originalRequest, useDecision);
</ins><span class="cx">         return useDecision != UseDecision::NoDueToDecodeFailure;
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Cache::store(const WebCore::ResourceRequest&amp; originalRequest, const WebCore::ResourceResponse&amp; response, RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp; responseData, std::function&lt;void (MappedBody&amp;)&gt; completionHandler)
</del><ins>+std::unique_ptr&lt;Entry&gt; Cache::store(const WebCore::ResourceRequest&amp; originalRequest, const WebCore::ResourceResponse&amp; response, RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp; responseData, std::function&lt;void (MappedBody&amp;)&gt; completionHandler)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isEnabled());
</span><span class="cx">     ASSERT(responseData);
</span><span class="lines">@@ -440,12 +452,12 @@
</span><span class="cx">         if (m_statistics)
</span><span class="cx">             m_statistics-&gt;recordNotCachingResponse(key, storeDecision);
</span><span class="cx"> 
</span><del>-        return;
</del><ins>+        return nullptr;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    Entry cacheEntry(makeCacheKey(originalRequest), response, WTF::move(responseData), collectVaryingRequestHeaders(originalRequest, response));
</del><ins>+    std::unique_ptr&lt;Entry&gt; cacheEntry = std::make_unique&lt;Entry&gt;(makeCacheKey(originalRequest), response, WTF::move(responseData), collectVaryingRequestHeaders(originalRequest, response));
</ins><span class="cx"> 
</span><del>-    auto record = cacheEntry.encodeAsStorageRecord();
</del><ins>+    auto record = cacheEntry-&gt;encodeAsStorageRecord();
</ins><span class="cx"> 
</span><span class="cx">     m_storage-&gt;store(record, [completionHandler](const Data&amp; bodyData) {
</span><span class="cx">         MappedBody mappedBody;
</span><span class="lines">@@ -459,23 +471,27 @@
</span><span class="cx">         completionHandler(mappedBody);
</span><span class="cx">         LOG(NetworkCache, &quot;(NetworkProcess) stored&quot;);
</span><span class="cx">     });
</span><ins>+
+    return cacheEntry;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Cache::update(const WebCore::ResourceRequest&amp; originalRequest, uint64_t webPageID, const Entry&amp; existingEntry, const WebCore::ResourceResponse&amp; validatingResponse)
</del><ins>+std::unique_ptr&lt;Entry&gt; Cache::update(const WebCore::ResourceRequest&amp; originalRequest, const GlobalFrameID&amp; frameID, const Entry&amp; existingEntry, const WebCore::ResourceResponse&amp; validatingResponse)
</ins><span class="cx"> {
</span><span class="cx">     LOG(NetworkCache, &quot;(NetworkProcess) updating %s&quot;, originalRequest.url().string().latin1().data());
</span><span class="cx"> 
</span><span class="cx">     WebCore::ResourceResponse response = existingEntry.response();
</span><span class="cx">     WebCore::updateResponseHeadersAfterRevalidation(response, validatingResponse);
</span><ins>+    response.setSource(WebCore::ResourceResponse::Source::DiskCache);
</ins><span class="cx"> 
</span><del>-    Entry updateEntry(existingEntry.key(), response, existingEntry.buffer(), collectVaryingRequestHeaders(originalRequest, response));
</del><ins>+    auto updateEntry = std::make_unique&lt;Entry&gt;(existingEntry.key(), response, existingEntry.buffer(), collectVaryingRequestHeaders(originalRequest, response));
+    auto updateRecord = updateEntry-&gt;encodeAsStorageRecord();
</ins><span class="cx"> 
</span><del>-    auto updateRecord = updateEntry.encodeAsStorageRecord();
-
</del><span class="cx">     m_storage-&gt;store(updateRecord, { });
</span><span class="cx"> 
</span><span class="cx">     if (m_statistics)
</span><del>-        m_statistics-&gt;recordRevalidationSuccess(webPageID, existingEntry.key(), originalRequest);
</del><ins>+        m_statistics-&gt;recordRevalidationSuccess(frameID.first, existingEntry.key(), originalRequest);
+
+    return updateEntry;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Cache::remove(const Key&amp; key)
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -84,6 +84,8 @@
</span><span class="cx">     NoDueToDecodeFailure,
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+using GlobalFrameID = std::pair&lt;uint64_t /*webPageID*/, uint64_t /*webFrameID*/&gt;;
+
</ins><span class="cx"> class Cache {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(Cache);
</span><span class="cx">     friend class WTF::NeverDestroyed&lt;Cache&gt;;
</span><span class="lines">@@ -100,9 +102,9 @@
</span><span class="cx">     bool isEnabled() const { return !!m_storage; }
</span><span class="cx"> 
</span><span class="cx">     // Completion handler may get called back synchronously on failure.
</span><del>-    void retrieve(const WebCore::ResourceRequest&amp;, uint64_t webPageID, uint64_t webFrameID, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt;);
-    void store(const WebCore::ResourceRequest&amp;, const WebCore::ResourceResponse&amp;, RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp;, std::function&lt;void (MappedBody&amp;)&gt;);
-    void update(const WebCore::ResourceRequest&amp;, uint64_t webPageID, const Entry&amp;, const WebCore::ResourceResponse&amp; validatingResponse);
</del><ins>+    void retrieve(const WebCore::ResourceRequest&amp;, const GlobalFrameID&amp;, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt;);
+    std::unique_ptr&lt;Entry&gt; store(const WebCore::ResourceRequest&amp;, const WebCore::ResourceResponse&amp;, RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp;, std::function&lt;void (MappedBody&amp;)&gt;);
+    std::unique_ptr&lt;Entry&gt; update(const WebCore::ResourceRequest&amp;, const GlobalFrameID&amp;, const Entry&amp;, const WebCore::ResourceResponse&amp; validatingResponse);
</ins><span class="cx"> 
</span><span class="cx">     void traverse(std::function&lt;void (const Entry*)&gt;&amp;&amp;);
</span><span class="cx">     void remove(const Key&amp;);
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheEntrycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.cpp        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -49,6 +49,16 @@
</span><span class="cx">     ASSERT(m_key.type() == &quot;resource&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Entry::Entry(const Entry&amp; other)
+    : m_key(other.m_key)
+    , m_timeStamp(other.m_timeStamp)
+    , m_response(other.m_response)
+    , m_varyingRequestHeaders(other.m_varyingRequestHeaders)
+    , m_buffer(other.m_buffer)
+    , m_sourceStorageRecord(other.m_sourceStorageRecord)
+{
+}
+
</ins><span class="cx"> Entry::Entry(const Storage::Record&amp; storageEntry)
</span><span class="cx">     : m_key(storageEntry.key)
</span><span class="cx">     , m_timeStamp(storageEntry.timeStamp)
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheEntryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEntry.h        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -43,10 +43,11 @@
</span><span class="cx"> namespace NetworkCache {
</span><span class="cx"> 
</span><span class="cx"> class Entry {
</span><del>-    WTF_MAKE_NONCOPYABLE(Entry); WTF_MAKE_FAST_ALLOCATED;
</del><ins>+    WTF_MAKE_FAST_ALLOCATED;
</ins><span class="cx"> public:
</span><span class="cx">     Entry(const Key&amp;, const WebCore::ResourceResponse&amp;, RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp;, const Vector&lt;std::pair&lt;String, String&gt;&gt;&amp; varyingRequestHeaders);
</span><span class="cx">     explicit Entry(const Storage::Record&amp;);
</span><ins>+    Entry(const Entry&amp;);
</ins><span class="cx"> 
</span><span class="cx">     Storage::Record encodeAsStorageRecord() const;
</span><span class="cx">     static std::unique_ptr&lt;Entry&gt; decodeStorageRecord(const Storage::Record&amp;);
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp (0 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.cpp        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -0,0 +1,148 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+#include &quot;NetworkCacheSpeculativeLoad.h&quot;
+
+#include &quot;Logging.h&quot;
+#include &quot;NetworkCache.h&quot;
+#include &quot;NetworkLoad.h&quot;
+#include &lt;WebCore/SessionID.h&gt;
+#include &lt;wtf/CurrentTime.h&gt;
+#include &lt;wtf/RunLoop.h&gt;
+
+namespace WebKit {
+namespace NetworkCache {
+
+using namespace WebCore;
+
+SpeculativeLoad::SpeculativeLoad(const GlobalFrameID&amp; frameID, const ResourceRequest&amp; request, std::unique_ptr&lt;NetworkCache::Entry&gt; cacheEntryForValidation, RevalidationCompletionHandler&amp;&amp; completionHandler)
+    : m_frameID(frameID)
+    , m_completionHandler(WTF::move(completionHandler))
+    , m_originalRequest(request)
+    , m_bufferedDataForCache(SharedBuffer::create())
+    , m_cacheEntryForValidation(WTF::move(cacheEntryForValidation))
+{
+    ASSERT(m_cacheEntryForValidation);
+    ASSERT(m_cacheEntryForValidation-&gt;needsValidation());
+
+    NetworkLoadParameters parameters;
+    parameters.sessionID = SessionID::defaultSessionID();
+    parameters.allowStoredCredentials = AllowStoredCredentials;
+    parameters.contentSniffingPolicy = DoNotSniffContent;
+    parameters.request = m_originalRequest;
+    m_networkLoad = std::make_unique&lt;NetworkLoad&gt;(*this, parameters);
+}
+
+SpeculativeLoad::~SpeculativeLoad()
+{
+    ASSERT(!m_networkLoad);
+}
+
+void SpeculativeLoad::willSendRedirectedRequest(const ResourceRequest&amp; request, const ResourceResponse&amp; redirectResponse)
+{
+    updateRedirectChainStatus(m_redirectChainCacheStatus, redirectResponse);
+}
+
+auto SpeculativeLoad::didReceiveResponse(const ResourceResponse&amp; receivedResponse) -&gt; ShouldContinueDidReceiveResponse
+{
+    m_response = receivedResponse;
+
+    if (m_response.isMultipart())
+        m_bufferedDataForCache = nullptr;
+
+    ASSERT(m_cacheEntryForValidation);
+
+    bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
+    if (validationSucceeded) {
+        m_cacheEntryForValidation = NetworkCache::singleton().update(m_originalRequest, m_frameID, *m_cacheEntryForValidation, m_response);
+        didComplete();
+        return ShouldContinueDidReceiveResponse::No;
+    }
+
+    m_cacheEntryForValidation = nullptr;
+
+    return ShouldContinueDidReceiveResponse::Yes;
+}
+
+void SpeculativeLoad::didReceiveBuffer(RefPtr&lt;SharedBuffer&gt;&amp;&amp; buffer, int reportedEncodedDataLength)
+{
+    ASSERT(!m_cacheEntryForValidation);
+
+    if (m_bufferedDataForCache) {
+        // Prevent memory growth in case of streaming data.
+        const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
+        if (m_bufferedDataForCache-&gt;size() + buffer-&gt;size() &lt;= maximumCacheBufferSize)
+            m_bufferedDataForCache-&gt;append(buffer.get());
+        else
+            m_bufferedDataForCache = nullptr;
+    }
+}
+
+void SpeculativeLoad::didFinishLoading(double finishTime)
+{
+    ASSERT(!m_cacheEntryForValidation);
+
+    bool allowStale = m_originalRequest.cachePolicy() &gt;= ReturnCacheDataElseLoad;
+    bool hasCacheableRedirect = m_response.isHTTP() &amp;&amp; redirectChainAllowsReuse(m_redirectChainCacheStatus, allowStale ? ReuseExpiredRedirection : DoNotReuseExpiredRedirection);
+    if (hasCacheableRedirect &amp;&amp; m_redirectChainCacheStatus.status == RedirectChainCacheStatus::CachedRedirection) {
+        // Maybe we should cache the actual redirects instead of the end result?
+        auto now = std::chrono::system_clock::now();
+        auto responseEndOfValidity = now + computeFreshnessLifetimeForHTTPFamily(m_response, now) - computeCurrentAge(m_response, now);
+        hasCacheableRedirect = responseEndOfValidity &lt;= m_redirectChainCacheStatus.endOfValidity;
+    }
+
+    if (m_bufferedDataForCache &amp;&amp; hasCacheableRedirect)
+        m_cacheEntryForValidation = NetworkCache::singleton().store(m_originalRequest, m_response, WTF::move(m_bufferedDataForCache), [](NetworkCache::MappedBody&amp; mappedBody) { });
+    else if (!hasCacheableRedirect) {
+        // Make sure we don't keep a stale entry in the cache.
+        NetworkCache::singleton().remove(m_originalRequest);
+    }
+
+    didComplete();
+}
+
+void SpeculativeLoad::didFailLoading(const ResourceError&amp;)
+{
+    m_cacheEntryForValidation = nullptr;
+
+    didComplete();
+}
+
+void SpeculativeLoad::didComplete()
+{
+    RELEASE_ASSERT(RunLoop::isMain());
+
+    m_networkLoad = nullptr;
+
+    m_completionHandler(WTF::move(m_cacheEntryForValidation));
+}
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h (0 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoad.h        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -0,0 +1,87 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NetworkCacheSpeculativeLoad_h
+#define NetworkCacheSpeculativeLoad_h
+
+#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#include &quot;NetworkCache.h&quot;
+#include &quot;NetworkCacheEntry.h&quot;
+#include &quot;NetworkLoadClient.h&quot;
+#include &lt;WebCore/ResourceRequest.h&gt;
+#include &lt;WebCore/ResourceResponse.h&gt;
+#include &lt;WebCore/SharedBuffer.h&gt;
+
+namespace WebKit {
+
+class NetworkLoad;
+
+namespace NetworkCache {
+
+class SpeculativeLoad final : public NetworkLoadClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    typedef std::function&lt;void (std::unique_ptr&lt;NetworkCache::Entry&gt;)&gt; RevalidationCompletionHandler;
+    SpeculativeLoad(const GlobalFrameID&amp;, const WebCore::ResourceRequest&amp;, std::unique_ptr&lt;NetworkCache::Entry&gt;, RevalidationCompletionHandler&amp;&amp;);
+
+    virtual ~SpeculativeLoad();
+
+private:
+    // NetworkLoadClient.
+    virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override { }
+    virtual void canAuthenticateAgainstProtectionSpaceAsync(const WebCore::ProtectionSpace&amp;) override { }
+    virtual bool isSynchronous() const override { return false; }
+    virtual void willSendRedirectedRequest(const WebCore::ResourceRequest&amp;, const WebCore::ResourceResponse&amp; redirectResponse) override;
+    virtual ShouldContinueDidReceiveResponse didReceiveResponse(const WebCore::ResourceResponse&amp;) override;
+    virtual void didReceiveBuffer(RefPtr&lt;WebCore::SharedBuffer&gt;&amp;&amp;, int reportedEncodedDataLength) override;
+    virtual void didFinishLoading(double finishTime) override;
+    virtual void didFailLoading(const WebCore::ResourceError&amp;) override;
+#if PLATFORM(COCOA)
+    virtual void willCacheResponseAsync(CFCachedURLResponseRef) override { }
+#endif
+
+    void didComplete();
+
+    GlobalFrameID m_frameID;
+    RevalidationCompletionHandler m_completionHandler;
+    WebCore::ResourceRequest m_originalRequest;
+
+    std::unique_ptr&lt;NetworkLoad&gt; m_networkLoad;
+
+    WebCore::ResourceResponse m_response;
+
+    RefPtr&lt;WebCore::SharedBuffer&gt; m_bufferedDataForCache;
+    std::unique_ptr&lt;NetworkCache::Entry&gt; m_cacheEntryForValidation;
+
+    WebCore::RedirectChainCacheStatus m_redirectChainCacheStatus;
+};
+
+} // namespace NetworkCache
+} // namespace WebKit
+
+#endif // ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
+
+#endif // NetworkCacheSpeculativeLoad_h
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadManagercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.cpp        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -29,6 +29,8 @@
</span><span class="cx"> #include &quot;NetworkCacheSpeculativeLoadManager.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;Logging.h&quot;
</span><ins>+#include &quot;NetworkCacheEntry.h&quot;
+#include &quot;NetworkCacheSpeculativeLoad.h&quot;
</ins><span class="cx"> #include &quot;NetworkCacheSubresourcesEntry.h&quot;
</span><span class="cx"> #include &lt;WebCore/HysteresisActivity.h&gt;
</span><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><span class="lines">@@ -40,6 +42,8 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><ins>+static const auto preloadedEntryLifetime = 10_s;
+
</ins><span class="cx"> static const AtomicString&amp; subresourcesType()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="lines">@@ -52,12 +56,65 @@
</span><span class="cx">     return Key(resourceKey.partition(), subresourcesType(), resourceKey.range(), resourceKey.identifier());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline ResourceRequest constructRevalidationRequest(const Entry&amp; entry)
+{
+    ResourceRequest revalidationRequest(entry.key().identifier());
+
+    String eTag = entry.response().httpHeaderField(HTTPHeaderName::ETag);
+    if (!eTag.isEmpty())
+        revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag);
+
+    String lastModified = entry.response().httpHeaderField(HTTPHeaderName::LastModified);
+    if (!lastModified.isEmpty())
+        revalidationRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified);
+
+    return revalidationRequest;
+}
+
+static bool responseNeedsRevalidation(const ResourceResponse&amp; response, std::chrono::system_clock::time_point timestamp)
+{
+    if (response.cacheControlContainsNoCache())
+        return true;
+
+    auto age = computeCurrentAge(response, timestamp);
+    auto lifetime = computeFreshnessLifetimeForHTTPFamily(response, timestamp);
+    return age - lifetime &gt; 0_ms;
+}
+
+class SpeculativeLoadManager::PreloadedEntry {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    PreloadedEntry(std::unique_ptr&lt;Entry&gt; entry, std::function&lt;void()&gt;&amp;&amp; lifetimeReachedHandler)
+        : m_entry(WTF::move(entry))
+        , m_lifetimeTimer(*this, &amp;PreloadedEntry::lifetimeTimerFired)
+        , m_lifetimeReachedHandler(WTF::move(lifetimeReachedHandler))
+    {
+        m_lifetimeTimer.startOneShot(preloadedEntryLifetime);
+    }
+
+    std::unique_ptr&lt;Entry&gt; takeCacheEntry()
+    {
+        ASSERT(m_entry);
+        return WTF::move(m_entry);
+    }
+
+private:
+    void lifetimeTimerFired()
+    {
+        m_lifetimeReachedHandler();
+    }
+
+    std::unique_ptr&lt;Entry&gt; m_entry;
+    Timer m_lifetimeTimer;
+    std::function&lt;void()&gt; m_lifetimeReachedHandler;
+};
+
</ins><span class="cx"> class SpeculativeLoadManager::PendingFrameLoad {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><del>-    PendingFrameLoad(const Key&amp; mainResourceKey, std::function&lt;void()&gt; completionHandler)
</del><ins>+    PendingFrameLoad(const Key&amp; mainResourceKey, std::function&lt;void()&gt;&amp;&amp; completionHandler)
</ins><span class="cx">         : m_mainResourceKey(mainResourceKey)
</span><del>-        , m_completionHandler(completionHandler)
</del><ins>+        , m_completionHandler(WTF::move(completionHandler))
</ins><span class="cx">         , m_loadHysteresisActivity([this](HysteresisState state) { if (state == HysteresisState::Stopped) m_completionHandler(); })
</span><span class="cx">     { }
</span><span class="cx"> 
</span><span class="lines">@@ -109,23 +166,45 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeLoadManager::registerLoad(uint64_t webPageID, uint64_t webFrameID, const ResourceRequest&amp; request, const Key&amp; resourceKey)
</del><ins>+bool SpeculativeLoadManager::retrieve(const Key&amp; storageKey, const RetrieveCompletionHandler&amp; completionHandler)
</ins><span class="cx"> {
</span><ins>+    // Check already preloaded entries.
+    if (auto preloadedEntry = m_preloadedEntries.take(storageKey)) {
+        LOG(NetworkCacheSpeculativePreloading, &quot;(NetworkProcess) Retrieval: Using preloaded entry to satisfy request for '%s':&quot;, storageKey.identifier().utf8().data());
+        completionHandler(preloadedEntry-&gt;takeCacheEntry());
+        return true;
+    }
+
+    // Check pending speculative revalidations.
+    if (!m_pendingPreloads.contains(storageKey))
+        return false;
+
+    LOG(NetworkCacheSpeculativePreloading, &quot;(NetworkProcess) Retrieval: revalidation already in progress for '%s':&quot;, storageKey.identifier().utf8().data());
+
+    // FIXME: This breaks incremental loading when the revalidation is not successful.
+    auto addResult = m_pendingRetrieveRequests.add(storageKey, nullptr);
+    if (addResult.isNewEntry)
+        addResult.iterator-&gt;value = std::make_unique&lt;Vector&lt;RetrieveCompletionHandler&gt;&gt;();
+    addResult.iterator-&gt;value-&gt;append(completionHandler);
+    return true;
+}
+
+void SpeculativeLoadManager::registerLoad(const GlobalFrameID&amp; frameID, const ResourceRequest&amp; request, const Key&amp; resourceKey)
+{
</ins><span class="cx">     ASSERT(RunLoop::isMain());
</span><span class="cx"> 
</span><span class="cx">     if (!request.url().protocolIsInHTTPFamily() || request.httpMethod() != &quot;GET&quot;)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    auto frameKey = std::make_pair(webPageID, webFrameID);
</del><span class="cx">     auto isMainResource = request.requester() == ResourceRequest::Requester::Main;
</span><span class="cx">     if (isMainResource) {
</span><span class="cx">         // Mark previous load in this frame as completed if necessary.
</span><del>-        if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameKey))
</del><ins>+        if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameID))
</ins><span class="cx">             pendingFrameLoad-&gt;markAsCompleted();
</span><span class="cx"> 
</span><span class="cx">         // Start tracking loads in this frame.
</span><del>-        m_pendingFrameLoads.add(frameKey, std::make_unique&lt;PendingFrameLoad&gt;(resourceKey, [this, frameKey]() {
-            auto frameLoad = m_pendingFrameLoads.take(frameKey);
</del><ins>+        m_pendingFrameLoads.add(frameID, std::make_unique&lt;PendingFrameLoad&gt;(resourceKey, [this, frameID]() {
+            auto frameLoad = m_pendingFrameLoads.take(frameID);
</ins><span class="cx">             auto optionalRecord = frameLoad-&gt;encodeAsSubresourcesRecord();
</span><span class="cx">             if (!optionalRecord)
</span><span class="cx">                 return;
</span><span class="lines">@@ -134,10 +213,121 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameKey))
</del><ins>+    if (auto* pendingFrameLoad = m_pendingFrameLoads.get(frameID))
</ins><span class="cx">         pendingFrameLoad-&gt;registerSubresource(resourceKey);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeLoadManager::addPreloadedEntry(std::unique_ptr&lt;Entry&gt; entry)
+{
+    ASSERT(entry);
+    ASSERT(!entry-&gt;needsValidation());
+    auto key = entry-&gt;key();
+    m_preloadedEntries.add(key, std::make_unique&lt;PreloadedEntry&gt;(WTF::move(entry), [this, key]() {
+        m_preloadedEntries.remove(key);
+    }));
+}
+
+void SpeculativeLoadManager::retrieveEntryFromStorage(const Key&amp; key, const RetrieveCompletionHandler&amp; completionHandler)
+{
+    m_storage.retrieve(key, static_cast&lt;unsigned&gt;(ResourceLoadPriority::Medium), [completionHandler](std::unique_ptr&lt;Storage::Record&gt; record) {
+        if (!record) {
+            completionHandler(nullptr);
+            return false;
+        }
+        auto entry = Entry::decodeStorageRecord(*record);
+        if (!entry) {
+            completionHandler(nullptr);
+            return false;
+        }
+
+        auto&amp; response = entry-&gt;response();
+        if (!response.hasCacheValidatorFields()) {
+            completionHandler(nullptr);
+            return true;
+        }
+
+        if (responseNeedsRevalidation(response, entry-&gt;timeStamp()))
+            entry-&gt;setNeedsValidation();
+
+        completionHandler(WTF::move(entry));
+        return true;
+    });
+}
+
+bool SpeculativeLoadManager::satisfyPendingRequests(const Key&amp; key, Entry* entry)
+{
+    auto completionHandlers = m_pendingRetrieveRequests.take(key);
+    if (!completionHandlers)
+        return false;
+
+    for (auto&amp; completionHandler : *completionHandlers)
+        completionHandler(entry ? std::make_unique&lt;Entry&gt;(*entry) : nullptr);
+
+    return true;
+}
+
+void SpeculativeLoadManager::revalidateEntry(std::unique_ptr&lt;Entry&gt; entry, const GlobalFrameID&amp; frameID)
+{
+    ASSERT(entry);
+    ASSERT(entry-&gt;needsValidation());
+
+    auto key = entry-&gt;key();
+    LOG(NetworkCacheSpeculativePreloading, &quot;(NetworkProcess) Speculatively revalidating '%s':&quot;, key.identifier().utf8().data());
+    auto revalidator = std::make_unique&lt;SpeculativeLoad&gt;(frameID, constructRevalidationRequest(*entry), WTF::move(entry), [this, key](std::unique_ptr&lt;Entry&gt; revalidatedEntry) {
+        ASSERT(!revalidatedEntry || !revalidatedEntry-&gt;needsValidation());
+        auto protectRevalidator = m_pendingPreloads.take(key);
+        LOG(NetworkCacheSpeculativePreloading, &quot;(NetworkProcess) Speculative revalidation completed for '%s':&quot;, key.identifier().utf8().data());
+
+        if (satisfyPendingRequests(key, revalidatedEntry.get()))
+            return;
+
+        if (revalidatedEntry)
+            addPreloadedEntry(WTF::move(revalidatedEntry));
+    });
+    m_pendingPreloads.add(key, WTF::move(revalidator));
+}
+
+void SpeculativeLoadManager::preloadEntry(const Key&amp; key, const GlobalFrameID&amp; frameID)
+{
+    m_pendingPreloads.add(key, nullptr);
+    retrieveEntryFromStorage(key, [this, key, frameID](std::unique_ptr&lt;Entry&gt; entry) {
+        m_pendingPreloads.remove(key);
+
+        if (satisfyPendingRequests(key, entry.get()))
+            return;
+
+        if (!entry)
+            return;
+
+        if (entry-&gt;needsValidation())
+            revalidateEntry(WTF::move(entry), frameID);
+        else
+            addPreloadedEntry(WTF::move(entry));
+    });
+}
+
+void SpeculativeLoadManager::startSpeculativeRevalidation(const ResourceRequest&amp; originalRequest, const GlobalFrameID&amp; frameID, const Key&amp; storageKey)
+{
+    if (originalRequest.requester() != ResourceRequest::Requester::Main)
+        return;
+
+    auto subresourcesStorageKey = makeSubresourcesKey(storageKey);
+
+    m_storage.retrieve(subresourcesStorageKey, static_cast&lt;unsigned&gt;(ResourceLoadPriority::Medium), [this, frameID](std::unique_ptr&lt;Storage::Record&gt; record) {
+        if (!record)
+            return false;
+
+        auto subresourcesEntry = SubresourcesEntry::decodeStorageRecord(*record);
+        if (!subresourcesEntry)
+            return false;
+
+        for (auto&amp; subresourceKey : subresourcesEntry-&gt;subresourceKeys())
+            preloadEntry(subresourceKey, frameID);
+
+        return true;
+    });
+}
+
</ins><span class="cx"> } // namespace NetworkCache
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheSpeculativeLoadManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheSpeculativeLoadManager.h        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -28,27 +28,48 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
</span><span class="cx"> 
</span><ins>+#include &quot;NetworkCache.h&quot;
</ins><span class="cx"> #include &quot;NetworkCacheStorage.h&quot;
</span><span class="cx"> #include &lt;WebCore/ResourceRequest.h&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><ins>+#include &lt;wtf/Vector.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> namespace NetworkCache {
</span><span class="cx"> 
</span><ins>+class Entry;
+class SpeculativeLoad;
+
</ins><span class="cx"> class SpeculativeLoadManager {
</span><span class="cx"> public:
</span><span class="cx">     explicit SpeculativeLoadManager(Storage&amp;);
</span><span class="cx">     ~SpeculativeLoadManager();
</span><span class="cx"> 
</span><del>-    void registerLoad(uint64_t webPageID, uint64_t webFrameID, const WebCore::ResourceRequest&amp;, const Key&amp; resourceKey);
</del><ins>+    void registerLoad(const GlobalFrameID&amp;, const WebCore::ResourceRequest&amp;, const Key&amp; resourceKey);
</ins><span class="cx"> 
</span><ins>+    typedef std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt; RetrieveCompletionHandler;
+    bool retrieve(const Key&amp; storageKey, const RetrieveCompletionHandler&amp;);
+
+    void startSpeculativeRevalidation(const WebCore::ResourceRequest&amp;, const GlobalFrameID&amp;, const Key&amp; storageKey);
+
</ins><span class="cx"> private:
</span><ins>+    void addPreloadedEntry(std::unique_ptr&lt;Entry&gt;);
+    void preloadEntry(const Key&amp;, const GlobalFrameID&amp;);
+    void retrieveEntryFromStorage(const Key&amp;, const RetrieveCompletionHandler&amp;);
+    void revalidateEntry(std::unique_ptr&lt;Entry&gt;, const GlobalFrameID&amp;);
+    bool satisfyPendingRequests(const Key&amp;, Entry*);
+
</ins><span class="cx">     Storage&amp; m_storage;
</span><span class="cx"> 
</span><span class="cx">     class PendingFrameLoad;
</span><del>-    using GlobalFrameID = std::pair&lt;uint64_t /*webPageID*/, uint64_t /*webFrameID*/&gt;;
</del><span class="cx">     HashMap&lt;GlobalFrameID, std::unique_ptr&lt;PendingFrameLoad&gt;&gt; m_pendingFrameLoads;
</span><ins>+
+    HashMap&lt;Key, std::unique_ptr&lt;SpeculativeLoad&gt;&gt; m_pendingPreloads;
+    HashMap&lt;Key, std::unique_ptr&lt;Vector&lt;RetrieveCompletionHandler&gt;&gt;&gt; m_pendingRetrieveRequests;
+
+    class PreloadedEntry;
+    HashMap&lt;Key, std::unique_ptr&lt;PreloadedEntry&gt;&gt; m_preloadedEntries;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace NetworkCache
</span></span></pre></div>
<a id="trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (192327 => 192328)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2015-11-11 22:57:41 UTC (rev 192327)
+++ trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2015-11-11 23:01:30 UTC (rev 192328)
</span><span class="lines">@@ -1179,6 +1179,8 @@
</span><span class="cx">                 83048AE61ACA45DC0082C832 /* ProcessThrottlerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */; };
</span><span class="cx">                 8310428B1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 831042891BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h */; };
</span><span class="cx">                 8310428C1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8310428A1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp */; };
</span><ins>+                831EEBBD1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.h in Headers */ = {isa = PBXBuildFile; fileRef = 831EEBBB1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.h */; };
+                831EEBBE1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831EEBBC1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.cpp */; };
</ins><span class="cx">                 832AE2521BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.h */; };
</span><span class="cx">                 832AE2531BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.cpp */; };
</span><span class="cx">                 834B250F1A831A8D00CFB150 /* NetworkCacheFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B250E1A831A8D00CFB150 /* NetworkCacheFileSystem.h */; };
</span><span class="lines">@@ -3418,6 +3420,8 @@
</span><span class="cx">                 83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessThrottlerClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 831042891BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheSubresourcesEntry.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 8310428A1BD6B66F00A715E4 /* NetworkCacheSubresourcesEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSubresourcesEntry.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                831EEBBB1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheSpeculativeLoad.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                831EEBBC1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSpeculativeLoad.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheSpeculativeLoadManager.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSpeculativeLoadManager.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 834B250E1A831A8D00CFB150 /* NetworkCacheFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheFileSystem.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -7578,6 +7582,8 @@
</span><span class="cx">                                 E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */,
</span><span class="cx">                                 832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.cpp */,
</span><span class="cx">                                 832AE2501BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.h */,
</span><ins>+                                831EEBBC1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.cpp */,
+                                831EEBBB1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.h */,
</ins><span class="cx">                                 83BDCCB81AC5FDB6003F6441 /* NetworkCacheStatistics.cpp */,
</span><span class="cx">                                 834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */,
</span><span class="cx">                                 E4436EC31A0CFDB200EAD204 /* NetworkCacheStorage.cpp */,
</span><span class="lines">@@ -7816,6 +7822,7 @@
</span><span class="cx">                                 C0CE72AD1247E78D00BC0EC4 /* HandleMessage.h in Headers */,
</span><span class="cx">                                 1AC75A1B1B3368270056745B /* HangDetectionDisabler.h in Headers */,
</span><span class="cx">                                 37F90DE31376560E0051CF68 /* HTTPCookieAcceptPolicy.h in Headers */,
</span><ins>+                                831EEBBD1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.h in Headers */,
</ins><span class="cx">                                 5175095A1897249700408FAC /* IDBIdentifier.h in Headers */,
</span><span class="cx">                                 518353DB1885BF8C00D9FE44 /* IDBSerialization.h in Headers */,
</span><span class="cx">                                 51E351CB180F2CCC00E53BE9 /* IDBUtilities.h in Headers */,
</span><span class="lines">@@ -9869,6 +9876,7 @@
</span><span class="cx">                                 515E772F184015800007203F /* UniqueIDBDatabase.cpp in Sources */,
</span><span class="cx">                                 51654EFD184EF33F007DC837 /* UniqueIDBDatabaseBackingStoreSQLite.cpp in Sources */,
</span><span class="cx">                                 515E773318402D510007203F /* UniqueIDBDatabaseIdentifier.cpp in Sources */,
</span><ins>+                                831EEBBE1BD85C4300BB64C3 /* NetworkCacheSpeculativeLoad.cpp in Sources */,
</ins><span class="cx">                                 1A64245F12DE29A100CAAE2C /* UpdateInfo.cpp in Sources */,
</span><span class="cx">                                 1AC1336718565B5700F3EC05 /* UserData.cpp in Sources */,
</span><span class="cx">                                 15739BBC1B42040300D258C1 /* UserMediaPermissionRequestManager.cpp in Sources */,
</span></span></pre>
</div>
</div>

</body>
</html>