Commit 10d79437 authored by Alexander Timin's avatar Alexander Timin Committed by Commit Bot

[bfcache] Do not cache main documents with cache-control: no-store

Do not cache a page if the main resource of its main document had
cache-control: no-store header.

Note that it's the only set of conditions that disabled bfcache.
Back-forward cache is still enabled in the following scenarios:
- no-cache directive
- no-store on a non-main resource (e.g. image)
- no-store on a main resource of a subframe.

This matches Safari's implementation of back-forward cache:
https://bugs.webkit.org/show_bug.cgi?id=140302

R=arthursonzogni@chromium.org,lowell@chromium.org
BUG=1014925

Change-Id: Ie1185462dc0420dc2a4b1b16f93b22a649bb67ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865337
Commit-Queue: Alexander Timin <altimin@chromium.org>
Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707207}
parent 5021efbf
...@@ -2965,4 +2965,67 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ...@@ -2965,4 +2965,67 @@ IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
delete_observer_rfh.WaitUntilDeleted(); delete_observer_rfh.WaitUntilDeleted();
} }
namespace {
const char kResponseWithNoCache[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Cache-Control: no-store\r\n"
"\r\n"
"The server speaks HTTP!";
} // namespace
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
MainFrameWithNoStoreNotCached) {
net::test_server::ControllableHttpResponse response(embedded_test_server(),
"/main_document");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1. Load the document and specify no-store for the main resource.
TestNavigationObserver observer(web_contents());
shell()->LoadURL(url_a);
response.WaitForRequest();
response.Send(kResponseWithNoCache);
response.Done();
observer.Wait();
// 2. Navigate away and expect frame to be deleted.
RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
EXPECT_TRUE(NavigateToURL(shell(), url_b));
delete_observer_rfh_a.WaitUntilDeleted();
}
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeWithNoStoreCached) {
// iframe will try to load title1.html.
net::test_server::ControllableHttpResponse response(embedded_test_server(),
"/title1.html");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url_a(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
// 1) Load the document and specify no-store for the main resource.
TestNavigationObserver observer(web_contents());
shell()->LoadURL(url_a);
response.WaitForRequest();
response.Send(kResponseWithNoCache);
response.Done();
observer.Wait();
RenderFrameHostImpl* rfh_a = current_frame_host();
RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
// 2) Navigate away.
EXPECT_TRUE(NavigateToURL(shell(), url_b));
// 3) Navigate back and expect everything to be restored.
web_contents()->GetController().GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_FALSE(delete_observer_rfh_a.deleted());
EXPECT_EQ(rfh_a, current_frame_host());
}
} // namespace content } // namespace content
...@@ -82,7 +82,7 @@ bool IsExtendedSupportEnabled() { ...@@ -82,7 +82,7 @@ bool IsExtendedSupportEnabled() {
return extended_support_enabled.Get(); return extended_support_enabled.Get();
} }
uint64_t GetDisallowedFeatures() { uint64_t GetDisallowedFeatures(RenderFrameHostImpl* rfh) {
// TODO(lowell): Finalize disallowed feature list, and test for each // TODO(lowell): Finalize disallowed feature list, and test for each
// disallowed feature. // disallowed feature.
constexpr uint64_t kAlwaysDisallowedFeatures = constexpr uint64_t kAlwaysDisallowedFeatures =
...@@ -122,6 +122,13 @@ uint64_t GetDisallowedFeatures() { ...@@ -122,6 +122,13 @@ uint64_t GetDisallowedFeatures() {
WebSchedulerTrackedFeature::kRequestedGeolocationPermission); WebSchedulerTrackedFeature::kRequestedGeolocationPermission);
} }
// We do not cache documents which have cache-control: no-store header on
// their main resource.
if (!rfh->GetParent()) {
result |= ToFeatureBit(
WebSchedulerTrackedFeature::kMainResourceHasCacheControlNoStore);
}
return result; return result;
} }
...@@ -320,14 +327,13 @@ BackForwardCacheImpl::CanStoreDocument(RenderFrameHostImpl* rfh) { ...@@ -320,14 +327,13 @@ BackForwardCacheImpl::CanStoreDocument(RenderFrameHostImpl* rfh) {
BackForwardCacheMetrics::CanNotStoreDocumentReason::kDomainNotAllowed); BackForwardCacheMetrics::CanNotStoreDocumentReason::kDomainNotAllowed);
} }
return CanStoreRenderFrameHost(rfh, GetDisallowedFeatures()); return CanStoreRenderFrameHost(rfh);
} }
// Recursively checks whether this RenderFrameHost and all child frames // Recursively checks whether this RenderFrameHost and all child frames
// can be cached. // can be cached.
BackForwardCacheImpl::CanStoreDocumentResult BackForwardCacheImpl::CanStoreDocumentResult
BackForwardCacheImpl::CanStoreRenderFrameHost(RenderFrameHostImpl* rfh, BackForwardCacheImpl::CanStoreRenderFrameHost(RenderFrameHostImpl* rfh) {
uint64_t disallowed_features) {
if (!rfh->dom_content_loaded()) if (!rfh->dom_content_loaded())
return CanStoreDocumentResult::No( return CanStoreDocumentResult::No(
BackForwardCacheMetrics::CanNotStoreDocumentReason::kLoading); BackForwardCacheMetrics::CanNotStoreDocumentReason::kLoading);
...@@ -352,13 +358,13 @@ BackForwardCacheImpl::CanStoreRenderFrameHost(RenderFrameHostImpl* rfh, ...@@ -352,13 +358,13 @@ BackForwardCacheImpl::CanStoreRenderFrameHost(RenderFrameHostImpl* rfh,
// For reporting purposes it's a good idea to also collect this information // For reporting purposes it's a good idea to also collect this information
// from children. // from children.
if (uint64_t banned_features = if (uint64_t banned_features =
disallowed_features & rfh->scheduler_tracked_features()) { GetDisallowedFeatures(rfh) & rfh->scheduler_tracked_features()) {
return CanStoreDocumentResult::NoDueToFeatures(banned_features); return CanStoreDocumentResult::NoDueToFeatures(banned_features);
} }
for (size_t i = 0; i < rfh->child_count(); i++) { for (size_t i = 0; i < rfh->child_count(); i++) {
CanStoreDocumentResult can_store_child = CanStoreRenderFrameHost( CanStoreDocumentResult can_store_child =
rfh->child_at(i)->current_frame_host(), disallowed_features); CanStoreRenderFrameHost(rfh->child_at(i)->current_frame_host());
if (!can_store_child.can_store) if (!can_store_child.can_store)
return can_store_child; return can_store_child;
} }
......
...@@ -169,8 +169,7 @@ class CONTENT_EXPORT BackForwardCacheImpl : public BackForwardCache { ...@@ -169,8 +169,7 @@ class CONTENT_EXPORT BackForwardCacheImpl : public BackForwardCache {
// Helper for recursively checking each child. // Helper for recursively checking each child.
CanStoreDocumentResult CanStoreRenderFrameHost( CanStoreDocumentResult CanStoreRenderFrameHost(
RenderFrameHostImpl* render_frame_host, RenderFrameHostImpl* render_frame_host);
uint64_t disallowed_features);
// Checks if the url's host and path matches with the |allowed_urls_| host and // Checks if the url's host and path matches with the |allowed_urls_| host and
// path. This is controlled by "allowed_websites" param on BackForwardCache // path. This is controlled by "allowed_websites" param on BackForwardCache
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment