Don't cache resources that are very unlikely to be reused
https://bugs.webkit.org/show_bug.cgi?id=143226
<rdar://problem/20347160>

Reviewed by Geoff Garen.

Source/WebCore:

Allow overriding resource load priorities via Internals for testing.

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::addExtraFieldsToRequest):
(WebCore::FrameLoader::clearTestingOverrides):
* loader/FrameLoader.h:
(WebCore::FrameLoader::setOverrideResourceLoadPriorityForTesting):
(WebCore::FrameLoader::clearOverrideCachePolicyForTesting): Deleted.
* page/DiagnosticLoggingKeys.cpp:
(WebCore::DiagnosticLoggingKeys::unlikelyToReuseKey):
* page/DiagnosticLoggingKeys.h:

    Add a key.

* testing/Internals.cpp:
(WebCore::Internals::resetToConsistentState):
(WebCore::stringToResourceLoadPriority):
(WebCore::Internals::setOverrideResourceLoadPriority):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit2:

We are writing lots of resources to the cache that are never used again.

In browse-around-randomly test this reduced number of cache entries created by ~20% and bytes written by ~5%.

* NetworkProcess/cache/NetworkCache.cpp:
(WebKit::NetworkCache::makeUseDecision):
(WebKit::NetworkCache::makeRetrieveDecision):

    Rename for clarity.

(WebKit::NetworkCache::makeStoreDecision):

    Store only if the resource has non-zero expiration or has validation headers.

    Very High priority resources (main resources) keep the existing policy to minimize impact
    on back navigation and tab restore.

(WebKit::NetworkCache::Cache::retrieve):
(WebKit::NetworkCache::Cache::store):
(WebKit::NetworkCache::canUse): Deleted.
(WebKit::NetworkCache::canRetrieve): Deleted.
(WebKit::NetworkCache::canStore): Deleted.
* NetworkProcess/cache/NetworkCache.h:
* NetworkProcess/cache/NetworkCacheStatistics.cpp:
(WebKit::NetworkCache::storeDecisionToDiagnosticKey):

LayoutTests:

* http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt:
* http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.html:

    Keep max-age: 0 cacheable in this test by adding a validation header.

* http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt:
* http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html:

    Rebase and expand to cover the high priority resource case.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@182152 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 686ac5b..1ce369f 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,21 @@
+2015-03-30  Antti Koivisto  <antti@apple.com>
+
+        Don't cache resources that are very unlikely to be reused
+        https://bugs.webkit.org/show_bug.cgi?id=143226
+        <rdar://problem/20347160>
+
+        Reviewed by Geoff Garen.
+
+        * http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt:
+        * http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.html:
+
+            Keep max-age: 0 cacheable in this test by adding a validation header.
+
+        * http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt:
+        * http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html:
+
+            Rebase and expand to cover the high priority resource case.
+
 2015-03-30  Marcos Chavarría Teijeiro  <chavarria1991@gmail.com>
 
         Rebaseline accessibility/aria-toggle-button-with-title.html
diff --git a/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt b/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt
index aac0074..0fba14d 100644
--- a/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt
+++ b/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale-expected.txt
@@ -5,23 +5,23 @@
 
 running 36 tests
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100"}
 request headers: {"Cache-control":"max-stale=0"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale"}
 response source: Disk cache
 
@@ -29,7 +29,7 @@
 request headers: {"Cache-control":"max-stale"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale"}
 response source: Disk cache
 
@@ -37,7 +37,7 @@
 request headers: {"Cache-control":"max-stale"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=100"}
 response source: Disk cache
 
@@ -45,79 +45,79 @@
 request headers: {"Cache-control":"max-stale=100"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=100"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=100"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=0, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100"}
 request headers: {"Cache-control":"max-stale=0, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=0, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=0, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100"}
 request headers: {"Cache-control":"max-stale, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=100, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100"}
 request headers: {"Cache-control":"max-stale=100, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=100, max-age=0"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=100, max-age=0"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=0, max-age=100"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100"}
 request headers: {"Cache-control":"max-stale=0, max-age=100"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=0, max-age=100"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=0, max-age=100"}
 response source: Network
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale, max-age=100"}
 response source: Disk cache
 
@@ -125,7 +125,7 @@
 request headers: {"Cache-control":"max-stale, max-age=100"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale, max-age=100"}
 response source: Disk cache
 
@@ -133,7 +133,7 @@
 request headers: {"Cache-control":"max-stale, max-age=100"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0"}
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
 request headers: {"Cache-control":"max-stale=100, max-age=100"}
 response source: Disk cache
 
@@ -141,9 +141,9 @@
 request headers: {"Cache-control":"max-stale=100, max-age=100"}
 response source: Disk cache
 
-response headers: {"Cache-control":"max-age=0","Age":"200"}
+response headers: {"Cache-control":"max-age=0","ETag":"match","Age":"200"}
 request headers: {"Cache-control":"max-stale=100, max-age=100"}
-response source: Network
+response source: Disk cache after validation
 
 response headers: {"Cache-control":"max-age=100","Age":"200"}
 request headers: {"Cache-control":"max-stale=100, max-age=100"}
diff --git a/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale.html b/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale.html
index 25d856a..f7ee12b 100644
--- a/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale.html
+++ b/LayoutTests/http/tests/cache/disk-cache/disk-cache-request-max-stale.html
@@ -6,7 +6,7 @@
 var testMatrix =
 [
  [
-  { responseHeaders: {'Cache-control': 'max-age=0' } },
+  { responseHeaders: {'Cache-control': 'max-age=0', 'ETag': 'match' } },
   { responseHeaders: {'Cache-control': 'max-age=100' } },
   ],
  [
diff --git a/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt b/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt
index c0a5eb0..a5de237 100644
--- a/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt
+++ b/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy-expected.txt
@@ -6,6 +6,170 @@
 running 54 tests
 
 response headers: undefined
+response source: Network
+
+response headers: {"Cache-control":"max-age=0"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-cache"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-cache"}
+response source: Disk cache
+
+response headers: {"ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, no-cache","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, no-cache","ETag":"match"}
+response source: Disk cache
+
+response headers: {"ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, no-cache","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, no-cache","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, must-revalidate"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-cache, must-revalidate"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-cache, must-revalidate"}
+response source: Disk cache
+
+response headers: {"ETag":"match","Cache-control":"must-revalidate"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, must-revalidate","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, must-revalidate","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store, must-revalidate","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store, must-revalidate","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store, must-revalidate","ETag":"match"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache, must-revalidate","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, no-cache, must-revalidate","ETag":"match"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, no-cache, must-revalidate","ETag":"match"}
+response source: Disk cache
+
+response headers: {"ETag":"nomatch","Cache-control":"must-revalidate"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, must-revalidate","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, must-revalidate","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"no-store, must-revalidate","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=0, no-store, must-revalidate","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"max-age=100, no-store, must-revalidate","ETag":"nomatch"}
+response source: Network
+
+response headers: {"Cache-control":"no-cache, must-revalidate","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=0, no-cache, must-revalidate","ETag":"nomatch"}
+response source: Disk cache
+
+response headers: {"Cache-control":"max-age=100, no-cache, must-revalidate","ETag":"nomatch"}
+response source: Disk cache
+
+Testing high priority resources
+
+response headers: undefined
 response source: Disk cache
 
 response headers: {"Cache-control":"max-age=0"}
diff --git a/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html b/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html
index f9ec73f..570a40c 100644
--- a/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html
+++ b/LayoutTests/http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html
@@ -36,7 +36,12 @@
 debug("running " + tests.length + " tests");
 debug("");
 
-runTests(tests);
+runTests(tests, function () {
+    debug("Testing high priority resources");
+    debug("");
+    internals.setOverrideResourceLoadPriority("ResourceLoadPriorityVeryHigh");
+    runTests(tests);
+});
 
 </script>
 <script src="/js-test-resources/js-test-post.js"></script>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 1cd0b56..e7f3dad 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,32 @@
+2015-03-30  Antti Koivisto  <antti@apple.com>
+
+        Don't cache resources that are very unlikely to be reused
+        https://bugs.webkit.org/show_bug.cgi?id=143226
+        <rdar://problem/20347160>
+
+        Reviewed by Geoff Garen.
+
+        Allow overriding resource load priorities via Internals for testing.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::addExtraFieldsToRequest):
+        (WebCore::FrameLoader::clearTestingOverrides):
+        * loader/FrameLoader.h:
+        (WebCore::FrameLoader::setOverrideResourceLoadPriorityForTesting):
+        (WebCore::FrameLoader::clearOverrideCachePolicyForTesting): Deleted.
+        * page/DiagnosticLoggingKeys.cpp:
+        (WebCore::DiagnosticLoggingKeys::unlikelyToReuseKey):
+        * page/DiagnosticLoggingKeys.h:
+
+            Add a key.
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::resetToConsistentState):
+        (WebCore::stringToResourceLoadPriority):
+        (WebCore::Internals::setOverrideResourceLoadPriority):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2015-03-30  Javier Fernandez  <jfernandez@igalia.com>
 
         [CSS Grid Layout] Upgrade align-self and align-items parsing to CSS 3
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index 4e3a4f2..105c82c 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -2561,6 +2561,8 @@
 
     if (m_overrideCachePolicyForTesting)
         request.setCachePolicy(m_overrideCachePolicyForTesting.value());
+    if (m_overrideResourceLoadPriorityForTesting)
+        request.setPriority(m_overrideResourceLoadPriorityForTesting.value());
 
     if (request.cachePolicy() == ReloadIgnoringCacheData) {
         if (loadType == FrameLoadType::Reload)
@@ -3413,6 +3415,12 @@
     m_client.forcePageTransitionIfNeeded();
 }
 
+void FrameLoader::clearTestingOverrides()
+{
+    m_overrideCachePolicyForTesting = Nullopt;
+    m_overrideResourceLoadPriorityForTesting = Nullopt;
+}
+
 bool FrameLoaderClient::hasHTMLView() const
 {
     return true;
diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h
index 2c6748b..838a397 100644
--- a/Source/WebCore/loader/FrameLoader.h
+++ b/Source/WebCore/loader/FrameLoader.h
@@ -290,7 +290,8 @@
     void forcePageTransitionIfNeeded();
 
     void setOverrideCachePolicyForTesting(ResourceRequestCachePolicy policy) { m_overrideCachePolicyForTesting = policy; }
-    void clearOverrideCachePolicyForTesting() { m_overrideCachePolicyForTesting = Nullopt; }
+    void setOverrideResourceLoadPriorityForTesting(ResourceLoadPriority priority) { m_overrideResourceLoadPriorityForTesting = priority; }
+    WEBCORE_EXPORT void clearTestingOverrides();
 
 private:
     enum FormSubmissionCacheLoadPolicy {
@@ -442,6 +443,7 @@
     RefPtr<FrameNetworkingContext> m_networkingContext;
 
     Optional<ResourceRequestCachePolicy> m_overrideCachePolicyForTesting;
+    Optional<ResourceLoadPriority> m_overrideResourceLoadPriorityForTesting;
 
     URL m_previousURL;
     RefPtr<HistoryItem> m_requestedHistoryItem;
diff --git a/Source/WebCore/page/DiagnosticLoggingKeys.cpp b/Source/WebCore/page/DiagnosticLoggingKeys.cpp
index 9ddd63c..18c79bd 100644
--- a/Source/WebCore/page/DiagnosticLoggingKeys.cpp
+++ b/Source/WebCore/page/DiagnosticLoggingKeys.cpp
@@ -383,6 +383,11 @@
     return ASCIILiteral("uncacheableStatusCode");
 }
 
+String DiagnosticLoggingKeys::unlikelyToReuseKey()
+{
+    return ASCIILiteral("unlikelyToReuse");
+}
+
 String DiagnosticLoggingKeys::unsupportedHTTPMethodKey()
 {
     return ASCIILiteral("unsupportedHTTPMethod");
diff --git a/Source/WebCore/page/DiagnosticLoggingKeys.h b/Source/WebCore/page/DiagnosticLoggingKeys.h
index cb86b4e..f9bc1cc 100644
--- a/Source/WebCore/page/DiagnosticLoggingKeys.h
+++ b/Source/WebCore/page/DiagnosticLoggingKeys.h
@@ -108,6 +108,7 @@
     static String styleSheetKey();
     static String svgDocumentKey();
     WEBCORE_EXPORT static String uncacheableStatusCodeKey();
+    WEBCORE_EXPORT static String unlikelyToReuseKey();
     WEBCORE_EXPORT static String unsupportedHTTPMethodKey();
     static String unsuspendableDOMObjectKey();
     WEBCORE_EXPORT static String unusableCachedEntryKey();
diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp
index 39f2f35..99401f6 100644
--- a/Source/WebCore/testing/Internals.cpp
+++ b/Source/WebCore/testing/Internals.cpp
@@ -308,7 +308,7 @@
         page->mainFrame().editor().toggleContinuousSpellChecking();
     if (page->mainFrame().editor().isOverwriteModeEnabled())
         page->mainFrame().editor().toggleOverwriteModeEnabled();
-    page->mainFrame().loader().clearOverrideCachePolicyForTesting();
+    page->mainFrame().loader().clearTestingOverrides();
     ApplicationCacheStorage::singleton().setDefaultOriginQuota(ApplicationCacheStorage::noQuota());
 #if ENABLE(VIDEO)
     MediaSessionManager::sharedManager().resetRestrictions();
@@ -445,6 +445,27 @@
     frame()->loader().setOverrideCachePolicyForTesting(stringToResourceRequestCachePolicy(policy));
 }
 
+static ResourceLoadPriority stringToResourceLoadPriority(const String& policy)
+{
+    if (policy == "ResourceLoadPriorityVeryLow")
+        return ResourceLoadPriorityVeryLow;
+    if (policy == "ResourceLoadPriorityLow")
+        return ResourceLoadPriorityLow;
+    if (policy == "ResourceLoadPriorityMedium")
+        return ResourceLoadPriorityMedium;
+    if (policy == "ResourceLoadPriorityHigh")
+        return ResourceLoadPriorityHigh;
+    if (policy == "ResourceLoadPriorityVeryHigh")
+        return ResourceLoadPriorityVeryHigh;
+    ASSERT_NOT_REACHED();
+    return ResourceLoadPriorityLow;
+}
+
+void Internals::setOverrideResourceLoadPriority(const String& priority)
+{
+    frame()->loader().setOverrideResourceLoadPriorityForTesting(stringToResourceLoadPriority(priority));
+}
+
 void Internals::clearMemoryCache()
 {
     MemoryCache::singleton().evictResources();
diff --git a/Source/WebCore/testing/Internals.h b/Source/WebCore/testing/Internals.h
index 4e5dd55..71ff42e3 100644
--- a/Source/WebCore/testing/Internals.h
+++ b/Source/WebCore/testing/Internals.h
@@ -90,6 +90,7 @@
     bool isLoadingFromMemoryCache(const String& url);
     String xhrResponseSource(XMLHttpRequest*);
     void setOverrideCachePolicy(const String&);
+    void setOverrideResourceLoadPriority(const String&);
 
     void clearMemoryCache();
     void pruneMemoryCacheToSize(unsigned size);
diff --git a/Source/WebCore/testing/Internals.idl b/Source/WebCore/testing/Internals.idl
index 740eb2e..11884f0 100644
--- a/Source/WebCore/testing/Internals.idl
+++ b/Source/WebCore/testing/Internals.idl
@@ -37,6 +37,13 @@
     "ReturnCacheDataDontLoad"
 };
 
+enum ResourceLoadPriority {
+    "ResourceLoadPriorityVeryLow",
+    "ResourceLoadPriorityLow",
+    "ResourceLoadPriorityMedium",
+    "ResourceLoadPriorityHigh",
+    "ResourceLoadPriorityVeryHigh"
+};
 
 [
     NoInterfaceObject,
@@ -56,6 +63,7 @@
     void pruneMemoryCacheToSize(long size);
     long memoryCacheSize();
     void setOverrideCachePolicy(CachePolicy policy);
+    void setOverrideResourceLoadPriority(ResourceLoadPriority priority);
 
     void clearPageCache();
     unsigned int pageCacheSize();
diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog
index cbda0b6..14e91b2 100644
--- a/Source/WebKit2/ChangeLog
+++ b/Source/WebKit2/ChangeLog
@@ -1,3 +1,37 @@
+2015-03-30  Antti Koivisto  <antti@apple.com>
+
+        Don't cache resources that are very unlikely to be reused
+        https://bugs.webkit.org/show_bug.cgi?id=143226
+        <rdar://problem/20347160>
+
+        Reviewed by Geoff Garen.
+
+        We are writing lots of resources to the cache that are never used again.
+
+        In browse-around-randomly test this reduced number of cache entries created by ~20% and bytes written by ~5%.
+
+        * NetworkProcess/cache/NetworkCache.cpp:
+        (WebKit::NetworkCache::makeUseDecision):
+        (WebKit::NetworkCache::makeRetrieveDecision):
+
+            Rename for clarity.
+
+        (WebKit::NetworkCache::makeStoreDecision):
+
+            Store only if the resource has non-zero expiration or has validation headers.
+
+            Very High priority resources (main resources) keep the existing policy to minimize impact
+            on back navigation and tab restore.
+
+        (WebKit::NetworkCache::Cache::retrieve):
+        (WebKit::NetworkCache::Cache::store):
+        (WebKit::NetworkCache::canUse): Deleted.
+        (WebKit::NetworkCache::canRetrieve): Deleted.
+        (WebKit::NetworkCache::canStore): Deleted.
+        * NetworkProcess/cache/NetworkCache.h:
+        * NetworkProcess/cache/NetworkCacheStatistics.cpp:
+        (WebKit::NetworkCache::storeDecisionToDiagnosticKey):
+
 2015-03-30  Tim Horton  <timothy_horton@apple.com>
 
         Swipe snapshot removed too early (jumps around) on arstechnica and NYT
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
index c4fa7d8..d8a6cf8 100644
--- a/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCache.cpp
@@ -182,12 +182,10 @@
     return responseHasExpired(response, timestamp, requestDirectives.maxStale);
 }
 
-static UseDecision canUse(const Entry& entry, const WebCore::ResourceRequest& request)
+static UseDecision makeUseDecision(const Entry& entry, const WebCore::ResourceRequest& request)
 {
-    if (!verifyVaryingRequestHeaders(entry.varyingRequestHeaders(), request)) {
-        LOG(NetworkCache, "(NetworkProcess) varying header mismatch\n");
+    if (!verifyVaryingRequestHeaders(entry.varyingRequestHeaders(), request))
         return UseDecision::NoDueToVaryingHeaderMismatch;
-    }
 
     // We never revalidate in the case of a history navigation.
     if (cachePolicyAllowsExpired(request.cachePolicy()))
@@ -196,15 +194,13 @@
     if (!responseNeedsRevalidation(entry.response(), request, entry.timeStamp()))
         return UseDecision::Use;
 
-    bool hasValidatorFields = entry.response().hasCacheValidatorFields();
-    LOG(NetworkCache, "(NetworkProcess) needsRevalidation hasValidatorFields=%d", hasValidatorFields);
-    if (!hasValidatorFields)
+    if (!entry.response().hasCacheValidatorFields())
         return UseDecision::NoDueToMissingValidatorFields;
 
     return UseDecision::Validate;
 }
 
-static RetrieveDecision canRetrieve(const WebCore::ResourceRequest& request)
+static RetrieveDecision makeRetrieveDecision(const WebCore::ResourceRequest& request)
 {
     // FIXME: Support HEAD requests.
     if (request.httpMethod() != "GET")
@@ -218,67 +214,6 @@
     return RetrieveDecision::Yes;
 }
 
-void Cache::retrieve(const WebCore::ResourceRequest& originalRequest, uint64_t webPageID, std::function<void (std::unique_ptr<Entry>)> completionHandler)
-{
-    ASSERT(isEnabled());
-    ASSERT(originalRequest.url().protocolIsInHTTPFamily());
-
-    LOG(NetworkCache, "(NetworkProcess) retrieving %s priority %u", originalRequest.url().string().ascii().data(), originalRequest.priority());
-
-    if (m_statistics)
-        m_statistics->recordRetrievalRequest(webPageID);
-
-    Key storageKey = makeCacheKey(originalRequest);
-    RetrieveDecision retrieveDecision = canRetrieve(originalRequest);
-    if (retrieveDecision != RetrieveDecision::Yes) {
-        if (m_statistics)
-            m_statistics->recordNotUsingCacheForRequest(webPageID, storageKey, originalRequest, retrieveDecision);
-
-        completionHandler(nullptr);
-        return;
-    }
-
-    auto startTime = std::chrono::system_clock::now();
-    unsigned priority = originalRequest.priority();
-
-    m_storage->retrieve(storageKey, priority, [this, originalRequest, completionHandler, startTime, storageKey, webPageID](std::unique_ptr<Storage::Record> record) {
-        if (!record) {
-            LOG(NetworkCache, "(NetworkProcess) not found in storage");
-
-            if (m_statistics)
-                m_statistics->recordRetrievalFailure(webPageID, storageKey, originalRequest);
-
-            completionHandler(nullptr);
-            return false;
-        }
-
-        ASSERT(record->key == storageKey);
-
-        auto entry = Entry::decodeStorageRecord(*record);
-
-        auto useDecision = entry ? canUse(*entry, originalRequest) : UseDecision::NoDueToDecodeFailure;
-        switch (useDecision) {
-        case UseDecision::Use:
-            break;
-        case UseDecision::Validate:
-            entry->setNeedsValidation();
-            break;
-        default:
-            entry = nullptr;
-        };
-
-#if !LOG_DISABLED
-        auto elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime).count();
-        LOG(NetworkCache, "(NetworkProcess) retrieve complete useDecision=%d priority=%u time=%lldms", useDecision, originalRequest.priority(), elapsedMS);
-#endif
-        completionHandler(WTF::move(entry));
-
-        if (m_statistics)
-            m_statistics->recordRetrievedCachedEntry(webPageID, storageKey, originalRequest, useDecision);
-        return useDecision != UseDecision::NoDueToDecodeFailure;
-    });
-}
-
 // http://tools.ietf.org/html/rfc7231#page-48
 static bool isStatusCodeCacheableByDefault(int statusCode)
 {
@@ -317,7 +252,7 @@
     }
 }
 
-static StoreDecision canStore(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response)
+static StoreDecision makeStoreDecision(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response)
 {
     if (!originalRequest.url().protocolIsInHTTPFamily() || !response.isHTTP())
         return StoreDecision::NoDueToProtocol;
@@ -332,19 +267,87 @@
     if (response.cacheControlContainsNoStore())
         return StoreDecision::NoDueToNoStoreResponse;
 
-    if (isStatusCodeCacheableByDefault(response.httpStatusCode()))
-        return StoreDecision::Yes;
-
-    if (isStatusCodePotentiallyCacheable(response.httpStatusCode())) {
-        // Check for expiration headers allowing us to cache.
+    if (!isStatusCodeCacheableByDefault(response.httpStatusCode())) {
         // http://tools.ietf.org/html/rfc7234#section-4.3.2
-        if (std::isfinite(response.expires()) || std::isfinite(response.cacheControlMaxAge()))
-            return StoreDecision::Yes;
+        bool hasExpirationHeaders = std::isfinite(response.expires()) || std::isfinite(response.cacheControlMaxAge());
+        bool expirationHeadersAllowCaching = isStatusCodePotentiallyCacheable(response.httpStatusCode()) && hasExpirationHeaders;
+        if (!expirationHeadersAllowCaching)
+            return StoreDecision::NoDueToHTTPStatusCode;
     }
 
-    LOG(NetworkCache, "(NetworkProcess) status code %d not cacheable by default and no explicit expiration headers", response.httpStatusCode());
+    // Main resource has ResourceLoadPriorityVeryHigh.
+    bool storeUnconditionallyForHistoryNavigation = originalRequest.priority() == WebCore::ResourceLoadPriorityVeryHigh;
+    if (!storeUnconditionallyForHistoryNavigation) {
+        auto currentTime = std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch());
+        bool hasNonZeroLifetime = WebCore::computeFreshnessLifetimeForHTTPFamily(response, currentTime.count()) > 0;
 
-    return StoreDecision::NoDueToHTTPStatusCode;
+        bool possiblyReusable = response.hasCacheValidatorFields() || hasNonZeroLifetime;
+        if (!possiblyReusable)
+            return StoreDecision::NoDueToUnlikelyToReuse;
+    }
+
+    return StoreDecision::Yes;
+}
+
+void Cache::retrieve(const WebCore::ResourceRequest& originalRequest, uint64_t webPageID, std::function<void (std::unique_ptr<Entry>)> completionHandler)
+{
+    ASSERT(isEnabled());
+    ASSERT(originalRequest.url().protocolIsInHTTPFamily());
+
+    LOG(NetworkCache, "(NetworkProcess) retrieving %s priority %u", originalRequest.url().string().ascii().data(), originalRequest.priority());
+
+    if (m_statistics)
+        m_statistics->recordRetrievalRequest(webPageID);
+
+    Key storageKey = makeCacheKey(originalRequest);
+    auto retrieveDecision = makeRetrieveDecision(originalRequest);
+    if (retrieveDecision != RetrieveDecision::Yes) {
+        if (m_statistics)
+            m_statistics->recordNotUsingCacheForRequest(webPageID, storageKey, originalRequest, retrieveDecision);
+
+        completionHandler(nullptr);
+        return;
+    }
+
+    auto startTime = std::chrono::system_clock::now();
+    unsigned priority = originalRequest.priority();
+
+    m_storage->retrieve(storageKey, priority, [this, originalRequest, completionHandler, startTime, storageKey, webPageID](std::unique_ptr<Storage::Record> record) {
+        if (!record) {
+            LOG(NetworkCache, "(NetworkProcess) not found in storage");
+
+            if (m_statistics)
+                m_statistics->recordRetrievalFailure(webPageID, storageKey, originalRequest);
+
+            completionHandler(nullptr);
+            return false;
+        }
+
+        ASSERT(record->key == storageKey);
+
+        auto entry = Entry::decodeStorageRecord(*record);
+
+        auto useDecision = entry ? makeUseDecision(*entry, originalRequest) : UseDecision::NoDueToDecodeFailure;
+        switch (useDecision) {
+        case UseDecision::Use:
+            break;
+        case UseDecision::Validate:
+            entry->setNeedsValidation();
+            break;
+        default:
+            entry = nullptr;
+        };
+
+#if !LOG_DISABLED
+        auto elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime).count();
+        LOG(NetworkCache, "(NetworkProcess) retrieve complete useDecision=%d priority=%u time=%lldms", useDecision, originalRequest.priority(), elapsedMS);
+#endif
+        completionHandler(WTF::move(entry));
+
+        if (m_statistics)
+            m_statistics->recordRetrievedCachedEntry(webPageID, storageKey, originalRequest, useDecision);
+        return useDecision != UseDecision::NoDueToDecodeFailure;
+    });
 }
 
 void Cache::store(const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceResponse& response, RefPtr<WebCore::SharedBuffer>&& responseData, std::function<void (MappedBody&)> completionHandler)
@@ -354,7 +357,8 @@
 
     LOG(NetworkCache, "(NetworkProcess) storing %s, partition %s", originalRequest.url().string().latin1().data(), originalRequest.cachePartition().latin1().data());
 
-    StoreDecision storeDecision = canStore(originalRequest, response);
+    StoreDecision storeDecision = makeStoreDecision(originalRequest, response);
+
     if (storeDecision != StoreDecision::Yes) {
         LOG(NetworkCache, "(NetworkProcess) didn't store, storeDecision=%d", storeDecision);
         if (m_statistics) {
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCache.h b/Source/WebKit2/NetworkProcess/cache/NetworkCache.h
index 402fbdf..5056b51 100644
--- a/Source/WebKit2/NetworkProcess/cache/NetworkCache.h
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCache.h
@@ -62,14 +62,16 @@
     NoDueToReloadIgnoringCache
 };
 
+// FIXME: This enum is used in the Statistics code in a way that prevents removing or reordering anything.
 enum class StoreDecision {
     Yes,
     NoDueToProtocol,
     NoDueToHTTPMethod,
-    NoDueToAttachmentResponse,
+    NoDueToAttachmentResponse, // Unused.
     NoDueToNoStoreResponse,
     NoDueToHTTPStatusCode,
-    NoDueToNoStoreRequest
+    NoDueToNoStoreRequest,
+    NoDueToUnlikelyToReuse
 };
 
 enum class UseDecision {
diff --git a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp
index 12c8642..fa83219 100644
--- a/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp
+++ b/Source/WebKit2/NetworkProcess/cache/NetworkCacheStatistics.cpp
@@ -238,6 +238,8 @@
         return WebCore::DiagnosticLoggingKeys::cacheControlNoStoreKey();
     case StoreDecision::NoDueToHTTPStatusCode:
         return WebCore::DiagnosticLoggingKeys::uncacheableStatusCodeKey();
+    case StoreDecision::NoDueToUnlikelyToReuse:
+        return WebCore::DiagnosticLoggingKeys::unlikelyToReuseKey();
     case StoreDecision::Yes:
         // It was stored but could not be retrieved so it must have been pruned from the cache.
         return WebCore::DiagnosticLoggingKeys::noLongerInCacheKey();