blob: 014399c7f5874b49a3efc69e78e957e771f1ffe7 [file] [log] [blame]
yhirano72f62272016-08-13 12:50:061// 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/browser/loader/mojo_async_resource_handler.h"
6
tzikbedcbce2017-01-24 15:08:057#include <algorithm>
yhirano72f62272016-08-13 12:50:068#include <utility>
yhirano2a525f92017-01-18 08:16:469#include <vector>
yhirano72f62272016-08-13 12:50:0610
tzikad092abe2017-01-24 02:34:1711#include "base/bind.h"
tzikbedcbce2017-01-24 15:08:0512#include "base/location.h"
yhirano72f62272016-08-13 12:50:0613#include "base/logging.h"
14#include "base/macros.h"
yhirano72f62272016-08-13 12:50:0615#include "base/time/time.h"
John Delaney192e2b02018-08-14 16:46:3916#include "base/timer/timer.h"
tyoshino3b3ee8e92016-12-07 16:04:0717#include "content/browser/loader/resource_controller.h"
yhirano72f62272016-08-13 12:50:0618#include "content/browser/loader/resource_dispatcher_host_impl.h"
19#include "content/browser/loader/resource_request_info_impl.h"
yhirano59393702016-11-16 06:10:2420#include "content/public/browser/global_request_id.h"
yhirano72f62272016-08-13 12:50:0621#include "mojo/public/c/system/data_pipe.h"
yhirano7153dc472016-11-16 09:42:4622#include "mojo/public/cpp/bindings/message.h"
yhirano72f62272016-08-13 12:50:0623#include "net/base/mime_sniffer.h"
mmenke6add1722017-03-21 21:31:1724#include "net/base/net_errors.h"
yhirano72f62272016-08-13 12:50:0625#include "net/url_request/redirect_info.h"
John Abd-El-Malek46248032018-01-17 19:11:2326#include "services/network/public/cpp/resource_response.h"
Takashi Toyoshimaaa278662017-11-20 11:11:2627#include "services/network/public/cpp/url_loader_completion_status.h"
Yutaka Hirano4cd4e302018-02-01 17:38:0028#include "services/network/resource_scheduler.h"
yhirano72f62272016-08-13 12:50:0629
30namespace content {
31namespace {
32
33int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize;
34
35// MimeTypeResourceHandler *implicitly* requires that the buffer size
36// returned from OnWillRead should be larger than certain size.
37// TODO(yhirano): Fix MimeTypeResourceHandler.
38constexpr size_t kMinAllocationSize = 2 * net::kMaxBytesToSniff;
39
40constexpr size_t kMaxChunkSize = 32 * 1024;
41
rajendrant01219502018-07-03 00:56:4842// Time between sending the transfer size updates to renderer. This threshold is
43// chosen as a compromise between sending too frequent updates and the limit its
44// consumers (DevTools and page load metrics) expect.
45constexpr base::TimeDelta kTransferSizeReportInterval =
46 base::TimeDelta::FromMilliseconds(500);
47
48bool ShouldReportTransferSize(
49 const ResourceRequestInfoImpl* resource_request_info) {
50 // Transfer size is reported only when report_raw_headers is set or the
51 // renderer is allowed to receive the resource response metadata (e.g. by
52 // Cross-Origin Read Blocking).
53 return resource_request_info->ShouldReportRawHeaders() ||
54 !resource_request_info->blocked_response_from_reaching_renderer();
55}
56
yhirano72f62272016-08-13 12:50:0657} // namespace
58
59// This class is for sharing the ownership of a ScopedDataPipeProducerHandle
60// between WriterIOBuffer and MojoAsyncResourceHandler.
61class MojoAsyncResourceHandler::SharedWriter final
62 : public base::RefCountedThreadSafe<SharedWriter> {
63 public:
64 explicit SharedWriter(mojo::ScopedDataPipeProducerHandle writer)
65 : writer_(std::move(writer)) {}
66 mojo::DataPipeProducerHandle writer() { return writer_.get(); }
67
68 private:
69 friend class base::RefCountedThreadSafe<SharedWriter>;
70 ~SharedWriter() {}
71
72 const mojo::ScopedDataPipeProducerHandle writer_;
73
74 DISALLOW_COPY_AND_ASSIGN(SharedWriter);
75};
76
77// This class is a IOBuffer subclass for data gotten from a
78// ScopedDataPipeProducerHandle.
79class MojoAsyncResourceHandler::WriterIOBuffer final
80 : public net::IOBufferWithSize {
81 public:
Reilly Grant789c63e2017-08-04 15:30:1682 // |data| and |size| should be gotten from |writer| via BeginWriteData.
yhirano72f62272016-08-13 12:50:0683 // They will be accesible via IOBuffer methods. As |writer| is stored in this
84 // instance, |data| will be kept valid as long as the following conditions
85 // hold:
86 // 1. |data| is not invalidated via EndWriteDataRaw.
87 // 2. |this| instance is alive.
88 WriterIOBuffer(scoped_refptr<SharedWriter> writer, void* data, size_t size)
89 : net::IOBufferWithSize(static_cast<char*>(data), size),
90 writer_(std::move(writer)) {}
91
92 private:
93 ~WriterIOBuffer() override {
94 // Avoid deleting |data_| in the IOBuffer destructor.
95 data_ = nullptr;
96 }
97
98 // This member is for keeping the writer alive.
99 scoped_refptr<SharedWriter> writer_;
100
101 DISALLOW_COPY_AND_ASSIGN(WriterIOBuffer);
102};
103
104MojoAsyncResourceHandler::MojoAsyncResourceHandler(
105 net::URLRequest* request,
106 ResourceDispatcherHostImpl* rdh,
John Abd-El-Malekb165dc52018-01-18 17:12:18107 network::mojom::URLLoaderRequest mojo_request,
108 network::mojom::URLLoaderClientPtr url_loader_client,
arthursonzogni2e1524a72017-12-18 16:53:26109 ResourceType resource_type,
arthursonzognib521c6a2018-01-08 12:23:40110 uint32_t url_loader_options)
yhirano72f62272016-08-13 12:50:06111 : ResourceHandler(request),
112 rdh_(rdh),
113 binding_(this, std::move(mojo_request)),
arthursonzognib521c6a2018-01-08 12:23:40114 url_loader_options_(url_loader_options),
Hajime Hoshi1c97b842018-03-16 07:10:10115 handle_watcher_(FROM_HERE,
116 mojo::SimpleWatcher::ArmingPolicy::MANUAL,
117 base::SequencedTaskRunnerHandle::Get()),
yhiranobbc904d02016-11-26 05:59:26118 url_loader_client_(std::move(url_loader_client)),
John Delaney192e2b02018-08-14 16:46:39119 report_transfer_size_async_timer_(std::make_unique<base::OneShotTimer>()),
yhiranobbc904d02016-11-26 05:59:26120 weak_factory_(this) {
arthursonzognib521c6a2018-01-08 12:23:40121 DCHECK(IsResourceTypeFrame(resource_type) ||
Makoto Shimazuc6185fc2018-06-12 14:47:00122 resource_type == RESOURCE_TYPE_SERVICE_WORKER ||
John Abd-El-Malekb165dc52018-01-18 17:12:18123 !(url_loader_options_ &
124 network::mojom::kURLLoadOptionSendSSLInfoWithResponse));
arthursonzognib521c6a2018-01-08 12:23:40125 DCHECK(resource_type == RESOURCE_TYPE_MAIN_FRAME ||
126 !(url_loader_options_ &
John Abd-El-Malekb165dc52018-01-18 17:12:18127 network::mojom::kURLLoadOptionSendSSLInfoForCertificateError));
yhirano72f62272016-08-13 12:50:06128 DCHECK(url_loader_client_);
129 InitializeResourceBufferConstants();
yhirano59393702016-11-16 06:10:24130 // This unretained pointer is safe, because |binding_| is owned by |this| and
131 // the callback will never be called after |this| is destroyed.
Yuzhu Shen07e96312018-02-05 23:20:29132 binding_.set_connection_error_with_reason_handler(base::BindOnce(
tzik0f14f192017-08-15 02:43:33133 &MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
yhirano72f62272016-08-13 12:50:06134}
135
136MojoAsyncResourceHandler::~MojoAsyncResourceHandler() {
137 if (has_checked_for_sufficient_resources_)
138 rdh_->FinishedWithResourcesForRequest(request());
139}
140
Daniel Bratellf77777a2017-10-19 09:12:06141void MojoAsyncResourceHandler::InitializeResourceBufferConstants() {
142 static bool did_init = false;
143 if (did_init)
144 return;
145 did_init = true;
146
147 GetNumericArg("resource-buffer-size", &g_allocation_size);
148}
149
mmenke87f5c77a2017-01-31 16:11:26150void MojoAsyncResourceHandler::OnRequestRedirected(
yhirano72f62272016-08-13 12:50:06151 const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:23152 network::ResourceResponse* response,
mmenke87f5c77a2017-01-31 16:11:26153 std::unique_ptr<ResourceController> controller) {
yhirano7153dc472016-11-16 09:42:46154 // Unlike OnResponseStarted, OnRequestRedirected will NOT be preceded by
155 // OnWillRead.
mmenke87f5c77a2017-01-31 16:11:26156 DCHECK(!has_controller());
yhirano7153dc472016-11-16 09:42:46157 DCHECK(!shared_writer_);
158
yhirano7153dc472016-11-16 09:42:46159 request()->LogBlockedBy("MojoAsyncResourceHandler");
mmenke87f5c77a2017-01-31 16:11:26160 HoldController(std::move(controller));
yhirano7153dc472016-11-16 09:42:46161 did_defer_on_redirect_ = true;
162
yhirano7153dc472016-11-16 09:42:46163 response->head.encoded_data_length = request()->GetTotalReceivedBytes();
164 response->head.request_start = request()->creation_time();
165 response->head.response_start = base::TimeTicks::Now();
166 // TODO(davidben): Is it necessary to pass the new first party URL for
167 // cookies? The only case where it can change is top-level navigation requests
168 // and hopefully those will eventually all be owned by the browser. It's
169 // possible this is still needed while renderer-owned ones exist.
170 url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
yhirano72f62272016-08-13 12:50:06171}
172
mmenke87f5c77a2017-01-31 16:11:26173void MojoAsyncResourceHandler::OnResponseStarted(
John Abd-El-Malek46248032018-01-17 19:11:23174 network::ResourceResponse* response,
mmenke87f5c77a2017-01-31 16:11:26175 std::unique_ptr<ResourceController> controller) {
176 DCHECK(!has_controller());
177
tzikbedcbce2017-01-24 15:08:05178 if (upload_progress_tracker_) {
179 upload_progress_tracker_->OnUploadCompleted();
180 upload_progress_tracker_ = nullptr;
181 }
yhirano72f62272016-08-13 12:50:06182
yhiranoa275b3c2016-12-20 03:58:40183 response->head.encoded_data_length = request()->raw_header_size();
184 reported_total_received_bytes_ = response->head.encoded_data_length;
yhirano72f62272016-08-13 12:50:06185
186 response->head.request_start = request()->creation_time();
Arthur Sonzogni55c05e12018-06-13 15:20:54187 response->head.response_start = base::TimeTicks::Now();
yhirano72f62272016-08-13 12:50:06188 sent_received_response_message_ = true;
John Delaney81a44ef2018-10-05 21:35:51189 response->head.was_fetched_via_cache = request()->was_cached();
tzik47a9f9b2016-12-01 04:16:24190
Andrey Kosyakov87cd9252018-03-27 16:58:27191 if ((url_loader_options_ &
192 network::mojom::kURLLoadOptionSendSSLInfoWithResponse) &&
193 request()->ssl_info().cert) {
194 response->head.ssl_info = request()->ssl_info();
195 }
arthursonzognib521c6a2018-01-08 12:23:40196
Philip Rogers7178f5c2018-07-09 18:52:59197 url_loader_client_->OnReceiveResponse(response->head);
yhirano2a525f92017-01-18 08:16:46198
199 net::IOBufferWithSize* metadata = GetResponseMetadata(request());
200 if (metadata) {
201 const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
202
203 url_loader_client_->OnReceiveCachedMetadata(
204 std::vector<uint8_t>(data, data + metadata->size()));
205 }
mmenke87f5c77a2017-01-31 16:11:26206
John Abd-El-Malekb165dc52018-01-18 17:12:18207 if (url_loader_options_ &
208 network::mojom::kURLLoadOptionPauseOnResponseStarted) {
arthursonzogni2e1524a72017-12-18 16:53:26209 did_defer_on_response_started_ = true;
210 DCHECK(!has_controller());
211 request()->LogBlockedBy("MojoAsyncResourceHandler");
212 HoldController(std::move(controller));
213 return;
214 }
215
mmenke87f5c77a2017-01-31 16:11:26216 controller->Resume();
yhirano72f62272016-08-13 12:50:06217}
218
mmenke87f5c77a2017-01-31 16:11:26219void MojoAsyncResourceHandler::OnWillStart(
220 const GURL& url,
221 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05222 if (GetRequestInfo()->is_upload_progress_enabled() &&
223 request()->has_upload()) {
224 upload_progress_tracker_ = CreateUploadProgressTracker(
225 FROM_HERE,
226 base::BindRepeating(&MojoAsyncResourceHandler::SendUploadProgress,
227 base::Unretained(this)));
228 }
229
mmenke87f5c77a2017-01-31 16:11:26230 controller->Resume();
yhirano72f62272016-08-13 12:50:06231}
232
mmenke3c1d10c2017-03-09 16:25:45233void MojoAsyncResourceHandler::OnWillRead(
234 scoped_refptr<net::IOBuffer>* buf,
235 int* buf_size,
236 std::unique_ptr<ResourceController> controller) {
mmenke6add1722017-03-21 21:31:17237 // |buffer_| is set to nullptr on successful read completion (Except for the
238 // final 0-byte read, so this DCHECK will also catch OnWillRead being called
239 // after OnReadCompelted(0)).
240 DCHECK(!buffer_);
241 DCHECK_EQ(0u, buffer_offset_);
242
mmenke3c1d10c2017-03-09 16:25:45243 if (!CheckForSufficientResource()) {
244 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
245 return;
246 }
yhirano72f62272016-08-13 12:50:06247
Philip Rogers7178f5c2018-07-09 18:52:59248 bool first_call = false;
yhirano72f62272016-08-13 12:50:06249 if (!shared_writer_) {
Philip Rogers7178f5c2018-07-09 18:52:59250 first_call = true;
251 MojoCreateDataPipeOptions options;
252 options.struct_size = sizeof(MojoCreateDataPipeOptions);
253 options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
254 options.element_num_bytes = 1;
255 options.capacity_num_bytes = g_allocation_size;
256 mojo::ScopedDataPipeProducerHandle producer;
257 mojo::ScopedDataPipeConsumerHandle consumer;
258
259 MojoResult result = mojo::CreateDataPipe(&options, &producer, &consumer);
260 if (result != MOJO_RESULT_OK) {
261 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
262 return;
263 }
264 DCHECK(producer.is_valid());
265 DCHECK(consumer.is_valid());
266
267 response_body_consumer_handle_ = std::move(consumer);
268 shared_writer_ = new SharedWriter(std::move(producer));
269 handle_watcher_.Watch(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE,
270 base::Bind(&MojoAsyncResourceHandler::OnWritable,
271 base::Unretained(this)));
272 handle_watcher_.ArmOrNotify();
mmenke6add1722017-03-21 21:31:17273 }
yhirano72f62272016-08-13 12:50:06274
mmenke6add1722017-03-21 21:31:17275 bool defer = false;
276 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
277 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
278 return;
279 }
280
281 if (defer) {
282 DCHECK(!buffer_);
283 parent_buffer_ = buf;
284 parent_buffer_size_ = buf_size;
285 HoldController(std::move(controller));
286 request()->LogBlockedBy("MojoAsyncResourceHandler");
287 did_defer_on_will_read_ = true;
288 return;
289 }
290
291 // The first call to OnWillRead must return a buffer of at least
292 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an
293 // intermediary buffer.
Philip Rogers7178f5c2018-07-09 18:52:59294 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) {
mmenke6add1722017-03-21 21:31:17295 // The allocated buffer is too small, so need to create an intermediary one.
296 if (EndWrite(0) != MOJO_RESULT_OK) {
mmenke3c1d10c2017-03-09 16:25:45297 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
298 return;
299 }
yhirano72f62272016-08-13 12:50:06300 DCHECK(!is_using_io_buffer_not_from_writer_);
301 is_using_io_buffer_not_from_writer_ = true;
Victor Costan63c8b3d2018-09-01 01:34:10302 buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(kMinAllocationSize);
yhirano72f62272016-08-13 12:50:06303 }
304
yhirano72f62272016-08-13 12:50:06305 *buf = buffer_;
306 *buf_size = buffer_->size();
mmenke3c1d10c2017-03-09 16:25:45307 controller->Resume();
yhirano72f62272016-08-13 12:50:06308}
309
John Delaney192e2b02018-08-14 16:46:39310void MojoAsyncResourceHandler::set_report_transfer_size_async_timer_for_testing(
311 std::unique_ptr<base::OneShotTimer> timer) {
312 report_transfer_size_async_timer_ = std::move(timer);
313}
314
315void MojoAsyncResourceHandler::SendTransferSizeUpdate() {
316 int64_t transfer_size_diff = CalculateRecentlyReceivedBytes();
317 if (transfer_size_diff > 0) {
318 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
319 }
320}
321
322void MojoAsyncResourceHandler::EnsureTransferSizeUpdate() {
323 auto current_time = base::TimeTicks::Now();
324 if (earliest_time_next_transfer_size_report_.is_null() ||
325 earliest_time_next_transfer_size_report_ <= current_time) {
326 report_transfer_size_async_timer_->Stop();
327 SendTransferSizeUpdate();
328 earliest_time_next_transfer_size_report_ =
329 current_time + kTransferSizeReportInterval;
330 } else {
331 // Ensure that a single transfer update will eventually occur even if reads
332 // stop. Unretained is safe here because the callback will only live as long
333 // as |report_transfer_size_async_timer_|.
334 report_transfer_size_async_timer_->Start(
335 FROM_HERE, kTransferSizeReportInterval,
336 base::BindOnce(&MojoAsyncResourceHandler::SendTransferSizeUpdate,
337 base::Unretained(this)));
338 }
339}
340
mmenke87f5c77a2017-01-31 16:11:26341void MojoAsyncResourceHandler::OnReadCompleted(
342 int bytes_read,
343 std::unique_ptr<ResourceController> controller) {
344 DCHECK(!has_controller());
yhirano72f62272016-08-13 12:50:06345 DCHECK_GE(bytes_read, 0);
346 DCHECK(buffer_);
347
mmenke6add1722017-03-21 21:31:17348 if (bytes_read == 0) {
349 // Note that |buffer_| is not cleared here, which will cause a DCHECK on
350 // subsequent OnWillRead calls.
mmenke87f5c77a2017-01-31 16:11:26351 controller->Resume();
352 return;
353 }
yhirano72f62272016-08-13 12:50:06354
John Delaney192e2b02018-08-14 16:46:39355 if (ShouldReportTransferSize(GetRequestInfo())) {
356 EnsureTransferSizeUpdate();
yhiranoa275b3c2016-12-20 03:58:40357 }
358
Philip Rogers7178f5c2018-07-09 18:52:59359 if (response_body_consumer_handle_.is_valid()) {
360 // Send the data pipe on the first OnReadCompleted call.
361 url_loader_client_->OnStartLoadingResponseBody(
362 std::move(response_body_consumer_handle_));
363 response_body_consumer_handle_.reset();
364 }
yhirano246883ff62017-01-19 04:19:08365
yhirano72f62272016-08-13 12:50:06366 if (is_using_io_buffer_not_from_writer_) {
mmenke6add1722017-03-21 21:31:17367 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead.
yhirano72f62272016-08-13 12:50:06368 DCHECK_EQ(0u, buffer_bytes_read_);
369 buffer_bytes_read_ = bytes_read;
mmenke87f5c77a2017-01-31 16:11:26370 bool defer = false;
371 if (!CopyReadDataToDataPipe(&defer)) {
mmenke6add1722017-03-21 21:31:17372 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
mmenke87f5c77a2017-01-31 16:11:26373 return;
374 }
375 if (defer) {
yhirano7153dc472016-11-16 09:42:46376 request()->LogBlockedBy("MojoAsyncResourceHandler");
377 did_defer_on_writing_ = true;
mmenke87f5c77a2017-01-31 16:11:26378 HoldController(std::move(controller));
379 return;
yhirano7153dc472016-11-16 09:42:46380 }
mmenke87f5c77a2017-01-31 16:11:26381 controller->Resume();
382 return;
yhirano72f62272016-08-13 12:50:06383 }
384
mmenke87f5c77a2017-01-31 16:11:26385 if (EndWrite(bytes_read) != MOJO_RESULT_OK) {
386 controller->Cancel();
387 return;
388 }
mmenke87f5c77a2017-01-31 16:11:26389
mmenke6add1722017-03-21 21:31:17390 buffer_ = nullptr;
mmenke87f5c77a2017-01-31 16:11:26391 controller->Resume();
yhirano72f62272016-08-13 12:50:06392}
393
Chong Zhangf19dde92018-05-23 04:33:59394void MojoAsyncResourceHandler::FollowRedirect(
Jun Cai605ff0e72018-06-12 22:29:20395 const base::Optional<std::vector<std::string>>&
396 to_be_removed_request_headers,
Chong Zhangf19dde92018-05-23 04:33:59397 const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
yhirano7153dc472016-11-16 09:42:46398 if (!request()->status().is_success()) {
399 DVLOG(1) << "FollowRedirect for invalid request";
400 return;
401 }
402 if (!did_defer_on_redirect_) {
403 DVLOG(1) << "Malformed FollowRedirect request";
404 ReportBadMessage("Malformed FollowRedirect request");
405 return;
406 }
407
mmenke6add1722017-03-21 21:31:17408 DCHECK(!did_defer_on_will_read_);
yhirano7153dc472016-11-16 09:42:46409 DCHECK(!did_defer_on_writing_);
410 did_defer_on_redirect_ = false;
411 request()->LogUnblocked();
Chong Zhanga4e12afa2018-06-22 01:51:30412 ResumeForRedirect(modified_request_headers);
yhirano72f62272016-08-13 12:50:06413}
414
arthursonzogni2e1524a72017-12-18 16:53:26415void MojoAsyncResourceHandler::ProceedWithResponse() {
416 DCHECK(did_defer_on_response_started_);
arthursonzogni84dda212018-03-01 02:06:36417
arthursonzogni2e1524a72017-12-18 16:53:26418 request()->LogUnblocked();
419 Resume();
420}
421
yhirano933ee582017-01-27 13:28:40422void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority,
423 int32_t intra_priority_value) {
John Abd-El-Malekeb1a5382018-01-05 16:58:00424 auto* scheduler = ResourceDispatcherHostImpl::Get()->scheduler();
425 if (intra_priority_value == -1) {
426 scheduler->ReprioritizeRequest(request(), priority);
427 } else {
428 scheduler->ReprioritizeRequest(request(), priority, intra_priority_value);
429 }
yhirano933ee582017-01-27 13:28:40430}
431
Yuzhu Shen99681b12017-09-28 06:11:10432void MojoAsyncResourceHandler::PauseReadingBodyFromNet() {
Yuzhu Shen19cafda02018-02-01 19:45:20433 ResourceHandler::PauseReadingBodyFromNet();
Yuzhu Shen0bec9542017-09-16 01:31:59434}
435
Yuzhu Shen99681b12017-09-28 06:11:10436void MojoAsyncResourceHandler::ResumeReadingBodyFromNet() {
Yuzhu Shen19cafda02018-02-01 19:45:20437 ResourceHandler::ResumeReadingBodyFromNet();
Yuzhu Shen0bec9542017-09-16 01:31:59438}
439
yhirano7153dc472016-11-16 09:42:46440void MojoAsyncResourceHandler::OnWritableForTesting() {
441 OnWritable(MOJO_RESULT_OK);
yhirano72f62272016-08-13 12:50:06442}
443
444void MojoAsyncResourceHandler::SetAllocationSizeForTesting(size_t size) {
445 g_allocation_size = size;
446}
447
448MojoResult MojoAsyncResourceHandler::BeginWrite(void** data,
449 uint32_t* available) {
Reilly Grant789c63e2017-08-04 15:30:16450 MojoResult result = shared_writer_->writer().BeginWriteData(
451 data, available, MOJO_WRITE_DATA_FLAG_NONE);
yhirano72f62272016-08-13 12:50:06452 if (result == MOJO_RESULT_OK)
453 *available = std::min(*available, static_cast<uint32_t>(kMaxChunkSize));
rockot9eadaba2017-03-15 23:57:47454 else if (result == MOJO_RESULT_SHOULD_WAIT)
455 handle_watcher_.ArmOrNotify();
yhirano72f62272016-08-13 12:50:06456 return result;
457}
458
459MojoResult MojoAsyncResourceHandler::EndWrite(uint32_t written) {
Reilly Grant789c63e2017-08-04 15:30:16460 MojoResult result = shared_writer_->writer().EndWriteData(written);
horoe8442e62017-04-27 19:10:48461 if (result == MOJO_RESULT_OK) {
462 total_written_bytes_ += written;
rockot9eadaba2017-03-15 23:57:47463 handle_watcher_.ArmOrNotify();
horoe8442e62017-04-27 19:10:48464 }
rockot9eadaba2017-03-15 23:57:47465 return result;
yhirano72f62272016-08-13 12:50:06466}
467
yhirano2a525f92017-01-18 08:16:46468net::IOBufferWithSize* MojoAsyncResourceHandler::GetResponseMetadata(
469 net::URLRequest* request) {
470 return request->response_info().metadata.get();
471}
472
yhirano72f62272016-08-13 12:50:06473void MojoAsyncResourceHandler::OnResponseCompleted(
Takashi Toyoshima8f988532017-11-13 07:32:37474 const net::URLRequestStatus& request_status,
mmenke87f5c77a2017-01-31 16:11:26475 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05476 // Ensure sending the final upload progress message here, since
477 // OnResponseCompleted can be called without OnResponseStarted on cancellation
478 // or error cases.
479 if (upload_progress_tracker_) {
480 upload_progress_tracker_->OnUploadCompleted();
481 upload_progress_tracker_ = nullptr;
482 }
483
yhirano72f62272016-08-13 12:50:06484 shared_writer_ = nullptr;
485 buffer_ = nullptr;
486 handle_watcher_.Cancel();
487
yhirano72f62272016-08-13 12:50:06488 // TODO(gavinp): Remove this CHECK when we figure out the cause of
489 // http://crbug.com/124680 . This check mirrors closely check in
490 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
491 // ResourceHandleInternal which asserts on its state and crashes. By crashing
492 // when the message is sent, we should get better crash reports.
Takashi Toyoshima8f988532017-11-13 07:32:37493 CHECK(request_status.status() != net::URLRequestStatus::SUCCESS ||
yhirano72f62272016-08-13 12:50:06494 sent_received_response_message_);
495
Takashi Toyoshima8f988532017-11-13 07:32:37496 int error_code = request_status.error();
yhirano72f62272016-08-13 12:50:06497
Takashi Toyoshima8f988532017-11-13 07:32:37498 DCHECK_NE(request_status.status(), net::URLRequestStatus::IO_PENDING);
yhirano72f62272016-08-13 12:50:06499
Takashi Toyoshimaaa278662017-11-20 11:11:26500 network::URLLoaderCompletionStatus loader_status;
Takashi Toyoshima8f988532017-11-13 07:32:37501 loader_status.error_code = error_code;
Brad Lassey16c13f72018-03-19 19:37:50502 if (error_code == net::ERR_QUIC_PROTOCOL_ERROR) {
503 net::NetErrorDetails details;
504 request()->PopulateNetErrorDetails(&details);
505 loader_status.extended_error_code = details.quic_connection_error;
Johannes Henkel6a43fef2018-05-17 18:41:52506 } else if (error_code == net::ERR_BLOCKED_BY_CLIENT ||
507 error_code == net::ERR_BLOCKED_BY_RESPONSE) {
508 ResourceRequestInfoImpl* resource_request_info =
509 ResourceRequestInfoImpl::ForRequest(request());
510 auto maybe_reason =
511 resource_request_info->GetResourceRequestBlockedReason();
512 // Ideally, every blocked by client / blocked by response error
513 // would be annotated with a blocked reason, but we can't guarantee it
514 // here, so sometimes we won't populate extended_error_code which
515 // corresonds ResourceRequestBlockedReason::kOther.
516 if (maybe_reason) {
517 loader_status.extended_error_code =
518 static_cast<int>(maybe_reason.value());
519 }
Brad Lassey16c13f72018-03-19 19:37:50520 }
Arthur Sonzogni0b2b1a922018-03-15 15:24:15521 loader_status.exists_in_cache = request()->response_info().was_cached;
Takashi Toyoshima8f988532017-11-13 07:32:37522 loader_status.completion_time = base::TimeTicks::Now();
523 loader_status.encoded_data_length = request()->GetTotalReceivedBytes();
524 loader_status.encoded_body_length = request()->GetRawBodyBytes();
525 loader_status.decoded_body_length = total_written_bytes_;
Lukasz Anforowiczbf576b02018-06-06 17:47:31526 loader_status.should_report_corb_blocking =
527 GetRequestInfo()->should_report_corb_blocking();
yhirano72f62272016-08-13 12:50:06528
arthursonzognib521c6a2018-01-08 12:23:40529 if ((url_loader_options_ &
John Abd-El-Malekb165dc52018-01-18 17:12:18530 network::mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
arthursonzognib521c6a2018-01-08 12:23:40531 net::IsCertStatusError(request()->ssl_info().cert_status) &&
532 !net::IsCertStatusMinorError(request()->ssl_info().cert_status)) {
533 loader_status.ssl_info = request()->ssl_info();
534 }
535
rajendrant01219502018-07-03 00:56:48536 if (ShouldReportTransferSize(GetRequestInfo())) {
John Delaney192e2b02018-08-14 16:46:39537 // All received bytes will be reported.
538 report_transfer_size_async_timer_->Stop();
539 SendTransferSizeUpdate();
rajendrant01219502018-07-03 00:56:48540 }
541
Takashi Toyoshima8f988532017-11-13 07:32:37542 url_loader_client_->OnComplete(loader_status);
mmenke87f5c77a2017-01-31 16:11:26543 controller->Resume();
yhirano72f62272016-08-13 12:50:06544}
545
546bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) {
mmenke6add1722017-03-21 21:31:17547 while (buffer_bytes_read_ > 0) {
yhirano72f62272016-08-13 12:50:06548 scoped_refptr<net::IOBufferWithSize> dest;
549 if (!AllocateWriterIOBuffer(&dest, defer))
550 return false;
551 if (*defer)
552 return true;
yhirano72f62272016-08-13 12:50:06553
554 size_t copied_size =
555 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size()));
556 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size);
557 buffer_offset_ += copied_size;
558 buffer_bytes_read_ -= copied_size;
559 if (EndWrite(copied_size) != MOJO_RESULT_OK)
560 return false;
yhirano4fede0f2017-03-21 03:33:15561 }
mmenke6add1722017-03-21 21:31:17562
563 // All bytes are copied.
564 buffer_ = nullptr;
565 buffer_offset_ = 0;
566 is_using_io_buffer_not_from_writer_ = false;
567 return true;
yhirano72f62272016-08-13 12:50:06568}
569
570bool MojoAsyncResourceHandler::AllocateWriterIOBuffer(
571 scoped_refptr<net::IOBufferWithSize>* buf,
572 bool* defer) {
573 void* data = nullptr;
574 uint32_t available = 0;
575 MojoResult result = BeginWrite(&data, &available);
576 if (result == MOJO_RESULT_SHOULD_WAIT) {
577 *defer = true;
578 return true;
579 }
580 if (result != MOJO_RESULT_OK)
581 return false;
mmenke6add1722017-03-21 21:31:17582 DCHECK_GT(available, 0u);
yhirano72f62272016-08-13 12:50:06583 *buf = new WriterIOBuffer(shared_writer_, data, available);
584 return true;
585}
586
yhirano72f62272016-08-13 12:50:06587bool MojoAsyncResourceHandler::CheckForSufficientResource() {
588 if (has_checked_for_sufficient_resources_)
589 return true;
590 has_checked_for_sufficient_resources_ = true;
591
592 if (rdh_->HasSufficientResourcesForRequest(request()))
593 return true;
594
yhirano72f62272016-08-13 12:50:06595 return false;
596}
597
yhirano7153dc472016-11-16 09:42:46598void MojoAsyncResourceHandler::OnWritable(MojoResult result) {
mmenke6add1722017-03-21 21:31:17599 if (did_defer_on_will_read_) {
600 DCHECK(has_controller());
601 DCHECK(!did_defer_on_writing_);
602 DCHECK(!did_defer_on_redirect_);
603
604 did_defer_on_will_read_ = false;
605
606 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_;
607 parent_buffer_ = nullptr;
608 int* parent_buffer_size = parent_buffer_size_;
609 parent_buffer_size_ = nullptr;
610
611 request()->LogUnblocked();
612 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController());
613 return;
614 }
615
yhirano7153dc472016-11-16 09:42:46616 if (!did_defer_on_writing_)
617 return;
mmenke87f5c77a2017-01-31 16:11:26618 DCHECK(has_controller());
yhirano7153dc472016-11-16 09:42:46619 DCHECK(!did_defer_on_redirect_);
620 did_defer_on_writing_ = false;
621
mmenke6add1722017-03-21 21:31:17622 DCHECK(is_using_io_buffer_not_from_writer_);
623 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
624 // to the data pipe.
625 DCHECK_GT(buffer_bytes_read_, 0u);
626 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
627 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
628 return;
yhirano7153dc472016-11-16 09:42:46629 }
630
631 if (did_defer_on_writing_) {
632 // Continue waiting.
633 return;
634 }
635 request()->LogUnblocked();
mmenke87f5c77a2017-01-31 16:11:26636 Resume();
yhirano72f62272016-08-13 12:50:06637}
638
Yuzhu Shen07e96312018-02-05 23:20:29639void MojoAsyncResourceHandler::Cancel(uint32_t custom_reason,
640 const std::string& description) {
641 ResourceRequestInfoImpl* info = GetRequestInfo();
642
643 if (custom_reason == network::mojom::URLLoader::kClientDisconnectReason)
644 info->set_custom_cancel_reason(description);
645
yhirano59393702016-11-16 06:10:24646 ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer(
647 GlobalRequestID(info->GetChildID(), info->GetRequestID()));
648}
649
yhiranoa275b3c2016-12-20 03:58:40650int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() {
651 int64_t total_received_bytes = request()->GetTotalReceivedBytes();
652 int64_t bytes_to_report =
653 total_received_bytes - reported_total_received_bytes_;
654 reported_total_received_bytes_ = total_received_bytes;
655 DCHECK_LE(0, bytes_to_report);
656 return bytes_to_report;
657}
658
yhirano7153dc472016-11-16 09:42:46659void MojoAsyncResourceHandler::ReportBadMessage(const std::string& error) {
660 mojo::ReportBadMessage(error);
661}
662
John Abd-El-Malek3bbbdf92018-01-30 03:27:35663std::unique_ptr<network::UploadProgressTracker>
tzikbedcbce2017-01-24 15:08:05664MojoAsyncResourceHandler::CreateUploadProgressTracker(
Brett Wilson1c990022017-09-12 20:11:15665 const base::Location& from_here,
John Abd-El-Malek3bbbdf92018-01-30 03:27:35666 network::UploadProgressTracker::UploadProgressReportCallback callback) {
667 return std::make_unique<network::UploadProgressTracker>(
668 from_here, std::move(callback), request());
tzikbedcbce2017-01-24 15:08:05669}
670
tzikbedcbce2017-01-24 15:08:05671void MojoAsyncResourceHandler::SendUploadProgress(
672 const net::UploadProgress& progress) {
673 url_loader_client_->OnUploadProgress(
674 progress.position(), progress.size(),
tzik0f14f192017-08-15 02:43:33675 base::BindOnce(&MojoAsyncResourceHandler::OnUploadProgressACK,
676 weak_factory_.GetWeakPtr()));
tzikbedcbce2017-01-24 15:08:05677}
678
679void MojoAsyncResourceHandler::OnUploadProgressACK() {
680 if (upload_progress_tracker_)
681 upload_progress_tracker_->OnAckReceived();
682}
683
yhirano72f62272016-08-13 12:50:06684} // namespace content