blob: 130a2fea1bbd47fb1426c68823ebe10f88b4d7c1 [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"
tzikbedcbce2017-01-24 15:08:0515#include "base/memory/ptr_util.h"
yhirano72f62272016-08-13 12:50:0616#include "base/time/time.h"
tzik47a9f9b2016-12-01 04:16:2417#include "content/browser/loader/downloaded_temp_file_impl.h"
arthursonzogni84dda212018-03-01 02:06:3618#include "content/browser/loader/navigation_metrics.h"
tyoshino3b3ee8e92016-12-07 16:04:0719#include "content/browser/loader/resource_controller.h"
yhirano72f62272016-08-13 12:50:0620#include "content/browser/loader/resource_dispatcher_host_impl.h"
21#include "content/browser/loader/resource_request_info_impl.h"
yhirano59393702016-11-16 06:10:2422#include "content/public/browser/global_request_id.h"
yhirano72f62272016-08-13 12:50:0623#include "mojo/public/c/system/data_pipe.h"
yhirano7153dc472016-11-16 09:42:4624#include "mojo/public/cpp/bindings/message.h"
yhirano72f62272016-08-13 12:50:0625#include "net/base/mime_sniffer.h"
mmenke6add1722017-03-21 21:31:1726#include "net/base/net_errors.h"
yhirano72f62272016-08-13 12:50:0627#include "net/url_request/redirect_info.h"
John Abd-El-Malek46248032018-01-17 19:11:2328#include "services/network/public/cpp/resource_response.h"
Takashi Toyoshimaaa278662017-11-20 11:11:2629#include "services/network/public/cpp/url_loader_completion_status.h"
Yutaka Hirano4cd4e302018-02-01 17:38:0030#include "services/network/resource_scheduler.h"
yhirano72f62272016-08-13 12:50:0631
32namespace content {
33namespace {
34
35int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize;
36
37// MimeTypeResourceHandler *implicitly* requires that the buffer size
38// returned from OnWillRead should be larger than certain size.
39// TODO(yhirano): Fix MimeTypeResourceHandler.
40constexpr size_t kMinAllocationSize = 2 * net::kMaxBytesToSniff;
41
42constexpr size_t kMaxChunkSize = 32 * 1024;
43
John Abd-El-Malekb165dc52018-01-18 17:12:1844void NotReached(network::mojom::URLLoaderRequest mojo_request,
45 network::mojom::URLLoaderClientPtr url_loader_client) {
tzikad092abe2017-01-24 02:34:1746 NOTREACHED();
47}
48
yhirano72f62272016-08-13 12:50:0649} // namespace
50
51// This class is for sharing the ownership of a ScopedDataPipeProducerHandle
52// between WriterIOBuffer and MojoAsyncResourceHandler.
53class MojoAsyncResourceHandler::SharedWriter final
54 : public base::RefCountedThreadSafe<SharedWriter> {
55 public:
56 explicit SharedWriter(mojo::ScopedDataPipeProducerHandle writer)
57 : writer_(std::move(writer)) {}
58 mojo::DataPipeProducerHandle writer() { return writer_.get(); }
59
60 private:
61 friend class base::RefCountedThreadSafe<SharedWriter>;
62 ~SharedWriter() {}
63
64 const mojo::ScopedDataPipeProducerHandle writer_;
65
66 DISALLOW_COPY_AND_ASSIGN(SharedWriter);
67};
68
69// This class is a IOBuffer subclass for data gotten from a
70// ScopedDataPipeProducerHandle.
71class MojoAsyncResourceHandler::WriterIOBuffer final
72 : public net::IOBufferWithSize {
73 public:
Reilly Grant789c63e2017-08-04 15:30:1674 // |data| and |size| should be gotten from |writer| via BeginWriteData.
yhirano72f62272016-08-13 12:50:0675 // They will be accesible via IOBuffer methods. As |writer| is stored in this
76 // instance, |data| will be kept valid as long as the following conditions
77 // hold:
78 // 1. |data| is not invalidated via EndWriteDataRaw.
79 // 2. |this| instance is alive.
80 WriterIOBuffer(scoped_refptr<SharedWriter> writer, void* data, size_t size)
81 : net::IOBufferWithSize(static_cast<char*>(data), size),
82 writer_(std::move(writer)) {}
83
84 private:
85 ~WriterIOBuffer() override {
86 // Avoid deleting |data_| in the IOBuffer destructor.
87 data_ = nullptr;
88 }
89
90 // This member is for keeping the writer alive.
91 scoped_refptr<SharedWriter> writer_;
92
93 DISALLOW_COPY_AND_ASSIGN(WriterIOBuffer);
94};
95
96MojoAsyncResourceHandler::MojoAsyncResourceHandler(
97 net::URLRequest* request,
98 ResourceDispatcherHostImpl* rdh,
John Abd-El-Malekb165dc52018-01-18 17:12:1899 network::mojom::URLLoaderRequest mojo_request,
100 network::mojom::URLLoaderClientPtr url_loader_client,
arthursonzogni2e1524a72017-12-18 16:53:26101 ResourceType resource_type,
arthursonzognib521c6a2018-01-08 12:23:40102 uint32_t url_loader_options)
yhirano72f62272016-08-13 12:50:06103 : ResourceHandler(request),
104 rdh_(rdh),
105 binding_(this, std::move(mojo_request)),
arthursonzognib521c6a2018-01-08 12:23:40106 url_loader_options_(url_loader_options),
Hajime Hoshi1c97b842018-03-16 07:10:10107 handle_watcher_(FROM_HERE,
108 mojo::SimpleWatcher::ArmingPolicy::MANUAL,
109 base::SequencedTaskRunnerHandle::Get()),
yhiranobbc904d02016-11-26 05:59:26110 url_loader_client_(std::move(url_loader_client)),
111 weak_factory_(this) {
arthursonzognib521c6a2018-01-08 12:23:40112 DCHECK(IsResourceTypeFrame(resource_type) ||
John Abd-El-Malekb165dc52018-01-18 17:12:18113 !(url_loader_options_ &
114 network::mojom::kURLLoadOptionSendSSLInfoWithResponse));
arthursonzognib521c6a2018-01-08 12:23:40115 DCHECK(resource_type == RESOURCE_TYPE_MAIN_FRAME ||
116 !(url_loader_options_ &
John Abd-El-Malekb165dc52018-01-18 17:12:18117 network::mojom::kURLLoadOptionSendSSLInfoForCertificateError));
yhirano72f62272016-08-13 12:50:06118 DCHECK(url_loader_client_);
119 InitializeResourceBufferConstants();
yhirano59393702016-11-16 06:10:24120 // This unretained pointer is safe, because |binding_| is owned by |this| and
121 // the callback will never be called after |this| is destroyed.
Yuzhu Shen07e96312018-02-05 23:20:29122 binding_.set_connection_error_with_reason_handler(base::BindOnce(
tzik0f14f192017-08-15 02:43:33123 &MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
yhiranobbc904d02016-11-26 05:59:26124
tzikad092abe2017-01-24 02:34:17125 if (IsResourceTypeFrame(resource_type)) {
126 GetRequestInfo()->set_on_transfer(base::Bind(
127 &MojoAsyncResourceHandler::OnTransfer, weak_factory_.GetWeakPtr()));
128 } else {
129 GetRequestInfo()->set_on_transfer(base::Bind(&NotReached));
130 }
yhirano72f62272016-08-13 12:50:06131}
132
133MojoAsyncResourceHandler::~MojoAsyncResourceHandler() {
134 if (has_checked_for_sufficient_resources_)
135 rdh_->FinishedWithResourcesForRequest(request());
136}
137
Daniel Bratellf77777a2017-10-19 09:12:06138void MojoAsyncResourceHandler::InitializeResourceBufferConstants() {
139 static bool did_init = false;
140 if (did_init)
141 return;
142 did_init = true;
143
144 GetNumericArg("resource-buffer-size", &g_allocation_size);
145}
146
mmenke87f5c77a2017-01-31 16:11:26147void MojoAsyncResourceHandler::OnRequestRedirected(
yhirano72f62272016-08-13 12:50:06148 const net::RedirectInfo& redirect_info,
John Abd-El-Malek46248032018-01-17 19:11:23149 network::ResourceResponse* response,
mmenke87f5c77a2017-01-31 16:11:26150 std::unique_ptr<ResourceController> controller) {
yhirano7153dc472016-11-16 09:42:46151 // Unlike OnResponseStarted, OnRequestRedirected will NOT be preceded by
152 // OnWillRead.
mmenke87f5c77a2017-01-31 16:11:26153 DCHECK(!has_controller());
yhirano7153dc472016-11-16 09:42:46154 DCHECK(!shared_writer_);
155
yhirano7153dc472016-11-16 09:42:46156 request()->LogBlockedBy("MojoAsyncResourceHandler");
mmenke87f5c77a2017-01-31 16:11:26157 HoldController(std::move(controller));
yhirano7153dc472016-11-16 09:42:46158 did_defer_on_redirect_ = true;
159
yhirano7153dc472016-11-16 09:42:46160 response->head.encoded_data_length = request()->GetTotalReceivedBytes();
161 response->head.request_start = request()->creation_time();
162 response->head.response_start = base::TimeTicks::Now();
163 // TODO(davidben): Is it necessary to pass the new first party URL for
164 // cookies? The only case where it can change is top-level navigation requests
165 // and hopefully those will eventually all be owned by the browser. It's
166 // possible this is still needed while renderer-owned ones exist.
167 url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
yhirano72f62272016-08-13 12:50:06168}
169
mmenke87f5c77a2017-01-31 16:11:26170void MojoAsyncResourceHandler::OnResponseStarted(
John Abd-El-Malek46248032018-01-17 19:11:23171 network::ResourceResponse* response,
mmenke87f5c77a2017-01-31 16:11:26172 std::unique_ptr<ResourceController> controller) {
173 DCHECK(!has_controller());
arthursonzogni84dda212018-03-01 02:06:36174 time_response_started_ = base::TimeTicks::Now();
mmenke87f5c77a2017-01-31 16:11:26175
tzikbedcbce2017-01-24 15:08:05176 if (upload_progress_tracker_) {
177 upload_progress_tracker_->OnUploadCompleted();
178 upload_progress_tracker_ = nullptr;
179 }
yhirano72f62272016-08-13 12:50:06180
tzikbedcbce2017-01-24 15:08:05181 const ResourceRequestInfoImpl* info = GetRequestInfo();
yhiranoa275b3c2016-12-20 03:58:40182 response->head.encoded_data_length = request()->raw_header_size();
183 reported_total_received_bytes_ = response->head.encoded_data_length;
yhirano72f62272016-08-13 12:50:06184
185 response->head.request_start = request()->creation_time();
arthursonzogni84dda212018-03-01 02:06:36186 response->head.response_start = time_response_started_;
yhirano72f62272016-08-13 12:50:06187 sent_received_response_message_ = true;
tzik47a9f9b2016-12-01 04:16:24188
John Abd-El-Malekb165dc52018-01-18 17:12:18189 network::mojom::DownloadedTempFilePtr downloaded_file_ptr;
tzik47a9f9b2016-12-01 04:16:24190 if (!response->head.download_file_path.empty()) {
yzshen20d075102017-02-16 21:36:44191 downloaded_file_ptr = DownloadedTempFileImpl::Create(info->GetChildID(),
192 info->GetRequestID());
tzik47a9f9b2016-12-01 04:16:24193 rdh_->RegisterDownloadedTempFile(info->GetChildID(), info->GetRequestID(),
194 response->head.download_file_path);
195 }
196
arthursonzognib521c6a2018-01-08 12:23:40197 base::Optional<net::SSLInfo> ssl_info;
John Abd-El-Malekb165dc52018-01-18 17:12:18198 if (url_loader_options_ &
199 network::mojom::kURLLoadOptionSendSSLInfoWithResponse)
arthursonzognib521c6a2018-01-08 12:23:40200 ssl_info = request()->ssl_info();
201
202 url_loader_client_->OnReceiveResponse(response->head, std::move(ssl_info),
tzik47a9f9b2016-12-01 04:16:24203 std::move(downloaded_file_ptr));
yhirano2a525f92017-01-18 08:16:46204
205 net::IOBufferWithSize* metadata = GetResponseMetadata(request());
206 if (metadata) {
207 const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
208
209 url_loader_client_->OnReceiveCachedMetadata(
210 std::vector<uint8_t>(data, data + metadata->size()));
211 }
mmenke87f5c77a2017-01-31 16:11:26212
John Abd-El-Malekb165dc52018-01-18 17:12:18213 if (url_loader_options_ &
214 network::mojom::kURLLoadOptionPauseOnResponseStarted) {
arthursonzogni2e1524a72017-12-18 16:53:26215 did_defer_on_response_started_ = true;
216 DCHECK(!has_controller());
217 request()->LogBlockedBy("MojoAsyncResourceHandler");
218 HoldController(std::move(controller));
219 return;
220 }
221
mmenke87f5c77a2017-01-31 16:11:26222 controller->Resume();
yhirano72f62272016-08-13 12:50:06223}
224
mmenke87f5c77a2017-01-31 16:11:26225void MojoAsyncResourceHandler::OnWillStart(
226 const GURL& url,
227 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05228 if (GetRequestInfo()->is_upload_progress_enabled() &&
229 request()->has_upload()) {
230 upload_progress_tracker_ = CreateUploadProgressTracker(
231 FROM_HERE,
232 base::BindRepeating(&MojoAsyncResourceHandler::SendUploadProgress,
233 base::Unretained(this)));
234 }
235
mmenke87f5c77a2017-01-31 16:11:26236 controller->Resume();
yhirano72f62272016-08-13 12:50:06237}
238
mmenke3c1d10c2017-03-09 16:25:45239void MojoAsyncResourceHandler::OnWillRead(
240 scoped_refptr<net::IOBuffer>* buf,
241 int* buf_size,
242 std::unique_ptr<ResourceController> controller) {
mmenke6add1722017-03-21 21:31:17243 // |buffer_| is set to nullptr on successful read completion (Except for the
244 // final 0-byte read, so this DCHECK will also catch OnWillRead being called
245 // after OnReadCompelted(0)).
246 DCHECK(!buffer_);
247 DCHECK_EQ(0u, buffer_offset_);
248
mmenke3c1d10c2017-03-09 16:25:45249 if (!CheckForSufficientResource()) {
250 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
251 return;
252 }
yhirano72f62272016-08-13 12:50:06253
mmenke6add1722017-03-21 21:31:17254 bool first_call = false;
yhirano72f62272016-08-13 12:50:06255 if (!shared_writer_) {
mmenke6add1722017-03-21 21:31:17256 first_call = true;
yhirano72f62272016-08-13 12:50:06257 MojoCreateDataPipeOptions options;
258 options.struct_size = sizeof(MojoCreateDataPipeOptions);
259 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
260 options.element_num_bytes = 1;
261 options.capacity_num_bytes = g_allocation_size;
Ken Rockotd61caeda2017-05-01 22:52:22262 mojo::ScopedDataPipeProducerHandle producer;
263 mojo::ScopedDataPipeConsumerHandle consumer;
yhirano72f62272016-08-13 12:50:06264
Ken Rockotd61caeda2017-05-01 22:52:22265 MojoResult result = mojo::CreateDataPipe(&options, &producer, &consumer);
266 if (result != MOJO_RESULT_OK) {
267 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
268 return;
269 }
270 DCHECK(producer.is_valid());
271 DCHECK(consumer.is_valid());
yhirano72f62272016-08-13 12:50:06272
Ken Rockotd61caeda2017-05-01 22:52:22273 response_body_consumer_handle_ = std::move(consumer);
274 shared_writer_ = new SharedWriter(std::move(producer));
rockot9eadaba2017-03-15 23:57:47275 handle_watcher_.Watch(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE,
yhirano72f62272016-08-13 12:50:06276 base::Bind(&MojoAsyncResourceHandler::OnWritable,
277 base::Unretained(this)));
rockot9eadaba2017-03-15 23:57:47278 handle_watcher_.ArmOrNotify();
mmenke6add1722017-03-21 21:31:17279 }
yhirano72f62272016-08-13 12:50:06280
mmenke6add1722017-03-21 21:31:17281 bool defer = false;
282 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
283 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
284 return;
285 }
286
287 if (defer) {
288 DCHECK(!buffer_);
289 parent_buffer_ = buf;
290 parent_buffer_size_ = buf_size;
291 HoldController(std::move(controller));
292 request()->LogBlockedBy("MojoAsyncResourceHandler");
293 did_defer_on_will_read_ = true;
294 return;
295 }
296
297 // The first call to OnWillRead must return a buffer of at least
298 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an
299 // intermediary buffer.
300 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) {
301 // The allocated buffer is too small, so need to create an intermediary one.
302 if (EndWrite(0) != MOJO_RESULT_OK) {
mmenke3c1d10c2017-03-09 16:25:45303 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
304 return;
305 }
yhirano72f62272016-08-13 12:50:06306 DCHECK(!is_using_io_buffer_not_from_writer_);
307 is_using_io_buffer_not_from_writer_ = true;
308 buffer_ = new net::IOBufferWithSize(kMinAllocationSize);
309 }
310
yhirano72f62272016-08-13 12:50:06311 *buf = buffer_;
312 *buf_size = buffer_->size();
mmenke3c1d10c2017-03-09 16:25:45313 controller->Resume();
yhirano72f62272016-08-13 12:50:06314}
315
mmenke87f5c77a2017-01-31 16:11:26316void MojoAsyncResourceHandler::OnReadCompleted(
317 int bytes_read,
318 std::unique_ptr<ResourceController> controller) {
319 DCHECK(!has_controller());
yhirano72f62272016-08-13 12:50:06320 DCHECK_GE(bytes_read, 0);
321 DCHECK(buffer_);
322
mmenke6add1722017-03-21 21:31:17323 if (bytes_read == 0) {
324 // Note that |buffer_| is not cleared here, which will cause a DCHECK on
325 // subsequent OnWillRead calls.
mmenke87f5c77a2017-01-31 16:11:26326 controller->Resume();
327 return;
328 }
yhirano72f62272016-08-13 12:50:06329
yhiranoa275b3c2016-12-20 03:58:40330 const ResourceRequestInfoImpl* info = GetRequestInfo();
331 if (info->ShouldReportRawHeaders()) {
332 auto transfer_size_diff = CalculateRecentlyReceivedBytes();
333 if (transfer_size_diff > 0)
334 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
335 }
336
yhirano246883ff62017-01-19 04:19:08337 if (response_body_consumer_handle_.is_valid()) {
arthursonzogni84dda212018-03-01 02:06:36338 if (url_loader_options_ &
339 network::mojom::kURLLoadOptionPauseOnResponseStarted) {
340 base::TimeTicks time_first_read_completed = base::TimeTicks::Now();
341 RecordNavigationResourceHandlerMetrics(time_response_started_,
342 time_proceed_with_response_,
343 time_first_read_completed);
344 }
yhirano246883ff62017-01-19 04:19:08345 // Send the data pipe on the first OnReadCompleted call.
346 url_loader_client_->OnStartLoadingResponseBody(
347 std::move(response_body_consumer_handle_));
348 response_body_consumer_handle_.reset();
349 }
350
yhirano72f62272016-08-13 12:50:06351 if (is_using_io_buffer_not_from_writer_) {
mmenke6add1722017-03-21 21:31:17352 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead.
yhirano72f62272016-08-13 12:50:06353 DCHECK_EQ(0u, buffer_bytes_read_);
354 buffer_bytes_read_ = bytes_read;
mmenke87f5c77a2017-01-31 16:11:26355 bool defer = false;
356 if (!CopyReadDataToDataPipe(&defer)) {
mmenke6add1722017-03-21 21:31:17357 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
mmenke87f5c77a2017-01-31 16:11:26358 return;
359 }
360 if (defer) {
yhirano7153dc472016-11-16 09:42:46361 request()->LogBlockedBy("MojoAsyncResourceHandler");
362 did_defer_on_writing_ = true;
mmenke87f5c77a2017-01-31 16:11:26363 HoldController(std::move(controller));
364 return;
yhirano7153dc472016-11-16 09:42:46365 }
mmenke87f5c77a2017-01-31 16:11:26366 controller->Resume();
367 return;
yhirano72f62272016-08-13 12:50:06368 }
369
mmenke87f5c77a2017-01-31 16:11:26370 if (EndWrite(bytes_read) != MOJO_RESULT_OK) {
371 controller->Cancel();
372 return;
373 }
mmenke87f5c77a2017-01-31 16:11:26374
mmenke6add1722017-03-21 21:31:17375 buffer_ = nullptr;
mmenke87f5c77a2017-01-31 16:11:26376 controller->Resume();
yhirano72f62272016-08-13 12:50:06377}
378
379void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
yhiranoa275b3c2016-12-20 03:58:40380 url_loader_client_->OnDataDownloaded(bytes_downloaded,
381 CalculateRecentlyReceivedBytes());
yhirano72f62272016-08-13 12:50:06382}
383
384void MojoAsyncResourceHandler::FollowRedirect() {
yhirano7153dc472016-11-16 09:42:46385 if (!request()->status().is_success()) {
386 DVLOG(1) << "FollowRedirect for invalid request";
387 return;
388 }
389 if (!did_defer_on_redirect_) {
390 DVLOG(1) << "Malformed FollowRedirect request";
391 ReportBadMessage("Malformed FollowRedirect request");
392 return;
393 }
394
mmenke6add1722017-03-21 21:31:17395 DCHECK(!did_defer_on_will_read_);
yhirano7153dc472016-11-16 09:42:46396 DCHECK(!did_defer_on_writing_);
397 did_defer_on_redirect_ = false;
398 request()->LogUnblocked();
mmenke87f5c77a2017-01-31 16:11:26399 Resume();
yhirano72f62272016-08-13 12:50:06400}
401
arthursonzogni2e1524a72017-12-18 16:53:26402void MojoAsyncResourceHandler::ProceedWithResponse() {
403 DCHECK(did_defer_on_response_started_);
arthursonzogni84dda212018-03-01 02:06:36404
405 time_proceed_with_response_ = base::TimeTicks::Now();
406
arthursonzogni2e1524a72017-12-18 16:53:26407 request()->LogUnblocked();
408 Resume();
409}
410
yhirano933ee582017-01-27 13:28:40411void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority,
412 int32_t intra_priority_value) {
John Abd-El-Malekeb1a5382018-01-05 16:58:00413 auto* scheduler = ResourceDispatcherHostImpl::Get()->scheduler();
414 if (intra_priority_value == -1) {
415 scheduler->ReprioritizeRequest(request(), priority);
416 } else {
417 scheduler->ReprioritizeRequest(request(), priority, intra_priority_value);
418 }
yhirano933ee582017-01-27 13:28:40419}
420
Yuzhu Shen99681b12017-09-28 06:11:10421void MojoAsyncResourceHandler::PauseReadingBodyFromNet() {
Yuzhu Shen19cafda02018-02-01 19:45:20422 ResourceHandler::PauseReadingBodyFromNet();
Yuzhu Shen0bec9542017-09-16 01:31:59423}
424
Yuzhu Shen99681b12017-09-28 06:11:10425void MojoAsyncResourceHandler::ResumeReadingBodyFromNet() {
Yuzhu Shen19cafda02018-02-01 19:45:20426 ResourceHandler::ResumeReadingBodyFromNet();
Yuzhu Shen0bec9542017-09-16 01:31:59427}
428
yhirano7153dc472016-11-16 09:42:46429void MojoAsyncResourceHandler::OnWritableForTesting() {
430 OnWritable(MOJO_RESULT_OK);
yhirano72f62272016-08-13 12:50:06431}
432
433void MojoAsyncResourceHandler::SetAllocationSizeForTesting(size_t size) {
434 g_allocation_size = size;
435}
436
437MojoResult MojoAsyncResourceHandler::BeginWrite(void** data,
438 uint32_t* available) {
Reilly Grant789c63e2017-08-04 15:30:16439 MojoResult result = shared_writer_->writer().BeginWriteData(
440 data, available, MOJO_WRITE_DATA_FLAG_NONE);
yhirano72f62272016-08-13 12:50:06441 if (result == MOJO_RESULT_OK)
442 *available = std::min(*available, static_cast<uint32_t>(kMaxChunkSize));
rockot9eadaba2017-03-15 23:57:47443 else if (result == MOJO_RESULT_SHOULD_WAIT)
444 handle_watcher_.ArmOrNotify();
yhirano72f62272016-08-13 12:50:06445 return result;
446}
447
448MojoResult MojoAsyncResourceHandler::EndWrite(uint32_t written) {
Reilly Grant789c63e2017-08-04 15:30:16449 MojoResult result = shared_writer_->writer().EndWriteData(written);
horoe8442e62017-04-27 19:10:48450 if (result == MOJO_RESULT_OK) {
451 total_written_bytes_ += written;
rockot9eadaba2017-03-15 23:57:47452 handle_watcher_.ArmOrNotify();
horoe8442e62017-04-27 19:10:48453 }
rockot9eadaba2017-03-15 23:57:47454 return result;
yhirano72f62272016-08-13 12:50:06455}
456
yhirano2a525f92017-01-18 08:16:46457net::IOBufferWithSize* MojoAsyncResourceHandler::GetResponseMetadata(
458 net::URLRequest* request) {
459 return request->response_info().metadata.get();
460}
461
yhirano72f62272016-08-13 12:50:06462void MojoAsyncResourceHandler::OnResponseCompleted(
Takashi Toyoshima8f988532017-11-13 07:32:37463 const net::URLRequestStatus& request_status,
mmenke87f5c77a2017-01-31 16:11:26464 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05465 // Ensure sending the final upload progress message here, since
466 // OnResponseCompleted can be called without OnResponseStarted on cancellation
467 // or error cases.
468 if (upload_progress_tracker_) {
469 upload_progress_tracker_->OnUploadCompleted();
470 upload_progress_tracker_ = nullptr;
471 }
472
yhirano72f62272016-08-13 12:50:06473 shared_writer_ = nullptr;
474 buffer_ = nullptr;
475 handle_watcher_.Cancel();
476
yhirano72f62272016-08-13 12:50:06477 // TODO(gavinp): Remove this CHECK when we figure out the cause of
478 // http://crbug.com/124680 . This check mirrors closely check in
479 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
480 // ResourceHandleInternal which asserts on its state and crashes. By crashing
481 // when the message is sent, we should get better crash reports.
Takashi Toyoshima8f988532017-11-13 07:32:37482 CHECK(request_status.status() != net::URLRequestStatus::SUCCESS ||
yhirano72f62272016-08-13 12:50:06483 sent_received_response_message_);
484
Takashi Toyoshima8f988532017-11-13 07:32:37485 int error_code = request_status.error();
yhirano72f62272016-08-13 12:50:06486
Takashi Toyoshima8f988532017-11-13 07:32:37487 DCHECK_NE(request_status.status(), net::URLRequestStatus::IO_PENDING);
yhirano72f62272016-08-13 12:50:06488
Takashi Toyoshimaaa278662017-11-20 11:11:26489 network::URLLoaderCompletionStatus loader_status;
Takashi Toyoshima8f988532017-11-13 07:32:37490 loader_status.error_code = error_code;
Brad Lassey16c13f72018-03-19 19:37:50491 if (error_code == net::ERR_QUIC_PROTOCOL_ERROR) {
492 net::NetErrorDetails details;
493 request()->PopulateNetErrorDetails(&details);
494 loader_status.extended_error_code = details.quic_connection_error;
495 }
Arthur Sonzogni0b2b1a922018-03-15 15:24:15496 loader_status.exists_in_cache = request()->response_info().was_cached;
Takashi Toyoshima8f988532017-11-13 07:32:37497 loader_status.completion_time = base::TimeTicks::Now();
498 loader_status.encoded_data_length = request()->GetTotalReceivedBytes();
499 loader_status.encoded_body_length = request()->GetRawBodyBytes();
500 loader_status.decoded_body_length = total_written_bytes_;
Pavel Feldman8f361662018-01-03 01:55:07501 loader_status.blocked_cross_site_document =
502 GetRequestInfo()->blocked_cross_site_document();
yhirano72f62272016-08-13 12:50:06503
arthursonzognib521c6a2018-01-08 12:23:40504 if ((url_loader_options_ &
John Abd-El-Malekb165dc52018-01-18 17:12:18505 network::mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
arthursonzognib521c6a2018-01-08 12:23:40506 net::IsCertStatusError(request()->ssl_info().cert_status) &&
507 !net::IsCertStatusMinorError(request()->ssl_info().cert_status)) {
508 loader_status.ssl_info = request()->ssl_info();
509 }
510
Takashi Toyoshima8f988532017-11-13 07:32:37511 url_loader_client_->OnComplete(loader_status);
mmenke87f5c77a2017-01-31 16:11:26512 controller->Resume();
yhirano72f62272016-08-13 12:50:06513}
514
515bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) {
mmenke6add1722017-03-21 21:31:17516 while (buffer_bytes_read_ > 0) {
yhirano72f62272016-08-13 12:50:06517 scoped_refptr<net::IOBufferWithSize> dest;
518 if (!AllocateWriterIOBuffer(&dest, defer))
519 return false;
520 if (*defer)
521 return true;
yhirano72f62272016-08-13 12:50:06522
523 size_t copied_size =
524 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size()));
525 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size);
526 buffer_offset_ += copied_size;
527 buffer_bytes_read_ -= copied_size;
528 if (EndWrite(copied_size) != MOJO_RESULT_OK)
529 return false;
yhirano4fede0f2017-03-21 03:33:15530 }
mmenke6add1722017-03-21 21:31:17531
532 // All bytes are copied.
533 buffer_ = nullptr;
534 buffer_offset_ = 0;
535 is_using_io_buffer_not_from_writer_ = false;
536 return true;
yhirano72f62272016-08-13 12:50:06537}
538
539bool MojoAsyncResourceHandler::AllocateWriterIOBuffer(
540 scoped_refptr<net::IOBufferWithSize>* buf,
541 bool* defer) {
542 void* data = nullptr;
543 uint32_t available = 0;
544 MojoResult result = BeginWrite(&data, &available);
545 if (result == MOJO_RESULT_SHOULD_WAIT) {
546 *defer = true;
547 return true;
548 }
549 if (result != MOJO_RESULT_OK)
550 return false;
mmenke6add1722017-03-21 21:31:17551 DCHECK_GT(available, 0u);
yhirano72f62272016-08-13 12:50:06552 *buf = new WriterIOBuffer(shared_writer_, data, available);
553 return true;
554}
555
yhirano72f62272016-08-13 12:50:06556bool MojoAsyncResourceHandler::CheckForSufficientResource() {
557 if (has_checked_for_sufficient_resources_)
558 return true;
559 has_checked_for_sufficient_resources_ = true;
560
561 if (rdh_->HasSufficientResourcesForRequest(request()))
562 return true;
563
yhirano72f62272016-08-13 12:50:06564 return false;
565}
566
yhirano7153dc472016-11-16 09:42:46567void MojoAsyncResourceHandler::OnWritable(MojoResult result) {
mmenke6add1722017-03-21 21:31:17568 if (did_defer_on_will_read_) {
569 DCHECK(has_controller());
570 DCHECK(!did_defer_on_writing_);
571 DCHECK(!did_defer_on_redirect_);
572
573 did_defer_on_will_read_ = false;
574
575 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_;
576 parent_buffer_ = nullptr;
577 int* parent_buffer_size = parent_buffer_size_;
578 parent_buffer_size_ = nullptr;
579
580 request()->LogUnblocked();
581 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController());
582 return;
583 }
584
yhirano7153dc472016-11-16 09:42:46585 if (!did_defer_on_writing_)
586 return;
mmenke87f5c77a2017-01-31 16:11:26587 DCHECK(has_controller());
yhirano7153dc472016-11-16 09:42:46588 DCHECK(!did_defer_on_redirect_);
589 did_defer_on_writing_ = false;
590
mmenke6add1722017-03-21 21:31:17591 DCHECK(is_using_io_buffer_not_from_writer_);
592 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
593 // to the data pipe.
594 DCHECK_GT(buffer_bytes_read_, 0u);
595 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
596 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
597 return;
yhirano7153dc472016-11-16 09:42:46598 }
599
600 if (did_defer_on_writing_) {
601 // Continue waiting.
602 return;
603 }
604 request()->LogUnblocked();
mmenke87f5c77a2017-01-31 16:11:26605 Resume();
yhirano72f62272016-08-13 12:50:06606}
607
Yuzhu Shen07e96312018-02-05 23:20:29608void MojoAsyncResourceHandler::Cancel(uint32_t custom_reason,
609 const std::string& description) {
610 ResourceRequestInfoImpl* info = GetRequestInfo();
611
612 if (custom_reason == network::mojom::URLLoader::kClientDisconnectReason)
613 info->set_custom_cancel_reason(description);
614
yhirano59393702016-11-16 06:10:24615 ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer(
616 GlobalRequestID(info->GetChildID(), info->GetRequestID()));
617}
618
yhiranoa275b3c2016-12-20 03:58:40619int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() {
620 int64_t total_received_bytes = request()->GetTotalReceivedBytes();
621 int64_t bytes_to_report =
622 total_received_bytes - reported_total_received_bytes_;
623 reported_total_received_bytes_ = total_received_bytes;
624 DCHECK_LE(0, bytes_to_report);
625 return bytes_to_report;
626}
627
yhirano7153dc472016-11-16 09:42:46628void MojoAsyncResourceHandler::ReportBadMessage(const std::string& error) {
629 mojo::ReportBadMessage(error);
630}
631
John Abd-El-Malek3bbbdf92018-01-30 03:27:35632std::unique_ptr<network::UploadProgressTracker>
tzikbedcbce2017-01-24 15:08:05633MojoAsyncResourceHandler::CreateUploadProgressTracker(
Brett Wilson1c990022017-09-12 20:11:15634 const base::Location& from_here,
John Abd-El-Malek3bbbdf92018-01-30 03:27:35635 network::UploadProgressTracker::UploadProgressReportCallback callback) {
636 return std::make_unique<network::UploadProgressTracker>(
637 from_here, std::move(callback), request());
tzikbedcbce2017-01-24 15:08:05638}
639
yhiranobbc904d02016-11-26 05:59:26640void MojoAsyncResourceHandler::OnTransfer(
John Abd-El-Malekb165dc52018-01-18 17:12:18641 network::mojom::URLLoaderRequest mojo_request,
642 network::mojom::URLLoaderClientPtr url_loader_client) {
yhiranobbc904d02016-11-26 05:59:26643 binding_.Unbind();
644 binding_.Bind(std::move(mojo_request));
Yuzhu Shen07e96312018-02-05 23:20:29645 binding_.set_connection_error_with_reason_handler(base::BindOnce(
tzik0f14f192017-08-15 02:43:33646 &MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
yhiranobbc904d02016-11-26 05:59:26647 url_loader_client_ = std::move(url_loader_client);
648}
649
tzikbedcbce2017-01-24 15:08:05650void MojoAsyncResourceHandler::SendUploadProgress(
651 const net::UploadProgress& progress) {
652 url_loader_client_->OnUploadProgress(
653 progress.position(), progress.size(),
tzik0f14f192017-08-15 02:43:33654 base::BindOnce(&MojoAsyncResourceHandler::OnUploadProgressACK,
655 weak_factory_.GetWeakPtr()));
tzikbedcbce2017-01-24 15:08:05656}
657
658void MojoAsyncResourceHandler::OnUploadProgressACK() {
659 if (upload_progress_tracker_)
660 upload_progress_tracker_->OnAckReceived();
661}
662
yhirano72f62272016-08-13 12:50:06663} // namespace content