blob: 2b71ef48776b1edc99bfe34b81d2cebe4f720802 [file] [log] [blame]
Adithya Srinivasan4bc95ab2019-09-25 18:23:101// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Kevin McNee94ea52f52020-06-23 17:42:065#include <memory>
Jan Wilken Dörriead587c32021-03-11 14:09:276#include <string>
Adithya Srinivasan4bc95ab2019-09-25 18:23:107#include <vector>
8
Jeremy Romand26a7d12020-01-16 23:51:309#include "base/callback.h"
Lei Zhang435755f2021-05-11 20:58:5510#include "base/containers/contains.h"
Kevin McNee94ea52f52020-06-23 17:42:0611#include "base/containers/flat_set.h"
12#include "base/memory/scoped_refptr.h"
Jeremy Roman7e70bf952020-01-07 23:23:5813#include "base/strings/utf_string_conversions.h"
Kevin McNee94ea52f52020-06-23 17:42:0614#include "base/task/post_task.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1015#include "base/test/scoped_feature_list.h"
Lei Zhanga1e978b52021-03-18 04:00:1816#include "build/build_config.h"
Adithya Srinivasan5d50d1e2019-10-09 00:27:4817#include "chrome/browser/devtools/devtools_window_testing.h"
Kevin McNeef8eb64c2020-04-21 21:36:0618#include "chrome/browser/history/history_service_factory.h"
19#include "chrome/browser/history/history_test_utils.h"
Kevin McNee068c3eb2020-04-03 18:24:1920#include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
Kevin McNee3a2270732020-02-03 19:01:4021#include "chrome/browser/pdf/pdf_extension_test_util.h"
Kevin McNee94ea52f52020-06-23 17:42:0622#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
Jeremy Romand26a7d12020-01-16 23:51:3023#include "chrome/browser/task_manager/providers/task.h"
24#include "chrome/browser/task_manager/task_manager_browsertest_util.h"
25#include "chrome/browser/task_manager/task_manager_tester.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1026#include "chrome/browser/ui/browser.h"
Jeremy Romand26a7d12020-01-16 23:51:3027#include "chrome/browser/ui/browser_dialogs.h"
Jeremy Roman7e70bf952020-01-07 23:23:5828#include "chrome/browser/ui/login/login_handler.h"
29#include "chrome/browser/ui/login/login_handler_test_utils.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1030#include "chrome/browser/ui/tabs/tab_strip_model.h"
Jeremy Romand26a7d12020-01-16 23:51:3031#include "chrome/grit/generated_resources.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1032#include "chrome/test/base/in_process_browser_test.h"
33#include "chrome/test/base/ui_test_utils.h"
Colin Blundell9e1f7652021-06-25 20:24:3534#include "components/safe_browsing/core/browser/db/fake_database_manager.h"
Kevin McNee94ea52f52020-06-23 17:42:0635#include "content/public/browser/browser_task_traits.h"
36#include "content/public/browser/browser_thread.h"
Kevin McNee068c3eb2020-04-03 18:24:1937#include "content/public/browser/navigation_controller.h"
38#include "content/public/browser/navigation_entry.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1039#include "content/public/browser/web_contents.h"
Kevin McNee068c3eb2020-04-03 18:24:1940#include "content/public/common/page_type.h"
Peter Kasting919ce652020-05-07 10:22:3641#include "content/public/test/browser_test.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1042#include "content/public/test/browser_test_utils.h"
Kevin McNee068c3eb2020-04-03 18:24:1943#include "content/public/test/test_navigation_observer.h"
Kevin McNee94ea52f52020-06-23 17:42:0644#include "net/dns/mock_host_resolver.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1045#include "net/test/embedded_test_server/embedded_test_server.h"
Julie Jeongeun Kim9d6b0dd82021-01-21 04:06:1146#include "services/network/public/mojom/fetch_api.mojom.h"
Jeremy Romand26a7d12020-01-16 23:51:3047#include "testing/gmock/include/gmock/gmock.h"
48#include "testing/gtest/include/gtest/gtest.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1049#include "third_party/blink/public/common/features.h"
Jeremy Romand26a7d12020-01-16 23:51:3050#include "ui/base/l10n/l10n_util.h"
Kevin McNee94ea52f52020-06-23 17:42:0651#include "url/gurl.h"
Adithya Srinivasan4bc95ab2019-09-25 18:23:1052
53using content::WebContents;
54
55class PortalBrowserTest : public InProcessBrowserTest {
56 public:
57 PortalBrowserTest() = default;
58
59 void SetUp() override {
Jeremy Romanf369a9d62020-06-24 19:59:5460 scoped_feature_list_.InitWithFeatures(
61 /*enabled_features=*/{blink::features::kPortals,
62 blink::features::kPortalsCrossOrigin},
63 /*disabled_features=*/{});
Adithya Srinivasan4bc95ab2019-09-25 18:23:1064 InProcessBrowserTest::SetUp();
65 }
66
Kevin McNee94ea52f52020-06-23 17:42:0667 void SetUpOnMainThread() override {
68 host_resolver()->AddRule("*", "127.0.0.1");
69 InProcessBrowserTest::SetUpOnMainThread();
70 }
71
Adithya Srinivasan4bc95ab2019-09-25 18:23:1072 private:
73 base::test::ScopedFeatureList scoped_feature_list_;
74};
75
Lucas Furukawa Gadani4bfbe022020-01-06 18:28:2976IN_PROC_BROWSER_TEST_F(PortalBrowserTest, PortalActivation) {
Adithya Srinivasan4bc95ab2019-09-25 18:23:1077 ASSERT_TRUE(embedded_test_server()->Start());
78 GURL url(embedded_test_server()->GetURL("/portal/activate.html"));
79 ui_test_utils::NavigateToURL(browser(), url);
80 TabStripModel* tab_strip_model = browser()->tab_strip_model();
81 WebContents* contents = tab_strip_model->GetActiveWebContents();
82 EXPECT_EQ(1, tab_strip_model->count());
83
Adithya Srinivasana67e3ac2019-12-19 21:13:2084 EXPECT_EQ(true, content::EvalJs(contents, "loadPromise"));
Adithya Srinivasan4bc95ab2019-09-25 18:23:1085 std::vector<WebContents*> inner_web_contents =
86 contents->GetInnerWebContents();
87 EXPECT_EQ(1u, inner_web_contents.size());
88 WebContents* portal_contents = inner_web_contents[0];
89
Adithya Srinivasana67e3ac2019-12-19 21:13:2090 EXPECT_EQ(true, content::EvalJs(contents, "activate()"));
Adithya Srinivasan4bc95ab2019-09-25 18:23:1091 EXPECT_EQ(1, tab_strip_model->count());
92 EXPECT_EQ(portal_contents, tab_strip_model->GetActiveWebContents());
93}
Adithya Srinivasan5d50d1e2019-10-09 00:27:4894
Lei Zhanga1e978b52021-03-18 04:00:1895// Flaky on Linux ASAN. crbug.com/1182702
96#if defined(ADDRESS_SANITIZER) && defined(OS_LINUX)
97#define MAYBE_DevToolsWindowStaysOpenAfterActivation \
98 DISABLED_DevToolsWindowStaysOpenAfterActivation
99#else
100#define MAYBE_DevToolsWindowStaysOpenAfterActivation \
101 DevToolsWindowStaysOpenAfterActivation
102#endif
Adithya Srinivasan5d50d1e2019-10-09 00:27:48103IN_PROC_BROWSER_TEST_F(PortalBrowserTest,
Lei Zhanga1e978b52021-03-18 04:00:18104 MAYBE_DevToolsWindowStaysOpenAfterActivation) {
Adithya Srinivasan5d50d1e2019-10-09 00:27:48105 ASSERT_TRUE(embedded_test_server()->Start());
106 GURL url(embedded_test_server()->GetURL("/portal/activate.html"));
107 ui_test_utils::NavigateToURL(browser(), url);
108 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
109
Adithya Srinivasana67e3ac2019-12-19 21:13:20110 EXPECT_EQ(true, content::EvalJs(contents, "loadPromise"));
Adithya Srinivasan5d50d1e2019-10-09 00:27:48111 DevToolsWindow* dev_tools_window =
112 DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
113 WebContents* main_web_contents =
114 DevToolsWindowTesting::Get(dev_tools_window)->main_web_contents();
115 EXPECT_EQ(main_web_contents,
116 DevToolsWindow::GetInTabWebContents(contents, nullptr));
117
Adithya Srinivasana67e3ac2019-12-19 21:13:20118 EXPECT_EQ(true, content::EvalJs(contents, "activate()"));
Adithya Srinivasan5d50d1e2019-10-09 00:27:48119 EXPECT_EQ(main_web_contents,
120 DevToolsWindow::GetInTabWebContents(
121 browser()->tab_strip_model()->GetActiveWebContents(), nullptr));
122}
Jeremy Roman7e70bf952020-01-07 23:23:58123
Adithya Srinivasanb7204c82020-08-17 14:26:33124IN_PROC_BROWSER_TEST_F(
125 PortalBrowserTest,
126 DevToolsWindowIsAttachedToOriginalWebContentsWhenActivationFails) {
127 ASSERT_TRUE(embedded_test_server()->Start());
128 GURL url(embedded_test_server()->GetURL("/portal/portal-no-src.html"));
129 ui_test_utils::NavigateToURL(browser(), url);
130 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
131 DevToolsWindow* dev_tools_window =
132 DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
133 WebContents* main_web_contents =
134 DevToolsWindowTesting::Get(dev_tools_window)->main_web_contents();
135 EXPECT_EQ(main_web_contents,
136 DevToolsWindow::GetInTabWebContents(contents, nullptr));
137
138 EXPECT_EQ(true, content::EvalJs(contents, "activate()"));
139 EXPECT_EQ(main_web_contents,
140 DevToolsWindow::GetInTabWebContents(
141 browser()->tab_strip_model()->GetActiveWebContents(), nullptr));
142}
143
Kevin McNee55da71672021-01-29 22:43:58144IN_PROC_BROWSER_TEST_F(PortalBrowserTest, HttpBasicAuthenticationInPortal) {
Jeremy Roman7e70bf952020-01-07 23:23:58145 ASSERT_TRUE(embedded_test_server()->Start());
146 GURL url(embedded_test_server()->GetURL("/title1.html"));
147 ui_test_utils::NavigateToURL(browser(), url);
148 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
149
150 EXPECT_EQ(true,
151 content::EvalJs(contents,
152 "new Promise((resolve, reject) => {\n"
153 " let portal = document.createElement('portal');\n"
154 " portal.src = '/title2.html';\n"
155 " portal.onload = () => resolve(true);\n"
156 " document.body.appendChild(portal);\n"
157 "})"));
158 const auto& inner_contents = contents->GetInnerWebContents();
159 ASSERT_EQ(inner_contents.size(), 1u);
160 WebContents* portal_contents = inner_contents[0];
161 content::NavigationController& portal_controller =
162 portal_contents->GetController();
163
164 LoginPromptBrowserTestObserver login_observer;
165 login_observer.Register(
166 content::Source<content::NavigationController>(&portal_controller));
167 WindowedAuthNeededObserver auth_needed(&portal_controller);
168 ASSERT_TRUE(content::ExecJs(portal_contents,
169 "location.href = '/auth-basic?realm=Aperture'"));
170 auth_needed.Wait();
171
172 WindowedAuthSuppliedObserver auth_supplied(&portal_controller);
173 LoginHandler* login_handler = login_observer.handlers().front();
174 EXPECT_EQ(login_handler->auth_info().realm, "Aperture");
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22175 login_handler->SetAuth(u"basicuser", u"secret");
Jeremy Roman7e70bf952020-01-07 23:23:58176 auth_supplied.Wait();
177
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22178 std::u16string expected_title = u"basicuser/secret";
Jeremy Roman7e70bf952020-01-07 23:23:58179 content::TitleWatcher title_watcher(portal_contents, expected_title);
180 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
181}
Adithya Srinivasan374434a32020-01-16 18:33:12182
Jeremy Romand26a7d12020-01-16 23:51:30183// The task manager should show the portal tasks, and update the tasks after
184// activation as tab contents become portals and vice versa.
185IN_PROC_BROWSER_TEST_F(PortalBrowserTest, TaskManagerUpdatesAfterActivation) {
186 ASSERT_TRUE(embedded_test_server()->Start());
187
Jan Wilken Dörriedec99122021-03-11 18:02:30188 const std::u16string expected_tab_title_before_activation =
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22189 l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX, u"activate.html");
Jan Wilken Dörriedec99122021-03-11 18:02:30190 const std::u16string expected_tab_title_after_activation =
Jeremy Romand26a7d12020-01-16 23:51:30191 l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX,
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22192 u"activate-portal.html");
Jan Wilken Dörriedec99122021-03-11 18:02:30193 const std::u16string expected_portal_title = l10n_util::GetStringFUTF16(
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22194 IDS_TASK_MANAGER_PORTAL_PREFIX, u"http://127.0.0.1/");
Jeremy Romand26a7d12020-01-16 23:51:30195
196 ui_test_utils::NavigateToURL(
197 browser(), embedded_test_server()->GetURL("/portal/activate.html"));
198 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
199 EXPECT_EQ(true, content::EvalJs(tab, "loadPromise"));
200
201 // Check that both tasks appear.
202 chrome::ShowTaskManager(browser());
Alan Screendee363f2021-02-05 06:32:35203 auto tester =
204 task_manager::TaskManagerTester::Create(base::RepeatingClosure());
Jeremy Romand26a7d12020-01-16 23:51:30205 task_manager::browsertest_util::WaitForTaskManagerRows(
206 1, expected_tab_title_before_activation);
207 task_manager::browsertest_util::WaitForTaskManagerRows(1,
208 expected_portal_title);
Johannbf6bedc32021-07-22 22:17:25209 EXPECT_THAT(tester->GetWebContentsTaskTitles(),
Jeremy Romand26a7d12020-01-16 23:51:30210 ::testing::ElementsAre(expected_tab_title_before_activation,
211 expected_portal_title));
212
213 // Activate and check that this updates as expected.
214 EXPECT_EQ(true, content::EvalJs(tab, "activate()"));
215 task_manager::browsertest_util::WaitForTaskManagerRows(
216 1, expected_tab_title_after_activation);
217 task_manager::browsertest_util::WaitForTaskManagerRows(1,
218 expected_portal_title);
Johannbf6bedc32021-07-22 22:17:25219 EXPECT_THAT(tester->GetWebContentsTaskTitles(),
Jeremy Romand26a7d12020-01-16 23:51:30220 ::testing::ElementsAre(expected_tab_title_after_activation,
221 expected_portal_title));
222}
223
224// The task manager should show the portal tasks, and by default they should be
225// grouped with their respective tabs. This is similar to
226// TaskManagerOOPIFBrowserTest.OrderingOfDependentRows, but less exhaustive.
227IN_PROC_BROWSER_TEST_F(PortalBrowserTest, TaskManagerOrderingOfDependentRows) {
228 ASSERT_TRUE(embedded_test_server()->Start());
229
230 const unsigned kNumTabs = 3;
231 const unsigned kPortalsPerTab = 2;
232
Jan Wilken Dörriedec99122021-03-11 18:02:30233 const std::u16string expected_tab_title = l10n_util::GetStringFUTF16(
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22234 IDS_TASK_MANAGER_TAB_PREFIX, u"Title Of Awesomeness");
Jan Wilken Dörriedec99122021-03-11 18:02:30235 const std::u16string expected_portal_title = l10n_util::GetStringFUTF16(
Jan Wilken Dörrie78e88d82e2021-03-23 15:24:22236 IDS_TASK_MANAGER_PORTAL_PREFIX, u"http://127.0.0.1/");
Jan Wilken Dörriedec99122021-03-11 18:02:30237 std::vector<std::u16string> expected_titles;
Jeremy Romand26a7d12020-01-16 23:51:30238 for (unsigned i = 0; i < kNumTabs; i++) {
239 expected_titles.push_back(expected_tab_title);
240 for (unsigned j = 0; j < kPortalsPerTab; j++)
241 expected_titles.push_back(expected_portal_title);
242 }
243
244 // Open a number of new tabs.
245 std::vector<WebContents*> tab_contents;
246 for (unsigned i = 0; i < kNumTabs; i++) {
247 ui_test_utils::NavigateToURLWithDispositionBlockUntilNavigationsComplete(
248 browser(), embedded_test_server()->GetURL("/title2.html"), 1,
249 WindowOpenDisposition::NEW_FOREGROUND_TAB,
Fergal Dalyffa9bba2020-01-27 23:45:02250 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
Jeremy Romand26a7d12020-01-16 23:51:30251 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
252 tab_contents.push_back(tab);
253 }
254
255 // There's an initial tab that's implicitly created.
256 browser()->tab_strip_model()->CloseWebContentsAt(0,
257 TabStripModel::CLOSE_NONE);
258 EXPECT_EQ(static_cast<int>(kNumTabs), browser()->tab_strip_model()->count());
259
260 // Create portals in each tab.
261 for (WebContents* tab : tab_contents) {
262 EXPECT_EQ(static_cast<int>(kPortalsPerTab),
263 content::EvalJs(
264 tab, content::JsReplace(
265 "Promise.all([...Array($1)].map(() =>"
266 " new Promise((resolve, reject) => {"
267 " let portal = document.createElement('portal');"
268 " portal.src = '/title3.html';"
269 " portal.onload = () => resolve();"
270 " document.body.appendChild(portal);"
271 " }))).then(arr => arr.length)",
272 static_cast<int>(kPortalsPerTab))));
273 }
274
275 // Check that the tasks are grouped in the UI as expected.
276 chrome::ShowTaskManager(browser());
Alan Screendee363f2021-02-05 06:32:35277 auto tester =
278 task_manager::TaskManagerTester::Create(base::RepeatingClosure());
Jeremy Romand26a7d12020-01-16 23:51:30279 task_manager::browsertest_util::WaitForTaskManagerRows(kNumTabs,
280 expected_tab_title);
281 task_manager::browsertest_util::WaitForTaskManagerRows(
282 kNumTabs * kPortalsPerTab, expected_portal_title);
Johannbf6bedc32021-07-22 22:17:25283 EXPECT_THAT(tester->GetWebContentsTaskTitles(), expected_titles);
Jeremy Romand26a7d12020-01-16 23:51:30284}
Kevin McNee3a2270732020-02-03 19:01:40285
286IN_PROC_BROWSER_TEST_F(PortalBrowserTest, PdfViewerLoadsInPortal) {
287 ASSERT_TRUE(embedded_test_server()->Start());
288 GURL url(embedded_test_server()->GetURL("/title1.html"));
289 ui_test_utils::NavigateToURL(browser(), url);
290 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
291
292 ASSERT_EQ(true,
293 content::EvalJs(contents,
294 "new Promise((resolve) => {\n"
295 " let portal = document.createElement('portal');\n"
296 " portal.src = '/pdf/test.pdf';\n"
297 " portal.onload = () => { resolve(true); }\n"
298 " document.body.appendChild(portal);\n"
299 "});"));
300
301 std::vector<WebContents*> inner_web_contents =
302 contents->GetInnerWebContents();
303 ASSERT_EQ(1u, inner_web_contents.size());
304 WebContents* portal_contents = inner_web_contents[0];
305
Kevin McNeeba7a4ed2020-11-16 22:23:54306 ASSERT_TRUE(pdf_extension_test_util::EnsurePDFHasLoaded(portal_contents));
Kevin McNee3a2270732020-02-03 19:01:40307}
Kevin McNee068c3eb2020-04-03 18:24:19308
309// Test that we do not show main frame interstitials in portal contents. We
310// should treat portals like subframes in terms of how to display the error to
311// the user.
312IN_PROC_BROWSER_TEST_F(PortalBrowserTest, ShowSubFrameErrorPage) {
313 net::EmbeddedTestServer bad_https_server(net::EmbeddedTestServer::TYPE_HTTPS);
314 bad_https_server.AddDefaultHandlers(GetChromeTestDataDir());
315 bad_https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
316 ASSERT_TRUE(bad_https_server.Start());
317 ASSERT_TRUE(embedded_test_server()->Start());
318
319 GURL url(embedded_test_server()->GetURL("/title1.html"));
320 ui_test_utils::NavigateToURL(browser(), url);
321 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
322
323 GURL bad_cert_url(bad_https_server.GetURL("/title1.html"));
324 content::TestNavigationObserver portal_navigation_observer(nullptr, 1);
325 portal_navigation_observer.StartWatchingNewWebContents();
326 ASSERT_EQ(true,
327 content::EvalJs(
328 contents, content::JsReplace(
329 "new Promise((resolve) => {"
330 " let portal = document.createElement('portal');"
331 " portal.src = $1;"
332 " portal.onload = () => { resolve(true); };"
333 " document.body.appendChild(portal);"
334 "});",
335 bad_cert_url)));
336 portal_navigation_observer.StopWatchingNewWebContents();
337 portal_navigation_observer.Wait();
338 EXPECT_FALSE(portal_navigation_observer.last_navigation_succeeded());
339 EXPECT_EQ(net::ERR_CERT_DATE_INVALID,
340 portal_navigation_observer.last_net_error_code());
341
342 std::vector<WebContents*> inner_web_contents =
343 contents->GetInnerWebContents();
344 ASSERT_EQ(1u, inner_web_contents.size());
345 WebContents* portal_contents = inner_web_contents[0];
346
347 content::NavigationController& controller = portal_contents->GetController();
348 content::NavigationEntry* entry = controller.GetLastCommittedEntry();
349 ASSERT_TRUE(entry);
350 EXPECT_EQ(content::PAGE_TYPE_ERROR, entry->GetPageType());
351
352 // Ensure that this is the net error page and not an interstitial.
353 ASSERT_FALSE(
354 chrome_browser_interstitials::IsShowingInterstitial(portal_contents));
355 // Also ensure that the error page is using its subframe layout.
356 ASSERT_EQ(true, content::EvalJs(
357 portal_contents,
358 "document.documentElement.hasAttribute('subframe');"));
359}
Kevin McNeef8eb64c2020-04-21 21:36:06360
361IN_PROC_BROWSER_TEST_F(PortalBrowserTest, BrowserHistoryUpdatesOnActivation) {
362 ASSERT_TRUE(embedded_test_server()->Start());
363
364 Profile* profile = browser()->profile();
365 ASSERT_TRUE(profile);
366 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
367 profile, ServiceAccessType::EXPLICIT_ACCESS));
368
369 GURL url1(embedded_test_server()->GetURL("/title1.html"));
370 ui_test_utils::NavigateToURL(browser(), url1);
371 WaitForHistoryBackendToRun(profile);
372 EXPECT_TRUE(
373 base::Contains(ui_test_utils::HistoryEnumerator(profile).urls(), url1));
374
375 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
376 GURL url2(embedded_test_server()->GetURL("/title2.html"));
377 ASSERT_EQ(true,
378 content::EvalJs(
379 contents, content::JsReplace(
380 "new Promise((resolve) => {"
381 " let portal = document.createElement('portal');"
382 " portal.src = $1;"
383 " portal.onload = () => { resolve(true); };"
384 " document.body.appendChild(portal);"
385 "});",
386 url2)));
387 WaitForHistoryBackendToRun(profile);
388 // Content loaded in a portal should not be considered a page visit by the
389 // user.
390 EXPECT_FALSE(
391 base::Contains(ui_test_utils::HistoryEnumerator(profile).urls(), url2));
392
393 ASSERT_EQ(true,
394 content::EvalJs(contents,
395 "let portal = document.querySelector('portal');"
396 "portal.activate().then(() => { return true; });"));
397 WaitForHistoryBackendToRun(profile);
398 // Now that the portal has activated, its contents are presented to the user
399 // as a navigation in the tab, so this should be considered a page visit.
400 EXPECT_TRUE(
401 base::Contains(ui_test_utils::HistoryEnumerator(profile).urls(), url2));
402}
Kevin McNee94ea52f52020-06-23 17:42:06403
Kevin McNee94ea52f52020-06-23 17:42:06404class PortalSafeBrowsingBrowserTest : public PortalBrowserTest {
405 public:
406 PortalSafeBrowsingBrowserTest()
407 : safe_browsing_factory_(
408 std::make_unique<safe_browsing::TestSafeBrowsingServiceFactory>()) {
409 }
410
411 protected:
412 void CreatedBrowserMainParts(
413 content::BrowserMainParts* browser_main_parts) override {
414 fake_safe_browsing_database_manager_ =
Colin Blundellfe3f55a2021-06-17 16:33:47415 base::MakeRefCounted<safe_browsing::FakeSafeBrowsingDatabaseManager>(
416 content::GetUIThreadTaskRunner({}),
417 content::GetIOThreadTaskRunner({}));
Kevin McNee94ea52f52020-06-23 17:42:06418 safe_browsing_factory_->SetTestDatabaseManager(
419 fake_safe_browsing_database_manager_.get());
420 safe_browsing::SafeBrowsingService::RegisterFactory(
421 safe_browsing_factory_.get());
422 PortalBrowserTest::CreatedBrowserMainParts(browser_main_parts);
423 }
424
425 void TearDown() override {
426 PortalBrowserTest::TearDown();
427 safe_browsing::SafeBrowsingService::RegisterFactory(nullptr);
428 }
429
430 void AddDangerousUrl(const GURL& dangerous_url) {
Kevin McNeea89cc6902021-02-18 18:02:37431 fake_safe_browsing_database_manager_->AddDangerousUrl(
432 dangerous_url, safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
Kevin McNee94ea52f52020-06-23 17:42:06433 }
434
435 private:
Kevin McNeea89cc6902021-02-18 18:02:37436 scoped_refptr<safe_browsing::FakeSafeBrowsingDatabaseManager>
Kevin McNee94ea52f52020-06-23 17:42:06437 fake_safe_browsing_database_manager_;
438 std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory>
439 safe_browsing_factory_;
440};
441
442// Tests that if a page embeds a portal whose contents are considered dangerous
443// by Safe Browsing, the embedder is also treated as dangerous in terms of how
444// we display the Safe Browsing interstitial.
Theodore Olsauskas-Warrenafa3fee2021-07-13 09:12:15445// Flaky on ChromeOS & under Ozone (crbug.com/1220319)
446#if defined(OS_CHROMEOS) || defined(USE_OZONE)
447#define MAYBE_EmbedderOfDangerousPortalConsideredDangerous \
448 DISABLED_EmbedderOfDangerousPortalConsideredDangerous
449#else
450#define MAYBE_EmbedderOfDangerousPortalConsideredDangerous \
451 EmbedderOfDangerousPortalConsideredDangerous
452#endif
Kevin McNee94ea52f52020-06-23 17:42:06453IN_PROC_BROWSER_TEST_F(PortalSafeBrowsingBrowserTest,
Theodore Olsauskas-Warrenafa3fee2021-07-13 09:12:15454 MAYBE_EmbedderOfDangerousPortalConsideredDangerous) {
Kevin McNee94ea52f52020-06-23 17:42:06455 ASSERT_TRUE(embedded_test_server()->Start());
456
457 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
458 GURL dangerous_url(
459 embedded_test_server()->GetURL("evil.com", "/title2.html"));
460 AddDangerousUrl(dangerous_url);
461
462 ui_test_utils::NavigateToURL(browser(), main_url);
463 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
464
465 content::TestNavigationObserver error_observer(contents,
466 net::ERR_BLOCKED_BY_CLIENT);
467 ASSERT_TRUE(content::ExecJs(
468 contents,
469 content::JsReplace("let portal = document.createElement('portal');"
470 "portal.src = $1;"
471 "document.body.appendChild(portal);",
472 dangerous_url)));
473 error_observer.WaitForNavigationFinished();
474 EXPECT_TRUE(chrome_browser_interstitials::IsShowingInterstitial(contents));
475}
476
477// Test that if a page embeds a portal which contains a dangerous subresource,
478// the embedder is also treated as dangerous in terms of how we display the Safe
479// Browsing interstitial.
480IN_PROC_BROWSER_TEST_F(PortalSafeBrowsingBrowserTest,
481 PortalDangerousSubresource) {
482 ASSERT_TRUE(embedded_test_server()->Start());
483
484 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
485 GURL portal_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
486 GURL dangerous_url(
487 embedded_test_server()->GetURL("evil.com", "/title3.html"));
488 AddDangerousUrl(dangerous_url);
489
490 ui_test_utils::NavigateToURL(browser(), main_url);
491 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
492
493 ASSERT_EQ(true,
494 content::EvalJs(
495 contents, content::JsReplace(
496 "new Promise((resolve) => {"
497 " let portal = document.createElement('portal');"
498 " portal.src = $1;"
499 " portal.onload = () => { resolve(true); };"
500 " document.body.appendChild(portal);"
501 "});",
502 portal_url)));
503 std::vector<WebContents*> inner_web_contents =
504 contents->GetInnerWebContents();
505 ASSERT_EQ(1u, inner_web_contents.size());
506 WebContents* portal_contents = inner_web_contents[0];
507
508 content::TestNavigationObserver error_observer(contents,
509 net::ERR_BLOCKED_BY_CLIENT);
510 ASSERT_TRUE(content::ExecJs(
511 portal_contents,
512 content::JsReplace("let iframe = document.createElement('iframe');"
513 "iframe.src = $1;"
514 "document.body.appendChild(iframe);",
515 dangerous_url)));
516 error_observer.WaitForNavigationFinished();
517 EXPECT_TRUE(chrome_browser_interstitials::IsShowingInterstitial(contents));
518}
519
520IN_PROC_BROWSER_TEST_F(PortalSafeBrowsingBrowserTest, DangerousOrphanedPortal) {
521 ASSERT_TRUE(embedded_test_server()->Start());
522
523 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
524 GURL portal_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
525 GURL dangerous_url(
526 embedded_test_server()->GetURL("evil.com", "/title3.html"));
527 AddDangerousUrl(dangerous_url);
528
529 ui_test_utils::NavigateToURL(browser(), main_url);
530 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
531
532 ASSERT_EQ(true,
533 content::EvalJs(
534 contents, content::JsReplace(
535 "new Promise((resolve) => {"
536 " let portal = document.createElement('portal');"
537 " portal.src = $1;"
538 " portal.onload = () => { resolve(true); };"
539 " document.body.appendChild(portal);"
540 "});",
541 portal_url)));
542 std::vector<WebContents*> inner_web_contents =
543 contents->GetInnerWebContents();
544 ASSERT_EQ(1u, inner_web_contents.size());
545 WebContents* portal_contents = inner_web_contents[0];
546
547 // Block the activate callback so that the predecessor portal stays orphaned
548 // while it navigates to a dangerous URL.
549 ASSERT_TRUE(content::ExecJs(
550 portal_contents, "window.onportalactivate = e => { while(true) {} };"));
551
552 // Since the portal contents becomes the top level contents from the following
553 // activation, it's the contents where we show the interstitial.
554 content::TestNavigationObserver error_observer(portal_contents,
555 net::ERR_BLOCKED_BY_CLIENT);
556 ASSERT_TRUE(content::ExecJs(
557 contents,
558 content::JsReplace("document.querySelector('portal').activate();"
559 "window.location.href = $1;",
560 dangerous_url)));
561 error_observer.WaitForNavigationFinished();
562 EXPECT_TRUE(
563 chrome_browser_interstitials::IsShowingInterstitial(portal_contents));
564}