| // 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 |
| // FileSystemURLs 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 |
| // |
| // FileSystemURLs can wrap (provide an alternative name for) real (kernel |
| // visible) files, virtual files or even other FileSystemURLs. 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) and so its virtual_path() |
| // can 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 be done with |
| // the 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 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(). |
| // |
| // 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 an 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(); |
| |
| // 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); |
| |
| // Returns true if this instance represents a valid FileSystem URL. |
| 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_ |