[go: nahoru, domu]

blob: b6132def6ce2633bfec763cee24959f4e50d9c03 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "storage/browser/file_system/file_system_url.h"
#include <stddef.h>
#include <utility>
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/safe_base_name.h"
#include "base/strings/string_number_conversions.h"
#include "storage/browser/file_system/file_system_features.h"
#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/gurl.h"
#define FPL FILE_PATH_LITERAL
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
#define DRIVE FPL("C:")
#else
#define DRIVE FPL("/a/")
#endif
constexpr int kBucketId = 1;
namespace storage {
namespace {
FileSystemURL CreateFileSystemURL(const std::string& url_string) {
FileSystemURL url = FileSystemURL::CreateForTest(GURL(url_string));
EXPECT_TRUE(url.type() != kFileSystemTypeExternal &&
url.type() != kFileSystemTypeIsolated);
return url;
}
std::string NormalizedUTF8Path(const base::FilePath& path) {
return path.NormalizePathSeparators().AsUTF8Unsafe();
}
BucketLocator CreateNonDefaultBucket() {
return BucketLocator(
BucketId::FromUnsafeValue(kBucketId),
blink::StorageKey::CreateFromStringForTesting("http://www.example.com/"),
blink::mojom::StorageType::kTemporary, /*is_default=*/false);
}
} // namespace
TEST(FileSystemURLTest, ParsePersistent) {
FileSystemURL url = CreateFileSystemURL(
"filesystem:http://chromium.org/persistent/directory/file");
ASSERT_TRUE(url.is_valid());
EXPECT_EQ("http://chromium.org/", url.origin().GetURL().spec());
EXPECT_EQ(kFileSystemTypePersistent, url.type());
EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
EXPECT_EQ(FPL("directory"), url.path().DirName().value());
}
TEST(FileSystemURLTest, ParseTemporary) {
FileSystemURL url = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/directory/file");
ASSERT_TRUE(url.is_valid());
EXPECT_EQ("http://chromium.org/", url.origin().GetURL().spec());
EXPECT_EQ(kFileSystemTypeTemporary, url.type());
EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
EXPECT_EQ(FPL("directory"), url.path().DirName().value());
}
TEST(FileSystemURLTest, CreateSibling) {
// sibling_name is the common CreateSibling argument used further below.
//
// Another CreateSibling precondition is that the sibling_name is non-empty.
// We don't test for that here because a base::SafeBaseName is designed to be
// non-empty by construction: the base::SafeBaseName::Create factory function
// returns absl::Optional<base::SafeBaseName> not base::SafeBaseName.
//
// See also TODO(crbug.com/1269986)
const base::SafeBaseName sibling_name =
*base::SafeBaseName::Create(FPL("sister"));
// Test the happy case.
{
FileSystemURL original = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/parent/brother");
FileSystemURL sibling = original.CreateSibling(sibling_name);
ASSERT_TRUE(original.is_valid());
ASSERT_TRUE(sibling.is_valid());
EXPECT_EQ("filesystem:http://chromium.org/temporary/parent/sister",
sibling.ToGURL().spec());
EXPECT_EQ("http://chromium.org/", sibling.origin().GetURL().spec());
EXPECT_EQ(kFileSystemTypeTemporary, sibling.type());
EXPECT_FALSE(original.virtual_path().empty());
EXPECT_FALSE(original.path().empty());
EXPECT_FALSE(sibling.virtual_path().empty());
EXPECT_EQ(FPL("parent"),
VirtualPath::DirName(sibling.virtual_path()).value());
EXPECT_EQ(FPL("sister"),
VirtualPath::BaseName(sibling.virtual_path()).value());
EXPECT_FALSE(sibling.path().empty());
EXPECT_EQ(FPL("parent"), sibling.path().DirName().value());
EXPECT_EQ(FPL("sister"), sibling.path().BaseName().value());
}
// Test starting from an empty virtual path (whether by a "" or "/." suffix).
// CreateSibling is also happy here.
const std::string string_forms[] = {
"filesystem:http://chromium.org/temporary",
"filesystem:http://chromium.org/temporary/.",
};
for (const auto& string_form : string_forms) {
FileSystemURL original = CreateFileSystemURL(string_form);
FileSystemURL sibling = original.CreateSibling(sibling_name);
SCOPED_TRACE(testing::Message() << "string_form=" << string_form);
ASSERT_TRUE(original.is_valid());
ASSERT_TRUE(sibling.is_valid());
EXPECT_EQ("filesystem:http://chromium.org/temporary/sister",
sibling.ToGURL().spec());
EXPECT_EQ("http://chromium.org/", sibling.origin().GetURL().spec());
EXPECT_EQ(kFileSystemTypeTemporary, sibling.type());
EXPECT_TRUE(original.virtual_path().empty());
EXPECT_TRUE(original.path().empty());
EXPECT_FALSE(sibling.virtual_path().empty());
EXPECT_EQ(FPL("."), VirtualPath::DirName(sibling.virtual_path()).value());
EXPECT_EQ(FPL("sister"),
VirtualPath::BaseName(sibling.virtual_path()).value());
EXPECT_TRUE(sibling.path().empty());
}
// Test starting from an invalid URL.
{
FileSystemURL original;
FileSystemURL sibling = original.CreateSibling(sibling_name);
EXPECT_FALSE(sibling.is_valid());
}
const base::FilePath::StringType path_pairs[][2] = {
// Empty cracked path.
{FPL(""), FPL("")},
// Absolute cracked paths.
{FPL("/apple"), FPL("/sister")},
{FPL("/banana"), FPL("")},
{FPL("/green/apple"), FPL("/green/sister")},
{FPL("/green/banana"), FPL("")},
{FPL("/its/a/trapple"), FPL("")},
// Relative cracked paths.
{FPL("."), FPL("")},
{FPL("./apple"), FPL("sister")},
{FPL("./banana"), FPL("")},
{FPL("apple"), FPL("sister")},
{FPL("banana"), FPL("")},
{FPL("green/apple"), FPL("green/sister")},
{FPL("green/banana"), FPL("")},
{FPL("its/a/trapple"), FPL("")},
};
for (const auto& path_pair : path_pairs) {
// Interesting CreateForTest arguments, derived from the path_pair.
const base::FilePath virtual_path(FPL("red/apple"));
const base::FilePath cracked_path =
base::FilePath(path_pair[0]).NormalizePathSeparators();
// Non-interesting CreateForTest arguments, independent of path_pair.
const blink::StorageKey storage_key =
blink::StorageKey::CreateFromStringForTesting("http://foo");
const FileSystemType mount_type = kFileSystemTypeExternal;
const std::string mount_filesystem_id = "";
const FileSystemType cracked_type = kFileSystemTypeTest;
const std::string filesystem_id = "";
const FileSystemMountOption mount_option;
SCOPED_TRACE(testing::Message() << "cracked_path=" << cracked_path);
FileSystemURL original = FileSystemURL::CreateForTest(
storage_key, mount_type, virtual_path, mount_filesystem_id,
cracked_type, cracked_path, filesystem_id, mount_option);
FileSystemURL sibling = original.CreateSibling(sibling_name);
// Expected values.
const base::FilePath expected_sibling_path =
base::FilePath(path_pair[1]).NormalizePathSeparators();
const bool expected_sibling_is_valid =
cracked_path.empty() || !expected_sibling_path.empty();
EXPECT_EQ(expected_sibling_is_valid, sibling.is_valid());
EXPECT_EQ(expected_sibling_path, sibling.path());
}
}
TEST(FileSystemURLTest, CreateSiblingPreservesBuckets) {
BucketLocator bucket = CreateNonDefaultBucket();
FileSystemURL a_bucket = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/i/has/a.bucket");
a_bucket.SetBucket(bucket);
FileSystemURL with =
a_bucket.CreateSibling(*base::SafeBaseName::Create(FPL("with")));
FileSystemURL no_bucket = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/i/has/no.bucket");
FileSystemURL without =
no_bucket.CreateSibling(*base::SafeBaseName::Create(FPL("without")));
EXPECT_EQ(with.bucket(), bucket);
EXPECT_EQ(without.bucket(), absl::nullopt);
}
TEST(FileSystemURLTest, EnsureFilePathIsRelative) {
FileSystemURL url = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/////directory/file");
ASSERT_TRUE(url.is_valid());
EXPECT_EQ("http://chromium.org/", url.origin().GetURL().spec());
EXPECT_EQ(kFileSystemTypeTemporary, url.type());
EXPECT_EQ(FPL("file"), VirtualPath::BaseName(url.path()).value());
EXPECT_EQ(FPL("directory"), url.path().DirName().value());
EXPECT_FALSE(url.path().IsAbsolute());
}
TEST(FileSystemURLTest, RejectBadSchemes) {
EXPECT_FALSE(CreateFileSystemURL("http://chromium.org/").is_valid());
EXPECT_FALSE(CreateFileSystemURL("https://chromium.org/").is_valid());
EXPECT_FALSE(CreateFileSystemURL("file:///foo/bar").is_valid());
EXPECT_FALSE(CreateFileSystemURL("foobar:///foo/bar").is_valid());
}
TEST(FileSystemURLTest, UnescapePath) {
FileSystemURL url = CreateFileSystemURL(
"filesystem:http://chromium.org/persistent/%7Echromium/space%20bar");
ASSERT_TRUE(url.is_valid());
EXPECT_EQ(FPL("space bar"), VirtualPath::BaseName(url.path()).value());
EXPECT_EQ(FPL("~chromium"), url.path().DirName().value());
}
TEST(FileSystemURLTest, RejectBadType) {
EXPECT_FALSE(
CreateFileSystemURL("filesystem:http://c.org/foobar/file").is_valid());
EXPECT_FALSE(CreateFileSystemURL("filesystem:http://c.org/temporaryfoo/file")
.is_valid());
}
TEST(FileSystemURLTest, RejectMalformedURL) {
EXPECT_FALSE(CreateFileSystemURL("filesystem:///foobar/file").is_valid());
EXPECT_FALSE(CreateFileSystemURL("filesystem:foobar/file").is_valid());
}
TEST(FileSystemURLTest, CompareURLs) {
const GURL urls[] = {
GURL("filesystem:http://chromium.org/temporary/dir a/file a"),
GURL("filesystem:http://chromium.org/temporary/dir a/file a"),
GURL("filesystem:http://chromium.org/temporary/dir a/file b"),
GURL("filesystem:http://chromium.org/temporary/dir a/file aa"),
GURL("filesystem:http://chromium.org/temporary/dir b/file a"),
GURL("filesystem:http://chromium.org/temporary/dir aa/file b"),
GURL("filesystem:http://chromium.com/temporary/dir a/file a"),
GURL("filesystem:https://chromium.org/temporary/dir a/file a")};
FileSystemURL::Comparator compare;
for (size_t i = 0; i < std::size(urls); ++i) {
for (size_t j = 0; j < std::size(urls); ++j) {
SCOPED_TRACE(testing::Message() << i << " < " << j);
EXPECT_EQ(urls[i] < urls[j],
compare(FileSystemURL::CreateForTest(urls[i]),
FileSystemURL::CreateForTest(urls[j])));
}
}
FileSystemURL a = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/dir a/file a");
FileSystemURL b = CreateFileSystemURL(
"filesystem:http://chromium.org/persistent/dir a/file a");
EXPECT_EQ(a.type() < b.type(), compare(a, b));
EXPECT_EQ(b.type() < a.type(), compare(b, a));
// Testing comparison between FileSystemURLs that have a non-empty,
// non-default bucket value set.
BucketLocator bucket = CreateNonDefaultBucket();
a.SetBucket(bucket);
b.SetBucket(bucket);
// An identical bucket added to each URL does not alter type mismatch.
EXPECT_EQ(a.type() < b.type(), compare(a, b));
// c is a copy of a, just without a bucket value set.
const FileSystemURL c = CreateFileSystemURL(
"filesystem:http://chromium.org/temporary/dir a/file a");
// Ensure that buckets are taken into consideration for comparison.
EXPECT_EQ(a.bucket() < c.bucket(), compare(a, c));
}
TEST(FileSystemURLTest, IsParent) {
const std::string root1 =
GetFileSystemRootURI(GURL("http://example.com"), kFileSystemTypeTemporary)
.spec();
const std::string root2 = GetFileSystemRootURI(GURL("http://example.com"),
kFileSystemTypePersistent)
.spec();
const std::string root3 = GetFileSystemRootURI(GURL("http://chromium.org"),
kFileSystemTypeTemporary)
.spec();
const std::string parent("dir");
const std::string child("dir/child");
const std::string grandchild("dir/child/grandchild");
const std::string other("other");
// True cases.
EXPECT_TRUE(
CreateFileSystemURL(root1).IsParent(CreateFileSystemURL(root1 + parent)));
EXPECT_TRUE(
CreateFileSystemURL(root1).IsParent(CreateFileSystemURL(root1 + child)));
EXPECT_TRUE(CreateFileSystemURL(root1).IsParent(
CreateFileSystemURL(root1 + grandchild)));
EXPECT_TRUE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root1 + child)));
EXPECT_TRUE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root1 + grandchild)));
EXPECT_TRUE(CreateFileSystemURL(root1 + child)
.IsParent(CreateFileSystemURL(root1 + grandchild)));
EXPECT_TRUE(
CreateFileSystemURL(root2).IsParent(CreateFileSystemURL(root2 + parent)));
EXPECT_TRUE(CreateFileSystemURL(root2 + parent)
.IsParent(CreateFileSystemURL(root2 + child)));
EXPECT_TRUE(CreateFileSystemURL(root2 + parent)
.IsParent(CreateFileSystemURL(root2 + grandchild)));
// False cases: the path is not a child.
EXPECT_FALSE(CreateFileSystemURL(root1).IsParent(CreateFileSystemURL(root1)));
EXPECT_FALSE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root1 + other)));
EXPECT_FALSE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root1 + parent)));
EXPECT_FALSE(CreateFileSystemURL(root1 + child)
.IsParent(CreateFileSystemURL(root1 + parent)));
// False case: different types.
EXPECT_FALSE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root2 + child)));
EXPECT_FALSE(
CreateFileSystemURL(root1).IsParent(CreateFileSystemURL(root2 + parent)));
// False case: different origins.
EXPECT_FALSE(CreateFileSystemURL(root1 + parent)
.IsParent(CreateFileSystemURL(root3 + child)));
EXPECT_FALSE(
CreateFileSystemURL(root1).IsParent(CreateFileSystemURL(root3 + parent)));
}
TEST(FileSystemURLTest, ToGURL) {
EXPECT_TRUE(FileSystemURL().ToGURL().is_empty());
const char* kTestURL[] = {
"filesystem:http://chromium.org/persistent/directory/file0",
"filesystem:http://chromium.org/temporary/directory/file1",
"filesystem:http://chromium.org/isolated/directory/file2",
"filesystem:http://chromium.org/external/directory/file2",
"filesystem:http://chromium.org/test/directory/file3",
"filesystem:http://chromium.org/test/plus%2B/space%20/colon%3A",
};
for (const char* url : kTestURL)
EXPECT_EQ(url, FileSystemURL::CreateForTest(GURL(url)).ToGURL().spec());
}
TEST(FileSystemURLTest, DebugString) {
const base::FilePath kPath(FPL("dir/file"));
const FileSystemURL kURL1 = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://example.com"),
kFileSystemTypeTemporary, kPath);
EXPECT_EQ("{ uri: filesystem:http://example.com/temporary/" +
NormalizedUTF8Path(kPath) +
", storage key: " + kURL1.storage_key().GetDebugString() + " }",
kURL1.DebugString());
const FileSystemURL kURL2 = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://example.com"),
kFileSystemTypeLocal, kPath);
EXPECT_EQ("{ path: " + NormalizedUTF8Path(kPath) +
", storage key: " + kURL1.storage_key().GetDebugString() + " }",
kURL2.DebugString());
FileSystemURL kURL3 = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://example.com"),
kFileSystemTypeTemporary, kPath);
kURL3.SetBucket(CreateNonDefaultBucket());
EXPECT_EQ("{ uri: filesystem:http://example.com/temporary/" +
NormalizedUTF8Path(kPath) +
", storage key: " + kURL3.storage_key().GetDebugString() +
", bucket id: " + base::NumberToString(kBucketId) + " }",
kURL3.DebugString());
}
TEST(FileSystemURLTest, IsInSameFileSystem) {
FileSystemURL url_foo_temp_a = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("a"));
FileSystemURL url_foo_temp_b = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("b"));
FileSystemURL url_foo_perm_a = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypePersistent, base::FilePath::FromUTF8Unsafe("a"));
FileSystemURL url_bar_temp_a = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://bar"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("a"));
FileSystemURL url_bar_perm_a = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://bar"),
kFileSystemTypePersistent, base::FilePath::FromUTF8Unsafe("a"));
FileSystemURL url_opaque_a =
FileSystemURL::CreateForTest(blink::StorageKey(), kFileSystemTypeLocal,
base::FilePath::FromUTF8Unsafe("a"));
FileSystemURL url_opaque_b =
FileSystemURL::CreateForTest(blink::StorageKey(), kFileSystemTypeLocal,
base::FilePath::FromUTF8Unsafe("b"));
FileSystemURL url_invalid_a;
FileSystemURL url_invalid_b = url_invalid_a;
EXPECT_TRUE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_a));
EXPECT_TRUE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_b));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_foo_perm_a));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_bar_temp_a));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_bar_perm_a));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_opaque_a));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_opaque_b));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_invalid_a));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_invalid_b));
// Test that non-empty, non-default bucket values are taken into account when
// determining of two URLs are in the same FileSystem.
BucketLocator bucket = CreateNonDefaultBucket();
url_foo_temp_a.SetBucket(bucket);
url_foo_temp_b.SetBucket(bucket);
EXPECT_TRUE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_b));
// url_foo_temp_c is identical to url_foo_temp_a but without a bucket value.
FileSystemURL url_foo_temp_c = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("a"));
EXPECT_FALSE(url_foo_temp_a.IsInSameFileSystem(url_foo_temp_c));
// Test that opaque origins with differing nonces are considered to be in
// the same file system.
EXPECT_NE(url_opaque_a, url_opaque_b);
EXPECT_TRUE(url_opaque_a.IsInSameFileSystem(url_opaque_b));
// Test that identical, invalid URLs are considered not to be in the same
// file system.
EXPECT_EQ(url_invalid_a, url_invalid_b);
EXPECT_FALSE(url_invalid_a.IsInSameFileSystem(url_invalid_b));
}
TEST(FileSystemURLTest, ValidAfterMoves) {
// Move constructor.
{
FileSystemURL original = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("a"));
EXPECT_TRUE(original.is_valid());
FileSystemURL new_url(std::move(original));
EXPECT_TRUE(new_url.is_valid());
EXPECT_TRUE(original.is_valid());
}
// Move operator.
{
FileSystemURL original = FileSystemURL::CreateForTest(
blink::StorageKey::CreateFromStringForTesting("http://foo"),
kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe("a"));
EXPECT_TRUE(original.is_valid());
FileSystemURL new_url;
new_url = std::move(std::move(original));
EXPECT_TRUE(new_url.is_valid());
EXPECT_TRUE(original.is_valid());
}
}
} // namespace storage