1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/url_loader_factory_getter.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/feature_list.h"
14 #include "base/lazy_instance.h"
15 #include "base/run_loop.h"
16 #include "base/task/post_task.h"
17 #include "content/browser/storage_partition_impl.h"
18 #include "content/common/service_worker/service_worker_utils.h"
19 #include "content/public/browser/browser_task_traits.h"
20 #include "content/public/common/content_switches.h"
21 #include "services/network/public/cpp/features.h"
22 #include "services/network/public/cpp/shared_url_loader_factory.h"
23 #include "services/network/public/mojom/network_service.mojom.h"
24
25 namespace content {
26
27 namespace {
28 base::LazyInstance<URLLoaderFactoryGetter::GetNetworkFactoryCallback>::Leaky
29 g_get_network_factory_callback = LAZY_INSTANCE_INITIALIZER;
30 }
31
32 class URLLoaderFactoryGetter::PendingURLLoaderFactoryForIOThread
33 : public network::PendingSharedURLLoaderFactory {
34 public:
35 PendingURLLoaderFactoryForIOThread() = default;
PendingURLLoaderFactoryForIOThread(scoped_refptr<URLLoaderFactoryGetter> factory_getter)36 explicit PendingURLLoaderFactoryForIOThread(
37 scoped_refptr<URLLoaderFactoryGetter> factory_getter)
38 : factory_getter_(std::move(factory_getter)) {}
39 ~PendingURLLoaderFactoryForIOThread() override = default;
40
url_loader_factory_getter()41 scoped_refptr<URLLoaderFactoryGetter>& url_loader_factory_getter() {
42 return factory_getter_;
43 }
44
45 protected:
46 // PendingSharedURLLoaderFactory implementation.
47 scoped_refptr<network::SharedURLLoaderFactory> CreateFactory() override;
48
49 scoped_refptr<URLLoaderFactoryGetter> factory_getter_;
50
51 DISALLOW_COPY_AND_ASSIGN(PendingURLLoaderFactoryForIOThread);
52 };
53
54 class URLLoaderFactoryGetter::URLLoaderFactoryForIOThread
55 : public network::SharedURLLoaderFactory {
56 public:
URLLoaderFactoryForIOThread(scoped_refptr<URLLoaderFactoryGetter> factory_getter,bool is_corb_enabled)57 URLLoaderFactoryForIOThread(
58 scoped_refptr<URLLoaderFactoryGetter> factory_getter,
59 bool is_corb_enabled)
60 : factory_getter_(std::move(factory_getter)),
61 is_corb_enabled_(is_corb_enabled) {
62 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
63 BrowserThread::CurrentlyOn(BrowserThread::IO));
64 }
65
URLLoaderFactoryForIOThread(std::unique_ptr<PendingURLLoaderFactoryForIOThread> info)66 explicit URLLoaderFactoryForIOThread(
67 std::unique_ptr<PendingURLLoaderFactoryForIOThread> info)
68 : factory_getter_(std::move(info->url_loader_factory_getter())),
69 is_corb_enabled_(false) {
70 DCHECK_CURRENTLY_ON(BrowserThread::IO);
71 }
72
73 // mojom::URLLoaderFactory implementation:
CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> receiver,int32_t routing_id,int32_t request_id,uint32_t options,const network::ResourceRequest & url_request,mojo::PendingRemote<network::mojom::URLLoaderClient> client,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation)74 void CreateLoaderAndStart(
75 mojo::PendingReceiver<network::mojom::URLLoader> receiver,
76 int32_t routing_id,
77 int32_t request_id,
78 uint32_t options,
79 const network::ResourceRequest& url_request,
80 mojo::PendingRemote<network::mojom::URLLoaderClient> client,
81 const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
82 override {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
84 if (!factory_getter_)
85 return;
86 factory_getter_->GetURLLoaderFactory(is_corb_enabled_)
87 ->CreateLoaderAndStart(std::move(receiver), routing_id, request_id,
88 options, url_request, std::move(client),
89 traffic_annotation);
90 }
91
Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)92 void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
93 override {
94 if (!factory_getter_)
95 return;
96 factory_getter_->GetURLLoaderFactory(is_corb_enabled_)
97 ->Clone(std::move(receiver));
98 }
99
100 // SharedURLLoaderFactory implementation:
Clone()101 std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override {
102 NOTREACHED() << "This isn't supported. If you need a SharedURLLoaderFactory"
103 " on the UI thread, get it from StoragePartition.";
104 return nullptr;
105 }
106
107 private:
108 friend class base::RefCounted<URLLoaderFactoryForIOThread>;
109 ~URLLoaderFactoryForIOThread() override = default;
110
111 scoped_refptr<URLLoaderFactoryGetter> factory_getter_;
112 bool is_corb_enabled_;
113
114 DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryForIOThread);
115 };
116
117 scoped_refptr<network::SharedURLLoaderFactory>
CreateFactory()118 URLLoaderFactoryGetter::PendingURLLoaderFactoryForIOThread::CreateFactory() {
119 auto other = std::make_unique<PendingURLLoaderFactoryForIOThread>();
120 other->factory_getter_ = std::move(factory_getter_);
121
122 return base::MakeRefCounted<URLLoaderFactoryForIOThread>(std::move(other));
123 }
124
125 // -----------------------------------------------------------------------------
126
127 URLLoaderFactoryGetter::URLLoaderFactoryGetter() = default;
128
Initialize(StoragePartitionImpl * partition)129 void URLLoaderFactoryGetter::Initialize(StoragePartitionImpl* partition) {
130 DCHECK(partition);
131 partition_ = partition;
132
133 // Create a mojo::PendingRemote<URLLoaderFactory> synchronously and push it to
134 // the IO thread. If the pipe errors out later due to a network service crash,
135 // the pipe is created on the IO thread, and the request send back to the UI
136 // thread.
137 // TODO(mmenke): Is one less thread hop on startup worth the extra complexity
138 // of two different pipe creation paths?
139 mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory;
140 HandleNetworkFactoryRequestOnUIThread(
141 network_factory.InitWithNewPipeAndPassReceiver(), false);
142
143 base::PostTask(FROM_HERE, {BrowserThread::IO},
144 base::BindOnce(&URLLoaderFactoryGetter::InitializeOnIOThread,
145 this, std::move(network_factory)));
146 }
147
OnStoragePartitionDestroyed()148 void URLLoaderFactoryGetter::OnStoragePartitionDestroyed() {
149 DCHECK_CURRENTLY_ON(BrowserThread::UI);
150 partition_ = nullptr;
151 }
152
153 scoped_refptr<network::SharedURLLoaderFactory>
GetNetworkFactory()154 URLLoaderFactoryGetter::GetNetworkFactory() {
155 DCHECK_CURRENTLY_ON(BrowserThread::IO);
156 return base::MakeRefCounted<URLLoaderFactoryForIOThread>(
157 base::WrapRefCounted(this), false);
158 }
159
160 scoped_refptr<network::SharedURLLoaderFactory>
GetNetworkFactoryWithCORBEnabled()161 URLLoaderFactoryGetter::GetNetworkFactoryWithCORBEnabled() {
162 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
163 BrowserThread::CurrentlyOn(BrowserThread::IO));
164 return base::MakeRefCounted<URLLoaderFactoryForIOThread>(
165 base::WrapRefCounted(this), true);
166 }
167
168 std::unique_ptr<network::PendingSharedURLLoaderFactory>
GetPendingNetworkFactory()169 URLLoaderFactoryGetter::GetPendingNetworkFactory() {
170 return std::make_unique<PendingURLLoaderFactoryForIOThread>(
171 base::WrapRefCounted(this));
172 }
173
GetURLLoaderFactory(bool is_corb_enabled)174 network::mojom::URLLoaderFactory* URLLoaderFactoryGetter::GetURLLoaderFactory(
175 bool is_corb_enabled) {
176 DCHECK_CURRENTLY_ON(BrowserThread::IO);
177
178 // This needs to be done before returning |test_factory_|, as the
179 // |test_factory_| may fall back to |network_factory_|. The |is_bound()| check
180 // is only needed by unit tests.
181 mojo::Remote<network::mojom::URLLoaderFactory>* factory =
182 is_corb_enabled ? &network_factory_corb_enabled_ : &network_factory_;
183 if (!factory->is_bound() || !factory->is_connected()) {
184 mojo::Remote<network::mojom::URLLoaderFactory> network_factory;
185 base::PostTask(
186 FROM_HERE, {BrowserThread::UI},
187 base::BindOnce(
188 &URLLoaderFactoryGetter::HandleNetworkFactoryRequestOnUIThread,
189 this, network_factory.BindNewPipeAndPassReceiver(),
190 is_corb_enabled));
191 ReinitializeOnIOThread(std::move(network_factory), is_corb_enabled);
192 }
193
194 if (g_get_network_factory_callback.Get() && !test_factory_)
195 g_get_network_factory_callback.Get().Run(this);
196
197 if (is_corb_enabled && test_factory_corb_enabled_)
198 return test_factory_corb_enabled_;
199
200 if (!is_corb_enabled && test_factory_)
201 return test_factory_;
202
203 return factory->get();
204 }
205
CloneNetworkFactory(mojo::PendingReceiver<network::mojom::URLLoaderFactory> network_factory_receiver)206 void URLLoaderFactoryGetter::CloneNetworkFactory(
207 mojo::PendingReceiver<network::mojom::URLLoaderFactory>
208 network_factory_receiver) {
209 DCHECK_CURRENTLY_ON(BrowserThread::IO);
210 GetURLLoaderFactory(false)->Clone(std::move(network_factory_receiver));
211 }
212
SetNetworkFactoryForTesting(network::mojom::URLLoaderFactory * test_factory,bool is_corb_enabled)213 void URLLoaderFactoryGetter::SetNetworkFactoryForTesting(
214 network::mojom::URLLoaderFactory* test_factory,
215 bool is_corb_enabled) {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO);
217 if (is_corb_enabled) {
218 DCHECK(!test_factory_corb_enabled_ || !test_factory);
219 test_factory_corb_enabled_ = test_factory;
220 } else {
221 DCHECK(!test_factory_ || !test_factory);
222 test_factory_ = test_factory;
223 }
224 }
225
SetGetNetworkFactoryCallbackForTesting(const GetNetworkFactoryCallback & get_network_factory_callback)226 void URLLoaderFactoryGetter::SetGetNetworkFactoryCallbackForTesting(
227 const GetNetworkFactoryCallback& get_network_factory_callback) {
228 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO) ||
229 BrowserThread::CurrentlyOn(BrowserThread::IO));
230 DCHECK(!g_get_network_factory_callback.Get() ||
231 !get_network_factory_callback);
232 g_get_network_factory_callback.Get() = get_network_factory_callback;
233 }
234
FlushNetworkInterfaceOnIOThreadForTesting()235 void URLLoaderFactoryGetter::FlushNetworkInterfaceOnIOThreadForTesting() {
236 DCHECK_CURRENTLY_ON(BrowserThread::UI);
237 base::RunLoop run_loop;
238 base::PostTask(
239 FROM_HERE, {BrowserThread::IO},
240 base::BindOnce(&URLLoaderFactoryGetter::FlushNetworkInterfaceForTesting,
241 this, run_loop.QuitClosure()));
242 run_loop.Run();
243 }
244
FlushNetworkInterfaceForTesting(base::OnceClosure callback)245 void URLLoaderFactoryGetter::FlushNetworkInterfaceForTesting(
246 base::OnceClosure callback) {
247 DCHECK_CURRENTLY_ON(BrowserThread::IO);
248 if (network_factory_)
249 network_factory_.FlushAsyncForTesting(std::move(callback));
250 if (network_factory_corb_enabled_)
251 network_factory_corb_enabled_.FlushAsyncForTesting(std::move(callback));
252 }
253
~URLLoaderFactoryGetter()254 URLLoaderFactoryGetter::~URLLoaderFactoryGetter() {}
255
InitializeOnIOThread(mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory)256 void URLLoaderFactoryGetter::InitializeOnIOThread(
257 mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory) {
258 ReinitializeOnIOThread(mojo::Remote<network::mojom::URLLoaderFactory>(
259 std::move(network_factory)),
260 false);
261 }
262
ReinitializeOnIOThread(mojo::Remote<network::mojom::URLLoaderFactory> network_factory,bool is_corb_enabled)263 void URLLoaderFactoryGetter::ReinitializeOnIOThread(
264 mojo::Remote<network::mojom::URLLoaderFactory> network_factory,
265 bool is_corb_enabled) {
266 DCHECK(network_factory.is_bound());
267 // Set a disconnect handler so that connection errors on the pipes are
268 // noticed, but the class doesn't actually do anything when the error is
269 // observed - instead, a new pipe is created in GetURLLoaderFactory() as
270 // needed. This is to avoid incrementing the reference count of |this| in the
271 // callback, as that could result in increasing the reference count from 0 to
272 // 1 while there's a pending task to delete |this|. See
273 // https://crbug.com/870942 for more details.
274 network_factory.set_disconnect_handler(base::DoNothing());
275 if (is_corb_enabled) {
276 network_factory_corb_enabled_ = std::move(network_factory);
277 } else {
278 network_factory_ = std::move(network_factory);
279 }
280 }
281
HandleNetworkFactoryRequestOnUIThread(mojo::PendingReceiver<network::mojom::URLLoaderFactory> network_factory_receiver,bool is_corb_enabled)282 void URLLoaderFactoryGetter::HandleNetworkFactoryRequestOnUIThread(
283 mojo::PendingReceiver<network::mojom::URLLoaderFactory>
284 network_factory_receiver,
285 bool is_corb_enabled) {
286 DCHECK_CURRENTLY_ON(BrowserThread::UI);
287 // |StoragePartitionImpl| may have went away while |URLLoaderFactoryGetter| is
288 // still held by consumers.
289 if (!partition_)
290 return;
291 network::mojom::URLLoaderFactoryParamsPtr params =
292 network::mojom::URLLoaderFactoryParams::New();
293 // The browser process is considered trusted.
294 params->is_trusted = true;
295 params->process_id = network::mojom::kBrowserProcessId;
296 params->is_corb_enabled = is_corb_enabled;
297 params->disable_web_security =
298 base::CommandLine::ForCurrentProcess()->HasSwitch(
299 switches::kDisableWebSecurity);
300 partition_->GetNetworkContext()->CreateURLLoaderFactory(
301 std::move(network_factory_receiver), std::move(params));
302 }
303
304 } // namespace content
305