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
356
357
358
359
360
361
362
363
364
365
366
content / renderer / service_worker / service_worker_subresource_loader.h [blame]
// 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 response head has been sent to |url_loader_client_|.
kSentHeader,
// 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;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() 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:
void CommitResponseHeaders(
const network::mojom::URLResponseHeadPtr&) override;
// 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);
// If eligible, dispatch the network request which races the ServiceWorker
// fetch handler.
bool MaybeStartRaceNetworkRequest();
// 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_