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
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260

content / browser / worker_host / worker_script_fetcher.h [blame]

// Copyright 2018 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_WORKER_HOST_WORKER_SCRIPT_FETCHER_H_
#define CONTENT_BROWSER_WORKER_HOST_WORKER_SCRIPT_FETCHER_H_

#include <optional>

#include "base/functional/callback.h"
#include "content/browser/renderer_host/policy_container_host.h"
#include "content/common/content_export.h"
#include "content/public/browser/service_worker_client_info.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/storage_access_api/status.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/client_security_state.mojom-forward.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h"
#include "third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom.h"

namespace net {
class IsolationInfo;
class SiteForCookies;
}  // namespace net

namespace network {
struct ResourceRequest;
}  // namespace network

namespace blink {
class PendingURLLoaderFactoryBundle;
class StorageKey;
class ThrottlingURLLoader;
class URLLoaderThrottle;
}  // namespace blink

namespace content {

class DevToolsAgentHostImpl;
class RenderFrameHostImpl;
class ServiceWorkerContextWrapper;
class ServiceWorkerMainResourceHandle;
class StoragePartitionImpl;
class WorkerScriptLoaderFactory;

// Contains the result of successful worker script fetch. On fetch failure,
// `std::nullopt` is used instead.
struct CONTENT_EXPORT WorkerScriptFetcherResult final {
  WorkerScriptFetcherResult(
      std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
          subresource_loader_factories,
      blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
      PolicyContainerPolicies policy_container_policies,
      const GURL& final_response_url);
  ~WorkerScriptFetcherResult();

  WorkerScriptFetcherResult(WorkerScriptFetcherResult&& other);
  WorkerScriptFetcherResult& operator=(WorkerScriptFetcherResult&& other);

  // Sent to the renderer process and is to be used to request subresources
  // where applicable. For example, this allows the dedicated worker to load
  // chrome-extension:// URLs which the renderer's default loader factory can't
  // load.
  std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
      subresource_loader_factories;

  // Sent to the renderer process and to be used to load the worker main script
  // pre-requested by the browser process.
  // Always non-null and contains `response_head` and
  // `response_head->parsed_headers`.
  blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params;

  PolicyContainerPolicies policy_container_policies;

  // The script response URL.
  // https://fetch.spec.whatwg.org/#concept-response-url
  GURL final_response_url;
};

// NetworkService (PlzWorker):
// This is an implementation of the URLLoaderClient for web worker's main script
// fetch. The loader and client bounded with this class are to be unbound and
// forwarded to the renderer process on OnReceiveResponse, and the
// resource loader in the renderer process will take them over.
//
// WorkerScriptFetcher deletes itself when the ownership of the loader and
// client is passed to the renderer, or on failure. It lives on the UI
// thread.
// TODO(asamidoi): Remove the manual memory management like `delete this` and
// use `unique_ptr` to create WorkerScriptFetcher in a caller side.
class WorkerScriptFetcher : public network::mojom::URLLoaderClient {
 public:
  // Called with the result of fetching a script upon response received.
  using CompletionCallback =
      base::OnceCallback<void(std::optional<WorkerScriptFetcherResult>)>;

  // Used for specifying how URLLoaderFactoryBundle is used.
  enum class LoaderType { kMainResource, kSubResource };

  // Initiates a browser-side worker script fetch.
  // Creates a `WorkerScriptFetcher` and starts it.
  //
  // Must be called on the UI thread.
  //
  // - `ancestor_render_frame_host` points to the ancestor frame. If
  //   the worker being created is nested, then this is the ancestor of the
  //   creator worker. Otherwise, this is the creator frame. Cannot be nullptr.
  //   For dedicated workers, when the lifetime of the `DedicatedWorkerHost`
  //   does not exactly align with the parents, and they are destroyed
  //   asynchronously via mojo by the time the fetch is about to start,
  //   this method must not be called.
  // - `creator_render_frame_host` points to the creator frame, if any. May
  //   be nullptr if the worker being created is a nested dedicated worker.
  //   Since nested shared workers are not supported, for shared workers
  //   `ancestor_render_frame_host` and `creator_render_frame_host` are always
  //   equal.
  // - `client_security_state` specifies parameters to be passed to the network
  //   service `URLLoaderFactory`, for use when loading the script. It must not
  //   be nullptr.
  // - `callback` will be called with the result on the UI thread.
  static void CreateAndStart(
      int worker_process_id,
      const DedicatedOrSharedWorkerToken& worker_token,
      const GURL& initial_request_url,
      RenderFrameHostImpl& ancestor_render_frame_host,
      RenderFrameHostImpl* creator_render_frame_host,
      const net::SiteForCookies& site_for_cookies,
      const url::Origin& request_initiator,
      const blink::StorageKey& request_initiator_storage_key,
      const net::IsolationInfo& trusted_isolation_info,
      network::mojom::ClientSecurityStatePtr client_security_state,
      network::mojom::CredentialsMode credentials_mode,
      blink::mojom::FetchClientSettingsObjectPtr
          outside_fetch_client_settings_object,
      network::mojom::RequestDestination request_destination,
      scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
      ServiceWorkerMainResourceHandle* service_worker_handle,
      scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
      scoped_refptr<network::SharedURLLoaderFactory>
          url_loader_factory_override,
      StoragePartitionImpl* storage_partition,
      const std::string& storage_domain,
      DevToolsAgentHostImpl* devtools_agent_host,
      const base::UnguessableToken& devtools_worker_token,
      bool require_cross_site_request_for_cookies,
      net::StorageAccessApiStatus storage_access_api_status,
      CompletionCallback callback);

  // Creates a loader factory bundle. Must be called on the UI thread. For
  // nested workers, |creator_render_frame_host| can be null.
  static std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
  CreateFactoryBundle(LoaderType loader_type,
                      int worker_process_id,
                      StoragePartitionImpl* storage_partition,
                      const std::string& storage_domain,
                      bool file_support,
                      bool filesystem_url_support,
                      RenderFrameHostImpl* creator_render_frame_host,
                      const blink::StorageKey& request_initiator_storage_key);

  // Calculates the final response URL from the redirect chain, URLs fetched by
  // the service worker and the initial request URL. The logic is mostly based
  // on what blink::ResourceResponse::ResponseUrl() does.
  //
  // Exposed for testing.
  CONTENT_EXPORT static GURL DetermineFinalResponseUrl(
      const GURL& initial_request_url,
      blink::mojom::WorkerMainScriptLoadParams* main_script_load_params);

 private:
  // Callback invoked by this instance when the load ends, successfully or not.
  //
  // In case of success:
  //
  // - `main_script_load_params` is not nullptr.
  // - `completion_status` is nullptr.
  //
  // In case of error:
  //
  // - `main_script_load_params` is nullptr.
  // - `completion_status` is not nullptr.
  using CreateAndStartCallback = base::OnceCallback<void(
      blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
      const network::URLLoaderCompletionStatus* completion_status)>;

  WorkerScriptFetcher(
      std::unique_ptr<WorkerScriptLoaderFactory> script_loader_factory,
      std::unique_ptr<network::ResourceRequest> resource_request,
      CreateAndStartCallback callback);

  ~WorkerScriptFetcher() override;

  // Helper for `CreateAndStart()`.
  static void CreateScriptLoader(
      int worker_process_id,
      const DedicatedOrSharedWorkerToken& worker_token,
      const GURL& initial_request_url,
      RenderFrameHostImpl& ancestor_render_frame_host,
      RenderFrameHostImpl* creator_render_frame_host,
      const net::IsolationInfo& trusted_isolation_info,
      network::mojom::ClientSecurityStatePtr client_security_state,
      std::unique_ptr<network::ResourceRequest> resource_request,
      std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
          factory_bundle_for_browser_info,
      std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
          subresource_loader_factories,
      scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
      ServiceWorkerMainResourceHandle* service_worker_handle,
      scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
      scoped_refptr<network::SharedURLLoaderFactory>
          url_loader_factory_override,
      DevToolsAgentHostImpl* devtools_agent_host,
      const base::UnguessableToken& devtools_worker_token,
      bool require_cross_site_request_for_cookies,
      WorkerScriptFetcher::CompletionCallback callback);

  void Start(std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles);

  // network::mojom::URLLoaderClient
  void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
  void OnReceiveResponse(
      network::mojom::URLResponseHeadPtr head,
      mojo::ScopedDataPipeConsumerHandle body,
      std::optional<mojo_base::BigBuffer> cached_metadata) override;
  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                         network::mojom::URLResponseHeadPtr head) override;
  void OnUploadProgress(int64_t current_position,
                        int64_t total_size,
                        OnUploadProgressCallback callback) override;
  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
  void OnComplete(const network::URLLoaderCompletionStatus& status) override;

  void DidParseHeaders(network::mojom::ParsedHeadersPtr parsed_headers);

  std::unique_ptr<WorkerScriptLoaderFactory> script_loader_factory_;

  // Request ID for a browser-initiated request.
  const int request_id_;

  std::unique_ptr<network::ResourceRequest> resource_request_;
  CreateAndStartCallback callback_;

  // URLLoader instance backed by a request interceptor or the network service.
  std::unique_ptr<blink::ThrottlingURLLoader> url_loader_;

  blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params_;

  std::vector<net::RedirectInfo> redirect_infos_;
  std::vector<network::mojom::URLResponseHeadPtr> redirect_response_heads_;

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

}  // namespace content

#endif  // CONTENT_BROWSER_WORKER_HOST_WORKER_SCRIPT_FETCHER_H_