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