[go: nahoru, domu]

blob: df45f4942a8120546c048fcb97cac470b2806ed9 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_URL_H_
#define STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_URL_H_
#include <set>
#include <string>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "storage/common/file_system/file_system_mount_option.h"
#include "storage/common/file_system/file_system_types.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/gurl.h"
namespace storage {
// The equivalent of a file path, but for the virtual file systems that this
// C++ API serves. `storage::FileSystemContext::CreateFileStreamReader` takes a
// `storage::FileSystemURL` argument the same way that fopen takes a file path.
//
//
// # Historical Usage
//
// Originally (https://www.w3.org/TR/2012/WD-file-system-api-20120417/ is from
// 2012), a `FileSystemURL` (the C++ object) represented a URL whose scheme was
// "filesystem" (instead of e.g. "http", "file" or "data").
//
// For example, running this JavaScript
// (https://gist.github.com/miketaylr/df58ae669abc4eec1b514f4cfc71fc21) on
// https://example.com could produce
// "filesystem:https://example.com/temporary/coolguy.txt"
// which you could navigate to in the browser.
//
// Apart from some colons and slashes, this URL string literally concatenates:
// - a scheme, "filesystem".
// - an origin, "https://example.com".
// - a mount type, "temporary".
// - a relative path, also called a virtual path, "coolguy.txt". This example
// has no slashes but, in general, the relative path could be "a/b/c.dat".
//
// The C++ object (in 2012) was basically just those fields:
// https://chromiumcodereview.appspot.com/10566002/diff/18001/webkit/fileapi/file_system_url.h
//
// Note that the "File System" and "File System Entry" JS APIs are different to
// the similarly named but more recent "File System Access" JS API. Similarly,
// "filesystem:etc" URLs are not the same as "file:etc" URLs.
//
//
// # Evolution
//
// The C++ object has gained additional fields since then:
// - its optional `BucketLocator` configures partitioned storage.
// - its 'origin' has grown from an `url::Origin` to be a `blink::StorageKey`.
// The distinction can matter for web pages containing third-party iframes.
// - see the "Cracking" section, below.
//
// This extra data isn't part of the string form. Creating a `FileSystemURL`
// (from a factory method) and then optionally calling its setter methods
// (`SetBucket`) fills in these other fields. Converting such a `FileSystemURL`
// back to string form can lose information.
//
//
// # Current Usage
//
// Third party JavaScript can obtain a `FileSystemURL` (in string form) by
// calling the `FileSystemEntry.toURL()` JavaScript API.
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry/toURL
//
// Per that mozilla.org page, its use (in web-facing JS) is deprecated in favor
// of the "File System Access" API.
//
// Outside of web-facing JS, Chrome and particularly ChromeOS still uses
// `FileSystemURL`s internally (as C++ objects) to be 'virtual file paths' in
// its virtual file systems. But serialization to and from the string or `GURL`
// form (and subsequent sharing with JS code) is a legacy concept. The "URL" in
// the "FileSystemURL" class name is part of its history but now inaccurate.
//
//
// # Cracking
//
// `FileSystemURL`s can wrap (provide an alternative name for) real (kernel
// visible) files, virtual files or even other `FileSystemURL`s. Cracking is
// the process of recursively unwrapping the outer layers to recover a name or
// identifier for the underlying, inner-most resource.
//
// Cracking is a concept at the C++ API level but is not part of the JS API. It
// applies when the original URL's `mount_type()` identifies a `MountPoints`
// subclass (`ExternalMountPoints` or `IsolatedContext`); its `virtual_path()`
// can then be further resolved to a lower level `type()` and `path()`.
//
// When recursion occurs, also known as having multiple rounds of cracking,
// then `mount_filesystem_id()` and `filesystem_id()` return information from
// the outer-most (first round) and inner-most (last round). If there is only
// one round of cracking then the two strings should be equal. When cracking
// does not apply then these strings should be empty.
//
// Permission checking on the top-level mount information should use
// `mount_filesystem_id()`. Low-level operations should use `filesystem_id()`,
// as well as the `type()`, `path()` and `mount_option()` that also come from
// the last round of cracking.
//
// Cracking is done at `FileSystemURL`-constructor time, although the
// non-trivial `FileSystemURL` constructors are private. Outside of test code,
// use the `<Friend>::CrackURL` or `<Friend>::CreateCrackedFileSystemURL`
// factory methods, where `<Friend>` is one of the friended classes.
//
//
// # Accessors
//
// For example, parsing "filesystem:http://example.com/temporary/bar/qux":
// - `origin()` returns "http://example.com"
// - `mount_type()` returns kFileSystemTypeTemporary
// - `virtual_path()` returns "bar/qux"
// - `type()` returns the same value as `mount_type()`
// - `path()` returns the same value as `virtual_path()`
//
// For example, if path "/media/removable" is mounted at "my_mount_name" with
// type kFileSystemTypeFoo as an external file system, then parsing and
// cracking "filesystem:chrome://file-manager/external/my_mount_name/x/y":
// - `origin()` returns "chrome://file-manager"
// - `mount_type()` returns kFileSystemTypeExternal
// - `virtual_path()` returns "my_mount_name/x/y"
// - `type()` returns the kFileSystemTypeFoo
// - `path()` returns "/media/removable/x/y"
//
// Additionally:
// - `filesystem_id()` returns "my_mount_name".
//
// The naming is unfortunate, but URL paths (what `GURL::path()` returns) are
// not the same as what `FileSystemURL::path()` returns. The latter is not
// necessarily a 'substring' of the `FileSystemURL`'s string form.
// `FileSystemURL::path()` often locates a real file on the kernel-level file
// system but it does not have to and sometimes it's just a string identifier
// (presented in C++ as a `base::FilePath`) whose meaning depends on the
// `FileSystemURL::type()`. See the `TypeImpliesPathIsReal()` method.
//
// For example, `kFileSystemTypeProvided` (which corresponds to the
// https://developer.chrome.com/docs/extensions/reference/fileSystemProvider/
// JS API) does not serve real files. For that type, `path()` returns something
// like "/provided/extensionid:filesystemid:userhash/a/b/c.txt", where
// "/provided" is `ash::file_system_provider::util::kProvidedMountPointRoot`.
// The serving code path goes through the `ExternalMountPoints` class, but
// there's no "provided" directory in the root of the real file system.
//
//
// # Known Issues
//
// TODO(crbug.com/956231): Look into making `virtual_path()` [and all
// FileSystem API virtual paths] just a `std::string`, to prevent platform-
// specific `base::FilePath` behavior from getting invoked by accident.
// Currently the `base::FilePath` returned here needs special treatment, as it
// may contain paths that are illegal on the current platform.
//
// To avoid problems, use `VirtualPath::BaseName` and
// `VirtualPath::GetComponents` instead of the `base::FilePath` methods.
class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemURL {
public:
FileSystemURL();
FileSystemURL(const FileSystemURL&);
FileSystemURL(FileSystemURL&&) noexcept;
FileSystemURL& operator=(const FileSystemURL&);
FileSystemURL& operator=(FileSystemURL&&) noexcept;
~FileSystemURL();
// Returns a new `FileSystemURL` that is a sibling (it has the same parent
// directory) to this one. Starting from "filesystem:etc/foo/bar", it
// produces "filesystem:etc/foo/sibling_name".
//
// Its `virtual_path()` and `path()` are derived from this `FileSystemURL`'s
// `virtual_path()` and `path()`, with the base names changed over. The
// `path()` is unchanged if empty. All other fields (whether parsed from the
// URL string form or obtained from cracking) are copied from this.
//
// It returns an invalid `FileSystemURL` if `!is_valid()` or if `path()` is
// non-empty and its base name does not match the `virtual_path()` base name.
FileSystemURL CreateSibling(const base::SafeBaseName& sibling_name) const;
// Methods for creating `FileSystemURL` without attempting to crack them.
// Should be used only in tests.
static FileSystemURL CreateForTest(const GURL& url);
static FileSystemURL CreateForTest(const blink::StorageKey& storage_key,
FileSystemType mount_type,
const base::FilePath& virtual_path);
static FileSystemURL CreateForTest(const blink::StorageKey& storage_key,
FileSystemType mount_type,
const base::FilePath& virtual_path,
const std::string& mount_filesystem_id,
FileSystemType cracked_type,
const base::FilePath& cracked_path,
const std::string& filesystem_id,
const FileSystemMountOption& mount_option);
// Whether a `FileSystemURL`'s `path()` refers to a real (kernel visible, can
// be passed to https://man7.org/linux/man-pages/man2/open.2.html) file,
// instead of being a string identifier in `base::FilePath` clothing.
//
// Must be called on a `FileSystemURL`'s `type()`. Do not call this method
// with a `mount_type()`.
static bool TypeImpliesPathIsReal(FileSystemType type);
// Instance method is provided for convenience.
bool TypeImpliesPathIsReal() const { return TypeImpliesPathIsReal(type()); }
// Returns true if this instance represents a valid `FileSystemURL`.
bool is_valid() const { return is_valid_; }
// Returns the storage key. See the class comment for details.
const blink::StorageKey& storage_key() const { return storage_key_; }
// Returns the origin part of this URL. See the class comment for details.
const url::Origin& origin() const { return storage_key_.origin(); }
// Returns the type part of this URL. See the class comment for details.
FileSystemType type() const { return type_; }
// Returns the cracked path of this URL. See the class comment for details.
const base::FilePath& path() const { return path_; }
// Returns the original path part of this URL.
// See the class comment for details.
// TODO(crbug.com/956231): this must return std::string.
const base::FilePath& virtual_path() const { return virtual_path_; }
// Returns the filesystem ID/mount name for isolated/external filesystem URLs.
// See the class comment for details.
const std::string& filesystem_id() const { return filesystem_id_; }
const std::string& mount_filesystem_id() const {
return mount_filesystem_id_;
}
FileSystemType mount_type() const { return mount_type_; }
const FileSystemMountOption& mount_option() const { return mount_option_; }
// Returns the `BucketLocator` for this URL's partitioned file location. In
// the majority of cases, this will not be populated and the default storage
// bucket will be used.
const absl::optional<BucketLocator>& bucket() const { return bucket_; }
void SetBucket(const BucketLocator& bucket) { bucket_ = bucket; }
// Returns either `bucket_` or a `BucketLocator` corresponding to the default
// bucket for `storage_key_`.
BucketLocator GetBucket() const;
// Returns the formatted URL of this instance.
GURL ToGURL() const;
std::string DebugString() const;
// Returns true if this URL is a strict parent of the `child`.
bool IsParent(const FileSystemURL& child) const;
bool IsInSameFileSystem(const FileSystemURL& other) const;
bool operator==(const FileSystemURL& that) const;
bool operator!=(const FileSystemURL& that) const { return !(*this == that); }
struct COMPONENT_EXPORT(STORAGE_BROWSER) Comparator {
bool operator()(const FileSystemURL& lhs, const FileSystemURL& rhs) const;
};
private:
friend class FileSystemContext;
friend class ExternalMountPoints;
friend class IsolatedContext;
FileSystemURL(const GURL& filesystem_url,
const blink::StorageKey& storage_key);
FileSystemURL(const blink::StorageKey& storage_key,
FileSystemType mount_type,
const base::FilePath& virtual_path);
// Creates a cracked `FileSystemURL`.
FileSystemURL(const blink::StorageKey& storage_key,
FileSystemType mount_type,
const base::FilePath& virtual_path,
const std::string& mount_filesystem_id,
FileSystemType cracked_type,
const base::FilePath& cracked_path,
const std::string& filesystem_id,
const FileSystemMountOption& mount_option);
// Used to determine if a `FileSystemURL` was default constructed.
bool is_null_ = false;
bool is_valid_;
// Fields parsed from the original URL (the string form), although the
// `url::Origin` has grown into a `blink::StorageKey`.
blink::StorageKey storage_key_;
FileSystemType mount_type_;
base::FilePath virtual_path_;
// Fields obtained from cracking.
//
// `mount_filesystem_id_` is set from the first round of cracking. The other
// fields are set from recursive cracking (the last round).
std::string mount_filesystem_id_;
FileSystemType type_;
base::FilePath path_;
std::string filesystem_id_;
FileSystemMountOption mount_option_;
// Fields that must be explicitly set separately.
absl::optional<BucketLocator> bucket_;
};
using FileSystemURLSet = std::set<FileSystemURL, FileSystemURL::Comparator>;
} // namespace storage
#endif // STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_URL_H_