blob: f66e55ac34437d075c1c784a943651423b274fce [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/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/services/storage/public/cpp/buckets/constants.h"
#include "content/browser/native_io/native_io_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/common/database/database_identifier.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/gurl.h"
namespace content {
class NativeIOManagerBrowserTest : public ContentBrowserTest {
public:
NativeIOManagerBrowserTest() {
// SharedArrayBuffers are not enabled by default on Android, see also
// https://crbug.com/1144104 .
feature_list_.InitAndEnableFeature(features::kSharedArrayBuffer);
}
NativeIOManagerBrowserTest(const NativeIOManagerBrowserTest&) = delete;
NativeIOManagerBrowserTest& operator=(const NativeIOManagerBrowserTest&) =
delete;
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
ContentBrowserTest::SetUpCommandLine(command_line);
}
void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start());
}
base::FilePath GetNativeIODir(base::FilePath user_data_dir,
const GURL& test_url) {
std::string origin_identifier =
storage::GetIdentifierFromOrigin(test_url.DeprecatedGetOriginAsURL());
base::FilePath root_dir =
NativeIOManager::GetNativeIORootPath(user_data_dir);
return root_dir.AppendASCII(origin_identifier);
}
void RunOnIOThreadBlocking(base::OnceClosure task) {
base::RunLoop run_loop;
content::GetIOThreadTaskRunner({})->PostTaskAndReply(
FROM_HERE, std::move(task), run_loop.QuitClosure());
run_loop.Run();
}
static void DeleteNativeIODataOnIOThread(
scoped_refptr<storage::QuotaManager> quota_manager,
const blink::StorageKey& storage_key,
base::OnceCallback<void(blink::mojom::QuotaStatusCode)> callback) {
quota_manager->FindAndDeleteBucketData(
storage_key, storage::kDefaultBucketName, std::move(callback));
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(NativeIOManagerBrowserTest, ReadFromDeletedFile) {
const GURL& test_url = embedded_test_server()->GetURL(
"/native_io/read_from_deleted_file_test.html");
Shell* browser = CreateBrowser();
base::FilePath user_data_dir = GetNativeIODir(
browser->web_contents()->GetBrowserContext()->GetPath(), test_url);
NavigateToURLBlockUntilNavigationsComplete(browser, test_url,
/*number_of_navigations=*/1);
EXPECT_TRUE(EvalJs(browser, "writeToFile()").ExtractBool());
{
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::DeleteFile(user_data_dir.AppendASCII("test_file")));
}
EXPECT_TRUE(EvalJs(browser, "readFromFile()").ExtractBool());
}
// This test depends on POSIX file permissions, which do not work on Windows,
// Android, or Fuchsia.
#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
IN_PROC_BROWSER_TEST_F(NativeIOManagerBrowserTest, TryOpenProtectedFileTest) {
const GURL& test_url = embedded_test_server()->GetURL(
"/native_io/try_open_protected_file_test.html");
Shell* browser = CreateBrowser();
base::FilePath user_data_dir_ = GetNativeIODir(
browser->web_contents()->GetBrowserContext()->GetPath(), test_url);
NavigateToURLBlockUntilNavigationsComplete(browser, test_url,
/*number_of_navigations=*/1);
EXPECT_TRUE(EvalJs(browser, "createAndCloseFile()").ExtractBool());
{
base::ScopedAllowBlockingForTesting allow_blocking;
base::SetPosixFilePermissions(user_data_dir_.AppendASCII("test_file"),
0300); // not readable
}
std::string expected_caught_error = "InvalidStateError";
EXPECT_EQ(EvalJs(browser, "tryOpeningFile()").ExtractString(),
expected_caught_error);
}
#endif // !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_ANDROID) &&
// !BUILDFLAG(IS_FUCHSIA)
// TODO(http://crbug.com/1177307): This test might be flaky on some Windows
// configurations.
#if BUILDFLAG(IS_WIN)
#define MAYBE_FileUsageAfterOriginRemoval DISABLED_FileUsageAfterOriginRemoval
#else
#define MAYBE_FileUsageAfterOriginRemoval FileUsageAfterOriginRemoval
#endif
IN_PROC_BROWSER_TEST_F(NativeIOManagerBrowserTest,
MAYBE_FileUsageAfterOriginRemoval) {
const GURL& test_url = embedded_test_server()->GetURL(
"/native_io/file_usage_after_origin_removal.html");
Shell* browser = CreateBrowser();
base::RunLoop run_loop;
scoped_refptr<storage::QuotaManager> quota_manager =
browser->web_contents()
->GetBrowserContext()
->GetDefaultStoragePartition()
->GetQuotaManager();
NavigateToURLBlockUntilNavigationsComplete(browser, test_url,
/*number_of_navigations=*/1);
EXPECT_TRUE(EvalJs(browser, "openFile()").ExtractBool());
blink::mojom::QuotaStatusCode deletion_result;
RunOnIOThreadBlocking(base::BindOnce(
&NativeIOManagerBrowserTest::DeleteNativeIODataOnIOThread, quota_manager,
blink::StorageKey::CreateFromStringForTesting(test_url.spec()),
base::BindLambdaForTesting([&](blink::mojom::QuotaStatusCode result) {
deletion_result = result;
run_loop.Quit();
})));
run_loop.Run();
EXPECT_EQ(deletion_result, blink::mojom::QuotaStatusCode::kOk);
std::string expected_caught_error = "InvalidStateError";
EXPECT_EQ(EvalJs(browser, "tryAccessOpenedFile()").ExtractString(),
expected_caught_error);
EXPECT_EQ(EvalJs(browser, "countFiles()").ExtractInt(), 0);
EXPECT_TRUE(EvalJs(browser, "openAnotherFile()").ExtractBool());
}
IN_PROC_BROWSER_TEST_F(NativeIOManagerBrowserTest, ThrowsInIncognito) {
const GURL& test_url =
embedded_test_server()->GetURL("/native_io/throws_in_incognito.html");
Shell* browser = CreateOffTheRecordBrowser();
NavigateToURLBlockUntilNavigationsComplete(browser, test_url,
/*number_of_navigations=*/1);
EXPECT_TRUE(EvalJs(browser, "tryAccessStorageFoundation()").ExtractBool());
EXPECT_TRUE(
EvalJs(browser, "tryAccessStorageFoundationSync()").ExtractBool());
}
} // namespace content