// 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 <optional> #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/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. // // Buckets and storage keys are relevant for the kFileSystemTypeTemporary mount // type. // // Cracking is relevant for kFileSystemTypeIsolated and kFileSystemTypeExternal // mount types. // // 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/41454906): 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 { … }; FileSystemURLSet; } // namespace storage #endif // STORAGE_BROWSER_FILE_SYSTEM_FILE_SYSTEM_URL_H_