1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241

content / browser / service_worker / service_worker_register_job.h [blame]

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

#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_register_job_base.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_update_checker.h"
#include "content/public/browser/global_routing_id.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_ancestor_frame_type.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom-forward.h"
#include "third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom.h"
#include "url/gurl.h"

namespace content {

class ServiceWorkerNewScriptFetcher;

// Handles the initial registration of a Service Worker and the
// subsequent update of existing registrations.
//
// The control flow includes most or all of the following,
// depending on what is already registered:
//  - creating a ServiceWorkerRegistration instance if there isn't
//    already something registered
//  - creating a ServiceWorkerVersion for the new version.
//  - starting a worker for the ServiceWorkerVersion
//  - firing the 'install' event at the ServiceWorkerVersion
//  - firing the 'activate' event at the ServiceWorkerVersion
//  - waiting for older ServiceWorkerVersions to deactivate
//  - designating the new version to be the 'active' version
//  - updating storage
class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
 public:
  typedef base::OnceCallback<void(blink::ServiceWorkerStatusCode status,
                                  const std::string& status_message,
                                  ServiceWorkerRegistration* registration)>
      RegistrationCallback;

  // For registration jobs.
  ServiceWorkerRegisterJob(
      ServiceWorkerContextCore* context,
      const GURL& script_url,
      const blink::mojom::ServiceWorkerRegistrationOptions& options,
      const blink::StorageKey& key,
      blink::mojom::FetchClientSettingsObjectPtr
          outside_fetch_client_settings_object,
      const GlobalRenderFrameHostId& requesting_frame_id,
      blink::mojom::AncestorFrameType ancestor_frame_type,
      PolicyContainerPolicies policy_container_policies);

  // For update jobs.
  ServiceWorkerRegisterJob(ServiceWorkerContextCore* context,
                           ServiceWorkerRegistration* registration,
                           bool force_bypass_cache,
                           bool skip_script_comparison,
                           blink::mojom::FetchClientSettingsObjectPtr
                               outside_fetch_client_settings_object);

  ServiceWorkerRegisterJob(const ServiceWorkerRegisterJob&) = delete;
  ServiceWorkerRegisterJob& operator=(const ServiceWorkerRegisterJob&) = delete;

  ~ServiceWorkerRegisterJob() override;

  // Registers a callback to be called when the promise would resolve (whether
  // successfully or not). Multiple callbacks may be registered.
  void AddCallback(RegistrationCallback callback);

  // ServiceWorkerRegisterJobBase implementation:
  void Start() override;
  void Abort() override;
  bool Equals(ServiceWorkerRegisterJobBase* job) const override;
  RegistrationJobType GetType() const override;

  void DoomInstallingWorker();

 private:
  enum Phase {
    INITIAL,
    START,
    REGISTER,
    UPDATE,
    INSTALL,
    STORE,
    COMPLETE,
    ABORT,
  };

  // Holds internal state of ServiceWorkerRegistrationJob, to compel use of the
  // getter/setter functions.
  struct Internal {
    Internal();
    ~Internal();
    scoped_refptr<ServiceWorkerRegistration> registration;

    // Holds the version created by this job. It can be the 'installing',
    // 'waiting', or 'active' version depending on the phase.
    scoped_refptr<ServiceWorkerVersion> new_version;
  };

  void set_registration(scoped_refptr<ServiceWorkerRegistration> registration);
  ServiceWorkerRegistration* registration() const;
  void set_new_version(scoped_refptr<ServiceWorkerVersion> version);
  ServiceWorkerVersion* new_version();

  void SetPhase(Phase phase);

  void StartImpl();
  void ContinueWithRegistration(
      blink::ServiceWorkerStatusCode status,
      scoped_refptr<ServiceWorkerRegistration> registration);
  void ContinueWithUpdate(
      blink::ServiceWorkerStatusCode status,
      scoped_refptr<ServiceWorkerRegistration> registration);

  bool IsUpdateCheckNeeded() const;

  // Refer ServiceWorkerUpdateChecker::UpdateStatusCallback for the meaning of
  // the parameters.
  void OnUpdateCheckFinished(
      ServiceWorkerSingleScriptUpdateChecker::Result result,
      std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker::FailureInfo>
          failure_info,
      // TODO(crbug.com/40241479): `updated_sha256_script_checksums` will be
      // used in a follow-up CL.
      const std::map<GURL, std::string>& updated_sha256_script_checksums);

  void RegisterAndContinue();
  void ContinueWithNewRegistration(
      scoped_refptr<ServiceWorkerRegistration> new_registration);
  void ContinueWithUninstallingRegistration(
      scoped_refptr<ServiceWorkerRegistration> existing_registration,
      blink::ServiceWorkerStatusCode status);
  void ContinueWithRegistrationWithSameRegistrationOptions(
      scoped_refptr<ServiceWorkerRegistration> existing_registration,
      blink::ServiceWorkerStatusCode status);
  void UpdateAndContinue();

  // With PlzServiceWorker, we start fetching the script before starting the
  // worker. The 3 functions below represent the expected order of execution
  // in this process:
  // - Devtools might decide it wants to auto-attach to new targets and to start
  //   intercepting messages before the fetch starts. If so it needs to start
  //   some handlers asynchronously. We pass down to the handlers a "throttle"
  //   that can resume script fetching via a callback when ready.
  // - We create a factory and a pass it to a ServiceWorkerNewScriptFetcher.
  //   Once the script fetch succeeded (or failed), it calls into the final
  //   step.
  // - We inspect the response, determine if its a failure or not and update
  //   state. If successful we start the worker with load parameters returned by
  //   the ServiceWorkerNewScriptFetcher.
  void MaybeThrottleForDevToolsBeforeStartingScriptFetch(
      scoped_refptr<ServiceWorkerVersion> version);
  void StartScriptFetchForNewWorker(
      scoped_refptr<ServiceWorkerVersion> version);
  void OnScriptFetchCompleted(
      scoped_refptr<ServiceWorkerVersion> version,
      blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params);

  // Starts a service worker for [[Update]]. The script comparison has finished
  // at this point. It starts install phase.
  void StartWorkerForUpdate(scoped_refptr<ServiceWorkerVersion> version);
  void OnStartWorkerFinished(blink::ServiceWorkerStatusCode status);
  void OnStoreRegistrationComplete(blink::ServiceWorkerStatusCode status);
  void InstallAndContinue();
  void DispatchInstallEvent(blink::ServiceWorkerStatusCode start_worker_status);
  void OnInstallFinished(int request_id,
                         blink::mojom::ServiceWorkerEventStatus event_status,
                         uint32_t fetch_count);
  void OnInstallFailed(uint32_t fetch_count,
                       blink::ServiceWorkerStatusCode status);
  void Complete(blink::ServiceWorkerStatusCode status);
  void Complete(blink::ServiceWorkerStatusCode status,
                const std::string& status_message);
  void CompleteInternal(blink::ServiceWorkerStatusCode status,
                        const std::string& status_message);
  void ResolvePromise(blink::ServiceWorkerStatusCode status,
                      const std::string& status_message,
                      ServiceWorkerRegistration* registration);

  void AddRegistrationToMatchingContainerHosts(
      ServiceWorkerRegistration* registration);

  void OnPausedAfterDownload();

  void BumpLastUpdateCheckTimeIfNeeded();

  // The ServiceWorkerContextCore object must outlive this.
  const raw_ptr<ServiceWorkerContextCore> context_;

  // Valid when the worker is being updated.
  std::unique_ptr<ServiceWorkerUpdateChecker> update_checker_;
  // Valid when the worker is new.
  std::unique_ptr<ServiceWorkerNewScriptFetcher> new_script_fetcher_;

  RegistrationJobType job_type_;
  const GURL scope_;
  GURL script_url_;
  const blink::StorageKey key_;
  // "A job has a worker type ("classic" or "module")."
  // https://w3c.github.io/ServiceWorker/#dfn-job-worker-type
  blink::mojom::ScriptType worker_script_type_ =
      blink::mojom::ScriptType::kClassic;
  const blink::mojom::ServiceWorkerUpdateViaCache update_via_cache_;
  // "A job has a client (a service worker client). It is initially null."
  // https://w3c.github.io/ServiceWorker/#dfn-job-client
  // This fetch client settings object roughly corresponds to the job's client.
  blink::mojom::FetchClientSettingsObjectPtr
      outside_fetch_client_settings_object_;
  std::vector<RegistrationCallback> callbacks_;
  Phase phase_;
  Internal internal_;
  bool is_promise_resolved_;
  bool should_uninstall_on_failure_;
  bool force_bypass_cache_;
  bool skip_script_comparison_;
  blink::ServiceWorkerStatusCode promise_resolved_status_;
  std::string promise_resolved_status_message_;
  scoped_refptr<ServiceWorkerRegistration> promise_resolved_registration_;
  const GlobalRenderFrameHostId requesting_frame_id_;
  const blink::mojom::AncestorFrameType ancestor_frame_type_;
  PolicyContainerPolicies creator_policy_container_policies_;

  base::WeakPtrFactory<ServiceWorkerRegisterJob> weak_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTER_JOB_H_