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
content / browser / loader / keep_alive_url_loader_service.h [blame]
// Copyright 2023 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_LOADER_KEEP_ALIVE_URL_LOADER_SERVICE_H_
#define CONTENT_BROWSER_LOADER_KEEP_ALIVE_URL_LOADER_SERVICE_H_
#include <memory>
#include <optional>
#include "base/memory/scoped_refptr.h"
#include "content/browser/attribution_reporting/attribution_suitable_context.h"
#include "content/browser/loader/keep_alive_url_loader.h"
#include "content/common/content_export.h"
#include "content/public/browser/weak_document_ptr.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
#include "third_party/blink/public/mojom/loader/fetch_later.mojom.h"
namespace content {
class BrowserContext;
class PolicyContainerHost;
// A service that stores bound SharedURLLoaderFactory mojo pipes from renderers
// of the same storage partition, and the intermediate URLLoader receivers, i.e.
// KeepAliveURLLoader, they have created to load fetch keepalive requests.
//
// A fetch keepalive request is originated from a JS call to
// `fetch(..., {keepalive: true})` or `navigator.sendBeacon()`. A renderer can
// ask this service to handle such request by using a remote of
// mojom::URLLoaderFactory bound to this service by `BindFactory()`, which also
// binds RenderFrameHostImpl-specific context with every receiver.
//
// Calling the remote `CreateLoaderAndStart()` of a factory will create a
// `KeepAliveURLLoader` here in browser. The service is responsible for keeping
// these loaders in `loader_receivers_` until the corresponding request
// completes or fails.
//
// Handling keepalive requests in this service allows a request to continue even
// if a renderer unloads before completion, i.e. the request is "keepalive",
// without needing the renderer to stay extra longer than the necessary time.
//
// This service is created and stored in every `StoragePartitionImpl` instance.
// Hence, its lifetime is the same as the owner StoragePartition for a partition
// domain, which should be generally longer than any of the renderers spawned
// from the partition domain.
//
// Design Doc:
// https://docs.google.com/document/d/1ZzxMMBvpqn8VZBZKnb7Go8TWjnrGcXuLS_USwVVRUvY
class CONTENT_EXPORT KeepAliveURLLoaderService {
public:
// A context for the receiver of a `KeepAliveURLLoaderFactoriesBase`
// connection between a renderer and the browser.
//
// A FactoryContext is created whenever `BindFactory()` or
// `BindFetchLaterLoaderFactory()` is called by
// RenderFrameHostImpl::CommitNavigation(). It can also be cloned by the same
// corresponding renderer, or when new window or new child frame is created.
//
// See `mojo::ReceiverSetBase` for more details.
struct CONTENT_EXPORT FactoryContext {
FactoryContext(
scoped_refptr<network::SharedURLLoaderFactory> factory,
scoped_refptr<PolicyContainerHost> frame_policy_container_host);
// Called when a factory is cloned by URLLoaderFactory::Clone().
explicit FactoryContext(const std::unique_ptr<FactoryContext>& other);
~FactoryContext();
// Not Copyable.
FactoryContext(const FactoryContext&) = delete;
FactoryContext& operator=(const FactoryContext&) = delete;
// Updates `weak_document_ptr` and other document-related fields.
void OnDidCommitNavigation(WeakDocumentPtr committed_document);
// Updates `factory` using the given `new_factory`.
//
// Only called either
// (1) when DevTools tries to intercept every URLLoaderFactory
// (2) after network service crashes
//
// The default subresources loading, including non-keepalive fetch requests,
// don't go through browser. Hence, their intercepted URLLoaderFactory are
// updated via SubresourceLoaderUpdater::UpdateSubresourceLoaderFactories().
// On the other hand, calling this method can update the fetch keepalive
// factory directly in-browser.
void UpdateFactory(
scoped_refptr<network::SharedURLLoaderFactory> new_factory);
// The factory to use for the requests initiated from this context.
scoped_refptr<network::SharedURLLoaderFactory> factory;
// Upon NavigationRequest::DidCommitNavigation(), `weak_document_ptr` will
// be set to the document that this `BindContext` is associated with. It
// will become null whenever the document navigates away.
WeakDocumentPtr weak_document_ptr;
// The `PolicyContainerHost` of the document connecting to an implementation
// of `KeepAliveURLLoaderFactoriesBase` using this context.
//
// This field keeps the pointed object alive such that any pending keepalive
// redirect requests can still be verified against these same policies.
//
// When `this` is constructed, this field is set to the PolicyContainerHost
// of the requesting RenderFrameHostImpl, which may be inherited from its
// creator (See `RenderFrameHostImpl::InitializePolicyContainerHost()`):
// when a factory is cloned due to creating new window/new child frame,
// this field will initially inherit the same value; if the new window/new
// child frame commits a new document after that, this field will be updated
// by `OnDidCommitNavigation()`.
scoped_refptr<PolicyContainerHost> policy_container_host;
// Attribution responses might be processed from keep alive requests. For
// them to be processed, the request must have been sent from a suitable
// context and information from that context is needed. Upon
// NavigationRequest::DidCommitNavigation(), if the context is suitable,
// the `attribution_context` is created.
std::optional<AttributionSuitableContext> attribution_context;
// This must be the last member.
base::WeakPtrFactory<FactoryContext> weak_ptr_factory{this};
};
// `browser_context` owns the StoragePartition creating the instance of this
// service. It must not be null and surpass the lifetime of this service.
explicit KeepAliveURLLoaderService(BrowserContext* browser_context);
~KeepAliveURLLoaderService();
// Not Copyable.
KeepAliveURLLoaderService(const KeepAliveURLLoaderService&) = delete;
KeepAliveURLLoaderService& operator=(const KeepAliveURLLoaderService&) =
delete;
// Binds the pending `receiver` with this service, using
// `subresource_proxying_factory_bundle`.
//
// The remote of `receiver` can be passed to another process, i.e. renderer,
// from which to create new fetch keepalive requests.
//
// `policy_container_host` is the policy host of the requester frame going to
// use the remote of `receiver` to load requests. It must not be null.
//
// Returns a `FactoryContext` bound to the new factory connecting with
// `receiver`. The caller can update the context when necessary.
base::WeakPtr<FactoryContext> BindFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<network::SharedURLLoaderFactory>
subresource_proxying_factory_bundle,
scoped_refptr<PolicyContainerHost> policy_container_host);
// Binds the pending FetchLaterLoaderFactory `receiver` with this service,
// which uses `factory` to load FetchLater URL requests.
// See also `BindFactory()` for other parameters. Note that the returned
// `FactoryContext` here is different from the one of `BindFactory()`.
base::WeakPtr<FactoryContext> BindFetchLaterLoaderFactory(
mojo::PendingAssociatedReceiver<blink::mojom::FetchLaterLoaderFactory>
receiver,
scoped_refptr<network::SharedURLLoaderFactory>
subresource_proxying_factory_bundle,
scoped_refptr<PolicyContainerHost> policy_container_host);
// Called when the `browser_context_` that owns this instance is shutting
// down.
void Shutdown();
// For testing only:
size_t NumLoadersForTesting() const;
size_t NumDisconnectedLoadersForTesting() const;
void SetLoaderObserverForTesting(
scoped_refptr<KeepAliveURLLoader::TestObserver> observer);
void SetURLLoaderThrottlesGetterForTesting(
KeepAliveURLLoader::URLLoaderThrottlesGetter
url_loader_throttles_getter_for_testing);
private:
template <typename Interface,
template <typename>
class PendingReceiverType,
template <typename, typename>
class ReceiverSetType>
class KeepAliveURLLoaderFactoriesBase;
class KeepAliveURLLoaderFactories;
class FetchLaterLoaderFactories;
// Handles every disconnection notification for `loader_receivers_`.
void OnLoaderDisconnected();
// Removes the KeepAliveURLLoader kept by this service, either from
// `loader_receivers_` or `disconnected_loaders_`.
void RemoveLoader(mojo::ReceiverId loader_receiver_id);
// The browsing session that owns this instance of the service.
const raw_ptr<BrowserContext> browser_context_;
// Many-to-one mojo receiver of URLLoaderFactory for Fetch keepalive requests.
std::unique_ptr<KeepAliveURLLoaderFactories> url_loader_factories_;
// Many-to-one mojo receiver of FetchLaterLoaderFactory for FetchLater
// keepalive requests.
std::unique_ptr<FetchLaterLoaderFactories> fetch_later_loader_factories_;
// For testing only:
// Not owned.
scoped_refptr<KeepAliveURLLoader::TestObserver> loader_test_observer_ =
nullptr;
KeepAliveURLLoader::URLLoaderThrottlesGetter
url_loader_throttles_getter_for_testing_ = base::NullCallback();
};
} // namespace content
#endif // CONTENT_BROWSER_LOADER_KEEP_ALIVE_URL_LOADER_SERVICE_H_