chromium/storage/browser/file_system/file_system_url.h

// 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_