Commit 6255033f authored by Lukasz Anforowicz's avatar Lukasz Anforowicz Committed by Commit Bot

Cover about:blank and about:srcdoc frames in CORB Extension Test.

This CL expands the following 2 test cases from the
CrossOriginReadBlockingExtensionTest test suite:

1) FromForegroundPage_NoSniffXml

   This CL adds coverage of a fetch performed from an about:srcdoc frame
   that belongs to an extension origin.

2) FromDeclarativeContentScript_NoSniffXml

   This CL adds coverage of a fetch performed from a content script
   injected into an about:blank page.

In both cases above, the fetch is performed before the browser commits
the frame.  The new tests help ensure that in this scenario the
extension scripts are still subject to relaxed CORB rules - because of
the timing the relaxed CORB rules do not depend on
URLLoaderFactoryManager::ReadyToCommitNavigation, but rather on having
the renderer inherit the right URLLoaderFactory for the subframe.

Bug: 846346
Change-Id: I45a4eba6d1351f2bf722f31fbcb7f201cd990d34
Reviewed-on: https://chromium-review.googlesource.com/c/1259291
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596711}
parent d69ab302
...@@ -48,13 +48,15 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest { ...@@ -48,13 +48,15 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest {
GURL resource_to_fetch_from_declarative_content_script = GURL()) { GURL resource_to_fetch_from_declarative_content_script = GURL()) {
bool use_declarative_content_script = bool use_declarative_content_script =
resource_to_fetch_from_declarative_content_script.is_valid(); resource_to_fetch_from_declarative_content_script.is_valid();
const char kContentScriptManifestEntry[] = R"( const char kContentScriptManifestEntry[] = R"(
"content_scripts": [{ "content_scripts": [{
"all_frames": true,
"match_about_blank": true,
"matches": ["*://*/*"], "matches": ["*://*/*"],
"js": ["content_script.js"] "js": ["content_script.js"]
}], }],
)"; )";
const char kManifestTemplate[] = R"( const char kManifestTemplate[] = R"(
{ {
"name": "CrossOriginReadBlockingTest", "name": "CrossOriginReadBlockingTest",
...@@ -141,6 +143,16 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest { ...@@ -141,6 +143,16 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest {
base::Unretained(this), base::Unretained(web_contents))); base::Unretained(this), base::Unretained(web_contents)));
} }
// Performs a fetch of |url| from a srcdoc subframe added to |parent_frame|
// and executing a script via <script> tag. Returns the body of the response.
std::string FetchViaSrcDocFrame(GURL url,
content::RenderFrameHost* parent_frame) {
return FetchHelper(
url, base::BindOnce(
&CrossOriginReadBlockingExtensionTest::ExecuteInSrcDocFrame,
base::Unretained(this), base::Unretained(parent_frame)));
}
void VerifyContentScriptHistogramIsPresent( void VerifyContentScriptHistogramIsPresent(
const base::HistogramTester& histograms, const base::HistogramTester& histograms,
content::ResourceType resource_type) { content::ResourceType resource_type) {
...@@ -197,6 +209,38 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest { ...@@ -197,6 +209,38 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest {
return true; return true;
} }
// Injects into |parent_frame| an "srcdoc" subframe that contains/executes
// |script_to_run_in_subframe| via <script> tag.
//
// This function is useful to exercise a scenario when a <script> tag may
// execute before the browser gets a chance to see the a frame/navigation
// commit is happening.
//
// This is an implementation of FetchCallback.
// Returns true if the script execution started succeessfully.
bool ExecuteInSrcDocFrame(content::RenderFrameHost* parent_frame,
const std::string& script_to_run_in_subframe) {
static int sequence_id = 0;
sequence_id++;
std::string filename =
base::StringPrintf("srcdoc_script_%d.js", sequence_id);
dir_.WriteFile(base::FilePath::FromUTF8Unsafe(filename).value(),
script_to_run_in_subframe);
// Using <script src=...></script> instead of <script>...</script> to avoid
// extensions CSP which forbids inline scripts.
const char kScriptTemplate[] = R"(
var subframe = document.createElement('iframe');
subframe.srcdoc = '<script src=' + $1 + '></script>';
document.body.appendChild(subframe); )";
std::string subframe_injection_script =
content::JsReplace(kScriptTemplate, filename);
content::ExecuteScriptAsync(parent_frame, subframe_injection_script);
// Report artificial success to meet FetchCallback's requirements.
return true;
}
std::string CreateFetchScript(const GURL& resource) { std::string CreateFetchScript(const GURL& resource) {
const char kXhrScriptTemplate[] = R"( const char kXhrScriptTemplate[] = R"(
fetch($1) fetch($1)
...@@ -263,33 +307,68 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest { ...@@ -263,33 +307,68 @@ class CrossOriginReadBlockingExtensionTest : public ExtensionBrowserTest {
IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
FromDeclarativeContentScript_NoSniffXml) { FromDeclarativeContentScript_NoSniffXml) {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
// Load the test extension. // Load the test extension.
GURL cross_site_resource( GURL cross_site_resource(
embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
ASSERT_TRUE(InstallExtension(cross_site_resource)); ASSERT_TRUE(InstallExtension(cross_site_resource));
// Navigate to a foo.com page - this should trigger execution of the // Test case #1: Declarative script injected after a browser-initiated
// |content_script| declared in the extension manifest. // navigation of the main frame.
base::HistogramTester histograms; {
content::DOMMessageQueue message_queue; // Monitor CORB behavior + result of the fetch.
content::WebContents* web_contents = base::HistogramTester histograms;
browser()->tab_strip_model()->GetActiveWebContents(); content::DOMMessageQueue message_queue;
GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
ui_test_utils::NavigateToURL(browser(), page_url);
EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(page_url),
web_contents->GetMainFrame()->GetLastCommittedOrigin());
// Extract results of the fetch done in the declarative content script. // Navigate to a foo.com page - this should trigger execution of the
std::string fetch_result = PopString(&message_queue); // |content_script| declared in the extension manifest.
GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
ui_test_utils::NavigateToURL(browser(), page_url);
EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(page_url),
web_contents->GetMainFrame()->GetLastCommittedOrigin());
// Verify that no blocking occurred. // Extract results of the fetch done in the declarative content script.
EXPECT_EQ("nosniff.xml - body\n", fetch_result); std::string fetch_result = PopString(&message_queue);
EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
testing::IsEmpty());
// Verify that LogInitiatorSchemeBypassingDocumentBlocking was called. // Verify that no blocking occurred.
VerifyContentScriptHistogramIsPresent(histograms, content::RESOURCE_TYPE_XHR); EXPECT_EQ("nosniff.xml - body\n", fetch_result);
EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
testing::IsEmpty());
// Verify that LogInitiatorSchemeBypassingDocumentBlocking was called.
VerifyContentScriptHistogramIsPresent(histograms,
content::RESOURCE_TYPE_XHR);
}
// Test case #2: Declarative script injected after a renderer-initiated
// creation of an about:blank frame.
{
// Monitor CORB behavior + result of the fetch.
base::HistogramTester histograms;
content::DOMMessageQueue message_queue;
// Inject an about:blank subframe - this should trigger execution of the
// |content_script| declared in the extension manifest.
const char kBlankSubframeInjectionScript[] = R"(
var subframe = document.createElement('iframe');
document.body.appendChild(subframe); )";
content::ExecuteScriptAsync(web_contents, kBlankSubframeInjectionScript);
// Extract results of the fetch done in the declarative content script.
std::string fetch_result = PopString(&message_queue);
// Verify that no blocking occurred.
EXPECT_EQ("nosniff.xml - body\n", fetch_result);
EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
testing::IsEmpty());
// Verify that LogInitiatorSchemeBypassingDocumentBlocking was called.
VerifyContentScriptHistogramIsPresent(histograms,
content::RESOURCE_TYPE_XHR);
}
} }
// Test that verifies the current, baked-in (but not necessarily desirable // Test that verifies the current, baked-in (but not necessarily desirable
...@@ -432,21 +511,44 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, ...@@ -432,21 +511,44 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
EXPECT_EQ(GetExtensionOrigin(), EXPECT_EQ(GetExtensionOrigin(),
web_contents->GetMainFrame()->GetLastCommittedOrigin()); web_contents->GetMainFrame()->GetLastCommittedOrigin());
// Perform a cross-origin XHR from the foreground extension page. // Test case #1: Fetch from a chrome-extension://... main frame.
base::HistogramTester histograms; {
GURL cross_site_resource( // Perform a cross-origin XHR from the foreground extension page.
embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); base::HistogramTester histograms;
std::string fetch_result = GURL cross_site_resource(
FetchViaWebContents(cross_site_resource, web_contents); embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
std::string fetch_result =
FetchViaWebContents(cross_site_resource, web_contents);
// Verify that no blocking occurred. // Verify that no blocking occurred.
EXPECT_EQ("nosniff.xml - body\n", fetch_result); EXPECT_EQ("nosniff.xml - body\n", fetch_result);
EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
testing::IsEmpty()); testing::IsEmpty());
// Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early
// for a request that wasn't from a content script. // for a request that wasn't from a content script.
VerifyContentScriptHistogramIsMissing(histograms); VerifyContentScriptHistogramIsMissing(histograms);
}
// Test case #2: Fetch from an about:srcdoc subframe of a
// chrome-extension://... frame.
{
// Perform a cross-origin XHR from the foreground extension page.
base::HistogramTester histograms;
GURL cross_site_resource(
embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
std::string fetch_result =
FetchViaSrcDocFrame(cross_site_resource, web_contents->GetMainFrame());
// Verify that no blocking occurred.
EXPECT_EQ("nosniff.xml - body\n", fetch_result);
EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
testing::IsEmpty());
// Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early
// for a request that wasn't from a content script.
VerifyContentScriptHistogramIsMissing(histograms);
}
} }
// Test that requests from an extension's service worker to the network use // Test that requests from an extension's service worker to the network use
......
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