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