blob: ac998f9740ef7c470e344f83edcdcb2f458abdb2 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/devtools/protocol/audits.h"
#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_agent_host_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
namespace content {
class DevToolsIssueStorageBrowserTest : public DevToolsProtocolTest {
public:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
SetupCrossSiteRedirector(embedded_test_server());
}
protected:
WebContentsImpl* web_contents() {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
RenderFrameHostImpl* main_frame_host() {
return web_contents()->GetPrimaryFrameTree().GetMainFrame();
}
void WaitForDummyIssueNotification() {
base::Value::Dict notification =
WaitForNotification("Audits.issueAdded", true);
EXPECT_EQ(*notification.FindStringByDottedPath("issue.code"),
protocol::Audits::InspectorIssueCodeEnum::CookieIssue);
}
};
namespace {
void ReportDummyIssue(RenderFrameHostImpl* rfh) {
auto issueDetails = protocol::Audits::InspectorIssueDetails::Create();
auto inspector_issue =
protocol::Audits::InspectorIssue::Create()
.SetCode(protocol::Audits::InspectorIssueCodeEnum::CookieIssue)
.SetDetails(issueDetails.Build())
.Build();
devtools_instrumentation::ReportBrowserInitiatedIssue(
rfh, std::move(inspector_issue));
}
} // namespace
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageBrowserTest,
DevToolsReceivesBrowserIssues) {
EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// Report an empty SameSite cookie issue.
ReportDummyIssue(main_frame_host());
Attach();
SendCommandSync("Audits.enable");
// Verify we have received the SameSite issue.
WaitForDummyIssueNotification();
}
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageBrowserTest,
DevToolsReceivesBrowserIssuesWhileAttached) {
EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
Attach();
SendCommandSync("Audits.enable");
// Report an empty SameSite cookie issue.
ReportDummyIssue(main_frame_host());
// Verify we have received the SameSite issue.
WaitForDummyIssueNotification();
}
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageBrowserTest,
DeleteSubframeWithIssue) {
// 1) Navigate to a page with an OOP iframe.
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url =
embedded_test_server()->GetURL("/devtools/page-with-oopif.html");
EXPECT_TRUE(NavigateToURL(shell(), test_url));
// 2) Report an empty SameSite cookie issue in the iframe.
RenderFrameHostImpl* main_frame = main_frame_host();
EXPECT_EQ(main_frame->child_count(), static_cast<unsigned>(1));
RenderFrameHostImpl* iframe = main_frame->child_at(0)->current_frame_host();
EXPECT_FALSE(iframe->is_main_frame());
ReportDummyIssue(iframe);
// 3) Delete the iframe from the page. This should cause the issue to be
// re-assigned
// to the root frame.
main_frame->RemoveChild(iframe->frame_tree_node());
// 4) Open DevTools and enable Audits domain.
Attach();
SendCommandSync("Audits.enable");
// 5) Verify we have received the SameSite issue on the main target.
WaitForDummyIssueNotification();
}
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageBrowserTest,
MainFrameNavigationClearsIssues) {
// 1) Navigate to about:blank.
EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
// 2) Report an empty SameSite cookie issue.
ReportDummyIssue(main_frame_host());
// 3) Navigate to /devtools/navigation.html
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
EXPECT_TRUE(NavigateToURL(shell(), test_url));
// 4) Open DevTools and enable Audits domain.
Attach();
SendCommandSync("Audits.enable");
// 5) Verify that we haven't received any notifications.
ASSERT_FALSE(HasExistingNotification());
}
class DevToolsIssueStorageWithBackForwardCacheBrowserTest
: public DevToolsIssueStorageBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
// Enable BackForwardCache, omitting this feature results in a crash.
feature_list_.InitWithFeaturesAndParameters(
GetDefaultEnabledBackForwardCacheFeaturesForTesting(),
GetDefaultDisabledBackForwardCacheFeaturesForTesting());
}
protected:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageWithBackForwardCacheBrowserTest,
BackForwardCacheGoBack) {
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.
EXPECT_TRUE(NavigateToURL(shell(), url_a));
RenderFrameHostImpl* rfh_a = main_frame_host();
RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
// 2) Report an empty SameSite cookie issue.
ReportDummyIssue(rfh_a);
// 3) Navigate to B.
// The previous test verifies that the issue storage is cleared at
// this point.
EXPECT_TRUE(NavigateToURL(shell(), url_b));
EXPECT_TRUE(rfh_a->IsInBackForwardCache());
// 4) Go back to A and expect that it is restored from the back-forward cache.
web_contents()->GetController().GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_FALSE(rfh_a_deleted.deleted());
EXPECT_EQ(main_frame_host(), rfh_a);
// 5) Open DevTools and enable Audits domain.
Attach();
SendCommandSync("Audits.enable");
// 6) Verify we have received the SameSite issue on the main target.
WaitForDummyIssueNotification();
}
class DevToolsIssueStorageWithPrerenderBrowserTest
: public DevToolsIssueStorageBrowserTest {
public:
DevToolsIssueStorageWithPrerenderBrowserTest()
: prerender_test_helper_(base::BindRepeating(
&DevToolsIssueStorageWithPrerenderBrowserTest::GetWebContents,
base::Unretained(this))) {}
void SetUp() override {
prerender_test_helper().RegisterServerRequestMonitor(
embedded_test_server());
DevToolsIssueStorageBrowserTest::SetUp();
}
test::PrerenderTestHelper& prerender_test_helper() {
return prerender_test_helper_;
}
private:
WebContents* GetWebContents() { return web_contents(); }
test::PrerenderTestHelper prerender_test_helper_;
};
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageWithPrerenderBrowserTest,
IssueWhilePrerendering) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL main_url(embedded_test_server()->GetURL("/empty.html"));
GURL prerender_url(embedded_test_server()->GetURL("/title1.html"));
// 1) Navigate to |main_url|.
EXPECT_TRUE(NavigateToURL(shell(), main_url));
// 2) Prerender |prerender_url|.
FrameTreeNodeId host_id = prerender_test_helper().AddPrerender(prerender_url);
RenderFrameHostImpl* prerender_rfh = static_cast<RenderFrameHostImpl*>(
prerender_test_helper().GetPrerenderedMainFrameHost(host_id));
// 3) Report an empty SameSite cookie issue in prerendering page.
ReportDummyIssue(prerender_rfh);
// 4) Activate prerendering page.
prerender_test_helper().NavigatePrimaryPage(prerender_url);
// 5) Open DevTools and enable Audits domain.
Attach();
SendCommandSync("Audits.enable");
// 6) Verify we have received the SameSite issue on the main target.
WaitForDummyIssueNotification();
}
class DevToolsIssueStorageFencedFrameTest
: public DevToolsIssueStorageBrowserTest {
public:
content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
return fenced_frame_helper_;
}
protected:
content::test::FencedFrameTestHelper fenced_frame_helper_;
};
IN_PROC_BROWSER_TEST_F(DevToolsIssueStorageFencedFrameTest,
DeleteFencedFrameWithIssue) {
// 1) Navigate to a page.
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/title1.html");
EXPECT_TRUE(NavigateToURL(shell(), test_url));
// 2) Create a fenced frame.
GURL fenced_frame_url =
embedded_test_server()->GetURL("/fenced_frames/title1.html");
content::RenderFrameHostImpl* fenced_frame_rfh =
static_cast<RenderFrameHostImpl*>(
fenced_frame_test_helper().CreateFencedFrame(
web_contents()->GetPrimaryMainFrame(), fenced_frame_url));
EXPECT_NE(nullptr, fenced_frame_rfh);
// 3) Report an empty SameSite cookie issue in the fenced frame.
ReportDummyIssue(fenced_frame_rfh);
// 4) Delete the fenced frame from the page. This should cause the issue to be
// re-assigned to the primary root frame.
EXPECT_TRUE(ExecJs(shell()->web_contents(),
"document.querySelector('fencedframe').remove()"));
// 5) Open DevTools and enable Audits domain.
Attach();
SendCommandSync("Audits.enable");
// 6) Verify we have received the SameSite issue on the main target.
WaitForDummyIssueNotification();
}
} // namespace content