blob: 6e696dbcebc637cb885fb0222251c25166073c3a [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/test/bind.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"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
#include "net/dns/mock_host_resolver.h"
namespace content {
class WebBundleNetworkBrowserTest
: public web_bundle_browsertest_utils::WebBundleBrowserTestBase {
public:
WebBundleNetworkBrowserTest(const WebBundleNetworkBrowserTest&) = delete;
WebBundleNetworkBrowserTest& operator=(const WebBundleNetworkBrowserTest&) =
delete;
protected:
WebBundleNetworkBrowserTest() = default;
~WebBundleNetworkBrowserTest() override = default;
void SetUpOnMainThread() override {
WebBundleBrowserTestBase::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
}
void TearDownOnMainThread() override {
// Shutdown the server to avoid the data race of |headers_| and |contents_|
// caused by page reload on error.
EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
WebBundleBrowserTestBase::TearDownOnMainThread();
}
void SetUp() override {
feature_list_.InitWithFeatures({features::kWebBundlesFromNetwork}, {});
WebBundleBrowserTestBase::SetUp();
}
void RegisterRequestHandler(const std::string& relative_url) {
embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting(
[this, relative_url](const net::test_server::HttpRequest& request)
-> std::unique_ptr<net::test_server::HttpResponse> {
if (request.relative_url != relative_url)
return nullptr;
return std::make_unique<net::test_server::RawHttpResponse>(headers_,
contents_);
}));
}
void TestNavigationFailure(const GURL& url,
const std::string& expected_console_error) {
std::string console_message = web_bundle_browsertest_utils::
ExpectNavigationFailureAndReturnConsoleMessage(shell()->web_contents(),
url);
EXPECT_EQ(expected_console_error, console_message);
}
void HistoryBackAndWaitUntilConsoleError(
const std::string& expected_error_message) {
WebContents* web_contents = shell()->web_contents();
WebContentsConsoleObserver console_observer(web_contents);
base::RunLoop run_loop;
web_bundle_browsertest_utils::FinishNavigationObserver
finish_navigation_observer(web_contents, run_loop.QuitClosure());
EXPECT_TRUE(ExecJs(web_contents, "history.back();"));
run_loop.Run();
ASSERT_TRUE(finish_navigation_observer.error_code());
EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
*finish_navigation_observer.error_code());
if (console_observer.messages().empty())
ASSERT_TRUE(console_observer.Wait());
ASSERT_FALSE(console_observer.messages().empty());
EXPECT_EQ(expected_error_message,
base::UTF16ToUTF8(console_observer.messages()[0].message));
}
void SetHeaders(const std::string& headers) { headers_ = headers; }
void AddHeaders(const std::string& headers) { headers_ += headers; }
void SetContents(const std::string& contents) { contents_ = contents; }
const std::string& contents() const { return contents_; }
void RunSharedNavigationTest(
void (*setup_func)(net::EmbeddedTestServer*, GURL*, std::string*),
void (*run_test_func)(WebContents*,
const GURL&,
const GURL&,
base::RepeatingCallback<GURL(const GURL&)>)) {
const std::string wbn_path = "/test.wbn";
RegisterRequestHandler(wbn_path);
GURL url_origin;
std::string web_bundle_content;
(*setup_func)(embedded_test_server(), &url_origin, &web_bundle_content);
SetContents(web_bundle_content);
(*run_test_func)(shell()->web_contents(), url_origin.Resolve(wbn_path),
url_origin,
base::BindRepeating([](const GURL& url) { return url; }));
}
private:
base::test::ScopedFeatureList feature_list_;
std::string headers_ = web_bundle_browsertest_utils::kDefaultHeaders;
std::string contents_;
};
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, Simple) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, SimpleWithScript) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/test.html");
const GURL script_url =
embedded_test_server()->GetURL("/web_bundle/script.js");
web_package::WebBundleBuilder builder;
builder.AddPrimaryURL(primary_url);
builder.AddExchange(primary_url,
{{":status", "200"}, {"content-type", "text/html"}},
"<script src=\"script.js\"></script>");
builder.AddExchange(
script_url,
{{":status", "200"}, {"content-type", "application/javascript"}},
"document.title = 'Ready';");
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, Download) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
AddHeaders("Content-Disposition:attachment; filename=test.wbn\n");
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
WebContents* web_contents = shell()->web_contents();
std::unique_ptr<web_bundle_browsertest_utils::DownloadObserver>
download_observer =
std::make_unique<web_bundle_browsertest_utils::DownloadObserver>(
web_contents->GetBrowserContext()->GetDownloadManager());
EXPECT_FALSE(NavigateToURL(web_contents, wbn_url));
download_observer->WaitUntilDownloadCreated();
EXPECT_EQ(wbn_url, download_observer->observed_url());
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, ContentLength) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
AddHeaders(
base::StringPrintf("Content-Length: %" PRIuS "\n", contents().size()));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, NonSecureUrl) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL("example.com", wbn_path);
const GURL primary_url =
embedded_test_server()->GetURL("example.com", primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
TestNavigationFailure(
wbn_url,
"Web Bundle response must be served from HTTPS or localhost HTTP.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, MissingNosniff) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
SetHeaders(
"HTTP/1.1 200 OK\n"
"Content-Type: application/webbundle\n");
TestNavigationFailure(wbn_url,
"Web Bundle response must have "
"\"X-Content-Type-Options: nosniff\" header.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
PrimaryURLResourceNotFound) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
const GURL inner_url =
embedded_test_server()->GetURL("/web_bundle/inner.html");
web_package::WebBundleBuilder builder;
builder.AddPrimaryURL(primary_url);
builder.AddExchange(inner_url,
{{":status", "200"}, {"content-type", "text/html"}},
"<title>Ready</title>");
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
TestNavigationFailure(
wbn_url, "The primary URL resource is not found in the web bundle.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, PrimaryURLNotFound) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL inner_url =
embedded_test_server()->GetURL("/web_bundle/inner.html");
web_package::WebBundleBuilder builder;
builder.AddExchange(inner_url,
{{":status", "200"}, {"content-type", "text/html"}},
"<title>Ready</title>");
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
TestNavigationFailure(
wbn_url, "Web Bundle is missing the Primary URL to navigate to.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
PrimaryURLHasInvalidScheme) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
web_package::WebBundleBuilder builder;
builder.AddPrimaryURL("foo://bar/");
builder.AddExchange("foo://bar/",
{{":status", "200"}, {"content-type", "text/html"}},
"<title>Ready</title>");
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
TestNavigationFailure(wbn_url,
web_bundle_utils::kInvalidPrimaryUrlErrorMessage);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, ExchangeHasInvalidScheme) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
web_package::WebBundleBuilder builder;
builder.AddPrimaryURL(primary_url);
builder.AddExchange(primary_url,
{{":status", "200"}, {"content-type", "text/html"}},
"<title>Ready</title>");
builder.AddExchange("foo://bar",
{{":status", "200"}, {"content-type", "text/html"}},
"<title>Ready</title>");
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
TestNavigationFailure(wbn_url,
web_bundle_utils::kInvalidExchangeUrlErrorMessage);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, OriginMismatch) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL primary_url =
embedded_test_server()->GetURL("localhost", primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
TestNavigationFailure(
embedded_test_server()->GetURL("127.0.0.1", wbn_path),
"The origin of primary URL doesn't match with the origin of the web "
"bundle.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, InvalidFile) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
SetContents("This is an invalid Web Bundle file.");
ASSERT_TRUE(embedded_test_server()->Start());
TestNavigationFailure(embedded_test_server()->GetURL(wbn_path),
"Failed to read metadata of Web Bundle file: Wrong "
"magic bytes.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, DataDecoderRestart) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/test.html");
const GURL script_url =
embedded_test_server()->GetURL("/web_bundle/script.js");
const std::string primary_url_content = "<title>Ready</title>";
const std::string script_url_content = "document.title = 'OK'";
SetContents(primary_url_content + script_url_content);
std::vector<std::pair<GURL, const std::string&>> items = {
{primary_url, primary_url_content}, {script_url, script_url_content}};
web_bundle_browsertest_utils::MockParserFactory mock_factory(items);
NavigateToBundleAndWaitForReady(embedded_test_server()->GetURL(wbn_path),
primary_url);
EXPECT_EQ(1, mock_factory.GetParserCreationCount());
mock_factory.SimulateParserDisconnect();
ExecuteScriptAndWaitForTitle(R"(
const script = document.createElement("script");
script.src = "script.js";
document.body.appendChild(script);)",
"OK");
EXPECT_EQ(2, mock_factory.GetParserCreationCount());
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, ParseMetadataCrash) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
SetContents("<title>Ready</title>");
ASSERT_TRUE(embedded_test_server()->Start());
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/test.html");
std::vector<std::pair<GURL, const std::string&>> items = {
{primary_url, contents()}};
web_bundle_browsertest_utils::MockParserFactory mock_factory(items);
mock_factory.SimulateParseMetadataCrash();
TestNavigationFailure(embedded_test_server()->GetURL(wbn_path),
"Failed to read metadata of Web Bundle file: Cannot "
"connect to the remote parser service");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, ParseResponseCrash) {
const std::string wbn_path = "/web_bundle/test.wbn";
RegisterRequestHandler(wbn_path);
SetContents("<title>Ready</title>");
ASSERT_TRUE(embedded_test_server()->Start());
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/test.html");
std::vector<std::pair<GURL, const std::string&>> items = {
{primary_url, contents()}};
web_bundle_browsertest_utils::MockParserFactory mock_factory(items);
mock_factory.SimulateParseResponseCrash();
TestNavigationFailure(embedded_test_server()->GetURL(wbn_path),
"Failed to read response header of Web Bundle file: "
"Cannot connect to the remote parser service");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, PathMismatch) {
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/other_dir/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
TestNavigationFailure(
wbn_url,
base::StringPrintf("Path restriction mismatch: Can't navigate to %s in "
"the web bundle served from %s.",
primary_url.spec().c_str(), wbn_url.spec().c_str()));
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, BasicNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpBasicNavigationTest,
&web_bundle_browsertest_utils::RunBasicNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
BrowserInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(&web_bundle_browsertest_utils::
SetUpBrowserInitiatedOutOfBundleNavigationTest,
&web_bundle_browsertest_utils::
RunBrowserInitiatedOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
RendererInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(&web_bundle_browsertest_utils::
SetUpRendererInitiatedOutOfBundleNavigationTest,
&web_bundle_browsertest_utils::
RunRendererInitiatedOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, SameDocumentNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpSameDocumentNavigationTest,
&web_bundle_browsertest_utils::RunSameDocumentNavigationTest);
}
// https://crbug.com/1219373 fails with BFCache field trial testing config.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_IframeNavigation DISABLED_IframeNavigation
#else
#define MAYBE_IframeNavigation IframeNavigation
#endif
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, MAYBE_IframeNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
IframeOutOfBundleNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeOutOfBundleNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
IframeParentInitiatedOutOfBundleNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::
RunIframeParentInitiatedOutOfBundleNavigationTest);
}
// https://crbug.com/1219373 fails with BFCache field trial testing config.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_IframeSameDocumentNavigation DISABLED_IframeSameDocumentNavigation
#else
#define MAYBE_IframeSameDocumentNavigation IframeSameDocumentNavigation
#endif
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
MAYBE_IframeSameDocumentNavigation) {
RunSharedNavigationTest(
&web_bundle_browsertest_utils::SetUpIframeNavigationTest,
&web_bundle_browsertest_utils::RunIframeSameDocumentNavigationTest);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, CrossScopeNavigations) {
const std::string wbn_path = "/web_bundle/path_test/in_scope/path_test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
SetContents(web_bundle_browsertest_utils::CreatePathTestWebBundle(
embedded_test_server()->base_url()));
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/path_test/in_scope/");
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL(
"/web_bundle/path_test/in_scope/page.html"),
"In scope page in Web Bundle / in scope script in Web Bundle");
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL(
"/web_bundle/path_test/out_scope/page.html"),
"Out scope page from server / out scope script from server");
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL(
"/web_bundle/path_test/in_scope/page.html"),
"In scope page from server / in scope script from server");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
CrossScopeHistoryNavigations) {
const std::string wbn_path = "/web_bundle/path_test/in_scope/path_test.wbn";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
SetContents(web_bundle_browsertest_utils::CreatePathTestWebBundle(
embedded_test_server()->base_url()));
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url =
embedded_test_server()->GetURL("/web_bundle/path_test/in_scope/");
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL(
"/web_bundle/path_test/in_scope/page.html"),
"In scope page in Web Bundle / in scope script in Web Bundle");
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/path_test/in_scope/"),
"Ready");
ExecuteScriptAndWaitForTitle(
"history.back();",
"In scope page in Web Bundle / in scope script in Web Bundle");
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(),
embedded_test_server()->GetURL(
"/web_bundle/path_test/in_scope/page.html"));
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL(
"/web_bundle/path_test/out_scope/page.html"),
"Out scope page from server / out scope script from server");
ExecuteScriptAndWaitForTitle(
"history.back();",
"In scope page in Web Bundle / in scope script in Web Bundle");
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(),
embedded_test_server()->GetURL(
"/web_bundle/path_test/in_scope/page.html"));
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
HistoryNavigationError_UnexpectedContentType) {
// The test assumes the previous page gets deleted after navigation and doing
// back navigation will recreate the page. Disable back/forward cache to
// ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetHeaders(
"HTTP/1.1 200 OK\n"
"Cache-Control:no-store\n"
"Content-Type:application/webbundle\n"
"X-Content-Type-Options: nosniff\n");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/empty_page.html"),
"Empty Page");
SetHeaders(
"HTTP/1.1 200 OK\n"
"Cache-Control:no-store\n"
"Content-Type:application/foo_bar\n"
"X-Content-Type-Options: nosniff\n");
HistoryBackAndWaitUntilConsoleError("Unexpected content type.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
HistoryNavigationError_MissingNosniff) {
// The test assumes the previous page gets deleted after navigation and doing
// back navigation will recreate the page. Disable back/forward cache to
// ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetHeaders(
"HTTP/1.1 200 OK\n"
"Cache-Control:no-store\n"
"Content-Type:application/webbundle\n"
"X-Content-Type-Options: nosniff\n");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/empty_page.html"),
"Empty Page");
SetHeaders(
"HTTP/1.1 200 OK\n"
"Cache-Control:no-store\n"
"Content-Type:application/webbundle\n");
HistoryBackAndWaitUntilConsoleError(
"Web Bundle response must have \"X-Content-Type-Options: nosniff\" "
"header.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
HistoryNavigationError_UnexpectedRedirect) {
// The test assumes the previous page gets deleted after navigation and doing
// back navigation will recreate the page. Disable back/forward cache to
// ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
SetHeaders(
"HTTP/1.1 200 OK\n"
"Cache-Control:no-store\n"
"Content-Type:application/webbundle\n"
"X-Content-Type-Options: nosniff\n");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/empty_page.html"),
"Empty Page");
SetHeaders(
"HTTP/1.1 302 OK\n"
"Location:/web_bundle/empty_page.html\n"
"X-Content-Type-Options: nosniff\n");
SetContents("");
HistoryBackAndWaitUntilConsoleError("Unexpected redirect.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
HistoryNavigationError_ReadMetadataFailure) {
// The test assumes the previous page gets deleted after navigation. Disable
// back/forward cache to ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
AddHeaders("Cache-Control:no-store\n");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/empty_page.html"),
"Empty Page");
SetContents("This is an invalid Web Bundle file.");
HistoryBackAndWaitUntilConsoleError(
"Failed to read metadata of Web Bundle file: Wrong magic bytes.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest,
HistoryNavigationError_ExpectedUrlNotFound) {
// The test assumes the previous page gets deleted after navigation and doing
// back navigation will recreate the page. Disable back/forward cache to
// ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
const std::string wbn_path = "/web_bundle/test.wbn";
const std::string primary_url_path = "/web_bundle/test.html";
const std::string alt_primary_url_path = "/web_bundle/alt.html";
RegisterRequestHandler(wbn_path);
ASSERT_TRUE(embedded_test_server()->Start());
const GURL wbn_url = embedded_test_server()->GetURL(wbn_path);
const GURL primary_url = embedded_test_server()->GetURL(primary_url_path);
AddHeaders("Cache-Control:no-store\n");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(primary_url));
NavigateToBundleAndWaitForReady(wbn_url, primary_url);
NavigateToURLAndWaitForTitle(
embedded_test_server()->GetURL("/web_bundle/empty_page.html"),
"Empty Page");
SetContents(web_bundle_browsertest_utils::CreateSimpleWebBundle(
embedded_test_server()->GetURL(alt_primary_url_path)));
HistoryBackAndWaitUntilConsoleError(
"The expected URL resource is not found in the web bundle.");
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, Iframe) {
const std::string wbn_path = "/test.wbn";
RegisterRequestHandler(wbn_path);
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);
SetContents(web_bundle_content);
NavigateToBundleAndWaitForReady(primary_url_origin.Resolve(wbn_path),
primary_url_origin.Resolve("/top"));
web_bundle_browsertest_utils::RunSubPageTest(
shell()->web_contents(), primary_url_origin, third_party_origin,
&web_bundle_browsertest_utils::AddIframeAndWaitForMessage,
false /* support_third_party_wbn_page */);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, WindowOpen) {
const std::string wbn_path = "/test.wbn";
RegisterRequestHandler(wbn_path);
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);
SetContents(web_bundle_content);
NavigateToBundleAndWaitForReady(primary_url_origin.Resolve(wbn_path),
primary_url_origin.Resolve("/top"));
web_bundle_browsertest_utils::RunSubPageTest(
shell()->web_contents(), primary_url_origin, third_party_origin,
&web_bundle_browsertest_utils::WindowOpenAndWaitForMessage,
false /* support_third_party_wbn_page */);
}
IN_PROC_BROWSER_TEST_F(WebBundleNetworkBrowserTest, OutScopeSubPage) {
const std::string wbn_path = "/in_scope/test.wbn";
const std::string primary_url_path = "/in_scope/test.html";
RegisterRequestHandler(wbn_path);
web_bundle_browsertest_utils::RegisterRequestHandlerForSubPageTest(
embedded_test_server(), "");
ASSERT_TRUE(embedded_test_server()->Start());
const GURL origin = embedded_test_server()->GetURL("/");
web_package::WebBundleBuilder builder;
builder.AddPrimaryURL(origin.Resolve(primary_url_path));
web_bundle_browsertest_utils::AddHtmlFile(&builder, origin, primary_url_path,
R"(
<script>
window.addEventListener('message',
event => domAutomationController.send(event.data),
false);
document.title = 'Ready';
</script>
)");
web_bundle_browsertest_utils::AddHtmlFile(
&builder, origin, "/in_scope/subpage",
web_bundle_browsertest_utils::CreateSubPageHtml("in-scope-wbn-page"));
web_bundle_browsertest_utils::AddScriptFile(
&builder, origin, "/in_scope/script",
web_bundle_browsertest_utils::CreateScriptForSubPageTest(
"in-scope-wbn-script"));
web_bundle_browsertest_utils::AddHtmlFile(
&builder, origin, "/out_scope/subpage",
web_bundle_browsertest_utils::CreateSubPageHtml("out-scope-wbn-page"));
web_bundle_browsertest_utils::AddScriptFile(
&builder, origin, "/out_scope/script",
web_bundle_browsertest_utils::CreateScriptForSubPageTest(
"out-scope-wbn-script"));
std::vector<uint8_t> bundle = builder.CreateBundle();
SetContents(std::string(bundle.begin(), bundle.end()));
NavigateToBundleAndWaitForReady(origin.Resolve(wbn_path),
origin.Resolve(primary_url_path));
const auto funcs = {
&web_bundle_browsertest_utils::AddIframeAndWaitForMessage,
&web_bundle_browsertest_utils::WindowOpenAndWaitForMessage};
for (const auto func : funcs) {
EXPECT_EQ(
"in-scope-wbn-page in-scope-wbn-script",
(*func)(
shell()->web_contents(),
origin.Resolve("/in_scope/subpage").Resolve("#/in_scope/script")));
EXPECT_EQ(
"in-scope-wbn-page server-script",
(*func)(
shell()->web_contents(),
origin.Resolve("/in_scope/subpage").Resolve("#/out_scope/script")));
EXPECT_EQ(
"server-page server-script",
(*func)(
shell()->web_contents(),
origin.Resolve("/out_scope/subpage").Resolve("#/in_scope/script")));
EXPECT_EQ(
"server-page server-script",
(*func)(shell()->web_contents(), origin.Resolve("/out_scope/subpage")
.Resolve("#/out_scope/script")));
}
}
} // namespace content