diff --git a/chrome/browser/extensions/back_forward_cache_browsertest.cc b/chrome/browser/extensions/back_forward_cache_browsertest.cc new file mode 100644 index 00000000000000..1a3d826d0ad74e --- /dev/null +++ b/chrome/browser/extensions/back_forward_cache_browsertest.cc @@ -0,0 +1,137 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/common/content_features.h" +#include "content/public/test/browser_test.h" +#include "extensions/common/extension.h" +#include "net/dns/mock_host_resolver.h" + +namespace extensions { + +class ExtensionBackForwardCacheBrowserTest : public ExtensionBrowserTest { + public: + explicit ExtensionBackForwardCacheBrowserTest( + bool allow_content_scripts = true) { + feature_list_.InitWithFeaturesAndParameters( + {{features::kBackForwardCache, + {{"content_injection_supported", + allow_content_scripts ? "true" : "false"}}}}, + {features::kBackForwardCacheMemoryControls}); + } + + void SetUpOnMainThread() override { + host_resolver()->AddRule("*", "127.0.0.1"); + ExtensionBrowserTest::SetUpOnMainThread(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +class ExtensionBackForwardCacheContentScriptDisabledBrowserTest + : public ExtensionBackForwardCacheBrowserTest { + public: + ExtensionBackForwardCacheContentScriptDisabledBrowserTest() + : ExtensionBackForwardCacheBrowserTest(/*allow_content_scripts=*/false) {} +}; + +IN_PROC_BROWSER_TEST_F( + ExtensionBackForwardCacheContentScriptDisabledBrowserTest, + ScriptDisallowed) { + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("content_script"))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + // Expect that |rfh_a| is destroyed as it wouldn't be placed in the cache. + EXPECT_TRUE(delete_observer_rfh_a.deleted()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionBackForwardCacheBrowserTest, ScriptAllowed) { + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("content_script"))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + // Ensure that |rfh_a| is in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_TRUE(rfh_a->IsInBackForwardCache()); +} + +IN_PROC_BROWSER_TEST_F( + ExtensionBackForwardCacheContentScriptDisabledBrowserTest, + CSSDisallowed) { + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("content_css"))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + // Expect that |rfh_a| is destroyed as it wouldn't be placed in the cache. + EXPECT_TRUE(delete_observer_rfh_a.deleted()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionBackForwardCacheBrowserTest, CSSAllowed) { + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("back_forward_cache") + .AppendASCII("content_css"))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + content::RenderFrameHost* rfh_a = + ui_test_utils::NavigateToURL(browser(), url_a); + content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + + // 2) Navigate to B. + content::RenderFrameHost* rfh_b = + ui_test_utils::NavigateToURL(browser(), url_b); + content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + // Ensure that |rfh_a| is in the cache. + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_NE(rfh_a, rfh_b); + EXPECT_TRUE(rfh_a->IsInBackForwardCache()); +} + +} // namespace extensions diff --git a/chrome/renderer/cart/commerce_hint_agent.cc b/chrome/renderer/cart/commerce_hint_agent.cc index d684c458282783..8fed647a0ccf60 100644 --- a/chrome/renderer/cart/commerce_hint_agent.cc +++ b/chrome/renderer/cart/commerce_hint_agent.cc @@ -439,7 +439,8 @@ void CommerceHintAgent::ExtractProducts() { new JavaScriptRequest(weak_factory_.GetWeakPtr()); main_frame->RequestExecuteScriptInIsolatedWorld( ISOLATED_WORLD_ID_CHROME_INTERNAL, &source, 1, false, - blink::WebLocalFrame::kAsynchronous, request); + blink::WebLocalFrame::kAsynchronous, request, + blink::BackForwardCacheAware::kAllow); } CommerceHintAgent::JavaScriptRequest::JavaScriptRequest( diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3e710461ace193..ab8c7bdf6fb6e1 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn @@ -2042,6 +2042,7 @@ if (!is_android) { "../browser/extensions/app_process_apitest.cc", "../browser/extensions/app_window_overrides_browsertest.cc", "../browser/extensions/autoplay_browsertest.cc", + "../browser/extensions/back_forward_cache_browsertest.cc", "../browser/extensions/background_header_browsertest.cc", "../browser/extensions/background_page_apitest.cc", "../browser/extensions/background_scripts_apitest.cc", diff --git a/chrome/test/data/extensions/back_forward_cache/content_css/color.css b/chrome/test/data/extensions/back_forward_cache/content_css/color.css new file mode 100644 index 00000000000000..bab6c7a230e429 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_css/color.css @@ -0,0 +1,5 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +body {background-color: cyan;} diff --git a/chrome/test/data/extensions/back_forward_cache/content_css/manifest.json b/chrome/test/data/extensions/back_forward_cache/content_css/manifest.json new file mode 100644 index 00000000000000..8d1041526861bf --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_css/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "no caching", + "version": "0.1", + "manifest_version": 2, + "description": "Checks that injected CSS do prevent back forward cache.", + "permissions": ["http://*/*", "https://*/*"], + "content_scripts": [ + { + "matches": ["http://*/*", "https://*/*"], + "css": ["color.css"], + "run_at": "document_start" + } + ] +} diff --git a/chrome/test/data/extensions/back_forward_cache/content_script/change_page_title.js b/chrome/test/data/extensions/back_forward_cache/content_script/change_page_title.js new file mode 100644 index 00000000000000..f4e4ab13e97b37 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_script/change_page_title.js @@ -0,0 +1,5 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +document.title = "modified"; diff --git a/chrome/test/data/extensions/back_forward_cache/content_script/manifest.json b/chrome/test/data/extensions/back_forward_cache/content_script/manifest.json new file mode 100644 index 00000000000000..369cf50c391578 --- /dev/null +++ b/chrome/test/data/extensions/back_forward_cache/content_script/manifest.json @@ -0,0 +1,14 @@ +{ + "name": "no caching", + "version": "0.1", + "manifest_version": 2, + "description": "Checks that content scripts do prevent back forward cache.", + "permissions": ["http://*/*", "https://*/*"], + "content_scripts": [ + { + "matches": ["http://*/*", "https://*/*"], + "js": ["change_page_title.js"], + "run_at": "document_end" + } + ] +} diff --git a/components/translate/content/renderer/per_frame_translate_agent.cc b/components/translate/content/renderer/per_frame_translate_agent.cc index 3b9a93191c3c2c..d01f0ea0a139fe 100644 --- a/components/translate/content/renderer/per_frame_translate_agent.cc +++ b/components/translate/content/renderer/per_frame_translate_agent.cc @@ -200,7 +200,8 @@ void PerFrameTranslateAgent::ExecuteScript(const std::string& script) { return; WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); - local_frame->ExecuteScriptInIsolatedWorld(world_id_, source); + local_frame->ExecuteScriptInIsolatedWorld( + world_id_, source, blink::BackForwardCacheAware::kAllow); } bool PerFrameTranslateAgent::ExecuteScriptAndGetBoolResult( @@ -214,8 +215,8 @@ bool PerFrameTranslateAgent::ExecuteScriptAndGetBoolResult( v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, - source); + local_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); DCHECK(result->IsBoolean()); return result.As()->Value(); @@ -232,8 +233,8 @@ std::string PerFrameTranslateAgent::ExecuteScriptAndGetStringResult( v8::HandleScope handle_scope(isolate); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, - source); + local_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); DCHECK(result->IsString()); v8::Local v8_str = result.As(); @@ -253,8 +254,8 @@ double PerFrameTranslateAgent::ExecuteScriptAndGetDoubleResult( v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, - source); + local_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); DCHECK(result->IsNumber()); return result.As()->Value(); @@ -270,8 +271,8 @@ int64_t PerFrameTranslateAgent::ExecuteScriptAndGetIntegerResult( v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, - source); + local_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); DCHECK(result->IsNumber()); return result.As()->Value(); diff --git a/components/translate/content/renderer/translate_agent.cc b/components/translate/content/renderer/translate_agent.cc index 85acd978e4348c..a05badb8559e63 100644 --- a/components/translate/content/renderer/translate_agent.cc +++ b/components/translate/content/renderer/translate_agent.cc @@ -250,7 +250,8 @@ void TranslateAgent::ExecuteScript(const std::string& script) { return; WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); - main_frame->ExecuteScriptInIsolatedWorld(world_id_, source); + main_frame->ExecuteScriptInIsolatedWorld( + world_id_, source, blink::BackForwardCacheAware::kAllow); } bool TranslateAgent::ExecuteScriptAndGetBoolResult(const std::string& script, @@ -262,7 +263,8 @@ bool TranslateAgent::ExecuteScriptAndGetBoolResult(const std::string& script, v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source); + main_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); if (result.IsEmpty() || !result->IsBoolean()) { NOTREACHED(); return fallback; @@ -281,7 +283,8 @@ std::string TranslateAgent::ExecuteScriptAndGetStringResult( v8::HandleScope handle_scope(isolate); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source); + main_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); if (result.IsEmpty() || !result->IsString()) { NOTREACHED(); return std::string(); @@ -306,7 +309,8 @@ double TranslateAgent::ExecuteScriptAndGetDoubleResult( v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source); + main_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); if (result.IsEmpty() || !result->IsNumber()) { NOTREACHED(); return 0.0; @@ -324,7 +328,8 @@ int64_t TranslateAgent::ExecuteScriptAndGetIntegerResult( v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); WebScriptSource source = WebScriptSource(WebString::FromASCII(script)); v8::Local result = - main_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_, source); + main_frame->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id_, source, blink::BackForwardCacheAware::kAllow); if (result.IsEmpty() || !result->IsNumber()) { NOTREACHED(); return 0; diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc index a229a72e8cf565..e653db8d3bc006 100644 --- a/content/browser/renderer_host/back_forward_cache_impl.cc +++ b/content/browser/renderer_host/back_forward_cache_impl.cc @@ -99,6 +99,14 @@ bool IsGeolocationSupported() { return geolocation_supported.Get(); } +bool IsContentInjectionSupported() { + if (!IsBackForwardCacheEnabled()) + return false; + static constexpr base::FeatureParam content_injection_supported( + &features::kBackForwardCache, "content_injection_supported", false); + return content_injection_supported.Get(); +} + bool IsFileSystemSupported() { if (!IsBackForwardCacheEnabled()) return false; @@ -204,6 +212,11 @@ uint64_t GetDisallowedFeatures(RenderFrameHostImpl* rfh, WebSchedulerTrackedFeature::kRequestedGeolocationPermission); } + if (!IsContentInjectionSupported()) { + result |= FeatureToBit(WebSchedulerTrackedFeature::kIsolatedWorldScript) | + FeatureToBit(WebSchedulerTrackedFeature::kInjectedStyleSheet); + } + if (!IgnoresOutstandingNetworkRequestForTesting()) { result |= FeatureToBit( diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 580974507f1a30..2810ba8bee7647 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -2446,7 +2446,8 @@ void RenderFrameImpl::JavaScriptExecuteRequestForTests( WebScriptSource(WebString::FromUTF16(javascript))); } else { result = frame_->ExecuteScriptInIsolatedWorldAndReturnValue( - world_id, WebScriptSource(WebString::FromUTF16(javascript))); + world_id, WebScriptSource(WebString::FromUTF16(javascript)), + blink::BackForwardCacheAware::kAllow); } if (!weak_this) @@ -2481,7 +2482,8 @@ void RenderFrameImpl::JavaScriptExecuteRequestInIsolatedWorld( JavaScriptIsolatedWorldRequest* request = new JavaScriptIsolatedWorldRequest( weak_factory_.GetWeakPtr(), wants_result, std::move(callback)); frame_->RequestExecuteScriptInIsolatedWorld( - world_id, &script, 1, false, WebLocalFrame::kSynchronous, request); + world_id, &script, 1, false, WebLocalFrame::kSynchronous, request, + blink::BackForwardCacheAware::kAllow); } RenderFrameImpl::JavaScriptIsolatedWorldRequest::JavaScriptIsolatedWorldRequest( diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc index 4a5ecbda970ac2..166a49c770fc59 100644 --- a/content/web_test/renderer/test_runner.cc +++ b/content/web_test/renderer/test_runner.cc @@ -1075,8 +1075,8 @@ TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue( return {}; blink::WebScriptSource source = blink::WebString::FromUTF8(script); - return GetWebFrame()->ExecuteScriptInIsolatedWorldAndReturnValue(world_id, - source); + return GetWebFrame()->ExecuteScriptInIsolatedWorldAndReturnValue( + world_id, source, blink::BackForwardCacheAware::kAllow); } void TestRunnerBindings::EvaluateScriptInIsolatedWorld( @@ -1086,7 +1086,8 @@ void TestRunnerBindings::EvaluateScriptInIsolatedWorld( return; blink::WebScriptSource source = blink::WebString::FromUTF8(script); - GetWebFrame()->ExecuteScriptInIsolatedWorld(world_id, source); + GetWebFrame()->ExecuteScriptInIsolatedWorld( + world_id, source, blink::BackForwardCacheAware::kAllow); } void TestRunnerBindings::SetIsolatedWorldInfo( diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc index d9a28ff7598363..a66860efaae403 100644 --- a/extensions/renderer/script_injection.cc +++ b/extensions/renderer/script_injection.cc @@ -336,7 +336,8 @@ void ScriptInjection::InjectJs(std::set* executing_scripts, render_frame_->GetWebFrame()->RequestExecuteScriptInIsolatedWorld( world_id, &sources.front(), sources.size(), is_user_gesture, - execution_option, callback.release()); + execution_option, callback.release(), + blink::BackForwardCacheAware::kPossiblyDisallow); } void ScriptInjection::OnJsInjectionCompleted( @@ -436,8 +437,9 @@ void ScriptInjection::InjectOrRemoveCss( } else { DCHECK(adding_css); for (const blink::WebString& css : css_sources) - web_frame->GetDocument().InsertStyleSheet(css, &style_sheet_key, - blink_css_origin); + web_frame->GetDocument().InsertStyleSheet( + css, &style_sheet_key, blink_css_origin, + blink::BackForwardCacheAware::kPossiblyDisallow); } } diff --git a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc index ad0dd40c2365e5..8783d916d7f22f 100644 --- a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc +++ b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc @@ -133,6 +133,10 @@ FeatureNames FeatureToNames(WebSchedulerTrackedFeature feature) { case WebSchedulerTrackedFeature::kOutstandingNetworkRequestDirectSocket: return {"OutstandingNetworkRequestDirectSocket", "outstanding network request (direct socket)"}; + case WebSchedulerTrackedFeature::kIsolatedWorldScript: + return {"IsolatedWorldScript", "Isolated world ran script"}; + case WebSchedulerTrackedFeature::kInjectedStyleSheet: + return {"InjectedStyleSheet", "External systesheet injected"}; } return {}; } @@ -218,7 +222,9 @@ uint64_t StickyFeaturesBitmask() { FeatureToBit(WebSchedulerTrackedFeature::kIdleManager) | FeatureToBit(WebSchedulerTrackedFeature::kPaymentManager) | FeatureToBit(WebSchedulerTrackedFeature::kKeyboardLock) | - FeatureToBit(WebSchedulerTrackedFeature::kWebOTPService); + FeatureToBit(WebSchedulerTrackedFeature::kWebOTPService) | + FeatureToBit(WebSchedulerTrackedFeature::kIsolatedWorldScript) | + FeatureToBit(WebSchedulerTrackedFeature::kInjectedStyleSheet); } } // namespace scheduler diff --git a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h index d7dfda5cadd930..5a13da1c0a5271 100644 --- a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h +++ b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h @@ -100,9 +100,11 @@ enum class WebSchedulerTrackedFeature : uint32_t { kKeyboardLock = 51, kWebOTPService = 52, kOutstandingNetworkRequestDirectSocket = 53, + kIsolatedWorldScript = 54, + kInjectedStyleSheet = 55, // NB: This enum is used in a bitmask, so kMaxValue must be less than 64. - kMaxValue = kOutstandingNetworkRequestDirectSocket + kMaxValue = kInjectedStyleSheet }; static_assert(static_cast(WebSchedulerTrackedFeature::kMaxValue) < 64, diff --git a/third_party/blink/public/web/web_document.h b/third_party/blink/public/web/web_document.h index b6f3b4e3b8dae2..d181ff3be4608a 100644 --- a/third_party/blink/public/web/web_document.h +++ b/third_party/blink/public/web/web_document.h @@ -53,6 +53,13 @@ struct WebDistillabilityFeatures; using WebStyleSheetKey = WebString; +// An enumeration used to enumerate usage of APIs that may prevent a document +// from entering the back forward cache. |kAllow| means usage of the API will +// not restrict the back forward cache. |kPossiblyDisallow| means usage of the +// API will be marked as such and the back forward cache may not allow the +// document to enter at its discretion. +enum class BackForwardCacheAware { kAllow, kPossiblyDisallow }; + // Provides readonly access to some properties of a DOM document. class WebDocument : public WebNode { public: @@ -106,10 +113,11 @@ class WebDocument : public WebNode { BLINK_EXPORT WebElement FocusedElement() const; // Inserts the given CSS source code as a style sheet in the document. - BLINK_EXPORT WebStyleSheetKey InsertStyleSheet( - const WebString& source_code, - const WebStyleSheetKey* = nullptr, - CSSOrigin = kAuthorOrigin); + BLINK_EXPORT WebStyleSheetKey + InsertStyleSheet(const WebString& source_code, + const WebStyleSheetKey* = nullptr, + CSSOrigin = kAuthorOrigin, + BackForwardCacheAware = BackForwardCacheAware::kAllow); // Removes the CSS which was previously inserted by a call to // InsertStyleSheet(). diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h index 50702c6c3a1871..e947d7f412dfe5 100644 --- a/third_party/blink/public/web/web_local_frame.h +++ b/third_party/blink/public/web/web_local_frame.h @@ -39,6 +39,7 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/web_url_error.h" #include "third_party/blink/public/platform/web_url_request.h" +#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_document_loader.h" #include "third_party/blink/public/web/web_frame.h" #include "third_party/blink/public/web/web_frame_load_type.h" @@ -72,7 +73,6 @@ class WebAssociatedURLLoader; class WebAutofillClient; class WebContentCaptureClient; class WebContentSettingsClient; -class WebDocument; class WebLocalFrameClient; class WebFrameWidget; class WebHistoryItem; @@ -324,14 +324,16 @@ class WebLocalFrame : public WebFrame { // worldID must be > 0 (as 0 represents the main world). // worldID must be < kEmbedderWorldIdLimit, high number used internally. virtual void ExecuteScriptInIsolatedWorld(int32_t world_id, - const WebScriptSource&) = 0; + const WebScriptSource&, + BackForwardCacheAware) = 0; // worldID must be > 0 (as 0 represents the main world). // worldID must be < kEmbedderWorldIdLimit, high number used internally. // DEPRECATED: Use WebLocalFrame::requestExecuteScriptInIsolatedWorld. WARN_UNUSED_RESULT virtual v8::Local ExecuteScriptInIsolatedWorldAndReturnValue(int32_t world_id, - const WebScriptSource&) = 0; + const WebScriptSource&, + BackForwardCacheAware) = 0; // Clears the isolated world CSP stored for |world_id| by this frame's // Document. @@ -404,7 +406,8 @@ class WebLocalFrame : public WebFrame { unsigned num_sources, bool user_gesture, ScriptExecutionType, - WebScriptExecutionCallback*) = 0; + WebScriptExecutionCallback*, + BackForwardCacheAware) = 0; // Logs to the console associated with this frame. If |discard_duplicates| is // set, the message will only be added if it is unique (i.e. has not been diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc b/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc index ca16c31ce9d3ad..a09d16b0684e9d 100644 --- a/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/window_proxy_test.cc @@ -68,13 +68,15 @@ TEST_F(WindowProxyTest, IsolatedWorldReinitializedAfterNavigation) { // Save a reference to the top `window` in the isolated world. v8::Local window_top = MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue( - kIsolatedWorldId, WebScriptSource("window")); + kIsolatedWorldId, WebScriptSource("window"), + BackForwardCacheAware::kAllow); ASSERT_TRUE(window_top->IsObject()); // Save a reference to the child frame's window proxy in the isolated world. v8::Local saved_child_window = MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue( - kIsolatedWorldId, WebScriptSource("saved = window[0]")); + kIsolatedWorldId, WebScriptSource("saved = window[0]"), + BackForwardCacheAware::kAllow); ASSERT_TRUE(saved_child_window->IsObject()); frame_test_helpers::LoadFrame(MainFrame().FirstChild()->ToWebLocalFrame(), @@ -87,7 +89,8 @@ TEST_F(WindowProxyTest, IsolatedWorldReinitializedAfterNavigation) { // cached earlier. v8::Local top_via_saved = MainFrame().ExecuteScriptInIsolatedWorldAndReturnValue( - kIsolatedWorldId, WebScriptSource("saved.top")); + kIsolatedWorldId, WebScriptSource("saved.top"), + BackForwardCacheAware::kAllow); EXPECT_TRUE(top_via_saved->IsObject()); EXPECT_TRUE(window_top->StrictEquals(top_via_saved)); } diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_party/blink/renderer/core/exported/web_document.cc index 739e0f95e37e69..a2c1db262ff05c 100644 --- a/third_party/blink/renderer/core/exported/web_document.cc +++ b/third_party/blink/renderer/core/exported/web_document.cc @@ -207,11 +207,18 @@ WebElement WebDocument::FocusedElement() const { return WebElement(ConstUnwrap()->FocusedElement()); } -WebStyleSheetKey WebDocument::InsertStyleSheet(const WebString& source_code, - const WebStyleSheetKey* key, - CSSOrigin origin) { +WebStyleSheetKey WebDocument::InsertStyleSheet( + const WebString& source_code, + const WebStyleSheetKey* key, + CSSOrigin origin, + BackForwardCacheAware back_forward_cache_aware) { Document* document = Unwrap(); DCHECK(document); + if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) { + document->GetFrame()->GetFrameScheduler()->RegisterStickyFeature( + SchedulingPolicy::Feature::kInjectedStyleSheet, + {SchedulingPolicy::DisableBackForwardCache()}); + } auto* parsed_sheet = MakeGarbageCollected( MakeGarbageCollected(*document)); parsed_sheet->ParseString(source_code); diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc index ba23dee2970d57..3ea95962c4248e 100644 --- a/third_party/blink/renderer/core/frame/web_frame_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_test.cc @@ -4602,7 +4602,7 @@ TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds) { int32_t isolated_world_id = 42; WebScriptSource script_source("hi!"); web_view_helper.LocalMainFrame()->ExecuteScriptInIsolatedWorld( - isolated_world_id, script_source); + isolated_world_id, script_source, BackForwardCacheAware::kAllow); // We should now have a new create notification. ASSERT_EQ(1u, create_notifications.size()); diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index 80f58a5f2762fa..82b127eaabf813 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc @@ -864,11 +864,18 @@ void WebLocalFrameImpl::ExecuteScript(const WebScriptSource& source) { void WebLocalFrameImpl::ExecuteScriptInIsolatedWorld( int32_t world_id, - const WebScriptSource& source_in) { + const WebScriptSource& source_in, + BackForwardCacheAware back_forward_cache_aware) { DCHECK(GetFrame()); CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId); CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit); + if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) { + GetFrame()->GetFrameScheduler()->RegisterStickyFeature( + SchedulingPolicy::Feature::kIsolatedWorldScript, + {SchedulingPolicy::DisableBackForwardCache()}); + } + // Note: An error event in an isolated world will never be dispatched to // a foreign world. v8::HandleScope handle_scope(ToIsolate(GetFrame())); @@ -881,11 +888,18 @@ void WebLocalFrameImpl::ExecuteScriptInIsolatedWorld( v8::Local WebLocalFrameImpl::ExecuteScriptInIsolatedWorldAndReturnValue( int32_t world_id, - const WebScriptSource& source_in) { + const WebScriptSource& source_in, + BackForwardCacheAware back_forward_cache_aware) { DCHECK(GetFrame()); CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId); CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit); + if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) { + GetFrame()->GetFrameScheduler()->RegisterStickyFeature( + SchedulingPolicy::Feature::kIsolatedWorldScript, + {SchedulingPolicy::DisableBackForwardCache()}); + } + // Note: An error event in an isolated world will never be dispatched to // a foreign world. return ClassicScript::CreateUnspecifiedScript( @@ -987,11 +1001,18 @@ void WebLocalFrameImpl::RequestExecuteScriptInIsolatedWorld( unsigned num_sources, bool user_gesture, ScriptExecutionType option, - WebScriptExecutionCallback* callback) { + WebScriptExecutionCallback* callback, + BackForwardCacheAware back_forward_cache_aware) { DCHECK(GetFrame()); CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId); CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit); + if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) { + GetFrame()->GetFrameScheduler()->RegisterStickyFeature( + SchedulingPolicy::Feature::kIsolatedWorldScript, + {SchedulingPolicy::DisableBackForwardCache()}); + } + scoped_refptr isolated_world = DOMWrapperWorld::EnsureIsolatedWorld(ToIsolate(GetFrame()), world_id); auto* executor = MakeGarbageCollected( diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h index 04035ce2827f28..a7266407e593d9 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h @@ -144,11 +144,15 @@ class CORE_EXPORT WebLocalFrameImpl final void GetPageDescription(uint32_t page_index, WebPrintPageDescription*) override; void ExecuteScript(const WebScriptSource&) override; - void ExecuteScriptInIsolatedWorld(int32_t world_id, - const WebScriptSource&) override; + void ExecuteScriptInIsolatedWorld( + int32_t world_id, + const WebScriptSource&, + BackForwardCacheAware back_forward_cache_aware) override; WARN_UNUSED_RESULT v8::Local - ExecuteScriptInIsolatedWorldAndReturnValue(int32_t world_id, - const WebScriptSource&) override; + ExecuteScriptInIsolatedWorldAndReturnValue( + int32_t world_id, + const WebScriptSource&, + BackForwardCacheAware back_forward_cache_aware) override; void ClearIsolatedWorldCSPForTesting(int32_t world_id) override; v8::Local ExecuteScriptAndReturnValue( const WebScriptSource&) override; @@ -181,7 +185,8 @@ class CORE_EXPORT WebLocalFrameImpl final unsigned num_sources, bool user_gesture, ScriptExecutionType, - WebScriptExecutionCallback*) override; + WebScriptExecutionCallback*, + BackForwardCacheAware back_forward_cache_aware) override; void Alert(const WebString& message) override; bool Confirm(const WebString& message) override; WebString Prompt(const WebString& message, diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 68b17a3670262d..6d720f3dbe48fe 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml @@ -82128,6 +82128,8 @@ Called by update_scheduler_enums.py.--> + +