1 // Copyright 2018 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 "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/threading/sequenced_task_runner_handle.h"
14 #include "mojo/public/cpp/bindings/pending_receiver.h"
15 #include "mojo/public/cpp/bindings/pending_remote.h"
16 #include "net/traffic_annotation/network_traffic_annotation.h"
17 #include "services/network/public/cpp/resource_request.h"
18 #include "services/network/public/mojom/url_loader.mojom.h"
19 #include "services/network/public/mojom/url_loader_factory.mojom.h"
20 
21 namespace network {
22 
23 // State and methods that need to live on the same sequence |task_runner_|
24 // as the wrapped SharedURLLoaderFactory |base_factory_|.
25 //
26 // Used by both CrossThreadPendingSharedURLLoaderFactory and
27 // CrossThreadSharedURLLoaderFactory, and shared across chains of
28 // CreateFactory() and Clone() calls. Ref count accommodates both this sharing,
29 // as well as lifetime management for cross-thread calls into the object.
30 class CrossThreadPendingSharedURLLoaderFactory::State
31     : public base::RefCountedThreadSafe<State, StateDeleterTraits> {
32  public:
33   explicit State(scoped_refptr<SharedURLLoaderFactory> base_factory);
34 
35   // |this| must be deleted on same thread as |base_factory_| as the refcount
36   // on SharedURLLoaderFactory is not thread-safe.
37   void DeleteOnCorrectThread() const;
38 
39   // Delegation for mojom::URLLoaderFactory API.
40   void CreateLoaderAndStart(
41       mojo::PendingReceiver<mojom::URLLoader> loader,
42       int32_t routing_id,
43       int32_t request_id,
44       uint32_t options,
45       const ResourceRequest& request,
46       mojo::PendingRemote<mojom::URLLoaderClient> client,
47       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
48 
49   void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver);
50 
51   // Sequence |base_factory()| and |this| run on.
task_runner() const52   base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
base_factory() const53   SharedURLLoaderFactory* base_factory() const { return base_factory_.get(); }
54 
55  private:
56   // To permit use of TaskRunner::DeleteSoon.
57   friend class base::DeleteHelper<State>;
58   ~State();
59 
60   scoped_refptr<SharedURLLoaderFactory> base_factory_;
61   scoped_refptr<base::SequencedTaskRunner> task_runner_;
62   SEQUENCE_CHECKER(sequence_checker_);
63 };
64 
65 struct CrossThreadPendingSharedURLLoaderFactory::StateDeleterTraits {
Destructnetwork::CrossThreadPendingSharedURLLoaderFactory::StateDeleterTraits66   static void Destruct(const State* state) { state->DeleteOnCorrectThread(); }
67 };
68 
69 // The implementation of SharedURLLoaderFactory provided by
70 // CrossThreadPendingSharedURLLoaderFactory::CreateFactory(). Uses the exact
71 // same State object, and posts URLLoaderFactory API calls to it on the
72 // appropriate thread.
73 class CrossThreadSharedURLLoaderFactory : public SharedURLLoaderFactory {
74  public:
75   using State = CrossThreadPendingSharedURLLoaderFactory::State;
76 
77   // |state| contains information on the SharedURLLoaderFactory to wrap, and
78   // what thread it runs on, and may be shared with other
79   // CrossThreadSharedURLLoaderFactory and
80   // CrossThreadPendingSharedURLLoaderFactory objects wrapping the same
81   // SharedURLLoaderFactory.
82   explicit CrossThreadSharedURLLoaderFactory(scoped_refptr<State> state);
83 
84   // mojom::URLLoaderFactory implementation:
85   void CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> loader,
86                             int32_t routing_id,
87                             int32_t request_id,
88                             uint32_t options,
89                             const ResourceRequest& request,
90                             mojo::PendingRemote<mojom::URLLoaderClient> client,
91                             const net::MutableNetworkTrafficAnnotationTag&
92                                 traffic_annotation) override;
93   void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) override;
94 
95   // SharedURLLoaderFactory implementation:
96   std::unique_ptr<PendingSharedURLLoaderFactory> Clone() override;
97 
98  private:
99   ~CrossThreadSharedURLLoaderFactory() override;
100   scoped_refptr<State> state_;
101 
102   // CrossThreadSharedURLLoaderFactory should live on a consistent thread as
103   // well, though one that may be different from |state_->task_runner()|.
104   SEQUENCE_CHECKER(sequence_checker_);
105 };
106 
CrossThreadSharedURLLoaderFactory(scoped_refptr<CrossThreadPendingSharedURLLoaderFactory::State> state)107 CrossThreadSharedURLLoaderFactory::CrossThreadSharedURLLoaderFactory(
108     scoped_refptr<CrossThreadPendingSharedURLLoaderFactory::State> state)
109     : state_(std::move(state)) {
110   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
111 }
112 
~CrossThreadSharedURLLoaderFactory()113 CrossThreadSharedURLLoaderFactory::~CrossThreadSharedURLLoaderFactory() {
114   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
115 }
116 
CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> loader,int32_t routing_id,int32_t request_id,uint32_t options,const ResourceRequest & request,mojo::PendingRemote<mojom::URLLoaderClient> client,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation)117 void CrossThreadSharedURLLoaderFactory::CreateLoaderAndStart(
118     mojo::PendingReceiver<mojom::URLLoader> loader,
119     int32_t routing_id,
120     int32_t request_id,
121     uint32_t options,
122     const ResourceRequest& request,
123     mojo::PendingRemote<mojom::URLLoaderClient> client,
124     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
125   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
126   base::SequencedTaskRunner* runner = state_->task_runner();
127   if (runner->RunsTasksInCurrentSequence()) {
128     state_->base_factory()->CreateLoaderAndStart(
129         std::move(loader), routing_id, request_id, options, request,
130         std::move(client), traffic_annotation);
131   } else {
132     state_->task_runner()->PostTask(
133         FROM_HERE,
134         base::BindOnce(&State::CreateLoaderAndStart, state_, std::move(loader),
135                        routing_id, request_id, options, request,
136                        std::move(client), traffic_annotation));
137   }
138 }
139 
Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver)140 void CrossThreadSharedURLLoaderFactory::Clone(
141     mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) {
142   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
143   base::SequencedTaskRunner* runner = state_->task_runner();
144   if (runner->RunsTasksInCurrentSequence()) {
145     state_->base_factory()->Clone(std::move(receiver));
146   } else {
147     state_->task_runner()->PostTask(
148         FROM_HERE, base::BindOnce(&State::Clone, state_, std::move(receiver)));
149   }
150 }
151 
152 std::unique_ptr<PendingSharedURLLoaderFactory>
Clone()153 CrossThreadSharedURLLoaderFactory::Clone() {
154   return base::WrapUnique(new CrossThreadPendingSharedURLLoaderFactory(state_));
155 }
156 
157 CrossThreadPendingSharedURLLoaderFactory::
CrossThreadPendingSharedURLLoaderFactory(scoped_refptr<SharedURLLoaderFactory> url_loader_factory)158     CrossThreadPendingSharedURLLoaderFactory(
159         scoped_refptr<SharedURLLoaderFactory> url_loader_factory)
160     : state_(base::MakeRefCounted<State>(std::move(url_loader_factory))) {}
161 
162 CrossThreadPendingSharedURLLoaderFactory::
163     ~CrossThreadPendingSharedURLLoaderFactory() = default;
164 
165 scoped_refptr<SharedURLLoaderFactory>
CreateFactory()166 CrossThreadPendingSharedURLLoaderFactory::CreateFactory() {
167   return base::MakeRefCounted<CrossThreadSharedURLLoaderFactory>(state_);
168 }
169 
170 CrossThreadPendingSharedURLLoaderFactory::
CrossThreadPendingSharedURLLoaderFactory(scoped_refptr<State> state)171     CrossThreadPendingSharedURLLoaderFactory(scoped_refptr<State> state)
172     : state_(std::move(state)) {}
173 
State(scoped_refptr<SharedURLLoaderFactory> base_factory)174 CrossThreadPendingSharedURLLoaderFactory::State::State(
175     scoped_refptr<SharedURLLoaderFactory> base_factory)
176     : base_factory_(std::move(base_factory)),
177       task_runner_(base::SequencedTaskRunnerHandle::Get()) {
178   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
179 }
180 
~State()181 CrossThreadPendingSharedURLLoaderFactory::State::~State() {
182   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
183 }
184 
DeleteOnCorrectThread() const185 void CrossThreadPendingSharedURLLoaderFactory::State::DeleteOnCorrectThread()
186     const {
187   if (task_runner_->RunsTasksInCurrentSequence())
188     delete this;
189   else
190     task_runner_->DeleteSoon(FROM_HERE, this);
191 }
192 
CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> loader,int32_t routing_id,int32_t request_id,uint32_t options,const ResourceRequest & request,mojo::PendingRemote<mojom::URLLoaderClient> client,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation)193 void CrossThreadPendingSharedURLLoaderFactory::State::CreateLoaderAndStart(
194     mojo::PendingReceiver<mojom::URLLoader> loader,
195     int32_t routing_id,
196     int32_t request_id,
197     uint32_t options,
198     const ResourceRequest& request,
199     mojo::PendingRemote<mojom::URLLoaderClient> client,
200     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
201   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
202   base_factory_->CreateLoaderAndStart(std::move(loader), routing_id, request_id,
203                                       options, request, std::move(client),
204                                       traffic_annotation);
205 }
206 
Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver)207 void CrossThreadPendingSharedURLLoaderFactory::State::Clone(
208     mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) {
209   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
210   base_factory_->Clone(std::move(receiver));
211 }
212 
213 }  // namespace network
214