1 // Copyright 2016 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/renderer/loader/url_loader_client_impl.h"
6 
7 #include <iterator>
8 
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/feature_list.h"
12 #include "base/single_thread_task_runner.h"
13 #include "content/public/common/url_utils.h"
14 #include "content/public/renderer/content_renderer_client.h"
15 #include "content/renderer/loader/resource_dispatcher.h"
16 #include "net/url_request/redirect_info.h"
17 #include "services/network/public/cpp/features.h"
18 #include "services/network/public/mojom/url_response_head.mojom.h"
19 #include "third_party/blink/public/common/features.h"
20 
21 namespace content {
22 namespace {
23 
24 // Determines whether it is safe to redirect from |from_url| to |to_url|.
IsRedirectSafe(const GURL & from_url,const GURL & to_url)25 bool IsRedirectSafe(const GURL& from_url, const GURL& to_url) {
26   return IsSafeRedirectTarget(from_url, to_url) &&
27          (!GetContentClient()->renderer() ||  // null in unit tests.
28           GetContentClient()->renderer()->IsSafeRedirectTarget(to_url));
29 }
30 
31 }  // namespace
32 
33 class URLLoaderClientImpl::DeferredMessage {
34  public:
35   DeferredMessage() = default;
36   virtual void HandleMessage(ResourceDispatcher* dispatcher,
37                              int request_id) = 0;
38   virtual bool IsCompletionMessage() const = 0;
39   virtual ~DeferredMessage() = default;
40 
41  private:
42   DISALLOW_COPY_AND_ASSIGN(DeferredMessage);
43 };
44 
45 class URLLoaderClientImpl::DeferredOnReceiveResponse final
46     : public DeferredMessage {
47  public:
DeferredOnReceiveResponse(network::mojom::URLResponseHeadPtr response_head)48   explicit DeferredOnReceiveResponse(
49       network::mojom::URLResponseHeadPtr response_head)
50       : response_head_(std::move(response_head)) {}
51 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)52   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
53     dispatcher->OnReceivedResponse(request_id, std::move(response_head_));
54   }
IsCompletionMessage() const55   bool IsCompletionMessage() const override { return false; }
56 
57  private:
58   network::mojom::URLResponseHeadPtr response_head_;
59 };
60 
61 class URLLoaderClientImpl::DeferredOnReceiveRedirect final
62     : public DeferredMessage {
63  public:
DeferredOnReceiveRedirect(const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr response_head,scoped_refptr<base::SingleThreadTaskRunner> task_runner)64   DeferredOnReceiveRedirect(
65       const net::RedirectInfo& redirect_info,
66       network::mojom::URLResponseHeadPtr response_head,
67       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
68       : redirect_info_(redirect_info),
69         response_head_(std::move(response_head)),
70         task_runner_(std::move(task_runner)) {}
71 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)72   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
73     dispatcher->OnReceivedRedirect(request_id, redirect_info_,
74                                    std::move(response_head_), task_runner_);
75   }
IsCompletionMessage() const76   bool IsCompletionMessage() const override { return false; }
77 
78  private:
79   const net::RedirectInfo redirect_info_;
80   network::mojom::URLResponseHeadPtr response_head_;
81   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
82 };
83 
84 class URLLoaderClientImpl::DeferredOnUploadProgress final
85     : public DeferredMessage {
86  public:
DeferredOnUploadProgress(int64_t current,int64_t total)87   DeferredOnUploadProgress(int64_t current, int64_t total)
88       : current_(current), total_(total) {}
89 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)90   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
91     dispatcher->OnUploadProgress(request_id, current_, total_);
92   }
IsCompletionMessage() const93   bool IsCompletionMessage() const override { return false; }
94 
95  private:
96   const int64_t current_;
97   const int64_t total_;
98 };
99 
100 class URLLoaderClientImpl::DeferredOnReceiveCachedMetadata final
101     : public DeferredMessage {
102  public:
DeferredOnReceiveCachedMetadata(mojo_base::BigBuffer data)103   explicit DeferredOnReceiveCachedMetadata(mojo_base::BigBuffer data)
104       : data_(std::move(data)) {}
105 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)106   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
107     dispatcher->OnReceivedCachedMetadata(request_id, std::move(data_));
108   }
IsCompletionMessage() const109   bool IsCompletionMessage() const override { return false; }
110 
111  private:
112   mojo_base::BigBuffer data_;
113 };
114 
115 class URLLoaderClientImpl::DeferredOnStartLoadingResponseBody final
116     : public DeferredMessage {
117  public:
DeferredOnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)118   explicit DeferredOnStartLoadingResponseBody(
119       mojo::ScopedDataPipeConsumerHandle body)
120       : body_(std::move(body)) {}
121 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)122   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
123     dispatcher->OnStartLoadingResponseBody(request_id, std::move(body_));
124   }
IsCompletionMessage() const125   bool IsCompletionMessage() const override { return false; }
126 
127  private:
128   mojo::ScopedDataPipeConsumerHandle body_;
129 };
130 
131 class URLLoaderClientImpl::DeferredOnComplete final : public DeferredMessage {
132  public:
DeferredOnComplete(const network::URLLoaderCompletionStatus & status)133   explicit DeferredOnComplete(const network::URLLoaderCompletionStatus& status)
134       : status_(status) {}
135 
HandleMessage(ResourceDispatcher * dispatcher,int request_id)136   void HandleMessage(ResourceDispatcher* dispatcher, int request_id) override {
137     dispatcher->OnRequestComplete(request_id, status_);
138   }
IsCompletionMessage() const139   bool IsCompletionMessage() const override { return true; }
140 
141  private:
142   const network::URLLoaderCompletionStatus status_;
143 };
144 
URLLoaderClientImpl(int request_id,ResourceDispatcher * resource_dispatcher,scoped_refptr<base::SingleThreadTaskRunner> task_runner,bool bypass_redirect_checks,const GURL & request_url)145 URLLoaderClientImpl::URLLoaderClientImpl(
146     int request_id,
147     ResourceDispatcher* resource_dispatcher,
148     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
149     bool bypass_redirect_checks,
150     const GURL& request_url)
151     : request_id_(request_id),
152       resource_dispatcher_(resource_dispatcher),
153       task_runner_(std::move(task_runner)),
154       bypass_redirect_checks_(bypass_redirect_checks),
155       last_loaded_url_(request_url) {}
156 
157 URLLoaderClientImpl::~URLLoaderClientImpl() = default;
158 
SetDefersLoading()159 void URLLoaderClientImpl::SetDefersLoading() {
160   is_deferred_ = true;
161 }
162 
UnsetDefersLoading()163 void URLLoaderClientImpl::UnsetDefersLoading() {
164   is_deferred_ = false;
165 
166   task_runner_->PostTask(
167       FROM_HERE, base::BindOnce(&URLLoaderClientImpl::FlushDeferredMessages,
168                                 weak_factory_.GetWeakPtr()));
169 }
170 
FlushDeferredMessages()171 void URLLoaderClientImpl::FlushDeferredMessages() {
172   if (is_deferred_)
173     return;
174   std::vector<std::unique_ptr<DeferredMessage>> messages;
175   messages.swap(deferred_messages_);
176   bool has_completion_message = false;
177   base::WeakPtr<URLLoaderClientImpl> weak_this = weak_factory_.GetWeakPtr();
178   // First, dispatch all messages excluding the followings:
179   //  - transfer size change
180   //  - completion
181   // These two types of messages are dispatched later.
182   for (size_t index = 0; index < messages.size(); ++index) {
183     if (messages[index]->IsCompletionMessage()) {
184       // The completion message arrives at the end of the message queue.
185       DCHECK(!has_completion_message);
186       DCHECK_EQ(index, messages.size() - 1);
187       has_completion_message = true;
188       break;
189     }
190 
191     messages[index]->HandleMessage(resource_dispatcher_, request_id_);
192     if (!weak_this)
193       return;
194     if (is_deferred_) {
195       deferred_messages_.insert(
196           deferred_messages_.begin(),
197           std::make_move_iterator(messages.begin()) + index + 1,
198           std::make_move_iterator(messages.end()));
199       return;
200     }
201   }
202 
203   // Dispatch the transfer size update.
204   if (accumulated_transfer_size_diff_during_deferred_ > 0) {
205     auto transfer_size_diff = accumulated_transfer_size_diff_during_deferred_;
206     accumulated_transfer_size_diff_during_deferred_ = 0;
207     resource_dispatcher_->OnTransferSizeUpdated(request_id_,
208                                                 transfer_size_diff);
209     if (!weak_this)
210       return;
211     if (is_deferred_) {
212       if (has_completion_message) {
213         DCHECK_GT(messages.size(), 0u);
214         DCHECK(messages.back()->IsCompletionMessage());
215         deferred_messages_.emplace_back(std::move(messages.back()));
216       }
217       return;
218     }
219   }
220 
221   // Dispatch the completion message.
222   if (has_completion_message) {
223     DCHECK_GT(messages.size(), 0u);
224     DCHECK(messages.back()->IsCompletionMessage());
225     messages.back()->HandleMessage(resource_dispatcher_, request_id_);
226   }
227 }
228 
Bind(network::mojom::URLLoaderClientEndpointsPtr endpoints)229 void URLLoaderClientImpl::Bind(
230     network::mojom::URLLoaderClientEndpointsPtr endpoints) {
231   url_loader_.Bind(std::move(endpoints->url_loader), task_runner_);
232   url_loader_client_receiver_.Bind(std::move(endpoints->url_loader_client),
233                                    task_runner_);
234   url_loader_client_receiver_.set_disconnect_handler(base::BindOnce(
235       &URLLoaderClientImpl::OnConnectionClosed, weak_factory_.GetWeakPtr()));
236 }
237 
OnReceiveResponse(network::mojom::URLResponseHeadPtr response_head)238 void URLLoaderClientImpl::OnReceiveResponse(
239     network::mojom::URLResponseHeadPtr response_head) {
240   has_received_response_head_ = true;
241   if (NeedsStoringMessage()) {
242     StoreAndDispatch(
243         std::make_unique<DeferredOnReceiveResponse>(std::move(response_head)));
244   } else {
245     resource_dispatcher_->OnReceivedResponse(request_id_,
246                                              std::move(response_head));
247   }
248 }
249 
OnReceiveRedirect(const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr response_head)250 void URLLoaderClientImpl::OnReceiveRedirect(
251     const net::RedirectInfo& redirect_info,
252     network::mojom::URLResponseHeadPtr response_head) {
253   DCHECK(!has_received_response_head_);
254   if (!bypass_redirect_checks_ &&
255       !IsRedirectSafe(last_loaded_url_, redirect_info.new_url)) {
256     OnComplete(network::URLLoaderCompletionStatus(net::ERR_UNSAFE_REDIRECT));
257     return;
258   }
259 
260   last_loaded_url_ = redirect_info.new_url;
261   if (NeedsStoringMessage()) {
262     StoreAndDispatch(std::make_unique<DeferredOnReceiveRedirect>(
263         redirect_info, std::move(response_head), task_runner_));
264   } else {
265     resource_dispatcher_->OnReceivedRedirect(
266         request_id_, redirect_info, std::move(response_head), task_runner_);
267   }
268 }
269 
OnUploadProgress(int64_t current_position,int64_t total_size,OnUploadProgressCallback ack_callback)270 void URLLoaderClientImpl::OnUploadProgress(
271     int64_t current_position,
272     int64_t total_size,
273     OnUploadProgressCallback ack_callback) {
274   if (NeedsStoringMessage()) {
275     StoreAndDispatch(std::make_unique<DeferredOnUploadProgress>(
276         current_position, total_size));
277   } else {
278     resource_dispatcher_->OnUploadProgress(request_id_, current_position,
279                                            total_size);
280   }
281   std::move(ack_callback).Run();
282 }
283 
OnReceiveCachedMetadata(mojo_base::BigBuffer data)284 void URLLoaderClientImpl::OnReceiveCachedMetadata(mojo_base::BigBuffer data) {
285   if (NeedsStoringMessage()) {
286     StoreAndDispatch(
287         std::make_unique<DeferredOnReceiveCachedMetadata>(std::move(data)));
288   } else {
289     resource_dispatcher_->OnReceivedCachedMetadata(request_id_,
290                                                    std::move(data));
291   }
292 }
293 
OnTransferSizeUpdated(int32_t transfer_size_diff)294 void URLLoaderClientImpl::OnTransferSizeUpdated(int32_t transfer_size_diff) {
295   if (NeedsStoringMessage()) {
296     accumulated_transfer_size_diff_during_deferred_ += transfer_size_diff;
297   } else {
298     resource_dispatcher_->OnTransferSizeUpdated(request_id_,
299                                                 transfer_size_diff);
300   }
301 }
302 
OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)303 void URLLoaderClientImpl::OnStartLoadingResponseBody(
304     mojo::ScopedDataPipeConsumerHandle body) {
305   TRACE_EVENT1("loading", "URLLoaderClientImpl::OnStartLoadingResponseBody",
306                "url", last_loaded_url_.possibly_invalid_spec());
307 
308   DCHECK(has_received_response_head_);
309   DCHECK(!has_received_response_body_);
310   has_received_response_body_ = true;
311 
312   if (NeedsStoringMessage()) {
313     StoreAndDispatch(
314         std::make_unique<DeferredOnStartLoadingResponseBody>(std::move(body)));
315   } else {
316     resource_dispatcher_->OnStartLoadingResponseBody(request_id_,
317                                                      std::move(body));
318   }
319 }
320 
OnComplete(const network::URLLoaderCompletionStatus & status)321 void URLLoaderClientImpl::OnComplete(
322     const network::URLLoaderCompletionStatus& status) {
323   has_received_complete_ = true;
324 
325   // Dispatch completion status to the ResourceDispatcher.
326   // Except for errors, there must always be a response's body.
327   DCHECK(has_received_response_body_ || status.error_code != net::OK);
328   if (NeedsStoringMessage()) {
329     StoreAndDispatch(std::make_unique<DeferredOnComplete>(status));
330   } else {
331     resource_dispatcher_->OnRequestComplete(request_id_, status);
332   }
333 }
334 
NeedsStoringMessage() const335 bool URLLoaderClientImpl::NeedsStoringMessage() const {
336   return is_deferred_ || deferred_messages_.size() > 0 ||
337          accumulated_transfer_size_diff_during_deferred_ > 0;
338 }
339 
StoreAndDispatch(std::unique_ptr<DeferredMessage> message)340 void URLLoaderClientImpl::StoreAndDispatch(
341     std::unique_ptr<DeferredMessage> message) {
342   DCHECK(NeedsStoringMessage());
343   if (is_deferred_) {
344     deferred_messages_.push_back(std::move(message));
345   } else if (deferred_messages_.size() > 0 ||
346              accumulated_transfer_size_diff_during_deferred_ > 0) {
347     deferred_messages_.push_back(std::move(message));
348     FlushDeferredMessages();
349   } else {
350     NOTREACHED();
351   }
352 }
353 
OnConnectionClosed()354 void URLLoaderClientImpl::OnConnectionClosed() {
355   // If the connection aborts before the load completes, mark it as aborted.
356   if (!has_received_complete_) {
357     OnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED));
358     return;
359   }
360 }
361 
362 }  // namespace content
363