|  | // Copyright 2016 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/browser/renderer_host/ancestor_throttle.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/callback_helpers.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/test/scoped_feature_list.h" | 
|  | #include "content/browser/renderer_host/frame_tree_node.h" | 
|  | #include "content/browser/renderer_host/render_frame_host_impl.h" | 
|  | #include "content/public/browser/navigation_handle.h" | 
|  | #include "content/public/browser/navigation_throttle.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/common/content_features.h" | 
|  | #include "content/public/test/test_renderer_host.h" | 
|  | #include "content/test/navigation_simulator_impl.h" | 
|  | #include "content/test/test_navigation_url_loader.h" | 
|  | #include "net/http/http_response_headers.h" | 
|  | #include "services/network/public/cpp/content_security_policy/content_security_policy.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | class AncestorThrottleNavigationTest : public RenderViewHostTestHarness { | 
|  | public: | 
|  | AncestorThrottleNavigationTest() { | 
|  | scoped_feature_list.InitAndEnableFeature(features::kEmbeddingRequiresOptIn); | 
|  | } | 
|  | ~AncestorThrottleNavigationTest() override = default; | 
|  |  | 
|  | AncestorThrottleNavigationTest(const AncestorThrottleNavigationTest& other) = | 
|  | delete; | 
|  | AncestorThrottleNavigationTest& operator=( | 
|  | const AncestorThrottleNavigationTest& other) = delete; | 
|  |  | 
|  | private: | 
|  | base::test::ScopedFeatureList scoped_feature_list; | 
|  | }; | 
|  |  | 
|  | TEST_F(AncestorThrottleNavigationTest, EmbeddingOptInRequirement) { | 
|  | // Set up the main frame. We'll add nested frames to it in the tests below. | 
|  | NavigateAndCommit(GURL("https://www.example.org")); | 
|  | auto* main_frame = static_cast<TestRenderFrameHost*>(main_rfh()); | 
|  |  | 
|  | struct TestCase { | 
|  | const char* name; | 
|  | const char* frame_url; | 
|  | const char* xfo; | 
|  | const char* csp; | 
|  | NavigationThrottle::ThrottleAction expected_result; | 
|  | } cases[] = {{ | 
|  | "Same-origin, no XFO, no CSP", | 
|  | "https://www.example.org", | 
|  | nullptr, | 
|  | nullptr, | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Same-site, no XFO, no CSP", | 
|  | "https://not.example.org", | 
|  | nullptr, | 
|  | nullptr, | 
|  | NavigationThrottle::BLOCK_RESPONSE, | 
|  | }, | 
|  | { | 
|  | "Same-site, XFO: ALLOWALL, no CSP", | 
|  | "https://not.example.org", | 
|  | "ALLOWALL", | 
|  | nullptr, | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Same-site, XFO: INVALID, no CSP", | 
|  | "https://not.example.org", | 
|  | "INVALID", | 
|  | nullptr, | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Same-site, no XFO, CSP: frame-ancestors *", | 
|  | "https://not.example.org", | 
|  | nullptr, | 
|  | "frame-ancestors *", | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Same-site, no XFO, CSP without frame-ancestors", | 
|  | "https://not.example.org", | 
|  | nullptr, | 
|  | "img-src 'self'", | 
|  | NavigationThrottle::BLOCK_RESPONSE, | 
|  | }, | 
|  | { | 
|  | "Cross-origin, no XFO, no CSP", | 
|  | "https://www.not-example.org", | 
|  | nullptr, | 
|  | nullptr, | 
|  | NavigationThrottle::BLOCK_RESPONSE, | 
|  | }, | 
|  | { | 
|  | "Cross-origin, XFO: ALLOWALL, no CSP", | 
|  | "https://www.not-example.org", | 
|  | "ALLOWALL", | 
|  | nullptr, | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Cross-origin, XFO: INVALID, no CSP", | 
|  | "https://www.not-example.org", | 
|  | "INVALID", | 
|  | nullptr, | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Cross-origin, no XFO, CSP: frame-ancestors *", | 
|  | "https://www.not-example.org", | 
|  | nullptr, | 
|  | "frame-ancestors *", | 
|  | NavigationThrottle::PROCEED, | 
|  | }, | 
|  | { | 
|  | "Cross-origin, no XFO, CSP without frame-ancestors", | 
|  | "https://www.not-example.org", | 
|  | nullptr, | 
|  | "img-src 'self'", | 
|  | NavigationThrottle::BLOCK_RESPONSE, | 
|  | }}; | 
|  |  | 
|  | for (auto test : cases) { | 
|  | SCOPED_TRACE(test.name); | 
|  | auto* frame = static_cast<TestRenderFrameHost*>( | 
|  | content::RenderFrameHostTester::For(main_frame) | 
|  | ->AppendChild(test.name)); | 
|  | std::unique_ptr<NavigationSimulator> simulator = | 
|  | content::NavigationSimulator::CreateRendererInitiated( | 
|  | GURL(test.frame_url), frame); | 
|  |  | 
|  | auto response_headers = | 
|  | base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK"); | 
|  | if (test.xfo) | 
|  | response_headers->SetHeader("X-Frame-Options", test.xfo); | 
|  | if (test.csp) | 
|  | response_headers->SetHeader("Content-Security-Policy", test.csp); | 
|  |  | 
|  | simulator->SetResponseHeaders(response_headers); | 
|  | simulator->ReadyToCommit(); | 
|  |  | 
|  | EXPECT_EQ(test.expected_result, simulator->GetLastThrottleCheckResult()); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace content |