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 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
|
// Copyright 2017 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_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_
#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_
#include <optional>
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/task/sequenced_task_runner.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/forwarded_race_network_request_url_loader_factory.h"
#include "content/common/service_worker/race_network_request_url_loader_client.h"
#include "content/common/service_worker/service_worker_resource_loader.h"
#include "content/common/service_worker/service_worker_router_evaluator.h"
#include "content/renderer/service_worker/controller_service_worker_connector.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-forward.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_fetch_response_callback.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_stream_handle.mojom-forward.h"
namespace network {
class SharedURLLoaderFactory;
} // namespace network
namespace content {
class ControllerServiceWorkerConnector;
class ServiceWorkerSubresourceLoaderFactory;
// A custom URLLoader implementation used by Service Worker controllees
// for loading subresources via the controller Service Worker.
// Currently an instance of this class is created and used only on
// the main thread (while the implementation itself is thread agnostic).
class CONTENT_EXPORT ServiceWorkerSubresourceLoader
: public network::mojom::URLLoader,
public blink::mojom::ServiceWorkerFetchResponseCallback,
public ControllerServiceWorkerConnector::Observer,
public ServiceWorkerResourceLoader {
public:
// See the comments for ServiceWorkerSubresourceLoaderFactory's ctor (below)
// to see how each parameter is used.
ServiceWorkerSubresourceLoader(
mojo::PendingReceiver<network::mojom::URLLoader>,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<ServiceWorkerSubresourceLoaderFactory>
service_worker_subresource_loader_factory);
ServiceWorkerSubresourceLoader(const ServiceWorkerSubresourceLoader&) =
delete;
ServiceWorkerSubresourceLoader& operator=(
const ServiceWorkerSubresourceLoader&) = delete;
~ServiceWorkerSubresourceLoader() override;
// ControllerServiceWorkerConnector::Observer overrides:
void OnConnectionClosed() override;
private:
class StreamWaiter;
enum class Status {
kNotStarted,
// |binding_| is bound and the fetch event is being dispatched to the
// service worker.
kStarted,
// A redirect happened, waiting for FollowRedirect().
kSentRedirect,
// The data pipe for the response body has been sent to
// |url_loader_client_|. The body is being written to the pipe.
kSentBody,
// OnComplete() was called on |url_loader_client_|, or fallback to network
// occurred so the request was not handled.
kCompleted,
};
void OnMojoDisconnect();
void StartRequest(const network::ResourceRequest& resource_request);
void DispatchFetchEvent();
void DispatchFetchEventForSubresource();
void OnFetchEventFinished(blink::mojom::ServiceWorkerEventStatus status);
// Called when this loader no longer needs to restart dispatching the fetch
// event on failure. Null |status| means the event dispatch was not attempted.
void SettleFetchEventDispatch(
std::optional<blink::ServiceWorkerStatusCode> status);
// blink::mojom::ServiceWorkerFetchResponseCallback overrides:
void OnResponse(
blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void OnResponseStream(
blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void OnFallback(
std::optional<network::DataElementChunkedDataPipe> request_body,
blink::mojom::ServiceWorkerFetchEventTimingPtr timing) override;
void UpdateResponseTiming(
blink::mojom::ServiceWorkerFetchEventTimingPtr timing);
void StartResponse(blink::mojom::FetchAPIResponsePtr response,
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream);
// network::mojom::URLLoader overrides:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const std::optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int intra_priority_value) override;
int StartBlobReading(mojo::ScopedDataPipeConsumerHandle* body_pipe);
void OnSideDataReadingComplete(mojo::ScopedDataPipeConsumerHandle data_pipe,
std::optional<mojo_base::BigBuffer> metadata);
void OnBodyReadingComplete(int net_error);
void SetCommitResponsibility(FetchResponseFrom fetch_response_from) override;
// ServiceWorkerResourceLoader overrides:
// Calls url_loader_client_->OnReceiveResponse() with given |response_head|,
// |response_body|, and |cached_metadata|.
void CommitResponseBody(
const network::mojom::URLResponseHeadPtr& response_head,
mojo::ScopedDataPipeConsumerHandle response_body,
std::optional<mojo_base::BigBuffer> cached_metadata) override;
// Creates and sends an empty response's body with the net::OK status.
// Sends net::ERR_INSUFFICIENT_RESOURCES when it can't be created.
void CommitEmptyResponseAndComplete() override;
// Calls url_loader_client_->OnComplete(). Expected to be called after
// CommitResponseHeaders (i.e. status_ == kSentHeader).
void CommitCompleted(int error_code, const char* reason) override;
// Calls url_loader_client_->OnReceiveRedirect(). Sends too many redirects
// error if it hits the redirect limit.
void HandleRedirect(
const net::RedirectInfo& redirect_info,
const network::mojom::URLResponseHeadPtr& response_head) override;
bool IsMainResourceLoader() override;
// Record loading milestones. Called after a response is completed or
// a request is fall back to network. Never called when an error is
// occurred.
bool InitRecordTimingMetricsIfEligible(
const net::LoadTimingInfo& load_timing);
// Called when the fetch handler handles the request.
void RecordTimingMetricsForFetchHandlerHandledCase();
// Called when the fetch handler doesn't handle the requset (i.e. network
// fallback case).
void RecordTimingMetricsForNetworkFallbackCase();
// Called when the response from RaceNetworkRequest is faster than the
// response from the fetch handler.
void RecordTimingMetricsForRaceNetworkReqestCase();
// Time between the request is made and the request is routed to this loader.
void RecordStartToForwardServiceWorkerTiming(
const net::LoadTimingInfo& load_timing);
// Mojo message delay. If the controller service worker lives in the same
// process this captures service worker thread -> background thread delay.
// Otherwise, this captures IPC delay (this renderer process -> other
// renderer process).
void RecordFetchHandlerEndToResponseReceivedTiming(
const net::LoadTimingInfo& load_timing);
// Time spent reading response body.
void RecordResponseReceivedToCompletedTiming(
const net::LoadTimingInfo& load_timing);
// Time spent for service worker startup including mojo message delay.
void RecordForwardServiceWorkerToWorkerReadyTiming(
const net::LoadTimingInfo& load_timing);
// Time spent by fetch handlers.
void RecordWorkerReadyToFetchHandlerEndTiming(
const net::LoadTimingInfo& load_timing);
// Renderer -> Browser IPC delay (network fallback case).
void RecordFetchHandlerEndToFallbackNetworkTiming(
const net::LoadTimingInfo& load_timing);
// Time between the request is made and complete reading response body.
void RecordStartToCompletedTiming(const net::LoadTimingInfo& load_timing);
base::TimeTicks completion_time_;
void TransitionToStatus(Status new_status);
// Returns false if fails to start race network request.
// A caller should handle the case.
bool StartRaceNetworkRequest();
std::optional<ServiceWorkerRouterEvaluator::Result> EvaluateRouterConditions()
const;
bool MaybeStartAutoPreload();
void DidCacheStorageMatch(base::TimeTicks event_dispatch_time,
blink::mojom::MatchResultPtr result);
void MaybeDeleteThis();
bool IsResponseAlreadyCommittedByRaceNetworkRequest();
network::mojom::URLResponseHeadPtr response_head_;
std::optional<net::RedirectInfo> redirect_info_;
int redirect_limit_;
mojo::Remote<network::mojom::URLLoaderClient> url_loader_client_;
mojo::Receiver<network::mojom::URLLoader> url_loader_receiver_;
// For handling FetchEvent response.
mojo::Receiver<blink::mojom::ServiceWorkerFetchResponseCallback>
response_callback_receiver_{this};
// The blob needs to be held while it's read to keep it alive.
mojo::Remote<blink::mojom::Blob> body_as_blob_;
uint64_t body_as_blob_size_;
// The blob needs to be held while it's read to keep it alive.
mojo::Remote<blink::mojom::Blob> side_data_as_blob_;
scoped_refptr<ControllerServiceWorkerConnector> controller_connector_;
// Observes |controller_connector_| while this loader dispatches a fetch event
// to the controller. If a broken connection is observed, this loader attempts
// to restart the controller and dispatch the event again.
base::ScopedObservation<ControllerServiceWorkerConnector,
ControllerServiceWorkerConnector::Observer>
controller_connector_observation_{this};
bool fetch_request_restarted_;
bool body_reading_complete_;
bool side_data_reading_complete_;
// These are given by the constructor (as the params for
// URLLoaderFactory::CreateLoaderAndStart).
const int request_id_;
const uint32_t options_;
net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
// |resource_request_| is initialized in the constructor, and may change
// over the lifetime of this loader due to redirects.
network::ResourceRequest resource_request_;
std::unique_ptr<StreamWaiter> stream_waiter_;
// For network fallback.
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
Status status_ = Status::kNotStarted;
// The task runner where this loader is running.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtr<ServiceWorkerSubresourceLoaderFactory>
service_worker_subresource_loader_factory_;
blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_;
network::mojom::FetchResponseSource response_source_;
scoped_refptr<network::SharedURLLoaderFactory>
race_network_request_url_loader_factory_;
std::optional<ServiceWorkerRaceNetworkRequestURLLoaderClient>
race_network_request_loader_client_;
std::optional<ServiceWorkerForwardedRaceNetworkRequestURLLoaderFactory>
forwarded_race_network_request_url_loader_factory_;
mojo::PendingRemote<network::mojom::URLLoaderFactory>
remote_forwarded_race_network_request_url_loader_factory_;
base::WeakPtrFactory<ServiceWorkerSubresourceLoader> weak_factory_{this};
};
// A custom URLLoaderFactory implementation used by Service Worker controllees
// for loading subresources via the controller Service Worker.
// Self destroys when no more bindings exist.
class CONTENT_EXPORT ServiceWorkerSubresourceLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
// |controller_connector| is used to get a connection to the controller
// ServiceWorker.
// |fallback_factory| is used to get the associated loading context's
// default URLLoaderFactory for network fallback. This should be the
// URLLoaderFactory that directly goes to network without going through
// any custom URLLoader factories.
// |task_runner| is the runner where this loader runs. In production it runs,
// on a background thread.
static void Create(
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner);
ServiceWorkerSubresourceLoaderFactory(
const ServiceWorkerSubresourceLoaderFactory&) = delete;
ServiceWorkerSubresourceLoaderFactory& operator=(
const ServiceWorkerSubresourceLoaderFactory&) = delete;
~ServiceWorkerSubresourceLoaderFactory() override;
// network::mojom::URLLoaderFactory overrides:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& resource_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override;
void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
override;
private:
ServiceWorkerSubresourceLoaderFactory(
scoped_refptr<ControllerServiceWorkerConnector> controller_connector,
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner);
void OnMojoDisconnect();
scoped_refptr<ControllerServiceWorkerConnector> controller_connector_;
// Used when a request falls back to network.
scoped_refptr<network::SharedURLLoaderFactory> fallback_factory_;
mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
// The task runner where this factory is running.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtrFactory<ServiceWorkerSubresourceLoaderFactory> weak_factory_{
this};
};
} // namespace content
#endif // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SUBRESOURCE_LOADER_H_
|