chromium/components/services/storage/public/mojom/service_worker_storage_control.mojom

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module storage.mojom;

import "components/services/storage/public/mojom/service_worker_database.mojom";
import "components/services/storage/public/mojom/storage_policy_update.mojom";
import "mojo/public/mojom/base/big_buffer.mojom";
import "mojo/public/mojom/base/byte_string.mojom";
import "mojo/public/mojom/base/time.mojom";
import "services/network/public/mojom/url_response_head.mojom";
import "third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom";
import "third_party/blink/public/mojom/storage_key/storage_key.mojom";
import "url/mojom/url.mojom";

// An interface that is used to keep track of which service worker versions are
// being used by clients of the storage service. This is an empty interface that
// is mapped internally by the storage service to a single version.
//
// This is used to decide when it's safe to purge resources for a service worker
// version whose registration has been deleted. A service worker version can be
// still be used and may need to be started and stopped multiple times after
// unregistration. The client of the storage service should hold on to the
// reference as long as it's using the version, i.e., by making the reference
// owned by the C++ ServiceWorkerVersion instance.
interface ServiceWorkerLiveVersionRef {};

// Conveys information about a live service worker version. Sent from the
// browser to the Storage Service to recover resource purging state after a
// Storage Service restart.
struct ServiceWorkerLiveVersionInfo {
  // Version id.
  int64 id;
  // Contains resource ids which are purgeable when `reference` is disconnected.
  // Non-empty only when the associated service worker registration has been
  // deleted from the storage but the corresponding service worker version is
  // still being used.
  array<int64> purgeable_resources;
  // A receiver which is associated with `id`.
  pending_receiver<ServiceWorkerLiveVersionRef> reference;
};

// Conveys a result of finding a registration.
// The Storage Service (components/services/storage) supplies this
// information and the //content consumes the information.
struct ServiceWorkerFindRegistrationResult {
  // A reference to a service worker version associated with
  // |registration->version_id|.
  pending_remote<ServiceWorkerLiveVersionRef> version_reference;
  // Stored registration.
  ServiceWorkerRegistrationData registration;
  // Resources associated with |registration|.
  array<ServiceWorkerResourceRecord> resources;
};

// Used to tell the browser process or embedders if there are registrations
// after ServiceWorkerStorageControl::DeleteRegistration().
enum ServiceWorkerStorageStorageKeyState {
  // Registrations may exist for the StorageKey. It cannot be deleted.
  kKeep,
  // No registrations exist for the StorageKey. It can be deleted.
  kDelete,
};

// An interface that reads a service worker script (resource) to storage.
// This is hosted in the browser process and should be only used from the
// browser process, and relies on the callers to satisfy the calling order
// invariant below.
//
// A valid use of this interface is that
// 1. Exactly one call to ReadResponseHead().
// 2. A call to PrepareReadData() followed by a call to ReadData().
// Step 2 can be repeated multiple times.
// Each call must not be overlapped.
//
// TODO(crbug.com/40858529): Clarify whether we should really support multiple
// `PrepareReadData()` calls.
//
// TODO(crbug.com/40858529): Enforce the calling order requirement. See
// https://chromium-review.googlesource.com/c/chromium/src/+/3823684/comments/fd5170e2_19c5fb5e
interface ServiceWorkerResourceReader {
  // Reads the response head of the resource associated with this reader.
  // |status| is the number of bytes read, or a //net error.
  // Also returns metadata associated with the resource if it exists.
  ReadResponseHead() =>
      (int32 status,
       network.mojom.URLResponseHead? response_head,
       mojo_base.mojom.BigBuffer? metadata);

  // Prepare for reading the content of the resource associated with this
  // reader. `pipe` can be empty when creating a data pipe fails.
  // TODO(crbug.com/40858529): Clarify the meaning of `size` parameter.
  PrepareReadData(int64 size) =>
      (handle<data_pipe_consumer>? pipe);

  // Actually reads the content, and returns when finished.
  // On success, |status| is the number of bytes written.
  // On failure, |status| is a //net error, which is a negative number.
  ReadData() => (int32 status);
};

// An interface that writes a service worker script (resource) to storage.
// A valid use of this interface is that exactly one call to
// WriteResponseHead(), followed by at most one call to WriteData(). These calls
// must not be overlapped.
interface ServiceWorkerResourceWriter {
  // Writes the response head to storage. Returns the number of bytes written,
  // or a //net error.
  WriteResponseHead(network.mojom.URLResponseHead response_head)
      => (int32 status);
  // Writes the content of the resource to storage. Returns the number of bytes
  // written, or a //net error.
  WriteData(mojo_base.mojom.BigBuffer data) => (int32 status);
};

// An interface that writes a metadata (script cache) of a service worker script
// to storage. WriteMetadata() should be called at most once.
interface ServiceWorkerResourceMetadataWriter {
  // Writes the metadata of the resource associated with this writer. Returns
  // the number of bytes written, or a //net error.
  WriteMetadata(mojo_base.mojom.BigBuffer data) => (int32 status);
};

// Represents an entry of user data which is stored with a service worker
// registration. An entry of user data is an arbitrary key-value pair. The
// lifetime of user data is tied up with the registration.
// It will be deleted when the corresponding registration is deleted.
struct ServiceWorkerUserData {
  int64 registration_id;
  string key;
  mojo_base.mojom.ByteString value;
};

// Controls the state of service worker storage within a partition. This is a
// privileged interface and must not be brokered to untrusted clients.
//
// Currently this is consumed and implemented in the browser process, but the
// implementation will eventually live in the Storage Service.
interface ServiceWorkerStorageControl {
  // Disables the storage. The callback is invoked after the storage is
  // disabled.
  Disable() => ();

  // Deletes the whole storage.
  Delete() => (ServiceWorkerDatabaseStatus status);

  // Called by the browser after a Storage Service restart. Tells the Storage
  // Service which service worker versions are being used, which is needed to
  // decide when it's safe to purge resources for service worker versions that
  // have been deleted.
  Recover(array<ServiceWorkerLiveVersionInfo> versions) => ();

  // Returns all StorageKeys which have service worker registrations.
  GetRegisteredStorageKeys() => (array<blink.mojom.StorageKey> keys);

  // Reads a stored registration for `client_url` that is associated
  // with `key`.  `scopes` contains all of the service worker's
  // registration scopes that are relevant to the `key` so that we can
  // cache scope URLs in the UI thread. The 'scopes' is valid only when
  // the status is `kOk` or `kErrorNotFound`. The `scopes` must be
  // optional because `scopes` can be empty if the scope count exceeds
  // the threshold even when there are scopes in DB so that we can avoid
  // sending too large information via mojo API. When this API returns
  // null for `scopes`, the caller of this API can't cache the
  // scopes. This means that the caller needs to fall back to the slow
  // code path that queries the registration from the DB.
  FindRegistrationForClientUrl(url.mojom.Url client_url,
                               blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status,
       ServiceWorkerFindRegistrationResult? result,
       array<url.mojom.Url>? scopes);
  // Reads a stored registration for `scope` that is associated with `key`.
  FindRegistrationForScope(url.mojom.Url scope, blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status,
       ServiceWorkerFindRegistrationResult? result);
  // Reads a stored registration for `registration_id`. `key` is to
  // be used as a hint to look up the registration faster.
  FindRegistrationForId(int64 registration_id, blink.mojom.StorageKey? key) =>
      (ServiceWorkerDatabaseStatus status,
       ServiceWorkerFindRegistrationResult? result);

  // Returns all stored registrations for a given StorageKey.
  GetRegistrationsForStorageKey(blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status,
       array<ServiceWorkerFindRegistrationResult> registrations);

  // Returns the total resource size for a given StorageKey.
  GetUsageForStorageKey(blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status, int64 usage);

  // Returns all stored registrations.
  // NOTE: Don't use this method for new code. Reading all registrations
  // from storage doesn't scale. See https://crbug.com/807440 for details.
  GetAllRegistrationsDeprecated() =>
      (ServiceWorkerDatabaseStatus status,
       array<ServiceWorkerRegistrationData> registrations);

  // Stores |registration_data| and |resources|. If exists, the previous
  // registration for `registration.registration_id` will be deleted when
  // storing succeeds. `deleted_resources_size` carries the total size of
  // deleted resources.
  StoreRegistration(ServiceWorkerRegistrationData registration,
                    array<ServiceWorkerResourceRecord> resources) =>
      (ServiceWorkerDatabaseStatus status, uint64 deleted_resources_size);

  // Deletes the registration specified by `registration_id`.
  // `deleted_resources_size` carries the total size of deleted resources.
  // `storage_key_state` is kDelete if there is no registration for `key` after
  // deletion.
  DeleteRegistration(int64 registration_id, blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status,
       uint64 deleted_resources_size,
       ServiceWorkerStorageStorageKeyState storage_key_state);

  // Updates the state of the registration's stored version to active.
  UpdateToActiveState(int64 registration_id, blink.mojom.StorageKey key) =>
      (ServiceWorkerDatabaseStatus status);
  // Updates the last update check time on the storage.
  UpdateLastUpdateCheckTime(int64 registration_id,
                            blink.mojom.StorageKey key,
                            mojo_base.mojom.Time last_update_check_time) =>
      (ServiceWorkerDatabaseStatus status);
  // Updates the registration's navigation preload enabled flag in storage.
  UpdateNavigationPreloadEnabled(int64 registration_id,
                                 blink.mojom.StorageKey key,
                                 bool enable) =>
      (ServiceWorkerDatabaseStatus status);
  // Updates the registration's navigation preload header in storage.
  UpdateNavigationPreloadHeader(int64 registration_id,
                                blink.mojom.StorageKey key,
                                string value) =>
      (ServiceWorkerDatabaseStatus status);
  // Updates the fetch handler type in storage.
  UpdateFetchHandlerType(int64 registration_id,
                         blink.mojom.StorageKey key,
                         blink.mojom.ServiceWorkerFetchHandlerType type) =>
      (ServiceWorkerDatabaseStatus status);
  // Updates sha256 checksum fields in resource records.
  UpdateResourceSha256Checksums(int64 registratation_id,
                                blink.mojom.StorageKey key,
                                map<int64, string> updated_sha256_checksums) =>
      (ServiceWorkerDatabaseStatus status);
  // Returns a new registration id which is guaranteed to be unique in the
  // storage. Returns blink::mojom::kInvalidServiceWorkerRegistrationId if the
  // storage is disabled.
  GetNewRegistrationId() => (int64 registration_id);
  // Returns a new service worker version id, which is guaranteed to be unique
  // in the storage, and a reference to the version id.
  // blink::mojom::kInvalidServiceWorkerVersionId and null reference are
  // returned if the storage is disabled.
  GetNewVersionId() =>
      (int64 version_id,
       pending_remote<ServiceWorkerLiveVersionRef>? version_reference);
  // Returns a new resource id which is guaranteed to be unique in the storage.
  // Returns blink::mojom::kInvalidServiceWorkerResourceId if the storage
  // is disabled.
  GetNewResourceId() => (int64 resource_id);

  // Creates a resource reader for the given |resource_id|.
  CreateResourceReader(int64 resource_id,
                       pending_receiver<ServiceWorkerResourceReader> reader);
  // Creates a resource writer for the given |resource_id|.
  CreateResourceWriter(int64 resource_id,
                       pending_receiver<ServiceWorkerResourceWriter> writer);
  // Creates a metadata writer for the given |resource_id|.
  CreateResourceMetadataWriter(
      int64 resource_id,
      pending_receiver<ServiceWorkerResourceMetadataWriter> writer);

  // Puts |resource_id| on the uncommitted resource list in storage. Once
  // |resource_id| is put on the uncommitted resource list, the corresponding
  // resource is considered to be existing in storage but it's not associated
  // with any registration yet.
  // StoreRegistration() or DoomUncommittedResources() needs to be
  // called later to clear the |resource_id| from the uncommitted resource list.
  StoreUncommittedResourceId(int64 resource_id) =>
      (ServiceWorkerDatabaseStatus status);

  // Removes |resource_ids| from the uncommitted resource list.
  DoomUncommittedResources(array<int64> resource_ids) =>
      (ServiceWorkerDatabaseStatus status);

  // Gets user data associated with the given |registration_id|.
  // Succeeds only when all keys are found. On success, the size and the order
  // of |values| are the same as |keys|.
  GetUserData(int64 registration_id, array<string> keys) =>
      (ServiceWorkerDatabaseStatus status,
       array<mojo_base.mojom.ByteString> values);
  // Stores `user_data` on persistent storage.
  StoreUserData(int64 registration_id,
                blink.mojom.StorageKey key,
                array<ServiceWorkerUserData> user_data) =>
      (ServiceWorkerDatabaseStatus status);
  // Clears user data specified by |registration_id| and |keys|.
  ClearUserData(int64 registration_id, array<string> keys) =>
      (ServiceWorkerDatabaseStatus status);

  // Gets user data values associated with the given |registration_id|
  // filtered by |key_prefix|.
  GetUserDataByKeyPrefix(int64 registration_id, string key_prefix) =>
      (ServiceWorkerDatabaseStatus status,
       array<mojo_base.mojom.ByteString> values);
  // Gets user data associated with the given |registration_id| filtered by
  // |key_prefix|. Returns user data as key-value pairs.
  GetUserKeysAndDataByKeyPrefix(int64 registration_id, string key_prefix) =>
      (ServiceWorkerDatabaseStatus status,
       map<string, mojo_base.mojom.ByteString> user_data);
  // Clears user data associated with the given |registration_id| filtered by
  // |key_prefix|.
  ClearUserDataByKeyPrefixes(int64 registratation_id,
                             array<string> key_prefixes) =>
      (ServiceWorkerDatabaseStatus status);

  // Gets the user data from all registrations that have user data for |key|.
  GetUserDataForAllRegistrations(string key) =>
      (ServiceWorkerDatabaseStatus status,
       array<ServiceWorkerUserData> values);
  // Gets the user data from all registrations that have user data for
  // |key_prefix| where |key_prefix| is a prefix of keys.
  GetUserDataForAllRegistrationsByKeyPrefix(string key_prefix) =>
      (ServiceWorkerDatabaseStatus status,
       array<ServiceWorkerUserData> values);
  // Clears the user data from all registrations using |key_prefix| as a prefix
  // of keys.
  ClearUserDataForAllRegistrationsByKeyPrefix(string key_prefix) =>
      (ServiceWorkerDatabaseStatus status);

  // Removes traces of deleted data on disk.
  PerformStorageCleanup() => ();

  // Applies changes to data retention policy which are relevant at shutdown.
  // This is analogous to LocalStorageControl::ApplyPolicyUpdates.
  ApplyPolicyUpdates(array<StoragePolicyUpdate> policy_updates) =>
      (ServiceWorkerDatabaseStatus status);

  // Gets resource ids which are scheduled to purge.
  GetPurgingResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
                                     array<int64> resource_ids);

  // Gets resource ids which will be scheduled to purge once the version with
  // the given id is no longer alive.
  GetPurgingResourceIdsForLiveVersionForTest(int64 version_id) =>
      (ServiceWorkerDatabaseStatus status,
      array<int64> resource_ids);

  // Gets resource ids which are purgeable.
  GetPurgeableResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
                                       array<int64> resource_ids);
  // Gets resource ids which are uncommitted.
  GetUncommittedResourceIdsForTest() => (ServiceWorkerDatabaseStatus status,
                                         array<int64> resource_ids);
  // Sets a callback which is executed when purging resources completes.
  // Only a single callback can be set at a time. Overlapped calls are not
  // allowed.
  SetPurgingCompleteCallbackForTest() => ();
};