blob: aae0ab1048d253907f58a55d8cce341203a41c2e [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fdio/directory.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/vmo_file.h>
#include "fuchsia/engine/test/web_engine_browser_test.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/path_service.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_test_suite_base.h"
#include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/engine/browser/content_directory_loader_factory.h"
#include "fuchsia/engine/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/url_util.h"
namespace {
// Adds an in-memory file containing |data| to |dir| at the location |path|.
void AddFileToPseudoDir(base::StringPiece data,
const base::FilePath& path,
vfs::PseudoDir* dir) {
zx::vmo contents_vmo;
zx_status_t status = zx::vmo::create(data.size(), 0, &contents_vmo);
ASSERT_EQ(status, ZX_OK);
status = contents_vmo.write(data.data(), 0, data.size());
ASSERT_EQ(status, ZX_OK);
auto vmo_file = std::make_unique<vfs::VmoFile>(
std::move(contents_vmo), 0, data.size(),
vfs::VmoFile::WriteOption::READ_ONLY, vfs::VmoFile::Sharing::CLONE_COW);
status = dir->AddEntry(path.value(), std::move(vmo_file));
ASSERT_EQ(status, ZX_OK);
}
// Serves |dir| as a ContentDirectory under the path |name|.
void ServePseudoDir(base::StringPiece name, vfs::PseudoDir* dir) {
fuchsia::web::ContentDirectoryProvider provider;
provider.set_name(name.as_string());
fidl::InterfaceHandle<fuchsia::io::Directory> directory_channel;
dir->Serve(
fuchsia::io::OPEN_FLAG_DIRECTORY | fuchsia::io::OPEN_RIGHT_READABLE,
directory_channel.NewRequest().TakeChannel());
provider.set_directory(std::move(directory_channel));
std::vector<fuchsia::web::ContentDirectoryProvider> providers;
providers.emplace_back(std::move(provider));
ContentDirectoryLoaderFactory::SetContentDirectoriesForTest(
std::move(providers));
}
class ContentDirectoryTest : public cr_fuchsia::WebEngineBrowserTest {
public:
ContentDirectoryTest() = default;
~ContentDirectoryTest() override = default;
void SetUp() override {
// Set this flag early so that the fuchsia-dir:// scheme will be
// registered at browser startup.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kContentDirectories);
// Scheme initialization for the WebEngineContentClient depends on the above
// command line modification, which won't have been present when the schemes
// were initially registered.
content::ContentTestSuiteBase::ReRegisterContentSchemes();
cr_fuchsia::WebEngineBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
std::vector<fuchsia::web::ContentDirectoryProvider> providers;
fuchsia::web::ContentDirectoryProvider provider;
provider.set_name("testdata");
base::FilePath pkg_path;
base::PathService::Get(base::DIR_ASSETS, &pkg_path);
provider.set_directory(base::fuchsia::OpenDirectory(
pkg_path.AppendASCII("fuchsia/engine/test/data")));
providers.emplace_back(std::move(provider));
provider = {};
provider.set_name("alternate");
provider.set_directory(base::fuchsia::OpenDirectory(
pkg_path.AppendASCII("fuchsia/engine/test/data")));
providers.emplace_back(std::move(provider));
ContentDirectoryLoaderFactory::SetContentDirectoriesForTest(
std::move(providers));
cr_fuchsia::WebEngineBrowserTest::SetUpOnMainThread();
}
void TearDown() override {
ContentDirectoryLoaderFactory::SetContentDirectoriesForTest({});
}
protected:
// Creates a Frame with |navigation_listener_| attached.
fuchsia::web::FramePtr CreateFrame() {
return WebEngineBrowserTest::CreateFrame(&navigation_listener_);
}
cr_fuchsia::TestNavigationListener navigation_listener_;
private:
url::ScopedSchemeRegistryForTests scoped_registry_;
DISALLOW_COPY_AND_ASSIGN(ContentDirectoryTest);
};
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, Navigate) {
const GURL kUrl("fuchsia-dir://testdata/title1.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlEquals(kUrl);
}
// Navigate to a resource stored under a secondary provider.
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, NavigateAlternate) {
const GURL kUrl("fuchsia-dir://alternate/title1.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlEquals(kUrl);
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, ScriptSubresource) {
const GURL kUrl("fuchsia-dir://testdata/include_script.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "title set by script");
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, ImgSubresource) {
const GURL kUrl("fuchsia-dir://testdata/include_image.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "image fetched");
}
// Reads content sourced from VFS PseudoDirs and VmoFiles.
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, FromVfsPseudoDir) {
base::ScopedAllowBlockingForTesting allow_block;
std::string contents;
base::FilePath pkg_path;
base::PathService::Get(base::DIR_ASSETS, &pkg_path);
ASSERT_TRUE(base::ReadFileToString(
pkg_path.AppendASCII("fuchsia/engine/test/data/title1.html"), &contents));
vfs::PseudoDir pseudo_dir;
AddFileToPseudoDir(contents, base::FilePath("title1.html"), &pseudo_dir);
ServePseudoDir("pseudo-dir", &pseudo_dir);
// Access the VmoFile under the PseudoDir.
const GURL kUrl("fuchsia-dir://pseudo-dir/title1.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "title 1");
}
// Verify that resource providers are origin-isolated.
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, ScriptSrcCrossOriginBlocked) {
const GURL kUrl("fuchsia-dir://testdata/cross_origin_include_script.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
// If the cross-origin script succeeded, then we should see "title set by
// script". If "not clobbered" remains set, then we know that CROS enforcement
// is working.
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "same origin ftw");
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, CrossOriginImgBlocked) {
const GURL kUrl("fuchsia-dir://testdata/cross_origin_include_image.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl, "image rejected");
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, MetadataFileParsed) {
const GURL kUrl("fuchsia-dir://testdata/mime_override.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(
kUrl, "content-type: text/bleep; charset=US-ASCII");
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, BadMetadataFile) {
const GURL kUrl("fuchsia-dir://testdata/mime_override_invalid.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl,
"content-type: text/html");
}
IN_PROC_BROWSER_TEST_F(ContentDirectoryTest, BigFilesAreSniffable) {
base::ScopedAllowBlockingForTesting allow_block;
std::string contents;
base::FilePath pkg_path;
base::PathService::Get(base::DIR_ASSETS, &pkg_path);
ASSERT_TRUE(base::ReadFileToString(
pkg_path.AppendASCII("fuchsia/engine/test/data/mime_override.html"),
&contents));
vfs::PseudoDir pseudo_dir;
AddFileToPseudoDir(contents, base::FilePath("test.html"), &pseudo_dir);
// Produce an HTML file that's a megabyte in size by appending a lot of
// zeroes to the end of an existing HTML file.
contents.resize(1000000, ' ');
AddFileToPseudoDir(contents, base::FilePath("blob.bin"), &pseudo_dir);
ServePseudoDir("pseudo-dir", &pseudo_dir);
// Access the VmoFile under the PseudoDir.
const GURL kUrl("fuchsia-dir://pseudo-dir/test.html");
fuchsia::web::FramePtr frame = CreateFrame();
fuchsia::web::NavigationControllerPtr controller;
frame->GetNavigationController(controller.NewRequest());
EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
controller.get(), fuchsia::web::LoadUrlParams(), kUrl.spec()));
navigation_listener_.RunUntilUrlAndTitleEquals(kUrl,
"content-type: text/html");
}
} // namespace