blob: 4fabd904000419e4ec1232e42554cefec8d865a3 [file] [log] [blame]
// Copyright 2021 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/files/file_util.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/web_package/web_bundle_browsertest_base.h"
#include "content/browser/web_package/web_bundle_utils.h"
namespace content {
class WebBundleFileBrowserTest
: public testing::WithParamInterface<
web_bundle_browsertest_utils::TestFilePathMode>,
public web_bundle_browsertest_utils::WebBundleBrowserTestBase {
public:
WebBundleFileBrowserTest(const WebBundleFileBrowserTest&) = delete;
WebBundleFileBrowserTest& operator=(const WebBundleFileBrowserTest&) = delete;
protected:
WebBundleFileBrowserTest() = default;
~WebBundleFileBrowserTest() override = default;
void SetUp() override {
feature_list_.InitWithFeatures({features::kWebBundles}, {});
web_bundle_browsertest_utils::WebBundleBrowserTestBase::SetUp();
}
GURL GetTestUrlForFile(base::FilePath file_path) const {
GURL content_uri;
if (GetParam() ==
web_bundle_browsertest_utils::TestFilePathMode::kNormalFilePath) {
content_uri = net::FilePathToFileURL(file_path);
} else {
#if BUILDFLAG(IS_ANDROID)
DCHECK_EQ(web_bundle_browsertest_utils::TestFilePathMode::kContentURI,
GetParam());
web_bundle_browsertest_utils::CopyFileAndGetContentUri(
file_path, &content_uri, nullptr /* new_file_path */);
#endif // BUILDFLAG(IS_ANDROID)
}
return content_uri;
}
void RunSharedNavigationTest(
void (*setup_func)(net::EmbeddedTestServer*, GURL*, std::string*),
void (*run_test_func)(WebContents*,
const GURL&,
const GURL&,
base::RepeatingCallback<GURL(const GURL&)>)) {
GURL url_origin;
std::string web_bundle_content;
(*setup_func)(embedded_test_server(), &url_origin, &web_bundle_content);
base::FilePath file_path;
CreateTemporaryWebBundleFile(web_bundle_content, &file_path);
const GURL test_data_url = GetTestUrlForFile(file_path);
(*run_test_func)(
shell()->web_contents(), test_data_url, url_origin,
base::BindRepeating(&web_bundle_utils::GetSynthesizedUrlForWebBundle,
test_data_url));
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, BasicNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpBasicNavigationTest,
&web_bundle_browsertest_utils::RunBasicNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest,
BrowserInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(&web_bundle_browsertest_utils::
SetUpBrowserInitiatedOutOfBundleNavigationTest,
&web_bundle_browsertest_utils::
RunBrowserInitiatedOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest,
RendererInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(&web_bundle_browsertest_utils::
SetUpRendererInitiatedOutOfBundleNavigationTest,
&web_bundle_browsertest_utils::
RunRendererInitiatedOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, SameDocumentNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpSameDocumentNavigationTest,
&web_bundle_browsertest_utils::RunSameDocumentNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeOutOfBundleNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest,
IframeParentInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::
RunIframeParentInitiatedOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeSameDocumentNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeSameDocumentNavigationTest);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX)
#define MAYBE_InvalidWebBundleFile DISABLED_InvalidWebBundleFile
#else
#define MAYBE_InvalidWebBundleFile InvalidWebBundleFile
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_InvalidWebBundleFile) {
const GURL test_data_url = GetTestUrlForFile(
web_bundle_browsertest_utils::GetTestDataPath("invalid_web_bundle.wbn"));
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
test_data_url);
EXPECT_EQ(
"Failed to read metadata of Web Bundle file: Invalid bundle length.",
console_message);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX)
#define MAYBE_InvalidExchangeUrl DISABLED_InvalidExchangeUrl
#else
#define MAYBE_InvalidExchangeUrl InvalidExchangeUrl
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_InvalidExchangeUrl) {
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"foo_base_url_bundle_b2.wbn"));
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
test_data_url);
EXPECT_EQ(web_bundle_utils::kInvalidExchangeUrlErrorMessage, console_message);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX)
#define MAYBE_InvalidPrimaryUrl DISABLED_InvalidPrimaryUrl
#else
#define MAYBE_InvalidPrimaryUrl InvalidPrimaryUrl
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_InvalidPrimaryUrl) {
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"foo_primary_url_bundle_b2.wbn"));
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
test_data_url);
EXPECT_EQ(web_bundle_utils::kInvalidPrimaryUrlErrorMessage, console_message);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX)
#define MAYBE_ResponseParseErrorInMainResource \
DISABLED_ResponseParseErrorInMainResource
#else
#define MAYBE_ResponseParseErrorInMainResource ResponseParseErrorInMainResource
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest,
MAYBE_ResponseParseErrorInMainResource) {
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"broken_bundle_broken_first_entry_b2.wbn"));
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
test_data_url);
EXPECT_EQ(
"Failed to read response header of Web Bundle file: Response headers map "
"must have exactly one pseudo-header, :status.",
console_message);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest,
ResponseParseErrorInSubresource) {
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"broken_bundle_broken_script_entry_b2.wbn"));
NavigateToBundleAndWaitForReady(
test_data_url,
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)));
WebContents* web_contents = shell()->web_contents();
WebContentsConsoleObserver console_observer(web_contents);
ExecuteScriptAndWaitForTitle(R"(
const script = document.createElement("script");
script.onerror = () => { document.title = "load failed";};
script.src = "script.js";
document.body.appendChild(script);)",
"load failed");
if (console_observer.messages().empty())
ASSERT_TRUE(console_observer.Wait());
ASSERT_FALSE(console_observer.messages().empty());
EXPECT_EQ(
"Failed to read response header of Web Bundle file: Response headers map "
"must have exactly one pseudo-header, :status.",
base::UTF16ToUTF8(console_observer.messages()[0].message));
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, NoLocalFileScheme) {
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"web_bundle_browsertest_b2.wbn"));
NavigateToBundleAndWaitForReady(
test_data_url,
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)));
auto* expected_title = u"load failed";
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
title_watcher.AlsoWaitForTitle(u"Local Script");
const GURL script_file_url = net::FilePathToFileURL(
web_bundle_browsertest_utils::GetTestDataPath("local_script.js"));
const std::string script = base::StringPrintf(R"(
const script = document.createElement("script");
script.onerror = () => { document.title = "load failed";};
script.src = "%s";
document.body.appendChild(script);)",
script_file_url.spec().c_str());
EXPECT_TRUE(ExecJs(shell()->web_contents(), script));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, DataDecoderRestart) {
constexpr char kTestPage1Url[] = "https://test.example.org/page1.html";
constexpr char kTestPage2Url[] = "https://test.example.org/page2.html";
// The content of this file will be read as response body of any exchange.
base::FilePath test_file_path =
web_bundle_browsertest_utils::GetTestDataPath("mocked.wbn");
web_bundle_browsertest_utils::MockParserFactory mock_factory(
{GURL(web_bundle_browsertest_utils::kTestPageUrl), GURL(kTestPage1Url),
GURL(kTestPage2Url)},
test_file_path);
const GURL test_data_url = GetTestUrlForFile(test_file_path);
web_bundle_browsertest_utils::NavigateAndWaitForTitle(
shell()->web_contents(), test_data_url,
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)),
web_bundle_browsertest_utils::kTestPageUrl);
EXPECT_EQ(1, mock_factory.GetParserCreationCount());
mock_factory.SimulateParserDisconnect();
NavigateToURLAndWaitForTitle(GURL(kTestPage1Url), kTestPage1Url);
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(),
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(kTestPage1Url)));
EXPECT_EQ(2, mock_factory.GetParserCreationCount());
mock_factory.SimulateParserDisconnect();
NavigateToURLAndWaitForTitle(GURL(kTestPage2Url), kTestPage2Url);
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(),
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(kTestPage2Url)));
EXPECT_EQ(3, mock_factory.GetParserCreationCount());
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
BUILDFLAG(IS_MAC)
#define MAYBE_ParseMetadataCrash DISABLED_ParseMetadataCrash
#else
#define MAYBE_ParseMetadataCrash ParseMetadataCrash
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_ParseMetadataCrash) {
base::FilePath test_file_path =
web_bundle_browsertest_utils::GetTestDataPath("mocked.wbn");
web_bundle_browsertest_utils::MockParserFactory mock_factory(
{GURL(web_bundle_browsertest_utils::kTestPageUrl)}, test_file_path);
mock_factory.SimulateParseMetadataCrash();
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(
shell()->web_contents(), GetTestUrlForFile(test_file_path));
EXPECT_EQ(
"Failed to read metadata of Web Bundle file: Cannot connect to the "
"remote parser service",
console_message);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
#define MAYBE_ParseResponseCrash DISABLED_ParseResponseCrash
#else
#define MAYBE_ParseResponseCrash ParseResponseCrash
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_ParseResponseCrash) {
base::FilePath test_file_path =
web_bundle_browsertest_utils::GetTestDataPath("mocked.wbn");
web_bundle_browsertest_utils::MockParserFactory mock_factory(
{GURL(web_bundle_browsertest_utils::kTestPageUrl)}, test_file_path);
mock_factory.SimulateParseResponseCrash();
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(
shell()->web_contents(), GetTestUrlForFile(test_file_path));
EXPECT_EQ(
"Failed to read response header of Web Bundle file: Cannot connect to "
"the remote parser service",
console_message);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, IframeNavigationNoCrash) {
// Regression test for crbug.com/1058721. There was a bug that navigation of
// OOPIF's remote iframe in Web Bundle file cause crash.
const GURL test_data_url =
GetTestUrlForFile(web_bundle_browsertest_utils::GetTestDataPath(
"web_bundle_browsertest_b2.wbn"));
NavigateToBundleAndWaitForReady(
test_data_url,
web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, GURL(web_bundle_browsertest_utils::kTestPageUrl)));
const std::string empty_page_path = "/web_bundle/empty_page.html";
ASSERT_TRUE(embedded_test_server()->Start());
const GURL empty_page_url = embedded_test_server()->GetURL(empty_page_path);
ExecuteScriptAndWaitForTitle(
base::StringPrintf(R"(
(async function() {
const empty_page_url = '%s';
const iframe = document.createElement('iframe');
const onload = () => {
iframe.removeEventListener('load', onload);
document.title = 'Iframe loaded';
}
iframe.addEventListener('load', onload);
iframe.src = empty_page_url;
document.body.appendChild(iframe);
})();)",
empty_page_url.spec().c_str()),
"Iframe loaded");
ExecuteScriptAndWaitForTitle(R"(
(async function() {
const iframe = document.querySelector("iframe");
const onload = () => {
document.title = 'Iframe loaded again';
}
iframe.addEventListener('load', onload);
iframe.src = iframe.src + '?';
})();)",
"Iframe loaded again");
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, Iframe) {
net::EmbeddedTestServer third_party_server;
GURL primary_url_origin;
GURL third_party_origin;
std::string web_bundle_content;
web_bundle_browsertest_utils::SetUpSubPageTest(
embedded_test_server(), &third_party_server, &primary_url_origin,
&third_party_origin, &web_bundle_content);
base::FilePath file_path;
CreateTemporaryWebBundleFile(web_bundle_content, &file_path);
const GURL test_data_url = GetTestUrlForFile(file_path);
NavigateToBundleAndWaitForReady(
test_data_url, web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, primary_url_origin.Resolve("/top")));
web_bundle_browsertest_utils::RunSubPageTest(
shell()->web_contents(), primary_url_origin, third_party_origin,
&web_bundle_browsertest_utils::AddIframeAndWaitForMessage,
true /* support_third_party_wbn_page */);
}
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, WindowOpen) {
net::EmbeddedTestServer third_party_server;
GURL primary_url_origin;
GURL third_party_origin;
std::string web_bundle_content;
web_bundle_browsertest_utils::SetUpSubPageTest(
embedded_test_server(), &third_party_server, &primary_url_origin,
&third_party_origin, &web_bundle_content);
base::FilePath file_path;
CreateTemporaryWebBundleFile(web_bundle_content, &file_path);
const GURL test_data_url = GetTestUrlForFile(file_path);
NavigateToBundleAndWaitForReady(
test_data_url, web_bundle_utils::GetSynthesizedUrlForWebBundle(
test_data_url, primary_url_origin.Resolve("/top")));
web_bundle_browsertest_utils::RunSubPageTest(
shell()->web_contents(), primary_url_origin, third_party_origin,
&web_bundle_browsertest_utils::WindowOpenAndWaitForMessage,
true /* support_third_party_wbn_page */);
}
// TODO(https://crbug.com/1225178): flaky
#if BUILDFLAG(IS_LINUX)
#define MAYBE_NoPrimaryURLFound DISABLED_NoPrimaryURLFound
#else
#define MAYBE_NoPrimaryURLFound NoPrimaryURLFound
#endif
IN_PROC_BROWSER_TEST_P(WebBundleFileBrowserTest, MAYBE_NoPrimaryURLFound) {
const GURL test_data_url = GetTestUrlForFile(
web_bundle_browsertest_utils::GetTestDataPath("same_origin_b2.wbn"));
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
test_data_url);
EXPECT_EQ(web_bundle_utils::kNoPrimaryUrlErrorMessage, console_message);
}
INSTANTIATE_TEST_SUITE_P(WebBundleFileBrowserTest,
WebBundleFileBrowserTest,
TEST_FILE_PATH_MODE_PARAMS);
} // namespace content