<!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>[177294] 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/177294">177294</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2014-12-15 11:25:23 -0800 (Mon, 15 Dec 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebKit level persistent caching
https://bugs.webkit.org/show_bug.cgi?id=30322

Reviewed by Sam Weinig.

Source/WebCore:

Test: http/tests/cache/disk-cache-validation.html

* WebCore.exp.in:
* inspector/InspectorResourceAgent.cpp:
(WebCore::buildObjectForResourceResponse):
* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::ResourceResponseBase):
(WebCore::ResourceResponseBase::source):
(WebCore::ResourceResponseBase::setSource):
(WebCore::ResourceResponseBase::wasCached): Deleted.
(WebCore::ResourceResponseBase::setWasCached): Deleted.

    Replace wasCached bit with Source enum.
    This is useful for testing.

* platform/network/ResourceResponseBase.h:
(WebCore::ResourceResponseBase::containsCertificateInfo):
(WebCore::ResourceResponseBase::encode):
(WebCore::ResourceResponseBase::decode):
* testing/Internals.cpp:
(WebCore::Internals::xhrResponseSource):
(WebCore::Internals::clearMemoryCache):
* testing/Internals.h:
* testing/Internals.idl:

    Testing support.

* xml/XMLHttpRequest.h:

Source/WebKit2:

We can improve performance and open new optimization possibilities by bringing network caching into WebKit.

This patch implements an experimental HTTP cache living in the network process.

The main classes are:

NetworkCache
    - Implements HTTP cache validation logic including Vary header
    - Initially non-range GET only
    - Fast serialization using WebKit types (ResourcesResponse etc) instead of native network layer types

NetworkCacheKey
    - Unique identifier for cache entries
    - Keyed on method/partition/URL

NetworkCacheStorage
    - Storage backend
    - dispatch-IO based implementation (generic posix implementation wouldn't be difficult)
    - File system only (no SQLite or similar)
    - One file per resource containing both header and body data
    - Zero persistent global metadata
    - Bloom filter for fast fail

NetworkCacheEncoder/Decoder
    - Serializisation support with integrity verification.

The code is behind the NETWORK_CACHE feature flag and requires network process to be enabled to use.

This patch does not enable the feature yet by default.

Test: http/tests/cache/disk-cache-validation.html

* NetworkProcess/cache/NetworkCache.cpp: Added.
* NetworkProcess/cache/NetworkCache.h: Added.
* NetworkProcess/cache/NetworkCacheKey.cpp: Added.
* NetworkProcess/cache/NetworkCacheKey.h: Added.
* NetworkProcess/cache/NetworkCacheStorage.h: Added.
* NetworkProcess/cache/NetworkCacheStorage.mm: Added.
* NetworkProcess/cocoa/NetworkProcessCocoa.mm:
(WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa):
(WebKit::NetworkProcess::platformSetCacheModel):
* NetworkProcess/ios/NetworkProcessIOS.mm:
(WebKit::NetworkProcess::clearCacheForAllOrigins):
* NetworkProcess/mac/NetworkProcessMac.mm:
(WebKit::NetworkProcess::clearCacheForAllOrigins):
* NetworkProcess/mac/NetworkResourceLoaderMac.mm:
(WebKit::tryGetShareableHandleFromCFData):
* Platform/Logging.h:
* WebKit2.xcodeproj/project.pbxproj:
* config.h:

LayoutTests:

Add a cache validation test. The test generates large number of validation header permutations.

* TestExpectations: Skipped until the feature is enabled.
* http/tests/cache/disk-cache-validation-expected.txt: Added.
* http/tests/cache/disk-cache-validation.html: Added.
* http/tests/cache/resources/cache-test.js: Added.
(getServerDate):
(makeHeaderValue):
(generateTestURL):
(loadResource):
(loadResources):
(printResults):
(runTests):
(mergeFields):
(generateTests):
* http/tests/cache/resources/generate-response.cgi: Added.
* platform/mac-mountainlion/TestExpectations: Added.
* platform/mac-wk1/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformmacwk1TestExpectations">trunk/LayoutTests/platform/mac-wk1/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCoreexpin">trunk/Source/WebCore/WebCore.exp.in</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorResourceAgentcpp">trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceResponseBasecpp">trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceResponseBaseh">trunk/Source/WebCore/platform/network/ResourceResponseBase.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsh">trunk/Source/WebCore/testing/Internals.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsidl">trunk/Source/WebCore/testing/Internals.idl</a></li>
<li><a href="#trunkSourceWebCorexmlXMLHttpRequesth">trunk/Source/WebCore/xml/XMLHttpRequest.h</a></li>
<li><a href="#trunkSourceWebKit2CMakeListstxt">trunk/Source/WebKit2/CMakeLists.txt</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>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheEncodercpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscocoaNetworkProcessCocoamm">trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkProcessCocoa.mm</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcessiosNetworkProcessIOSmm">trunk/Source/WebKit2/NetworkProcess/ios/NetworkProcessIOS.mm</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcessmacNetworkProcessMacmm">trunk/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcessmacNetworkResourceLoaderMacmm">trunk/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm</a></li>
<li><a href="#trunkSourceWebKit2PlatformLoggingh">trunk/Source/WebKit2/Platform/Logging.h</a></li>
<li><a href="#trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj">trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebKit2configh">trunk/Source/WebKit2/config.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestscachediskcachevalidationexpectedtxt">trunk/LayoutTests/http/tests/cache/disk-cache-validation-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestscachediskcachevalidationhtml">trunk/LayoutTests/http/tests/cache/disk-cache-validation.html</a></li>
<li><a href="#trunkLayoutTestshttptestscacheresourcescachetestjs">trunk/LayoutTests/http/tests/cache/resources/cache-test.js</a></li>
<li><a href="#trunkLayoutTestshttptestscacheresourcesgenerateresponsecgi">trunk/LayoutTests/http/tests/cache/resources/generate-response.cgi</a></li>
<li><a href="#trunkLayoutTestsplatformmacmountainlionTestExpectations">trunk/LayoutTests/platform/mac-mountainlion/TestExpectations</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="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheKeycpp">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheKeyh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h</a></li>
<li><a href="#trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageCocoamm">trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/LayoutTests/ChangeLog        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2014-12-15  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        WebKit level persistent caching
+        https://bugs.webkit.org/show_bug.cgi?id=30322
+
+        Reviewed by Sam Weinig.
+
+        Add a cache validation test. The test generates large number of validation header permutations.
+
+        * TestExpectations: Skipped until the feature is enabled.
+        * http/tests/cache/disk-cache-validation-expected.txt: Added.
+        * http/tests/cache/disk-cache-validation.html: Added.
+        * http/tests/cache/resources/cache-test.js: Added.
+        (getServerDate):
+        (makeHeaderValue):
+        (generateTestURL):
+        (loadResource):
+        (loadResources):
+        (printResults):
+        (runTests):
+        (mergeFields):
+        (generateTests):
+        * http/tests/cache/resources/generate-response.cgi: Added.
+        * platform/mac-mountainlion/TestExpectations: Added.
+        * platform/mac-wk1/TestExpectations:
+
</ins><span class="cx"> 2014-12-15  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS] Codepoints not associated with languages are drawn as boxes
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/LayoutTests/TestExpectations        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -328,6 +328,9 @@
</span><span class="cx"> webkit.org/b/139548 fast/workers/worker-constructor.html [ Skip ]
</span><span class="cx"> webkit.org/b/139548 fast/xmlhttprequest/xmlhttprequest-recursive-sync-event.html [ Skip ]
</span><span class="cx"> 
</span><ins>+# Network process disk cache is not enabled yet
+webkit.org/b/30322 http/tests/cache/disk-cache-validation.html [ Skip ]
+
</ins><span class="cx"> webkit.org/b/139634 [ Debug ] fast/selectors/matches-backtracking.html [ Slow ]
</span><span class="cx"> webkit.org/b/139634 [ Debug ] fast/selectors/nth-child-of-register-requirement.html [ Slow ]
</span><span class="cx"> webkit.org/b/139634 [ Debug ] fast/selectors/not-backtracking.html [ Slow ]
</span></span></pre></div>
<a id="trunkLayoutTestshttptestscachediskcachevalidationexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/disk-cache-validation-expected.txt (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/disk-cache-validation-expected.txt                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/disk-cache-validation-expected.txt        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,902 @@
</span><ins>+Test permutations of various cache headers
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+running 243 tests
+
+response headers: undefined
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;}
+response source: Network
+
+response headers: {&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;}
+response source: Network
+
+response headers: {&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache after validation
+
+response headers: {&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Disk cache
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;en&quot;}
+response source: Network
+
+response headers: {&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;match&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-store&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-store&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(0)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(0)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Expires&quot;:&quot;now(100)&quot;,&quot;Cache-control&quot;:&quot;no-cache&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=0, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+response headers: {&quot;Cache-control&quot;:&quot;max-age=100, no-cache&quot;,&quot;Expires&quot;:&quot;now(100)&quot;,&quot;ETag&quot;:&quot;nomatch&quot;,&quot;Vary&quot;:&quot;Accept-Language&quot;}
+request headers: {&quot;Accept-Language&quot;:&quot;unique()&quot;}
+response source: Network
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscachediskcachevalidationhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/disk-cache-validation.html (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/disk-cache-validation.html                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/disk-cache-validation.html        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/cache-test.js&quot;&gt;&lt;/script&gt;
+&lt;body&gt;
+&lt;script&gt;
+
+var testMatrix =
+[
+ [
+  {},
+  { responseHeaders: {'Cache-control': 'max-age=0' } },
+  { responseHeaders: {'Cache-control': 'max-age=100' } },
+  ],
+ [
+  {},
+  { responseHeaders: {'Expires': 'now(0)' } },
+  { responseHeaders: {'Expires': 'now(100)' } },
+  ],
+ [
+  {},
+  { responseHeaders: {'Cache-control': 'no-store' } },
+  { responseHeaders: {'Cache-control': 'no-cache' } },
+  ],
+ [
+  {},
+  { responseHeaders: {'ETag': 'match' } },
+  { responseHeaders: {'ETag': 'nomatch' } },
+  ],
+ [
+  {},
+  { responseHeaders: {'Vary': 'Accept-Language' }, requestHeaders: { 'Accept-Language': 'en' } },
+  { responseHeaders: {'Vary': 'Accept-Language' }, requestHeaders: { 'Accept-Language': 'unique()' } },
+  ],
+ ];
+
+description(&quot;Test permutations of various cache headers&quot;);
+
+var tests = generateTests(testMatrix);
+
+debug(&quot;running &quot; + tests.length + &quot; tests&quot;);
+debug(&quot;&quot;);
+
+runTests(generateTests(testMatrix));
+
+&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="trunkLayoutTestshttptestscacheresourcescachetestjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/resources/cache-test.js (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/resources/cache-test.js                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/resources/cache-test.js        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,142 @@
</span><ins>+window.jsTestIsAsync = true;
+
+if (location.protocol != &quot;http:&quot; || location.host != &quot;127.0.0.1:8000&quot;) {
+    testFailed(&quot;This test must be run from http://127.0.0.1:8000&quot;);
+    finishJSTest();
+}
+
+if (!window.internals) {
+    testFailed(&quot;This test requires window.internals&quot;);
+    finishJSTest();
+}
+
+function getServerDate()
+{
+    var req = new XMLHttpRequest();
+    var t0 = new Date().getTime();
+    req.open('GET', &quot;/cache/resources/current-time.cgi&quot;, false /* blocking */);
+    req.send();
+    var serverToClientTime = (new Date().getTime() - t0) / 2;
+    if (req.status != 200) {
+        console.log(&quot;unexpected status code &quot; + req.status + &quot;, expected 200.&quot;);
+        return new Date();
+    }
+    return new Date((parseInt(req.responseText) * 1000) + serverToClientTime);
+}
+
+var serverClientTimeDelta = getServerDate().getTime() - new Date().getTime();
+
+var uniqueIdCounter = 0;
+function makeHeaderValue(value)
+{
+    if (value == 'now(0)')
+        return (new Date(new Date().getTime() + serverClientTimeDelta)).toUTCString();
+    if (value == 'now(100)')
+        return (new Date(new Date().getTime() + serverClientTimeDelta + 100 * 1000)).toUTCString();
+    if (value == 'unique()')
+        return &quot;&quot; + uniqueIdCounter++;
+    return value;
+}
+
+function generateTestURL(test)
+{
+    var uniqueTestId = Math.floor((Math.random() * 1000000000000));
+    var testURL = &quot;resources/generate-response.cgi?uniqueId=&quot; + uniqueTestId++ + &quot;&amp;Content-type=text/plain&quot;;
+    for (var header in test.responseHeaders)
+        testURL += '&amp;' + header + '=' + makeHeaderValue(test.responseHeaders[header]);
+    return testURL;
+}
+
+function loadResource(test, onload)
+{
+    if (!test.url)
+        test.url = generateTestURL(test);
+
+    test.xhr = new XMLHttpRequest();
+    test.xhr.onload = onload;
+    test.xhr.open(&quot;get&quot;, test.url, true);
+
+    for (var header in test.requestHeaders)
+        test.xhr.setRequestHeader(header, makeHeaderValue(test.requestHeaders[header]));
+
+    test.xhr.send();
+}
+
+function loadResources(tests, completetion)
+{
+    var pendingCount = tests.length;
+    for (var i = 0; i &lt; tests.length; ++i) {
+        loadResource(tests[i], function (ev) {
+            --pendingCount;
+            if (!pendingCount)
+                completetion();
+         });
+    }
+}
+
+function printResults(tests)
+{
+    for (var i = 0; i &lt; tests.length; ++i) {
+        var test = tests[i];
+        debug(&quot;response headers: &quot; + JSON.stringify(test.responseHeaders));
+        if (test.requestHeaders)
+            debug(&quot;request headers: &quot; + JSON.stringify(test.requestHeaders));
+        responseSource = internals.xhrResponseSource(test.xhr);
+        debug(&quot;response source: &quot; + responseSource);
+        debug(&quot;&quot;);
+    }
+}
+
+function runTests(tests)
+{
+    loadResources(tests, function () {
+        // Otherwise we just get responses from the memory cache.
+        internals.clearMemoryCache();
+        // Wait a bit so things settle down in the disk cache.
+        // FIXME: Shoudn't be needed, the cache should also return in-memory entries that are pending writing.
+        setTimeout(function () {
+            loadResources(tests, function () {
+                printResults(tests);
+                finishJSTest();
+            });
+        }, 2000);
+    });
+}
+
+function mergeFields(field, componentField)
+{
+    for (var name in componentField) {
+        if (field[name])
+            field[name] += &quot;, &quot; + componentField[name];
+        else
+            field[name] = componentField[name];
+    }
+}
+
+function generateTests(testMatrix)
+{
+    var tests = [];
+
+    var testCount = 1;
+    for (var i = 0; i &lt; testMatrix.length; ++i)
+        testCount *= testMatrix[i].length;
+
+    for (var testNumber = 0; testNumber &lt; testCount; ++testNumber) {
+        var test = {}
+
+        var index = testNumber;
+        for (var i = 0; i &lt; testMatrix.length; ++i) {
+            var components = testMatrix[i];
+            var component = components[index % components.length];
+            index = Math.floor(index / components.length);
+
+            for (var field in component) {
+                if (!test[field])
+                    test[field] = {}
+                mergeFields(test[field], component[field]);
+            }
+        }
+        tests.push(test);
+    }
+    return tests;
+}
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestscacheresourcesgenerateresponsecgi"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/cache/resources/generate-response.cgi (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/cache/resources/generate-response.cgi                                (rev 0)
+++ trunk/LayoutTests/http/tests/cache/resources/generate-response.cgi        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+#!/usr/bin/perl -w
+
+use CGI;
+use HTTP::Date;
+
+my $query = new CGI;
+@names = $query-&gt;param;
+
+if ($query-&gt;http(&quot;If-None-Match&quot;) eq &quot;match&quot;) {
+    print &quot;Status: 304\n&quot;;
+}
+
+foreach (@names) {
+    next if ($_ eq &quot;uniqueId&quot;);
+    print $_ . &quot;: &quot; . $query-&gt;param($_) . &quot;\n&quot;;
+}
+print &quot;\n&quot;;
+print &quot;test&quot;;
</ins><span class="cx">Property changes on: trunk/LayoutTests/http/tests/cache/resources/generate-response.cgi
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkLayoutTestsplatformmacmountainlionTestExpectations"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/mac-mountainlion/TestExpectations (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-mountainlion/TestExpectations                                (rev 0)
+++ trunk/LayoutTests/platform/mac-mountainlion/TestExpectations        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+# Disk cache requires NetworkProcess
+http/tests/cache/disk-cache-validation.html
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacwk1TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac-wk1/TestExpectations        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -80,5 +80,8 @@
</span><span class="cx"> 
</span><span class="cx"> compositing/iframes/overlapped-nested-iframes.html [ Pass Failure ]
</span><span class="cx"> 
</span><ins>+# Disk cache is WK2 only
+http/tests/cache/disk-cache-validation.html
+
</ins><span class="cx"> ### END OF (2) Failures without bug reports
</span><span class="cx"> ########################################
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/ChangeLog        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2014-12-15  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        WebKit level persistent caching
+        https://bugs.webkit.org/show_bug.cgi?id=30322
+
+        Reviewed by Sam Weinig.
+
+        Test: http/tests/cache/disk-cache-validation.html
+
+        * WebCore.exp.in:
+        * inspector/InspectorResourceAgent.cpp:
+        (WebCore::buildObjectForResourceResponse):
+        * platform/network/ResourceResponseBase.cpp:
+        (WebCore::ResourceResponseBase::ResourceResponseBase):
+        (WebCore::ResourceResponseBase::source):
+        (WebCore::ResourceResponseBase::setSource):
+        (WebCore::ResourceResponseBase::wasCached): Deleted.
+        (WebCore::ResourceResponseBase::setWasCached): Deleted.
+
+            Replace wasCached bit with Source enum.
+            This is useful for testing.
+
+        * platform/network/ResourceResponseBase.h:
+        (WebCore::ResourceResponseBase::containsCertificateInfo):
+        (WebCore::ResourceResponseBase::encode):
+        (WebCore::ResourceResponseBase::decode):
+        * testing/Internals.cpp:
+        (WebCore::Internals::xhrResponseSource):
+        (WebCore::Internals::clearMemoryCache):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
+            Testing support.
+
+        * xml/XMLHttpRequest.h:
+
</ins><span class="cx"> 2014-12-15  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Purge PassRefPtr from FocusEvent code.
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCoreexpin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.exp.in (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.exp.in        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/WebCore.exp.in        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -898,6 +898,7 @@
</span><span class="cx"> __ZN7WebCore20ResourceResponseBase19setTextEncodingNameERKN3WTF6StringE
</span><span class="cx"> __ZN7WebCore20ResourceResponseBase24setExpectedContentLengthEx
</span><span class="cx"> __ZN7WebCore20ResourceResponseBase6setURLERKNS_3URLE
</span><ins>+__ZN7WebCore20ResourceResponseBase9setSourceENS0_6SourceE
</ins><span class="cx"> __ZN7WebCore20ResourceResponseBaseC2Ev
</span><span class="cx"> __ZN7WebCore20StorageNamespaceImpl29createSessionStorageNamespaceEj
</span><span class="cx"> __ZN7WebCore20StorageNamespaceImpl32getOrCreateLocalStorageNamespaceERKN3WTF6StringEj
</span><span class="lines">@@ -1891,6 +1892,7 @@
</span><span class="cx"> __ZNK7WebCore20ResourceResponseBase34cacheControlContainsMustRevalidateEv
</span><span class="cx"> __ZNK7WebCore20ResourceResponseBase3urlEv
</span><span class="cx"> __ZNK7WebCore20ResourceResponseBase6isHTTPEv
</span><ins>+__ZNK7WebCore20ResourceResponseBase6sourceEv
</ins><span class="cx"> __ZNK7WebCore20ResourceResponseBase8lazyInitENS0_9InitLevelE
</span><span class="cx"> __ZNK7WebCore20ResourceResponseBase8mimeTypeEv
</span><span class="cx"> __ZNK7WebCore20TransformationMatrix7inverseEv
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorResourceAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -241,7 +241,7 @@
</span><span class="cx">         .setConnectionReused(response.connectionReused())
</span><span class="cx">         .setConnectionId(response.connectionID());
</span><span class="cx"> 
</span><del>-    responseObject-&gt;setFromDiskCache(response.wasCached());
</del><ins>+    responseObject-&gt;setFromDiskCache(response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation);
</ins><span class="cx">     responseObject-&gt;setTiming(buildObjectForTiming(response.resourceLoadTiming(), loader));
</span><span class="cx"> 
</span><span class="cx">     return responseObject;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceResponseBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -54,7 +54,6 @@
</span><span class="cx">     , m_date(0)
</span><span class="cx">     , m_expires(0)
</span><span class="cx">     , m_lastModified(0)
</span><del>-    , m_wasCached(false)
</del><span class="cx">     , m_connectionReused(false)
</span><span class="cx">     , m_isNull(true)
</span><span class="cx">     , m_haveParsedCacheControlHeader(false)
</span><span class="lines">@@ -65,6 +64,7 @@
</span><span class="cx">     , m_cacheControlContainsNoCache(false)
</span><span class="cx">     , m_cacheControlContainsNoStore(false)
</span><span class="cx">     , m_cacheControlContainsMustRevalidate(false)
</span><ins>+    , m_source(Source::Unknown)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -81,7 +81,6 @@
</span><span class="cx">     , m_date(0)
</span><span class="cx">     , m_expires(0)
</span><span class="cx">     , m_lastModified(0)
</span><del>-    , m_wasCached(false)
</del><span class="cx">     , m_connectionReused(false)
</span><span class="cx">     , m_isNull(false)
</span><span class="cx">     , m_haveParsedCacheControlHeader(false)
</span><span class="lines">@@ -92,6 +91,7 @@
</span><span class="cx">     , m_cacheControlContainsNoCache(false)
</span><span class="cx">     , m_cacheControlContainsNoStore(false)
</span><span class="cx">     , m_cacheControlContainsMustRevalidate(false)
</span><ins>+    , m_source(Source::Unknown)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -517,16 +517,16 @@
</span><span class="cx">     return equalIgnoringCase(value, &quot;attachment&quot;);
</span><span class="cx"> }
</span><span class="cx">   
</span><del>-bool ResourceResponseBase::wasCached() const
</del><ins>+ResourceResponseBase::Source ResourceResponseBase::source() const
</ins><span class="cx"> {
</span><span class="cx">     lazyInit(AllFields);
</span><span class="cx"> 
</span><del>-    return m_wasCached;
</del><ins>+    return m_source;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ResourceResponseBase::setWasCached(bool value)
</del><ins>+void ResourceResponseBase::setSource(Source source)
</ins><span class="cx"> {
</span><del>-    m_wasCached = value;
</del><ins>+    m_source = source;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ResourceResponseBase::connectionReused() const
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceResponseBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceResponseBase.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceResponseBase.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/platform/network/ResourceResponseBase.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx">     WEBCORE_EXPORT String suggestedFilename() const;
</span><span class="cx"> 
</span><span class="cx">     void includeCertificateInfo() const;
</span><ins>+    bool containsCertificateInfo() const { return m_includesCertificateInfo; }
</ins><span class="cx">     CertificateInfo certificateInfo() const;
</span><span class="cx">     
</span><span class="cx">     // These functions return parsed values of the corresponding response headers.
</span><span class="lines">@@ -114,8 +115,9 @@
</span><span class="cx">     bool connectionReused() const;
</span><span class="cx">     void setConnectionReused(bool);
</span><span class="cx"> 
</span><del>-    bool wasCached() const;
-    void setWasCached(bool);
</del><ins>+    enum class Source { Unknown, Network, DiskCache, DiskCacheAfterValidation };
+    Source source() const;
+    void setSource(Source);
</ins><span class="cx"> 
</span><span class="cx">     ResourceLoadTiming&amp; resourceLoadTiming() const { return m_resourceLoadTiming; }
</span><span class="cx"> 
</span><span class="lines">@@ -172,7 +174,6 @@
</span><span class="cx">     mutable double m_lastModified;
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    bool m_wasCached : 1;
</del><span class="cx">     bool m_connectionReused : 1;
</span><span class="cx"> 
</span><span class="cx">     bool m_isNull : 1;
</span><span class="lines">@@ -191,6 +192,8 @@
</span><span class="cx">     mutable bool m_cacheControlContainsNoCache : 1;
</span><span class="cx">     mutable bool m_cacheControlContainsNoStore : 1;
</span><span class="cx">     mutable bool m_cacheControlContainsMustRevalidate : 1;
</span><ins>+
+    Source m_source;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline bool operator==(const ResourceResponse&amp; a, const ResourceResponse&amp; b) { return ResourceResponseBase::compare(a, b); }
</span><span class="lines">@@ -216,6 +219,7 @@
</span><span class="cx">     encoder &lt;&lt; m_includesCertificateInfo;
</span><span class="cx">     if (m_includesCertificateInfo)
</span><span class="cx">         encoder &lt;&lt; m_certificateInfo;
</span><ins>+    encoder.encodeEnum(m_source);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;class Decoder&gt;
</span><span class="lines">@@ -256,6 +260,8 @@
</span><span class="cx">         if (!decoder.decode(response.m_certificateInfo))
</span><span class="cx">             return false;
</span><span class="cx">     }
</span><ins>+    if (!decoder.decodeEnum(response.m_source))
+        return false;
</ins><span class="cx">     response.m_isNull = false;
</span><span class="cx"> 
</span><span class="cx">     return true;
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/testing/Internals.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;AnimationController.h&quot;
</span><span class="cx"> #include &quot;ApplicationCacheStorage.h&quot;
</span><span class="cx"> #include &quot;BackForwardController.h&quot;
</span><ins>+#include &quot;CachedImage.h&quot;
</ins><span class="cx"> #include &quot;CachedResourceLoader.h&quot;
</span><span class="cx"> #include &quot;Chrome.h&quot;
</span><span class="cx"> #include &quot;ChromeClient.h&quot;
</span><span class="lines">@@ -52,6 +53,7 @@
</span><span class="cx"> #include &quot;FrameLoader.h&quot;
</span><span class="cx"> #include &quot;FrameView.h&quot;
</span><span class="cx"> #include &quot;HTMLIFrameElement.h&quot;
</span><ins>+#include &quot;HTMLImageElement.h&quot;
</ins><span class="cx"> #include &quot;HTMLInputElement.h&quot;
</span><span class="cx"> #include &quot;HTMLNames.h&quot;
</span><span class="cx"> #include &quot;HTMLPlugInElement.h&quot;
</span><span class="lines">@@ -102,6 +104,7 @@
</span><span class="cx"> #include &quot;ViewportArguments.h&quot;
</span><span class="cx"> #include &quot;WebConsoleAgent.h&quot;
</span><span class="cx"> #include &quot;WorkerThread.h&quot;
</span><ins>+#include &quot;XMLHttpRequest.h&quot;
</ins><span class="cx"> #include &lt;bytecode/CodeBlock.h&gt;
</span><span class="cx"> #include &lt;inspector/InspectorAgentBase.h&gt;
</span><span class="cx"> #include &lt;inspector/InspectorValues.h&gt;
</span><span class="lines">@@ -384,7 +387,31 @@
</span><span class="cx">     return resource &amp;&amp; resource-&gt;status() == CachedResource::Cached;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+String Internals::xhrResponseSource(XMLHttpRequest* xhr)
+{
+    if (!xhr)
+        return &quot;Null xhr&quot;;
+    if (xhr-&gt;resourceResponse().isNull())
+        return &quot;Null response&quot;;
+    switch (xhr-&gt;resourceResponse().source()) {
+    case ResourceResponse::Source::Unknown:
+        return &quot;Unknown&quot;;
+    case ResourceResponse::Source::Network:
+        return &quot;Network&quot;;
+    case ResourceResponse::Source::DiskCache:
+        return &quot;Disk cache&quot;;
+    case ResourceResponse::Source::DiskCacheAfterValidation:
+        return &quot;Disk cache after validation&quot;;
+    }
+    ASSERT_NOT_REACHED();
+    return &quot;Error&quot;;
+}
</ins><span class="cx"> 
</span><ins>+void Internals::clearMemoryCache()
+{
+    memoryCache().evictResources();
+}
+
</ins><span class="cx"> Node* Internals::treeScopeRootNode(Node* node, ExceptionCode&amp; ec)
</span><span class="cx"> {
</span><span class="cx">     if (!node) {
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/testing/Internals.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx"> class SourceBuffer;
</span><span class="cx"> class TimeRanges;
</span><span class="cx"> class TypeConversions;
</span><ins>+class XMLHttpRequest;
</ins><span class="cx"> 
</span><span class="cx"> typedef int ExceptionCode;
</span><span class="cx"> 
</span><span class="lines">@@ -82,6 +83,8 @@
</span><span class="cx"> 
</span><span class="cx">     bool isPreloaded(const String&amp; url);
</span><span class="cx">     bool isLoadingFromMemoryCache(const String&amp; url);
</span><ins>+    String xhrResponseSource(XMLHttpRequest*);
+    void clearMemoryCache();
</ins><span class="cx"> 
</span><span class="cx">     PassRefPtr&lt;CSSComputedStyleDeclaration&gt; computedStyleIncludingVisitedInfo(Node*, ExceptionCode&amp;) const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.idl (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.idl        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/testing/Internals.idl        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -42,6 +42,8 @@
</span><span class="cx">     [RaisesException] DOMString elementRenderTreeAsText(Element element);
</span><span class="cx">     boolean isPreloaded(DOMString url);
</span><span class="cx">     boolean isLoadingFromMemoryCache(DOMString url);
</span><ins>+    DOMString xhrResponseSource(XMLHttpRequest xhr);
+    void clearMemoryCache();
</ins><span class="cx"> 
</span><span class="cx">     [RaisesException] CSSStyleDeclaration computedStyleIncludingVisitedInfo(Node node);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorexmlXMLHttpRequesth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/xml/XMLHttpRequest.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/xml/XMLHttpRequest.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -144,6 +144,8 @@
</span><span class="cx">     XMLHttpRequestUpload* upload();
</span><span class="cx">     XMLHttpRequestUpload* optionalUpload() const { return m_upload.get(); }
</span><span class="cx"> 
</span><ins>+    const ResourceResponse&amp; resourceResponse() const { return m_response; }
+
</ins><span class="cx">     DEFINE_ATTRIBUTE_EVENT_LISTENER(readystatechange);
</span><span class="cx">     DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
</span><span class="cx">     DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
</span></span></pre></div>
<a id="trunkSourceWebKit2CMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/CMakeLists.txt (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/CMakeLists.txt        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/CMakeLists.txt        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -3,6 +3,7 @@
</span><span class="cx">     &quot;${WEBKIT2_DIR}&quot;
</span><span class="cx">     &quot;${WEBKIT2_DIR}/NetworkProcess&quot;
</span><span class="cx">     &quot;${WEBKIT2_DIR}/NetworkProcess/FileAPI&quot;
</span><ins>+    &quot;${WEBKIT2_DIR}/NetworkProcess/cache&quot;
</ins><span class="cx">     &quot;${WEBKIT2_DIR}/Platform&quot;
</span><span class="cx">     &quot;${WEBKIT2_DIR}/Platform/IPC&quot;
</span><span class="cx">     &quot;${WEBKIT2_DIR}/PluginProcess&quot;
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/ChangeLog        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -1,3 +1,61 @@
</span><ins>+2014-12-15  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        WebKit level persistent caching
+        https://bugs.webkit.org/show_bug.cgi?id=30322
+
+        Reviewed by Sam Weinig.
+
+        We can improve performance and open new optimization possibilities by bringing network caching into WebKit.
+
+        This patch implements an experimental HTTP cache living in the network process.
+
+        The main classes are:
+
+        NetworkCache
+            - Implements HTTP cache validation logic including Vary header
+            - Initially non-range GET only
+            - Fast serialization using WebKit types (ResourcesResponse etc) instead of native network layer types
+
+        NetworkCacheKey
+            - Unique identifier for cache entries
+            - Keyed on method/partition/URL
+
+        NetworkCacheStorage
+            - Storage backend
+            - dispatch-IO based implementation (generic posix implementation wouldn't be difficult)
+            - File system only (no SQLite or similar)
+            - One file per resource containing both header and body data
+            - Zero persistent global metadata
+            - Bloom filter for fast fail
+
+        NetworkCacheEncoder/Decoder
+            - Serializisation support with integrity verification.
+
+        The code is behind the NETWORK_CACHE feature flag and requires network process to be enabled to use.
+
+        This patch does not enable the feature yet by default.
+
+        Test: http/tests/cache/disk-cache-validation.html
+
+        * NetworkProcess/cache/NetworkCache.cpp: Added.
+        * NetworkProcess/cache/NetworkCache.h: Added.
+        * NetworkProcess/cache/NetworkCacheKey.cpp: Added.
+        * NetworkProcess/cache/NetworkCacheKey.h: Added.
+        * NetworkProcess/cache/NetworkCacheStorage.h: Added.
+        * NetworkProcess/cache/NetworkCacheStorage.mm: Added.
+        * NetworkProcess/cocoa/NetworkProcessCocoa.mm:
+        (WebKit::NetworkProcess::platformInitializeNetworkProcessCocoa):
+        (WebKit::NetworkProcess::platformSetCacheModel):
+        * NetworkProcess/ios/NetworkProcessIOS.mm:
+        (WebKit::NetworkProcess::clearCacheForAllOrigins):
+        * NetworkProcess/mac/NetworkProcessMac.mm:
+        (WebKit::NetworkProcess::clearCacheForAllOrigins):
+        * NetworkProcess/mac/NetworkResourceLoaderMac.mm:
+        (WebKit::tryGetShareableHandleFromCFData):
+        * Platform/Logging.h:
+        * WebKit2.xcodeproj/project.pbxproj:
+        * config.h:
+
</ins><span class="cx"> 2014-12-15  Gavin Barraclough  &lt;barraclough@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Simplify tracking of process suppression disabled for PluginProcessManager
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessNetworkResourceLoadercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;DataReference.h&quot;
</span><span class="cx"> #include &quot;Logging.h&quot;
</span><span class="cx"> #include &quot;NetworkBlobRegistry.h&quot;
</span><ins>+#include &quot;NetworkCache.h&quot;
</ins><span class="cx"> #include &quot;NetworkConnectionToWebProcess.h&quot;
</span><span class="cx"> #include &quot;NetworkProcess.h&quot;
</span><span class="cx"> #include &quot;NetworkProcessConnectionMessages.h&quot;
</span><span class="lines">@@ -44,6 +45,7 @@
</span><span class="cx"> #include &quot;WebResourceLoaderMessages.h&quot;
</span><span class="cx"> #include &lt;WebCore/BlobDataFileReference.h&gt;
</span><span class="cx"> #include &lt;WebCore/CertificateInfo.h&gt;
</span><ins>+#include &lt;WebCore/HTTPHeaderNames.h&gt;
</ins><span class="cx"> #include &lt;WebCore/NotImplemented.h&gt;
</span><span class="cx"> #include &lt;WebCore/ResourceHandle.h&gt;
</span><span class="cx"> #include &lt;WebCore/SharedBuffer.h&gt;
</span><span class="lines">@@ -130,17 +132,55 @@
</span><span class="cx">     if (m_defersLoading)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    m_currentRequest = originalRequest();
+
+#if ENABLE(NETWORK_CACHE)
+    if (!NetworkCache::shared().isEnabled() || sessionID().isEphemeral()) {
+        startNetworkLoad();
+        return;
+    }
+
+    RefPtr&lt;NetworkResourceLoader&gt; loader(this);
+    NetworkCache::shared().retrieve(originalRequest(), [loader](std::unique_ptr&lt;NetworkCache::Entry&gt; entry) {
+        if (loader-&gt;hasOneRef()) {
+            // The loader has been aborted and is only held alive by this lambda.
+            return;
+        }
+        if (!entry) {
+            loader-&gt;startNetworkLoad();
+            return;
+        }
+        if (loader-&gt;m_parameters.needsCertificateInfo &amp;&amp; !entry-&gt;response.containsCertificateInfo()) {
+            loader-&gt;startNetworkLoad();
+            return;
+        }
+        if (entry-&gt;needsRevalidation) {
+            loader-&gt;validateCacheEntry(WTF::move(entry));
+            return;
+        }
+        loader-&gt;didRetrieveCacheEntry(WTF::move(entry));
+    });
+#else
+    startNetworkLoad();
+#endif
+}
+
+void NetworkResourceLoader::startNetworkLoad()
+{
</ins><span class="cx">     m_networkingContext = RemoteNetworkingContext::create(sessionID(), m_parameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
</span><span class="cx"> 
</span><span class="cx">     consumeSandboxExtensions();
</span><span class="cx"> 
</span><del>-    m_currentRequest = originalRequest();
-
</del><span class="cx">     if (isSynchronous() || m_parameters.maximumBufferingTime &gt; 0_ms)
</span><span class="cx">         m_bufferedData = WebCore::SharedBuffer::create();
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    if (NetworkCache::shared().isEnabled())
+        m_bufferedDataForCache = WebCore::SharedBuffer::create();
+#endif
+
</ins><span class="cx">     bool shouldSniff = m_parameters.contentSniffingPolicy == SniffContent;
</span><del>-    m_handle = ResourceHandle::create(m_networkingContext.get(), m_currentRequest, this, false /* defersLoading */, shouldSniff);
</del><ins>+    m_handle = ResourceHandle::create(m_networkingContext.get(), m_currentRequest, this, m_defersLoading, shouldSniff);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkResourceLoader::setDefersLoading(bool defers)
</span><span class="lines">@@ -188,26 +228,57 @@
</span><span class="cx">     cleanup();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse&amp; response)
</del><ins>+#if ENABLE(NETWORK_CACHE)
+static bool isConditionalRequest(const WebCore::ResourceRequest&amp; request)
</ins><span class="cx"> {
</span><ins>+    if (!request.httpHeaderField(WebCore::HTTPHeaderName::IfNoneMatch).isEmpty())
+        return true;
+    if (!request.httpHeaderField(WebCore::HTTPHeaderName::IfModifiedSince).isEmpty())
+        return true;
+    return false;
+}
+#endif
+
+void NetworkResourceLoader::didReceiveResponseAsync(ResourceHandle* handle, const ResourceResponse&amp; receivedResponse)
+{
</ins><span class="cx">     ASSERT_UNUSED(handle, handle == m_handle);
</span><span class="cx"> 
</span><ins>+    m_response = receivedResponse;
+
+    m_response.setSource(ResourceResponse::Source::Network);
</ins><span class="cx">     if (m_parameters.needsCertificateInfo)
</span><del>-        response.includeCertificateInfo();
</del><ins>+        m_response.includeCertificateInfo();
+    // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
+    if (!isSynchronous() &amp;&amp; m_response.isMultipart())
+        m_bufferedData = nullptr;
</ins><span class="cx"> 
</span><del>-    if (isSynchronous())
-        m_synchronousLoadData-&gt;response = response;
-    else {
-        // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
-        if (response.isMultipart())
-            m_bufferedData = nullptr;
</del><ins>+    bool shouldSendDidReceiveResponse = true;
+#if ENABLE(NETWORK_CACHE)
+    if (m_cacheEntryForValidation) {
+        bool validationSucceeded = m_response.httpStatusCode() == 304; // 304 Not Modified
+        if (validationSucceeded)
+            NetworkCache::shared().update(originalRequest(), *m_cacheEntryForValidation, m_response);
+        if (!validationSucceeded || isConditionalRequest(originalRequest()))
+            m_cacheEntryForValidation = nullptr;
+    }
+    shouldSendDidReceiveResponse = !m_cacheEntryForValidation;
+#endif
</ins><span class="cx"> 
</span><del>-        if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(response, m_parameters.isMainResource)))
-            return;
</del><ins>+    if (shouldSendDidReceiveResponse) {
+        if (isSynchronous())
+            m_synchronousLoadData-&gt;response = m_response;
+        else {
+            if (!sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(m_response, m_parameters.isMainResource)))
+                return;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // For main resources, the web process is responsible for sending back a NetworkResourceLoader::ContinueDidReceiveResponse message.
</span><del>-    if (m_parameters.isMainResource)
</del><ins>+    bool shouldContinueDidReceiveResponse = !m_parameters.isMainResource;
+#if ENABLE(NETWORK_CACHE)
+    shouldContinueDidReceiveResponse = shouldContinueDidReceiveResponse || m_cacheEntryForValidation;
+#endif
+    if (!shouldContinueDidReceiveResponse)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     m_handle-&gt;continueDidReceiveResponse();
</span><span class="lines">@@ -223,7 +294,12 @@
</span><span class="cx"> void NetworkResourceLoader::didReceiveBuffer(ResourceHandle* handle, PassRefPtr&lt;SharedBuffer&gt; buffer, int reportedEncodedDataLength)
</span><span class="cx"> {
</span><span class="cx">     ASSERT_UNUSED(handle, handle == m_handle);
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    ASSERT(!m_cacheEntryForValidation);
</ins><span class="cx"> 
</span><ins>+    if (m_bufferedDataForCache)
+        m_bufferedDataForCache-&gt;append(buffer.get());
+#endif
</ins><span class="cx">     // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
</span><span class="cx">     unsigned encodedDataLength = reportedEncodedDataLength &gt;= 0 ? reportedEncodedDataLength : buffer-&gt;size();
</span><span class="cx"> 
</span><span class="lines">@@ -241,6 +317,30 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT_UNUSED(handle, handle == m_handle);
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    if (NetworkCache::shared().isEnabled()) {
+        if (m_cacheEntryForValidation) {
+            // 304 Not Modified
+            ASSERT(m_response.httpStatusCode() == 304);
+            LOG(NetworkCache, &quot;(NetworkProcess) revalidated&quot;);
+            didRetrieveCacheEntry(WTF::move(m_cacheEntryForValidation));
+            return;
+        }
+
+        bool hasCacheableRedirect = WebCore::redirectChainAllowsReuse(m_redirectChainCacheStatus);
+        if (hasCacheableRedirect &amp;&amp; m_redirectChainCacheStatus.status == RedirectChainCacheStatus::CachedRedirection) {
+            // FIXME: Cache the actual redirects instead of the end result.
+            double now = currentTime();
+            double responseEndOfValidity = now + WebCore::computeFreshnessLifetimeForHTTPFamily(m_response, now) - WebCore::computeCurrentAge(m_response, now);
+            hasCacheableRedirect = responseEndOfValidity &lt;= m_redirectChainCacheStatus.endOfValidity;
+        }
+
+        bool isPrivate = sessionID().isEphemeral();
+        if (hasCacheableRedirect &amp;&amp; !isPrivate)
+            NetworkCache::shared().store(originalRequest(), m_response, m_bufferedDataForCache.release());
+    }
+#endif
+
</ins><span class="cx">     if (isSynchronous())
</span><span class="cx">         sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
</span><span class="cx">     else {
</span><span class="lines">@@ -258,8 +358,12 @@
</span><span class="cx"> 
</span><span class="cx"> void NetworkResourceLoader::didFail(ResourceHandle* handle, const ResourceError&amp; error)
</span><span class="cx"> {
</span><del>-    ASSERT_UNUSED(handle, handle == m_handle);
</del><ins>+    ASSERT_UNUSED(handle, !handle || handle == m_handle);
</ins><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    m_cacheEntryForValidation = nullptr;
+#endif
+
</ins><span class="cx">     if (isSynchronous()) {
</span><span class="cx">         m_synchronousLoadData-&gt;error = error;
</span><span class="cx">         sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
</span><span class="lines">@@ -279,10 +383,14 @@
</span><span class="cx"> 
</span><span class="cx">     m_currentRequest = request;
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    WebCore::updateRedirectChainStatus(m_redirectChainCacheStatus, redirectResponse);
+#endif
+
</ins><span class="cx">     if (isSynchronous()) {
</span><span class="cx">         // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
</span><span class="cx">         // This includes at least updating host records, and comparing the current request instead of the original request here.
</span><del>-        if (!protocolHostAndPortAreEqual(originalRequest().url(), request.url())) {
</del><ins>+        if (!protocolHostAndPortAreEqual(originalRequest().url(), m_currentRequest.url())) {
</ins><span class="cx">             ASSERT(m_synchronousLoadData-&gt;error.isNull());
</span><span class="cx">             m_synchronousLoadData-&gt;error = SynchronousLoaderClient::platformBadResponseError();
</span><span class="cx">             m_currentRequest = ResourceRequest();
</span><span class="lines">@@ -290,7 +398,7 @@
</span><span class="cx">         continueWillSendRequest(m_currentRequest);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(request, redirectResponse));
</del><ins>+    sendAbortingOnFailure(Messages::WebResourceLoader::WillSendRequest(m_currentRequest, redirectResponse));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkResourceLoader::continueWillSendRequest(const ResourceRequest&amp; newRequest)
</span><span class="lines">@@ -428,6 +536,45 @@
</span><span class="cx">     return sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt; entry)
+{
+    if (isSynchronous()) {
+        m_synchronousLoadData-&gt;response = entry-&gt;response;
+        sendReplyToSynchronousRequest(*m_synchronousLoadData, entry-&gt;buffer.get());
+    } else {
+        sendAbortingOnFailure(Messages::WebResourceLoader::DidReceiveResponse(entry-&gt;response, m_parameters.isMainResource));
+
+        if (!entry-&gt;shareableResourceHandle.isNull())
+            send(Messages::WebResourceLoader::DidReceiveResource(entry-&gt;shareableResourceHandle, currentTime()));
+        else {
+            bool shouldContinue = sendBufferMaybeAborting(*entry-&gt;buffer, entry-&gt;buffer-&gt;size());
+            if (!shouldContinue)
+                return;
+            send(Messages::WebResourceLoader::DidFinishResourceLoad(currentTime()));
+        }
+    }
+
+    cleanup();
+}
+
+void NetworkResourceLoader::validateCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt; entry)
+{
+    ASSERT(!m_handle);
+
+    String eTag = entry-&gt;response.httpHeaderField(WebCore::HTTPHeaderName::ETag);
+    String lastModified = entry-&gt;response.httpHeaderField(WebCore::HTTPHeaderName::LastModified);
+    if (!eTag.isEmpty())
+        m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfNoneMatch, eTag);
+    if (!lastModified.isEmpty())
+        m_currentRequest.setHTTPHeaderField(WebCore::HTTPHeaderName::IfModifiedSince, lastModified);
+
+    m_cacheEntryForValidation = WTF::move(entry);
+
+    startNetworkLoad();
+}
+#endif
+
</ins><span class="cx"> IPC::Connection* NetworkResourceLoader::messageSenderConnection()
</span><span class="cx"> {
</span><span class="cx">     return connectionToWebProcess()-&gt;connection();
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessNetworkResourceLoaderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/NetworkResourceLoader.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -29,9 +29,11 @@
</span><span class="cx"> #if ENABLE(NETWORK_PROCESS)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;MessageSender.h&quot;
</span><ins>+#include &quot;NetworkCache.h&quot;
</ins><span class="cx"> #include &quot;NetworkConnectionToWebProcessMessages.h&quot;
</span><span class="cx"> #include &quot;NetworkResourceLoadParameters.h&quot;
</span><span class="cx"> #include &quot;ShareableResource.h&quot;
</span><ins>+#include &lt;WebCore/CacheValidation.h&gt;
</ins><span class="cx"> #include &lt;WebCore/ResourceError.h&gt;
</span><span class="cx"> #include &lt;WebCore/ResourceHandleClient.h&gt;
</span><span class="cx"> #include &lt;WebCore/ResourceLoaderOptions.h&gt;
</span><span class="lines">@@ -99,6 +101,9 @@
</span><span class="cx"> #endif
</span><span class="cx">     void continueWillSendRequest(const WebCore::ResourceRequest&amp; newRequest);
</span><span class="cx"> 
</span><ins>+    WebCore::SharedBuffer* bufferedData() { return m_bufferedData.get(); }
+    const WebCore::ResourceResponse&amp; response() const { return m_response; }
+
</ins><span class="cx">     NetworkConnectionToWebProcess* connectionToWebProcess() const { return m_connection.get(); }
</span><span class="cx">     WebCore::SessionID sessionID() const { return m_parameters.sessionID; }
</span><span class="cx">     ResourceLoadIdentifier identifier() const { return m_parameters.identifier; }
</span><span class="lines">@@ -142,6 +147,12 @@
</span><span class="cx"> #endif
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    void didRetrieveCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt;);
+    void validateCacheEntry(std::unique_ptr&lt;NetworkCache::Entry&gt;);
+#endif
+
+    void startNetworkLoad();
</ins><span class="cx">     void continueDidReceiveResponse();
</span><span class="cx"> 
</span><span class="cx">     void cleanup();
</span><span class="lines">@@ -167,6 +178,7 @@
</span><span class="cx">     RefPtr&lt;WebCore::ResourceHandle&gt; m_handle;
</span><span class="cx"> 
</span><span class="cx">     WebCore::ResourceRequest m_currentRequest;
</span><ins>+    WebCore::ResourceResponse m_response;
</ins><span class="cx"> 
</span><span class="cx">     size_t m_bytesReceived;
</span><span class="cx">     size_t m_bufferedDataEncodedDataLength;
</span><span class="lines">@@ -180,6 +192,12 @@
</span><span class="cx">     bool m_defersLoading;
</span><span class="cx"> 
</span><span class="cx">     WebCore::Timer m_bufferingTimer;
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    RefPtr&lt;WebCore::SharedBuffer&gt; m_bufferedDataForCache;
+    std::unique_ptr&lt;NetworkCache::Entry&gt; m_cacheEntryForValidation;
+
+    WebCore::RedirectChainCacheStatus m_redirectChainCacheStatus;
+#endif
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCachecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,335 @@
</span><ins>+/*
+ * Copyright (C) 2014 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;
+#include &quot;NetworkCache.h&quot;
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &quot;Logging.h&quot;
+#include &quot;NetworkCacheCoders.h&quot;
+#include &quot;NetworkCacheStorage.h&quot;
+#include &quot;NetworkResourceLoader.h&quot;
+#include &quot;WebCoreArgumentCoders.h&quot;
+#include &lt;WebCore/CacheValidation.h&gt;
+#include &lt;WebCore/HTTPHeaderNames.h&gt;
+#include &lt;WebCore/ResourceResponse.h&gt;
+#include &lt;WebCore/SharedBuffer.h&gt;
+#include &lt;wtf/NeverDestroyed.h&gt;
+#include &lt;wtf/StringHasher.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebKit {
+
+NetworkCache&amp; NetworkCache::shared()
+{
+    static NeverDestroyed&lt;NetworkCache&gt; instance;
+    return instance;
+}
+
+NetworkCache::NetworkCache()
+{
+}
+
+bool NetworkCache::initialize(const String&amp; cachePath)
+{
+    m_storage = NetworkCacheStorage::open(cachePath);
+
+    LOG(NetworkCache, &quot;(NetworkProcess) opened cache storage, success %d&quot;, !!m_storage);
+    return !!m_storage;
+}
+
+void NetworkCache::setMaximumSize(size_t maximumSize)
+{
+    if (!m_storage)
+        return;
+    m_storage-&gt;setMaximumSize(maximumSize);
+}
+
+static NetworkCacheStorage::Entry encodeStorageEntry(const WebCore::ResourceRequest&amp; request, const WebCore::ResourceResponse&amp; response, PassRefPtr&lt;WebCore::SharedBuffer&gt; responseData)
+{
+    NetworkCacheEncoder encoder;
+    encoder &lt;&lt; response;
+
+    String varyValue = response.httpHeaderField(WebCore::HTTPHeaderName::Vary);
+    bool hasVaryingRequestHeaders = !varyValue.isEmpty();
+
+    encoder &lt;&lt; hasVaryingRequestHeaders;
+
+    if (hasVaryingRequestHeaders) {
+        Vector&lt;String&gt; varyingHeaderNames;
+        varyValue.split(',', false, varyingHeaderNames);
+
+        Vector&lt;std::pair&lt;String, String&gt;&gt; varyingRequestHeaders;
+        for (auto&amp; varyHeaderName : varyingHeaderNames) {
+            String headerName = varyHeaderName.stripWhiteSpace();
+            varyingRequestHeaders.append(std::make_pair(headerName, request.httpHeaderField(headerName)));
+        }
+        encoder &lt;&lt; varyingRequestHeaders;
+    }
+    encoder.encodeChecksum();
+
+    auto timeStamp = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now().time_since_epoch());
+    NetworkCacheStorage::Data header(encoder.buffer(), encoder.bufferSize());
+    NetworkCacheStorage::Data body;
+    if (responseData)
+        body = NetworkCacheStorage::Data(reinterpret_cast&lt;const uint8_t*&gt;(responseData-&gt;data()), responseData-&gt;size());
+
+    return NetworkCacheStorage::Entry { timeStamp, header, body };
+}
+
+static bool verifyVaryingRequestHeaders(const Vector&lt;std::pair&lt;String, String&gt;&gt;&amp; varyingRequestHeaders, const WebCore::ResourceRequest&amp; request)
+{
+    for (auto&amp; varyingRequestHeader : varyingRequestHeaders) {
+        // FIXME: Vary: * in response would ideally trigger a cache delete instead of a store.
+        if (varyingRequestHeader.first == &quot;*&quot;)
+            return false;
+        String requestValue = request.httpHeaderField(varyingRequestHeader.first);
+        if (requestValue != varyingRequestHeader.second)
+            return false;
+    }
+    return true;
+}
+
+static bool cachePolicyAllowsExpired(WebCore::ResourceRequestCachePolicy policy)
+{
+    switch (policy) {
+    case WebCore::ReturnCacheDataElseLoad:
+    case WebCore::ReturnCacheDataDontLoad:
+        return true;
+    case WebCore::UseProtocolCachePolicy:
+    case WebCore::ReloadIgnoringCacheData:
+        return false;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
+}
+
+static std::unique_ptr&lt;NetworkCache::Entry&gt; decodeStorageEntry(const NetworkCacheStorage::Entry&amp; storageEntry, const WebCore::ResourceRequest&amp; request)
+{
+    NetworkCacheDecoder decoder(storageEntry.header.data(), storageEntry.header.size());
+
+    WebCore::ResourceResponse cachedResponse;
+    if (!decoder.decode(cachedResponse)) {
+        LOG(NetworkCache, &quot;(NetworkProcess) response decoding failed\n&quot;);
+        return nullptr;
+    }
+
+    bool hasVaryingRequestHeaders;
+    if (!decoder.decode(hasVaryingRequestHeaders))
+        return nullptr;
+
+    if (hasVaryingRequestHeaders) {
+        Vector&lt;std::pair&lt;String, String&gt;&gt; varyingRequestHeaders;
+        if (!decoder.decode(varyingRequestHeaders))
+            return nullptr;
+
+        if (!verifyVaryingRequestHeaders(varyingRequestHeaders, request)) {
+            LOG(NetworkCache, &quot;(NetworkProcess) varying header mistmatch\n&quot;);
+            return nullptr;
+        }
+    }
+    if (!decoder.verifyChecksum()) {
+        LOG(NetworkCache, &quot;(NetworkProcess) checksum verification failure\n&quot;);
+        return nullptr;
+    }
+
+    bool allowExpired = cachePolicyAllowsExpired(request.cachePolicy()) &amp;&amp; !cachedResponse.cacheControlContainsMustRevalidate();
+    auto timeStamp = std::chrono::duration_cast&lt;std::chrono::duration&lt;double&gt;&gt;(storageEntry.timeStamp);
+    double age = WebCore::computeCurrentAge(cachedResponse, timeStamp.count());
+    double lifetime = WebCore::computeFreshnessLifetimeForHTTPFamily(cachedResponse, timeStamp.count());
+    bool isExpired = age &gt; lifetime;
+    bool needsRevalidation = (isExpired &amp;&amp; !allowExpired) || cachedResponse.cacheControlContainsNoCache();
+
+    if (needsRevalidation) {
+        bool hasValidatorFields = cachedResponse.hasCacheValidatorFields();
+        LOG(NetworkCache, &quot;(NetworkProcess) needsRevalidation hasValidatorFields=%d isExpired=%d age=%f lifetime=%f&quot;, isExpired, hasValidatorFields, age, lifetime);
+        if (!hasValidatorFields)
+            return nullptr;
+    }
+
+    auto entry = std::make_unique&lt;NetworkCache::Entry&gt;();
+    entry-&gt;needsRevalidation = needsRevalidation;
+
+    cachedResponse.setSource(needsRevalidation ? WebCore::ResourceResponse::Source::DiskCacheAfterValidation : WebCore::ResourceResponse::Source::DiskCache);
+    entry-&gt;response = cachedResponse;
+
+    RefPtr&lt;SharedMemory&gt; sharedMemory = storageEntry.body.size() ? SharedMemory::createFromVMBuffer(const_cast&lt;uint8_t*&gt;(storageEntry.body.data()), storageEntry.body.size()) : nullptr;
+    RefPtr&lt;ShareableResource&gt; shareableResource = sharedMemory ? ShareableResource::create(sharedMemory.release(), 0, storageEntry.body.size()) : nullptr;
+
+    if (shareableResource &amp;&amp; shareableResource-&gt;createHandle(entry-&gt;shareableResourceHandle))
+        entry-&gt;buffer = entry-&gt;shareableResourceHandle.tryWrapInSharedBuffer();
+    else
+        entry-&gt;buffer = WebCore::SharedBuffer::create(storageEntry.body.data(), storageEntry.body.size());
+
+    return entry;
+}
+
+static bool canRetrieve(const WebCore::ResourceRequest&amp; request)
+{
+    if (!request.url().protocolIsInHTTPFamily())
+        return false;
+    // FIXME: Support HEAD and OPTIONS requests.
+    if (request.httpMethod() != &quot;GET&quot;)
+        return false;
+    // FIXME: We should be able to validate conditional requests using cache.
+    if (request.isConditional())
+        return false;
+    if (request.cachePolicy() == WebCore::ReloadIgnoringCacheData)
+        return false;
+
+    return true;
+}
+
+static NetworkCacheKey makeCacheKey(const WebCore::ResourceRequest&amp; request)
+{
+    String partition = request.cachePartition();
+    if (partition.isEmpty())
+        partition = ASCIILiteral(&quot;No partition&quot;);
+    return NetworkCacheKey(request.httpMethod(), partition, request.url().string());
+}
+
+void NetworkCache::retrieve(const WebCore::ResourceRequest&amp; originalRequest, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler)
+{
+    ASSERT(isEnabled());
+
+    LOG(NetworkCache, &quot;(NetworkProcess) retrieving %s priority %d&quot;, originalRequest.url().string().ascii().data(), originalRequest.priority());
+
+    if (!canRetrieve(originalRequest)) {
+        completionHandler(nullptr);
+        return;
+    }
+
+    auto startTime = std::chrono::system_clock::now();
+
+    NetworkCacheKey storageKey = makeCacheKey(originalRequest);
+    unsigned priority = originalRequest.priority();
+
+    // Captured data is going to be shuffled around threads. Avoid unsafe copying.
+    struct Capture {
+        WebCore::ResourceRequest originalRequest;
+        std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler;
+    };
+    // FIXME: With C++14 this could use unique_ptr and initialized lambda capture
+    auto capture = std::make_shared&lt;Capture&gt;(Capture { originalRequest, completionHandler });
+
+    m_storage-&gt;retrieve(storageKey, priority, [this, capture, startTime](std::unique_ptr&lt;NetworkCacheStorage::Entry&gt; entry) {
+        if (!entry) {
+            LOG(NetworkCache, &quot;(NetworkProcess) not found in storage&quot;);
+            capture-&gt;completionHandler(nullptr);
+            return false;
+        }
+        auto decodedEntry = decodeStorageEntry(*entry, capture-&gt;originalRequest);
+        bool success = !!decodedEntry;
+#if !LOG_DISABLED
+        auto elapsedMS = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;(std::chrono::system_clock::now() - startTime).count();
+#endif
+        LOG(NetworkCache, &quot;(NetworkProcess) retrieve complete success=%d priority=%d time=%lldms&quot;, success, capture-&gt;originalRequest.priority(), elapsedMS);
+        capture-&gt;completionHandler(WTF::move(decodedEntry));
+        return success;
+    });
+}
+
+static bool canStore(const WebCore::ResourceRequest&amp; originalRequest, const WebCore::ResourceResponse&amp; response)
+{
+    if (!originalRequest.url().protocolIsInHTTPFamily()) {
+        LOG(NetworkCache, &quot;(NetworkProcess) not HTTP&quot;);
+        return false;
+    }
+    if (originalRequest.httpMethod() != &quot;GET&quot;) {
+        LOG(NetworkCache, &quot;(NetworkProcess) method %s&quot;, originalRequest.httpMethod().utf8().data());
+        return false;
+    }
+    if (response.isAttachment()) {
+        LOG(NetworkCache, &quot;(NetworkProcess) attachment&quot;);
+        return false;
+    }
+
+    switch (response.httpStatusCode()) {
+    case 200: // OK
+    case 203: // Non-Authoritative Information
+    case 300: // Multiple Choices
+    case 301: // Moved Permanently
+    case 302: // Found
+    case 307: // Temporary Redirect
+    case 410: // Gone
+        if (response.cacheControlContainsNoStore()) {
+            LOG(NetworkCache, &quot;(NetworkProcess) Cache-control:no-store&quot;);
+            return false;
+        }
+        return true;
+    default:
+        LOG(NetworkCache, &quot;(NetworkProcess) status code %d&quot;, response.httpStatusCode());
+    }
+
+    return false;
+}
+
+void NetworkCache::store(const WebCore::ResourceRequest&amp; originalRequest, const WebCore::ResourceResponse&amp; response, PassRefPtr&lt;WebCore::SharedBuffer&gt; responseData)
+{
+    ASSERT(isEnabled());
+    ASSERT(responseData);
+
+    LOG(NetworkCache, &quot;(NetworkProcess) storing %s, partition %s&quot;, originalRequest.url().string().latin1().data(), originalRequest.cachePartition().latin1().data());
+
+    if (!canStore(originalRequest, response)) {
+        LOG(NetworkCache, &quot;(NetworkProcess) didn't store&quot;);
+        return;
+    }
+
+    auto key = makeCacheKey(originalRequest);
+    auto storageEntry = encodeStorageEntry(originalRequest, response, responseData);
+
+    m_storage-&gt;store(key, storageEntry, [](bool success) {
+        LOG(NetworkCache, &quot;(NetworkProcess) store success=%d&quot;, success);
+    });
+}
+
+void NetworkCache::update(const WebCore::ResourceRequest&amp; originalRequest, const Entry&amp; entry, const WebCore::ResourceResponse&amp; validatingResponse)
+{
+    LOG(NetworkCache, &quot;(NetworkProcess) updating %s&quot;, originalRequest.url().string().latin1().data());
+
+    WebCore::ResourceResponse response = entry.response;
+    WebCore::updateResponseHeadersAfterRevalidation(response, validatingResponse);
+
+    // FIXME: This rewrites the entire resource instead of just the header.
+    auto key = makeCacheKey(originalRequest);
+    auto storageEntry = encodeStorageEntry(originalRequest, response, entry.buffer);
+
+    m_storage-&gt;store(key, storageEntry, [](bool success) {
+        LOG(NetworkCache, &quot;(NetworkProcess) updated, success=%d&quot;, success);
+    });
+}
+
+void NetworkCache::clear()
+{
+    LOG(NetworkCache, &quot;(NetworkProcess) clearing cache&quot;);
+    if (m_storage)
+        m_storage-&gt;clear();
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCache.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+/*
+ * Copyright (C) 2014 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 NetworkCache_h
+#define NetworkCache_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &quot;NetworkCacheStorage.h&quot;
+#include &quot;ShareableResource.h&quot;
+#include &lt;Webcore/ResourceResponse.h&gt;
+#include &lt;wtf/BloomFilter.h&gt;
+#include &lt;wtf/Deque.h&gt;
+#include &lt;wtf/HashSet.h&gt;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+class ResourceRequest;
+class SharedBuffer;
+class URL;
+}
+
+namespace WebKit {
+
+class NetworkCache {
+    WTF_MAKE_NONCOPYABLE(NetworkCache);
+public:
+    static NetworkCache&amp; shared();
+
+    NetworkCache();
+
+    bool initialize(const String&amp; cachePath);
+    void setMaximumSize(size_t);
+
+    bool isEnabled() const { return !!m_storage; }
+
+    struct Entry {
+        WebCore::ResourceResponse response;
+        RefPtr&lt;WebCore::SharedBuffer&gt; buffer;
+        ShareableResource::Handle shareableResourceHandle;
+        bool needsRevalidation;
+    };
+    // Completion handler may get called back synchronously on failure.
+    void retrieve(const WebCore::ResourceRequest&amp;, std::function&lt;void (std::unique_ptr&lt;Entry&gt;)&gt;);
+    void store(const WebCore::ResourceRequest&amp;, const WebCore::ResourceResponse&amp;, PassRefPtr&lt;WebCore::SharedBuffer&gt;);
+    void update(const WebCore::ResourceRequest&amp;, const Entry&amp;, const WebCore::ResourceResponse&amp; validatingResponse);
+
+    void clear();
+
+private:
+    String fileNameForURL(const WebCore::URL&amp;);
+    String directoryPathForCachePartition(const String&amp;);
+    String filePathForRequest(const WebCore::ResourceRequest&amp;);
+
+    std::unique_ptr&lt;NetworkCacheStorage&gt; m_storage;
+};
+
+}
+#endif
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheEncodercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheEncoder.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -41,9 +41,9 @@
</span><span class="cx"> 
</span><span class="cx"> uint8_t* NetworkCacheEncoder::grow(size_t size)
</span><span class="cx"> {
</span><del>-    uint8_t* position = m_buffer.data() + m_buffer.size();
</del><ins>+    size_t newPosition = m_buffer.size();
</ins><span class="cx">     m_buffer.grow(m_buffer.size() + size);
</span><del>-    return position;
</del><ins>+    return m_buffer.data() + newPosition;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkCacheEncoder::updateChecksumForData(unsigned&amp; checksum, const uint8_t* data, size_t size)
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheKeycpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.cpp        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,106 @@
</span><ins>+/*
+ * Copyright (C) 2014 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;
+#include &quot;NetworkCacheKey.h&quot;
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &quot;NetworkCacheCoders.h&quot;
+
+namespace WebKit {
+
+NetworkCacheKey::NetworkCacheKey(const NetworkCacheKey&amp; o)
+    : m_method(o.m_method.isolatedCopy())
+    , m_partition(o.m_partition.isolatedCopy())
+    , m_identifier(o.m_identifier.isolatedCopy())
+    , m_hash(o.m_hash)
+{
+}
+
+NetworkCacheKey::NetworkCacheKey(NetworkCacheKey&amp;&amp; o)
+    : m_method(WTF::move(o.m_method))
+    , m_partition(WTF::move(o.m_partition))
+    , m_identifier(WTF::move(o.m_identifier))
+    , m_hash(o.m_hash)
+{
+}
+
+NetworkCacheKey::NetworkCacheKey(const String&amp; method, const String&amp; partition, const String&amp; identifier)
+    : m_method(method.isolatedCopy())
+    , m_partition(partition.isolatedCopy())
+    , m_identifier(identifier.isolatedCopy())
+    , m_hash(computeHash())
+{
+}
+
+static NetworkCacheKey::HashType hashString(const String&amp; string)
+{
+    // String::hash() masks away the top bits.
+    if (string.is8Bit())
+        return StringHasher::computeHash(string.characters8(), string.length());
+    return StringHasher::computeHash(string.characters16(), string.length());
+}
+
+NetworkCacheKey::HashType NetworkCacheKey::computeHash() const
+{
+    return WTF::pairIntHash(hashString(m_method), WTF::pairIntHash(hashString(m_identifier), hashString(m_partition)));
+}
+
+String NetworkCacheKey::hashAsString() const
+{
+    return String::format(&quot;%08x&quot;, m_hash);
+}
+
+bool NetworkCacheKey::stringToHash(const String&amp; string, HashType&amp; hash)
+{
+    if (string.length() != 8)
+        return false;
+    bool success;
+    hash = string.toUIntStrict(&amp;success, 16);
+    return success;
+}
+
+bool NetworkCacheKey::operator==(const NetworkCacheKey&amp; other) const
+{
+    return m_hash == other.m_hash &amp;&amp; m_method == other.m_method &amp;&amp; m_partition == other.m_partition &amp;&amp; m_identifier == other.m_identifier;
+}
+
+void NetworkCacheKey::encode(NetworkCacheEncoder&amp; encoder) const
+{
+    encoder &lt;&lt; m_method;
+    encoder &lt;&lt; m_partition;
+    encoder &lt;&lt; m_identifier;
+    encoder &lt;&lt; m_hash;
+}
+
+bool NetworkCacheKey::decode(NetworkCacheDecoder&amp; decoder, NetworkCacheKey&amp; key)
+{
+    return decoder.decode(key.m_method) &amp;&amp; decoder.decode(key.m_partition) &amp;&amp; decoder.decode(key.m_identifier) &amp;&amp; decoder.decode(key.m_hash);
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheKeyh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheKey.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * Copyright (C) 2014 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 NetworkCacheKey_h
+#define NetworkCacheKey_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebKit {
+
+class NetworkCacheEncoder;
+class NetworkCacheDecoder;
+
+class NetworkCacheKey {
+public:
+    typedef unsigned HashType;
+
+    NetworkCacheKey() { }
+    NetworkCacheKey(const NetworkCacheKey&amp;);
+    NetworkCacheKey(NetworkCacheKey&amp;&amp;);
+    NetworkCacheKey(const String&amp; method, const String&amp; partition, const String&amp; identifier);
+
+    const String&amp; method() const { return m_method; }
+    const String&amp; partition() const { return m_partition; }
+    const String&amp; identifier() const { return m_identifier; }
+    HashType hash() const { return m_hash; }
+
+    String hashAsString() const;
+    static bool stringToHash(const String&amp;, HashType&amp;);
+
+    void encode(NetworkCacheEncoder&amp;) const;
+    static bool decode(NetworkCacheDecoder&amp;, NetworkCacheKey&amp;);
+
+    bool operator==(const NetworkCacheKey&amp;) const;
+    bool operator!=(const NetworkCacheKey&amp; other) const { return !(*this == other); }
+
+private:
+    HashType computeHash() const;
+    void operator=(const NetworkCacheKey&amp;) = delete;
+
+    String m_method;
+    String m_partition;
+    String m_identifier;
+    HashType m_hash;
+};
+
+}
+
+#endif
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,125 @@
</span><ins>+/*
+ * Copyright (C) 2014 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 NetworkCacheStorage_h
+#define NetworkCacheStorage_h
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &quot;NetworkCacheKey.h&quot;
+#include &lt;WebCore/ResourceResponse.h&gt;
+#include &lt;wtf/BloomFilter.h&gt;
+#include &lt;wtf/Deque.h&gt;
+#include &lt;wtf/OSObjectPtr.h&gt;
+#include &lt;wtf/RetainPtr.h&gt;
+#include &lt;wtf/text/WTFString.h&gt;
+
+namespace WebCore {
+class SharedBuffer;
+}
+
+namespace IPC {
+class ArgumentEncoder;
+class ArgumentDecoder;
+}
+
+namespace WebKit {
+
+class ShareableResource;
+
+class NetworkCacheStorage {
+    WTF_MAKE_NONCOPYABLE(NetworkCacheStorage);
+public:
+    static std::unique_ptr&lt;NetworkCacheStorage&gt; open(const String&amp; cachePath);
+
+    class Data {
+    public:
+        Data();
+        Data(const uint8_t*, size_t);
+#if PLATFORM(COCOA)
+        explicit Data(OSObjectPtr&lt;dispatch_data_t&gt;);
+#endif
+        bool isNull() const { return !m_dispatchData; }
+
+        const uint8_t* data() const;
+        size_t size() const { return m_size; }
+
+#if PLATFORM(COCOA)
+        dispatch_data_t dispatchData() const { return m_dispatchData.get(); }
+#endif
+    private:
+#if PLATFORM(COCOA)
+        mutable OSObjectPtr&lt;dispatch_data_t&gt; m_dispatchData;
+#endif
+        mutable const uint8_t* m_data;
+        size_t m_size;
+    };
+
+    struct Entry {
+        std::chrono::milliseconds timeStamp;
+        Data header;
+        Data body;
+    };
+    // This may call completion handler synchronously on failure.
+    void retrieve(const NetworkCacheKey&amp;, unsigned priority, std::function&lt;bool (std::unique_ptr&lt;Entry&gt;)&gt;);
+    void store(const NetworkCacheKey&amp;, const Entry&amp;, std::function&lt;void (bool success)&gt;);
+
+    void setMaximumSize(size_t);
+    void clear();
+
+    static const unsigned version = 1;
+
+private:
+    NetworkCacheStorage(const String&amp; directoryPath);
+
+    void initializeKeyFilter();
+
+    void removeEntry(const NetworkCacheKey&amp;);
+
+    struct RetrieveOperation {
+        NetworkCacheKey key;
+        std::function&lt;bool (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler;
+    };
+    void dispatchRetrieveOperation(const RetrieveOperation&amp;);
+    void dispatchPendingRetrieveOperations();
+
+    const String m_directoryPath;
+
+    size_t m_maximumSize;
+
+    BloomFilter&lt;20&gt; m_keyFilter;
+
+    Vector&lt;Deque&lt;RetrieveOperation&gt;&gt; m_pendingRetrieveOperationsByPriority;
+    unsigned m_activeRetrieveOperationCount;
+
+#if PLATFORM(COCOA)
+    mutable OSObjectPtr&lt;dispatch_queue_t&gt; m_ioQueue;
+    mutable OSObjectPtr&lt;dispatch_queue_t&gt; m_backgroundIOQueue;
+#endif
+};
+
+}
+#endif
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscacheNetworkCacheStorageCocoamm"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm (0 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm                                (rev 0)
+++ trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorageCocoa.mm        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -0,0 +1,463 @@
</span><ins>+/*
+ * Copyright (C) 2014 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;
+#include &quot;NetworkCacheStorage.h&quot;
+
+#if ENABLE(NETWORK_CACHE)
+
+#include &quot;Logging.h&quot;
+#include &quot;NetworkCacheCoders.h&quot;
+#include &lt;WebCore/FileSystem.h&gt;
+#include &lt;dirent.h&gt;
+#include &lt;dispatch/dispatch.h&gt;
+#include &lt;sys/mman.h&gt;
+#include &lt;sys/stat.h&gt;
+#include &lt;wtf/RunLoop.h&gt;
+#include &lt;wtf/text/CString.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebKit {
+
+static const char* networkCacheSubdirectory = &quot;WebKitCache&quot;;
+
+template &lt;typename Function&gt;
+static void traverseDirectory(const String&amp; path, uint8_t type, const Function&amp; function)
+{
+    DIR* dir = opendir(WebCore::fileSystemRepresentation(path).data());
+    if (!dir)
+        return;
+    struct dirent* dp;
+    while ((dp = readdir(dir))) {
+        if (dp-&gt;d_type != type)
+            continue;
+        const char* name = dp-&gt;d_name;
+        if (!strcmp(name, &quot;.&quot;) || !strcmp(name, &quot;..&quot;))
+            continue;
+        function(String(name));
+    }
+    closedir(dir);
+}
+
+static void traverseCacheFiles(const String&amp; cachePath, std::function&lt;void (const String&amp; fileName, const String&amp; partitionPath)&gt; function)
+{
+    traverseDirectory(cachePath, DT_DIR, [&amp;cachePath, &amp;function](const String&amp; subdirName) {
+        String partitionPath = WebCore::pathByAppendingComponent(cachePath, subdirName);
+        traverseDirectory(partitionPath, DT_REG, [&amp;function, &amp;partitionPath](const String&amp; fileName) {
+            if (fileName.length() != 8)
+                return;
+            function(fileName, partitionPath);
+        });
+    });
+}
+
+NetworkCacheStorage::Data::Data()
+    : m_data(nullptr)
+    , m_size(0)
+{
+}
+
+NetworkCacheStorage::Data::Data(const uint8_t* data, size_t size)
+    : m_dispatchData(adoptOSObject(dispatch_data_create(data, size, nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT)))
+    , m_data(nullptr)
+    , m_size(size)
+{
+}
+
+NetworkCacheStorage::Data::Data(OSObjectPtr&lt;dispatch_data_t&gt; dispatchData)
+{
+    const void* data;
+    m_dispatchData = adoptOSObject(dispatch_data_create_map(dispatchData.get(), &amp;data, &amp;m_size));
+    m_data = static_cast&lt;const uint8_t*&gt;(data);
+}
+
+const uint8_t* NetworkCacheStorage::Data::data() const
+{
+    if (!m_data) {
+        const void* data;
+        size_t size;
+        m_dispatchData = adoptOSObject(dispatch_data_create_map(m_dispatchData.get(), &amp;data, &amp;size));
+        ASSERT(size == m_size);
+        m_data = static_cast&lt;const uint8_t*&gt;(data);
+    }
+    return m_data;
+}
+
+std::unique_ptr&lt;NetworkCacheStorage&gt; NetworkCacheStorage::open(const String&amp; cachePath)
+{
+    ASSERT(RunLoop::isMain());
+
+    String networkCachePath = WebCore::pathByAppendingComponent(cachePath, networkCacheSubdirectory);
+    if (!WebCore::makeAllDirectories(networkCachePath))
+        return nullptr;
+    return std::unique_ptr&lt;NetworkCacheStorage&gt;(new NetworkCacheStorage(networkCachePath));
+}
+
+NetworkCacheStorage::NetworkCacheStorage(const String&amp; directoryPath)
+    : m_directoryPath(directoryPath)
+    , m_maximumSize(std::numeric_limits&lt;size_t&gt;::max())
+    , m_activeRetrieveOperationCount(0)
+    , m_ioQueue(adoptOSObject(dispatch_queue_create(&quot;com.apple.WebKit.Cache.Storage&quot;, DISPATCH_QUEUE_CONCURRENT)))
+    , m_backgroundIOQueue(adoptOSObject(dispatch_queue_create(&quot;com.apple.WebKit.Cache.Storage.Background&quot;, DISPATCH_QUEUE_CONCURRENT)))
+{
+    dispatch_set_target_queue(m_backgroundIOQueue.get(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
+
+    initializeKeyFilter();
+}
+
+void NetworkCacheStorage::initializeKeyFilter()
+{
+    ASSERT(RunLoop::isMain());
+
+    StringCapture cachePathCapture(m_directoryPath);
+    auto&amp; keyFilter = m_keyFilter;
+
+    dispatch_async(m_backgroundIOQueue.get(), [cachePathCapture, &amp;keyFilter] {
+        String cachePath = cachePathCapture.string();
+        traverseCacheFiles(cachePath, [&amp;keyFilter](const String&amp; fileName, const String&amp;) {
+            NetworkCacheKey::HashType hash;
+            if (!NetworkCacheKey::stringToHash(fileName, hash))
+                return;
+            keyFilter.add(hash);
+        });
+    });
+}
+
+static String directoryPathForKey(const NetworkCacheKey&amp; key, const String&amp; cachePath)
+{
+    ASSERT(!key.partition().isEmpty());
+    return WebCore::pathByAppendingComponent(cachePath, key.partition());
+}
+
+static String filePathForKey(const NetworkCacheKey&amp; key, const String&amp; cachePath)
+{
+    return WebCore::pathByAppendingComponent(directoryPathForKey(key, cachePath), key.hashAsString());
+}
+
+enum class IOChannelType { Read, Write };
+static OSObjectPtr&lt;dispatch_io_t&gt; createIOChannelForKey(const NetworkCacheKey&amp; key, IOChannelType type, const String&amp; cachePath, int&amp; fd)
+{
+    int oflag;
+    mode_t mode;
+
+    switch (type) {
+    case IOChannelType::Write:
+        oflag = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
+        mode = S_IRUSR | S_IWUSR;
+        WebCore::makeAllDirectories(directoryPathForKey(key, cachePath));
+        break;
+    case IOChannelType::Read:
+        oflag = O_RDONLY | O_NONBLOCK;
+        mode = 0;
+    }
+
+    CString path = WebCore::fileSystemRepresentation(filePathForKey(key, cachePath));
+    fd = ::open(path.data(), oflag, mode);
+
+    LOG(NetworkCacheStorage, &quot;(NetworkProcess) opening %s type=%d&quot;, path.data(), type);
+
+    OSObjectPtr&lt;dispatch_io_t&gt; channel = adoptOSObject(dispatch_io_create(DISPATCH_IO_RANDOM, fd, dispatch_get_main_queue(), [fd, type](int error) {
+        close(fd);
+        if (error)
+            LOG(NetworkCacheStorage, &quot;(NetworkProcess) error creating io channel %d&quot;, error);
+    }));
+
+    ASSERT(channel);
+    dispatch_io_set_low_water(channel.get(), std::numeric_limits&lt;size_t&gt;::max());
+
+    return channel;
+}
+
+static unsigned hashData(dispatch_data_t data)
+{
+    if (!data || !dispatch_data_get_size(data))
+        return 0;
+    StringHasher hasher;
+    dispatch_data_apply(data, [&amp;hasher](dispatch_data_t, size_t, const void* data, size_t size) {
+        hasher.addCharacters(static_cast&lt;const uint8_t*&gt;(data), size);
+        return true;
+    });
+    return hasher.hash();
+}
+
+struct EntryMetaData {
+    EntryMetaData() { }
+    explicit EntryMetaData(const NetworkCacheKey&amp; key) : cacheStorageVersion(NetworkCacheStorage::version), key(key) { }
+
+    unsigned cacheStorageVersion;
+    NetworkCacheKey key;
+    std::chrono::milliseconds timeStamp;
+    unsigned headerChecksum;
+    uint64_t headerOffset;
+    uint64_t headerSize;
+    unsigned bodyChecksum;
+    uint64_t bodyOffset;
+    uint64_t bodySize;
+};
+
+static bool decodeEntryMetaData(EntryMetaData&amp; metaData, dispatch_data_t fileData)
+{
+    bool success = false;
+    dispatch_data_apply(fileData, [&amp;metaData, &amp;success](dispatch_data_t, size_t, const void* data, size_t size) {
+        NetworkCacheDecoder decoder(reinterpret_cast&lt;const uint8_t*&gt;(data), size);
+        if (!decoder.decode(metaData.cacheStorageVersion))
+            return false;
+        if (!decoder.decode(metaData.key))
+            return false;
+        if (!decoder.decode(metaData.timeStamp))
+            return false;
+        if (!decoder.decode(metaData.headerChecksum))
+            return false;
+        if (!decoder.decode(metaData.headerSize))
+            return false;
+        if (!decoder.decode(metaData.bodyChecksum))
+            return false;
+        if (!decoder.decode(metaData.bodySize))
+            return false;
+        if (!decoder.verifyChecksum())
+            return false;
+        metaData.headerOffset = decoder.currentOffset();
+        metaData.bodyOffset = round_page(metaData.headerOffset + metaData.headerSize);
+        success = true;
+        return false;
+    });
+    return success;
+}
+
+static std::unique_ptr&lt;NetworkCacheStorage::Entry&gt; decodeEntry(dispatch_data_t fileData, int fd, const NetworkCacheKey&amp; key)
+{
+    EntryMetaData metaData;
+    if (!decodeEntryMetaData(metaData, fileData))
+        return nullptr;
+
+    if (metaData.cacheStorageVersion != NetworkCacheStorage::version)
+        return nullptr;
+    if (metaData.key != key)
+        return nullptr;
+    if (metaData.headerOffset + metaData.headerSize &gt; metaData.bodyOffset)
+        return nullptr;
+    if (metaData.bodyOffset + metaData.bodySize != dispatch_data_get_size(fileData))
+        return nullptr;
+
+    auto headerData = adoptOSObject(dispatch_data_create_subrange(fileData, metaData.headerOffset, metaData.headerSize));
+    if (metaData.headerChecksum != hashData(headerData.get())) {
+        LOG(NetworkCacheStorage, &quot;(NetworkProcess) header checksum mismatch&quot;);
+        return nullptr;
+    }
+    size_t mapSize = metaData.bodySize;
+    void* map = mmap(nullptr, mapSize, PROT_READ, MAP_PRIVATE, fd, metaData.bodyOffset);
+    if (!map) {
+        LOG(NetworkCacheStorage, &quot;(NetworkProcess) map failed&quot;);
+        return nullptr;
+    }
+
+    auto bodyData = adoptOSObject(dispatch_data_create(map, metaData.bodySize, dispatch_get_main_queue(), [map, mapSize] {
+        munmap(map, mapSize);
+    }));
+
+    if (metaData.bodyChecksum != hashData(bodyData.get())) {
+        LOG(NetworkCacheStorage, &quot;(NetworkProcess) data checksum mismatch&quot;);
+        return nullptr;
+    }
+
+    return std::make_unique&lt;NetworkCacheStorage::Entry&gt;(NetworkCacheStorage::Entry {
+        metaData.timeStamp,
+        NetworkCacheStorage::Data(headerData),
+        NetworkCacheStorage::Data(bodyData)
+    });
+}
+
+static OSObjectPtr&lt;dispatch_data_t&gt; encodeEntryMetaData(const EntryMetaData&amp; entry)
+{
+    NetworkCacheEncoder encoder;
+
+    encoder &lt;&lt; entry.cacheStorageVersion;
+    encoder &lt;&lt; entry.key;
+    encoder &lt;&lt; entry.timeStamp;
+    encoder &lt;&lt; entry.headerChecksum;
+    encoder &lt;&lt; entry.headerSize;
+    encoder &lt;&lt; entry.bodyChecksum;
+    encoder &lt;&lt; entry.bodySize;
+
+    encoder.encodeChecksum();
+
+    return adoptOSObject(dispatch_data_create(encoder.buffer(), encoder.bufferSize(), nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT));
+}
+
+static OSObjectPtr&lt;dispatch_data_t&gt; encodeEntry(const NetworkCacheKey&amp; key, const NetworkCacheStorage::Entry&amp; entry)
+{
+    EntryMetaData metaData(key);
+    metaData.timeStamp = entry.timeStamp;
+    metaData.headerChecksum = hashData(entry.header.dispatchData());
+    metaData.headerSize = entry.header.size();
+    metaData.bodyChecksum = hashData(entry.body.dispatchData());
+    metaData.bodySize = entry.body.size();
+
+    auto encodedMetaData = encodeEntryMetaData(metaData);
+    auto headerData = adoptOSObject(dispatch_data_create_concat(encodedMetaData.get(), entry.header.dispatchData()));
+    if (!entry.body.size())
+        return headerData;
+
+    size_t headerSize = dispatch_data_get_size(headerData.get());
+    size_t dataOffset = round_page(headerSize);
+    Vector&lt;uint8_t, 4096&gt; filler(dataOffset - headerSize, 0);
+    OSObjectPtr&lt;dispatch_data_t&gt; alignmentData = adoptOSObject(dispatch_data_create(filler.data(), filler.size(), nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT));
+
+    OSObjectPtr&lt;dispatch_data_t&gt; headerWithAlignmentData = adoptOSObject(dispatch_data_create_concat(headerData.get(), alignmentData.get()));
+
+    return adoptOSObject(dispatch_data_create_concat(headerWithAlignmentData.get(), entry.body.dispatchData()));
+}
+
+void NetworkCacheStorage::removeEntry(const NetworkCacheKey&amp; key)
+{
+    ASSERT(RunLoop::isMain());
+
+    if (m_keyFilter.mayContain(key.hash()))
+        m_keyFilter.remove(key.hash());
+
+    StringCapture filePathCapture(filePathForKey(key, m_directoryPath));
+    dispatch_async(m_ioQueue.get(), [filePathCapture] {
+        CString path = WebCore::fileSystemRepresentation(filePathCapture.string());
+        unlink(path.data());
+    });
+}
+
+void NetworkCacheStorage::dispatchRetrieveOperation(const RetrieveOperation&amp; retrieve)
+{
+    ASSERT(RunLoop::isMain());
+
+    ++m_activeRetrieveOperationCount;
+
+    StringCapture cachePathCapture(m_directoryPath);
+    dispatch_async(m_ioQueue.get(), [this, retrieve, cachePathCapture] {
+        int fd;
+        auto channel = createIOChannelForKey(retrieve.key, IOChannelType::Read, cachePathCapture.string(), fd);
+
+        dispatch_io_read(channel.get(), 0, std::numeric_limits&lt;size_t&gt;::max(), dispatch_get_main_queue(), [this, fd, retrieve](bool done, dispatch_data_t fileData, int error) {
+            if (done) {
+                ASSERT(m_activeRetrieveOperationCount);
+                --m_activeRetrieveOperationCount;
+                dispatchPendingRetrieveOperations();
+            }
+            if (error) {
+                retrieve.completionHandler(nullptr);
+                removeEntry(retrieve.key);
+                return;
+            }
+            if (done)
+                return;
+            auto entry = decodeEntry(fileData, fd, retrieve.key);
+            bool success = retrieve.completionHandler(WTF::move(entry));
+            if (!success)
+                removeEntry(retrieve.key);
+        });
+    });
+}
+
+void NetworkCacheStorage::dispatchPendingRetrieveOperations()
+{
+    ASSERT(RunLoop::isMain());
+
+    const unsigned maximumActiveRetrieveOperationCount = 5;
+
+    for (int priority = m_pendingRetrieveOperationsByPriority.size() - 1; priority &gt;= 0; --priority) {
+        if (m_activeRetrieveOperationCount &gt; maximumActiveRetrieveOperationCount) {
+            LOG(NetworkCacheStorage, &quot;(NetworkProcess) limiting parallel retrieves&quot;);
+            return;
+        }
+        auto&amp; pendingRetrieveQueue = m_pendingRetrieveOperationsByPriority[priority];
+        if (pendingRetrieveQueue.isEmpty())
+            continue;
+        dispatchRetrieveOperation(pendingRetrieveQueue.takeFirst());
+    }
+}
+
+void NetworkCacheStorage::retrieve(const NetworkCacheKey&amp; key, unsigned priority, std::function&lt;bool (std::unique_ptr&lt;Entry&gt;)&gt; completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+
+    if (!m_keyFilter.mayContain(key.hash())) {
+        completionHandler(nullptr);
+        return;
+    }
+
+    if (m_pendingRetrieveOperationsByPriority.size() &lt; priority + 1)
+        m_pendingRetrieveOperationsByPriority.grow(priority + 1);
+    m_pendingRetrieveOperationsByPriority[priority].append(RetrieveOperation { key, completionHandler });
+
+    dispatchPendingRetrieveOperations();
+}
+
+void NetworkCacheStorage::store(const NetworkCacheKey&amp; key, const Entry&amp; entry, std::function&lt;void (bool success)&gt; completionHandler)
+{
+    ASSERT(RunLoop::isMain());
+
+    StringCapture cachePathCapture(m_directoryPath);
+    dispatch_async(m_backgroundIOQueue.get(), [this, key, entry, cachePathCapture, completionHandler]() {
+        auto data = encodeEntry(key, entry);
+        int fd;
+        auto channel = createIOChannelForKey(key, IOChannelType::Write, cachePathCapture.string(), fd);
+        dispatch_io_write(channel.get(), 0, data.get(), dispatch_get_main_queue(), [this, key, completionHandler](bool done, dispatch_data_t, int error) {
+            ASSERT_UNUSED(done, done);
+            LOG(NetworkCacheStorage, &quot;(NetworkProcess) write complete error=%d&quot;, error);
+            if (!error)
+                m_keyFilter.add(key.hash());
+            completionHandler(!error);
+        });
+    });
+}
+
+void NetworkCacheStorage::setMaximumSize(size_t size)
+{
+    ASSERT(RunLoop::isMain());
+    // FIXME: Implement.
+    m_maximumSize = size;
+}
+
+void NetworkCacheStorage::clear()
+{
+    ASSERT(RunLoop::isMain());
+    LOG(NetworkCacheStorage, &quot;(NetworkProcess) clearing cache&quot;);
+
+    m_keyFilter.clear();
+
+    StringCapture directoryPathCapture(m_directoryPath);
+
+    dispatch_async(m_ioQueue.get(), [directoryPathCapture] {
+        String directoryPath = directoryPathCapture.string();
+        traverseDirectory(directoryPath, DT_DIR, [&amp;directoryPath](const String&amp; subdirName) {
+            String subdirPath = WebCore::pathByAppendingComponent(directoryPath, subdirName);
+            traverseDirectory(subdirPath, DT_REG, [&amp;subdirPath](const String&amp; fileName) {
+                String filePath = WebCore::pathByAppendingComponent(subdirPath, fileName);
+                unlink(WebCore::fileSystemRepresentation(filePath).data());
+            });
+            rmdir(WebCore::fileSystemRepresentation(subdirPath).data());
+        });
+    });
+}
+
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcesscocoaNetworkProcessCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkProcessCocoa.mm (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkProcessCocoa.mm        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkProcessCocoa.mm        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETWORK_PROCESS)
</span><span class="cx"> 
</span><ins>+#import &quot;NetworkCache.h&quot;
</ins><span class="cx"> #import &quot;NetworkProcessCreationParameters.h&quot;
</span><span class="cx"> #import &quot;NetworkResourceLoader.h&quot;
</span><span class="cx"> #import &quot;SandboxExtension.h&quot;
</span><span class="lines">@@ -62,6 +63,13 @@
</span><span class="cx"> 
</span><span class="cx">     if (!m_diskCacheDirectory.isNull()) {
</span><span class="cx">         SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
</span><ins>+#if ENABLE(NETWORK_CACHE)
+        if (NetworkCache::shared().initialize(m_diskCacheDirectory)) {
+            NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
+            [NSURLCache setSharedURLCache:URLCache];
+            return;
+        }
+#endif
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">         [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
</span><span class="cx">             _initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
</span><span class="lines">@@ -127,6 +135,12 @@
</span><span class="cx">         cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval,
</span><span class="cx">         pageCacheCapacity, urlCacheMemoryCapacity, urlCacheDiskCapacity);
</span><span class="cx"> 
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    if (NetworkCache::shared().isEnabled()) {
+        NetworkCache::shared().setMaximumSize(urlCacheDiskCapacity);
+        return;
+    }
+#endif
</ins><span class="cx">     NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
</span><span class="cx">     [nsurlCache setMemoryCapacity:urlCacheMemoryCapacity];
</span><span class="cx">     if (!m_diskCacheIsDisabledForTesting)
</span><span class="lines">@@ -135,6 +149,10 @@
</span><span class="cx"> 
</span><span class="cx"> void NetworkProcess::clearDiskCache(std::chrono::system_clock::time_point modifiedSince, std::function&lt;void ()&gt; completionHandler)
</span><span class="cx"> {
</span><ins>+#if ENABLE(NETWORK_CACHE)
+    NetworkCache::shared().clear();
+#endif
+
</ins><span class="cx">     if (!m_clearCacheDispatchGroup)
</span><span class="cx">         m_clearCacheDispatchGroup = dispatch_group_create();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessiosNetworkProcessIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/ios/NetworkProcessIOS.mm (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/ios/NetworkProcessIOS.mm        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/ios/NetworkProcessIOS.mm        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -28,7 +28,9 @@
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS) &amp;&amp; ENABLE(NETWORK_PROCESS)
</span><span class="cx"> 
</span><ins>+#import &quot;NetworkCache.h&quot;
</ins><span class="cx"> #import &quot;NetworkProcessCreationParameters.h&quot;
</span><ins>+#import &quot;ResourceCachesToClear.h&quot;
</ins><span class="cx"> #import &quot;SandboxInitializationParameters.h&quot;
</span><span class="cx"> #import &quot;SecItemShim.h&quot;
</span><span class="cx"> #import &lt;WebCore/CertificateInfo.h&gt;
</span><span class="lines">@@ -74,8 +76,14 @@
</span><span class="cx">     [NSURLRequest setAllowsSpecificHTTPSCertificate:(NSArray *)certificateInfo.certificateChain() forHost:host];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void NetworkProcess::clearCacheForAllOrigins(uint32_t)
</del><ins>+void NetworkProcess::clearCacheForAllOrigins(uint32_t cachesToClear)
</ins><span class="cx"> {
</span><ins>+    ResourceCachesToClear resourceCachesToClear = static_cast&lt;ResourceCachesToClear&gt;(cachesToClear);
+    if (resourceCachesToClear == InMemoryResourceCachesOnly)
+        return;
+#if ENABLE(NETWORK_CACHE)
+    NetworkCache::shared().clear();
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void NetworkProcess::platformInitializeNetworkProcess(const NetworkProcessCreationParameters&amp; parameters)
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessmacNetworkProcessMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/mac/NetworkProcessMac.mm        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC) &amp;&amp; ENABLE(NETWORK_PROCESS)
</span><span class="cx"> 
</span><ins>+#import &quot;NetworkCache.h&quot;
</ins><span class="cx"> #import &quot;NetworkProcessCreationParameters.h&quot;
</span><span class="cx"> #import &quot;NetworkResourceLoader.h&quot;
</span><span class="cx"> #import &quot;ResourceCachesToClear.h&quot;
</span></span></pre></div>
<a id="trunkSourceWebKit2NetworkProcessmacNetworkResourceLoaderMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -42,9 +42,6 @@
</span><span class="cx"> 
</span><span class="cx"> static void tryGetShareableHandleFromCFData(ShareableResource::Handle&amp; handle, CFDataRef data)
</span><span class="cx"> {
</span><del>-    if (!data || CFDataGetLength(data) &lt; (CFIndex)NetworkResourceLoader::fileBackedResourceMinimumSize())
-        return;
-
</del><span class="cx">     RefPtr&lt;SharedMemory&gt; sharedMemory = SharedMemory::createFromVMBuffer((void*)CFDataGetBytePtr(data), CFDataGetLength(data));
</span><span class="cx">     if (!sharedMemory) {
</span><span class="cx">         LOG_ERROR(&quot;Failed to create VM shared memory for cached resource.&quot;);
</span></span></pre></div>
<a id="trunkSourceWebKit2PlatformLoggingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Platform/Logging.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Platform/Logging.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/Platform/Logging.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -51,6 +51,8 @@
</span><span class="cx">     M(TextInput) \
</span><span class="cx">     M(View) \
</span><span class="cx">     M(IDB) \
</span><ins>+    M(NetworkCache) \
+    M(NetworkCacheStorage) \
</ins><span class="cx"> 
</span><span class="cx"> #define DECLARE_LOG_CHANNEL(name) \
</span><span class="cx">     extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebKit2xcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -1672,6 +1672,12 @@
</span><span class="cx">                 E1E552C516AE065F004ED653 /* SandboxInitializationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = E1E552C316AE065E004ED653 /* SandboxInitializationParameters.h */; };
</span><span class="cx">                 E1EE53E311F8CFC000CCBEE4 /* InjectedBundlePageEditorClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EE53DC11F8CF9F00CCBEE4 /* InjectedBundlePageEditorClient.h */; };
</span><span class="cx">                 E1EE53E711F8CFFB00CCBEE4 /* InjectedBundlePageEditorClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1EE53E611F8CFFB00CCBEE4 /* InjectedBundlePageEditorClient.cpp */; };
</span><ins>+                E4436ECA1A0D03FA00EAD204 /* NetworkCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4436EBE1A0CFDB200EAD204 /* NetworkCache.cpp */; };
+                E4436ECC1A0D040B00EAD204 /* NetworkCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E4436EBF1A0CFDB200EAD204 /* NetworkCache.h */; };
+                E4436ECD1A0D040B00EAD204 /* NetworkCacheKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4436EC01A0CFDB200EAD204 /* NetworkCacheKey.cpp */; };
+                E4436ECE1A0D040B00EAD204 /* NetworkCacheKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */; };
+                E4436ECF1A0D040B00EAD204 /* NetworkCacheStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = E4436EC21A0CFDB200EAD204 /* NetworkCacheStorage.h */; };
+                E4436ED01A0D040B00EAD204 /* NetworkCacheStorageCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = E4436EC31A0CFDB200EAD204 /* NetworkCacheStorageCocoa.mm */; };
</ins><span class="cx">                 E489D28A1A0A2DB80078C06A /* NetworkCacheCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = E489D2831A0A2DB80078C06A /* NetworkCacheCoder.h */; };
</span><span class="cx">                 E489D28B1A0A2DB80078C06A /* NetworkCacheCoders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E489D2841A0A2DB80078C06A /* NetworkCacheCoders.cpp */; };
</span><span class="cx">                 E489D28C1A0A2DB80078C06A /* NetworkCacheCoders.h in Headers */ = {isa = PBXBuildFile; fileRef = E489D2851A0A2DB80078C06A /* NetworkCacheCoders.h */; };
</span><span class="lines">@@ -3802,6 +3808,12 @@
</span><span class="cx">                 E1EE53E611F8CFFB00CCBEE4 /* InjectedBundlePageEditorClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundlePageEditorClient.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E1FEF39A190F76F300731658 /* com.apple.WebKit.Databases.sb.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.WebKit.Databases.sb.in; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E1FEF39C190F791C00731658 /* DatabaseProcessIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DatabaseProcessIOS.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                E4436EBE1A0CFDB200EAD204 /* NetworkCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCache.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E4436EBF1A0CFDB200EAD204 /* NetworkCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCache.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E4436EC01A0CFDB200EAD204 /* NetworkCacheKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheKey.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheKey.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E4436EC21A0CFDB200EAD204 /* NetworkCacheStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheStorage.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                E4436EC31A0CFDB200EAD204 /* NetworkCacheStorageCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NetworkCacheStorageCocoa.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 E489D2831A0A2DB80078C06A /* NetworkCacheCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheCoder.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E489D2841A0A2DB80078C06A /* NetworkCacheCoders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheCoders.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E489D2851A0A2DB80078C06A /* NetworkCacheCoders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheCoders.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -7120,6 +7132,8 @@
</span><span class="cx">                 E489D2821A0A2BE80078C06A /* cache */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                E4436EBE1A0CFDB200EAD204 /* NetworkCache.cpp */,
+                                E4436EBF1A0CFDB200EAD204 /* NetworkCache.h */,
</ins><span class="cx">                                 E489D2831A0A2DB80078C06A /* NetworkCacheCoder.h */,
</span><span class="cx">                                 E489D2841A0A2DB80078C06A /* NetworkCacheCoders.cpp */,
</span><span class="cx">                                 E489D2851A0A2DB80078C06A /* NetworkCacheCoders.h */,
</span><span class="lines">@@ -7127,6 +7141,10 @@
</span><span class="cx">                                 E489D2871A0A2DB80078C06A /* NetworkCacheDecoder.h */,
</span><span class="cx">                                 E489D2881A0A2DB80078C06A /* NetworkCacheEncoder.cpp */,
</span><span class="cx">                                 E489D2891A0A2DB80078C06A /* NetworkCacheEncoder.h */,
</span><ins>+                                E4436EC01A0CFDB200EAD204 /* NetworkCacheKey.cpp */,
+                                E4436EC11A0CFDB200EAD204 /* NetworkCacheKey.h */,
+                                E4436EC21A0CFDB200EAD204 /* NetworkCacheStorage.h */,
+                                E4436EC31A0CFDB200EAD204 /* NetworkCacheStorageCocoa.mm */,
</ins><span class="cx">                         );
</span><span class="cx">                         name = cache;
</span><span class="cx">                         path = NetworkProcess/cache;
</span><span class="lines">@@ -7228,6 +7246,7 @@
</span><span class="cx">                                 BCBAAC73144E619E0053F82F /* WKBrowsingContextController.h in Headers */,
</span><span class="cx">                                 BCBAACF41452324F0053F82F /* WKBrowsingContextGroup.h in Headers */,
</span><span class="cx">                                 BCBAAD0B14560A430053F82F /* WKBrowsingContextLoadDelegate.h in Headers */,
</span><ins>+                                E4436ECE1A0D040B00EAD204 /* NetworkCacheKey.h in Headers */,
</ins><span class="cx">                                 BCA284D71492F2C7001F9042 /* WKConnection.h in Headers */,
</span><span class="cx">                                 BC017D0716260FF4007054F5 /* WKDOMDocument.h in Headers */,
</span><span class="cx">                                 BC017D0916260FF4007054F5 /* WKDOMElement.h in Headers */,
</span><span class="lines">@@ -7673,6 +7692,7 @@
</span><span class="cx">                                 51032F1E180F791700961BB7 /* DatabaseToWebProcessConnectionMessages.h in Headers */,
</span><span class="cx">                                 51A9E1061315CCFC009E7031 /* WebKeyValueStorageManager.h in Headers */,
</span><span class="cx">                                 373D122718A473F60066D9CC /* _WKFrameHandleInternal.h in Headers */,
</span><ins>+                                E4436ECF1A0D040B00EAD204 /* NetworkCacheStorage.h in Headers */,
</ins><span class="cx">                                 1AE00D611831792100087DD7 /* FrameLoadState.h in Headers */,
</span><span class="cx">                                 BCB63478116BF10600603215 /* WebKit2_C.h in Headers */,
</span><span class="cx">                                 1A81B38518BD673A0007FDAC /* _WKVisitedLinkProviderInternal.h in Headers */,
</span><span class="lines">@@ -7819,6 +7839,7 @@
</span><span class="cx">                                 BC5D24C716CD73C5007D5461 /* WKBundleRangeHandlePrivate.h in Headers */,
</span><span class="cx">                                 BC14DF9F120B635F00826C0C /* WKBundleScriptWorld.h in Headers */,
</span><span class="cx">                                 1AF4CEF018BC481800BC2D34 /* VisitedLinkTableController.h in Headers */,
</span><ins>+                                E4436ECC1A0D040B00EAD204 /* NetworkCache.h in Headers */,
</ins><span class="cx">                                 BC4075F6124FF0270068F20A /* WKCertificateInfo.h in Headers */,
</span><span class="cx">                                 BC407627124FF0400068F20A /* WKCertificateInfoMac.h in Headers */,
</span><span class="cx">                                 372CAF0B1833FD910040AC27 /* WKNSError.h in Headers */,
</span><span class="lines">@@ -9064,6 +9085,7 @@
</span><span class="cx">                                 513A163C163088F6005D7D22 /* NetworkProcessProxyMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 1A6280F31919982A006AD9F9 /* WebKit.m in Sources */,
</span><span class="cx">                                 51FD18B51651FBAD00DBE1CE /* NetworkResourceLoader.cpp in Sources */,
</span><ins>+                                E4436ECD1A0D040B00EAD204 /* NetworkCacheKey.cpp in Sources */,
</ins><span class="cx">                                 51E3B67F16F266B3009968DC /* NetworkResourceLoaderMac.mm in Sources */,
</span><span class="cx">                                 E152551A17011819003D7ADB /* NetworkResourceLoaderMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 51CBBA0F165219B6005BE8FD /* NetworkResourceLoadParameters.cpp in Sources */,
</span><span class="lines">@@ -9425,6 +9447,7 @@
</span><span class="cx">                                 1A043F6912514D8B00FFBFB5 /* WebProcessConnectionMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 9321D5881A38EE74008052BE /* WKImmediateActionController.mm in Sources */,
</span><span class="cx">                                 1A002D48196B345D00B9AD44 /* SessionStateCoding.mm in Sources */,
</span><ins>+                                E4436ED01A0D040B00EAD204 /* NetworkCacheStorageCocoa.mm in Sources */,
</ins><span class="cx">                                 BC306825125A6B9400E71278 /* WebProcessCreationParameters.cpp in Sources */,
</span><span class="cx">                                 1F7506B01859162C00EC0FF7 /* WKWebProcessPlugInScriptWorld.mm in Sources */,
</span><span class="cx">                                 75E749EB180DBB9800088BA6 /* WebOriginDataManagerProxyMessageReceiver.cpp in Sources */,
</span><span class="lines">@@ -9455,6 +9478,7 @@
</span><span class="cx">                                 51FB08FF1639DE1A00EC324A /* WebResourceLoadScheduler.cpp in Sources */,
</span><span class="cx">                                 0F5947A7187B517600437857 /* RemoteScrollingCoordinatorMessageReceiver.cpp in Sources */,
</span><span class="cx">                                 D3B9484811FF4B6500032B39 /* WebSearchPopupMenu.cpp in Sources */,
</span><ins>+                                E4436ECA1A0D03FA00EAD204 /* NetworkCache.cpp in Sources */,
</ins><span class="cx">                                 BCC5715C115ADAEF001CCAF9 /* WebSystemInterface.mm in Sources */,
</span><span class="cx">                                 C0337DD8127A51B6008FF4F4 /* WebTouchEvent.cpp in Sources */,
</span><span class="cx">                                 BCA0EF8012331E78007D3CFB /* WebUndoStep.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebKit2configh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/config.h (177293 => 177294)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/config.h        2014-12-15 19:17:04 UTC (rev 177293)
+++ trunk/Source/WebKit2/config.h        2014-12-15 19:25:23 UTC (rev 177294)
</span><span class="lines">@@ -92,3 +92,9 @@
</span><span class="cx"> #define HAVE_SEC_ACCESS_CONTROL 1
</span><span class="cx"> #endif
</span><span class="cx"> #endif
</span><ins>+
+#ifndef ENABLE_NETWORK_CACHE
+#if PLATFORM(MAC) &amp;&amp; ENABLE(NETWORK_PROCESS)
+#define ENABLE_NETWORK_CACHE 0
+#endif
+#endif
</ins></span></pre>
</div>
</div>

</body>
</html>