Chromium Code Reviews| Index: content/browser/site_per_process_browsertest.cc |
| diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc |
| index e0700c5d218d6ba7f6746f007a1deb249502d169..4129a477438a495593b356b691b1e64f145c4b0d 100644 |
| --- a/content/browser/site_per_process_browsertest.cc |
| +++ b/content/browser/site_per_process_browsertest.cc |
| @@ -55,6 +55,8 @@ |
| #include "ipc/ipc_security_test_util.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/web/WebInputEvent.h" |
| #include "third_party/WebKit/public/web/WebSandboxFlags.h" |
| #include "ui/display/display_switches.h" |
| @@ -72,6 +74,8 @@ |
| namespace content { |
| +using testing::MatchesRegex; |
| + |
| namespace { |
| // Helper function to send a postMessage and wait for a reply message. The |
| @@ -6179,6 +6183,196 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| } |
| } |
| +// Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| +// In this version of a test, CSP comes from HTTP headers. |
| +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| + CrossSiteIframeBlockedByParentCSPFromHeaders) { |
| + GURL main_url( |
| + embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html")); |
| + NavigateToURL(shell(), main_url); |
|
alexmos
2016/05/16 16:17:03
nit: EXPECT_TRUE (also below)
Łukasz Anforowicz
2016/05/16 19:44:45
Done (but only for the 3 new tests... :-/ ).
|
| + |
| + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| + |
| + // Sanity-check that the test page has the expected shape for testing. |
| + EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root)); |
| + EXPECT_THAT(root->child_at(0)->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
|
alexmos
2016/05/16 16:17:03
Why not just check against the exact URL, embedded
Łukasz Anforowicz
2016/05/16 19:44:45
Good idea. Done.
|
| + |
| + // Monitor subframe's load events via main frame's title. |
| + EXPECT_TRUE(ExecuteScript(shell()->web_contents(), |
| + "document.querySelector('iframe').onload = " |
| + " function() { document.title = 'loaded'; };")); |
| + EXPECT_TRUE( |
| + ExecuteScript(shell()->web_contents(), "document.title = 'not loaded';")); |
| + base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| + TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| + |
| + // Try to navigate the subframe to a blocked URL. |
| + TestNavigationObserver load_observer(shell()->web_contents()); |
| + GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
| + EXPECT_TRUE( |
| + ExecuteScript(root->child_at(0)->current_frame_host(), |
| + "window.location.href = '" + blocked_url.spec() + "';")); |
| + |
| + // The blocked frame should still fire a load event in its parent's process. |
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| + |
| + // Check that the current RenderFrameHost has stopped loading. |
| + if (root->child_at(0)->current_frame_host()->is_loading()) { |
| + ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| + load_observer.Wait(); |
| + } |
| + |
| + // The blocked frame should stay at the old location. |
| + EXPECT_THAT(root->child_at(0)->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
| + |
| + // The blocked frame should keep the old title. |
| + std::string frame_title; |
| + EXPECT_TRUE(ExecuteScriptAndExtractString( |
| + root->child_at(0)->current_frame_host(), |
| + "domAutomationController.send(document.title)", &frame_title)); |
| + EXPECT_EQ("Title Of Awesomeness", frame_title); |
| +} |
| + |
| +// Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| +// In this version of a test, CSP comes from a <meta> element added after the |
| +// page has already loaded. |
| +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| + CrossSiteIframeBlockedByParentCSPFromMeta) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| + NavigateToURL(shell(), main_url); |
| + |
| + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| + |
| + // Navigate the subframe to a location we will disallow in the future. |
| + TestNavigationObserver load_observer(shell()->web_contents()); |
| + GURL still_allowed_url = |
| + embedded_test_server()->GetURL("b.com", "/title2.html"); |
| + EXPECT_TRUE(ExecuteScript( |
| + root->child_at(0)->current_frame_host(), |
| + "window.location.href = '" + still_allowed_url.spec() + "';")); |
| + load_observer.Wait(); |
|
alexmos
2016/05/16 16:17:03
Is renderer-initiated navigation required here? U
Łukasz Anforowicz
2016/05/16 19:44:45
Done.
|
| + |
| + // Add frame-src CSP via a new <meta> element. |
| + EXPECT_TRUE(ExecuteScript( |
| + shell()->web_contents(), |
| + "var meta = document.createElement('meta');" |
| + "meta.httpEquiv = 'Content-Security-Policy';" |
| + "meta.content = 'frame-src https://a.com:*';" |
| + "document.getElementsByTagName('head')[0].appendChild(meta);")); |
| + |
| + // Sanity-check that the test page has the expected shape for testing. |
| + // (the CSP should not have an effect on the already loaded frames). |
| + EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root)); |
| + EXPECT_THAT(root->child_at(0)->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
| + |
| + // Monitor subframe's load events via main frame's title. |
| + EXPECT_TRUE(ExecuteScript(shell()->web_contents(), |
| + "document.querySelector('iframe').onload = " |
| + " function() { document.title = 'loaded'; };")); |
| + EXPECT_TRUE( |
| + ExecuteScript(shell()->web_contents(), "document.title = 'not loaded';")); |
| + base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| + TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| + |
| + // Try to navigate the subframe to a blocked URL. |
| + TestNavigationObserver load_observer2(shell()->web_contents()); |
| + GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
| + EXPECT_TRUE( |
| + ExecuteScript(root->child_at(0)->current_frame_host(), |
| + "window.location.href = '" + blocked_url.spec() + "';")); |
| + |
| + // The blocked frame should still fire a load event in its parent's process. |
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| + |
| + // Check that the current RenderFrameHost has stopped loading. |
| + if (root->child_at(0)->current_frame_host()->is_loading()) { |
| + ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| + load_observer2.Wait(); |
| + } |
| + |
| + // The blocked frame should stay at the old location. |
| + EXPECT_THAT(root->child_at(0)->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
| + |
| + // The blocked frame should keep the old title. |
| + std::string frame_title; |
| + EXPECT_TRUE(ExecuteScriptAndExtractString( |
| + root->child_at(0)->current_frame_host(), |
| + "domAutomationController.send(document.title)", &frame_title)); |
| + EXPECT_EQ("Title Of Awesomeness", frame_title); |
| +} |
| + |
| +// Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| +// In this version of a test, CSP is inherited by srcdoc iframe from a parent |
| +// that declared CSP via HTTP headers. Cross-origin frame navigating to a |
| +// blocked location is a child of the srcdoc iframe. |
| +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| + CrossSiteIframeBlockedByCSPInheritedBySrcDocParent) { |
| + GURL main_url( |
| + embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html")); |
| + NavigateToURL(shell(), main_url); |
| + |
| + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| + FrameTreeNode* srcdoc_frame = root->child_at(1); |
| + EXPECT_TRUE(srcdoc_frame != nullptr); |
| + FrameTreeNode* navigating_frame = srcdoc_frame->child_at(0); |
| + EXPECT_TRUE(navigating_frame != nullptr); |
| + |
| + // Sanity-check that the test page has the expected shape for testing. |
| + // (the CSP should not have an effect on the already loaded frames). |
| + EXPECT_TRUE(srcdoc_frame->HasSameOrigin(*root)); |
| + EXPECT_FALSE(srcdoc_frame->HasSameOrigin(*navigating_frame)); |
| + EXPECT_THAT(navigating_frame->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
| + |
| + // Monitor navigating_frame's load events via srcdoc_frame posting |
| + // a message to the parent frame. |
| + EXPECT_TRUE( |
| + ExecuteScript(root->current_frame_host(), |
| + "window.addEventListener('message', function(event) {" |
| + " document.title = event.data;" |
| + "});")); |
| + EXPECT_TRUE(ExecuteScript( |
| + srcdoc_frame->current_frame_host(), |
| + "document.querySelector('iframe').onload = " |
| + " function() { window.top.postMessage('loaded', '*'); };")); |
| + EXPECT_TRUE( |
| + ExecuteScript(shell()->web_contents(), "document.title = 'not loaded';")); |
| + base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| + TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| + |
| + // Try to navigate the subframe to a blocked URL. |
| + TestNavigationObserver load_observer2(shell()->web_contents()); |
| + GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
| + EXPECT_TRUE( |
| + ExecuteScript(navigating_frame->current_frame_host(), |
| + "window.location.href = '" + blocked_url.spec() + "';")); |
| + |
| + // The blocked frame should still fire a load event in its parent's process. |
| + EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| + |
| + // Check that the current RenderFrameHost has stopped loading. |
| + if (navigating_frame->current_frame_host()->is_loading()) { |
| + ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| + load_observer2.Wait(); |
| + } |
| + |
| + // The blocked frame should stay at the old location. |
| + EXPECT_THAT(navigating_frame->current_url().spec(), |
| + MatchesRegex("http://b.com.*/title2.html")); |
| + |
| + // The blocked frame should keep the old title. |
| + std::string frame_title; |
| + EXPECT_TRUE(ExecuteScriptAndExtractString( |
| + navigating_frame->current_frame_host(), |
| + "domAutomationController.send(document.title)", &frame_title)); |
| + EXPECT_EQ("Title Of Awesomeness", frame_title); |
| +} |
| + |
| IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScreenCoordinates) { |
| GURL main_url(embedded_test_server()->GetURL( |
| "a.com", "/cross_site_iframe_factory.html?a(b)")); |