blob: 505bfedfe55de90a24c02303de6692991df22c7c [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"
yhirano72f62272016-08-13 12:50:0612#include "base/command_line.h"
tzikbedcbce2017-01-24 15:08:0513#include "base/location.h"
yhirano72f62272016-08-13 12:50:0614#include "base/logging.h"
15#include "base/macros.h"
tzikbedcbce2017-01-24 15:08:0516#include "base/memory/ptr_util.h"
yhirano72f62272016-08-13 12:50:0617#include "base/strings/string_number_conversions.h"
18#include "base/time/time.h"
tzik47a9f9b2016-12-01 04:16:2419#include "content/browser/loader/downloaded_temp_file_impl.h"
tyoshino3b3ee8e92016-12-07 16:04:0720#include "content/browser/loader/resource_controller.h"
yhirano72f62272016-08-13 12:50:0621#include "content/browser/loader/resource_dispatcher_host_impl.h"
22#include "content/browser/loader/resource_request_info_impl.h"
yhirano933ee582017-01-27 13:28:4023#include "content/browser/loader/resource_scheduler.h"
tzikbedcbce2017-01-24 15:08:0524#include "content/browser/loader/upload_progress_tracker.h"
yhirano59393702016-11-16 06:10:2425#include "content/public/browser/global_request_id.h"
mmenke680c2142017-07-05 19:08:5626#include "content/public/common/resource_request_completion_status.h"
yhirano72f62272016-08-13 12:50:0627#include "content/public/common/resource_response.h"
28#include "mojo/public/c/system/data_pipe.h"
yhirano7153dc472016-11-16 09:42:4629#include "mojo/public/cpp/bindings/message.h"
yhirano72f62272016-08-13 12:50:0630#include "net/base/mime_sniffer.h"
mmenke6add1722017-03-21 21:31:1731#include "net/base/net_errors.h"
yhirano72f62272016-08-13 12:50:0632#include "net/url_request/redirect_info.h"
33
34namespace content {
35namespace {
36
37int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize;
38
39// MimeTypeResourceHandler *implicitly* requires that the buffer size
40// returned from OnWillRead should be larger than certain size.
41// TODO(yhirano): Fix MimeTypeResourceHandler.
42constexpr size_t kMinAllocationSize = 2 * net::kMaxBytesToSniff;
43
44constexpr size_t kMaxChunkSize = 32 * 1024;
45
46void GetNumericArg(const std::string& name, int* result) {
47 const std::string& value =
48 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
49 if (!value.empty())
50 base::StringToInt(value, result);
51}
52
53void InitializeResourceBufferConstants() {
54 static bool did_init = false;
55 if (did_init)
56 return;
57 did_init = true;
58
59 GetNumericArg("resource-buffer-size", &g_allocation_size);
60}
61
Yutaka Hirano4f87e232017-07-25 08:13:5262void NotReached(mojom::URLLoaderRequest mojo_request,
yhirano6f57b502017-03-01 03:44:2063 mojom::URLLoaderClientPtr url_loader_client) {
tzikad092abe2017-01-24 02:34:1764 NOTREACHED();
65}
66
yhirano72f62272016-08-13 12:50:0667} // namespace
68
69// This class is for sharing the ownership of a ScopedDataPipeProducerHandle
70// between WriterIOBuffer and MojoAsyncResourceHandler.
71class MojoAsyncResourceHandler::SharedWriter final
72 : public base::RefCountedThreadSafe<SharedWriter> {
73 public:
74 explicit SharedWriter(mojo::ScopedDataPipeProducerHandle writer)
75 : writer_(std::move(writer)) {}
76 mojo::DataPipeProducerHandle writer() { return writer_.get(); }
77
78 private:
79 friend class base::RefCountedThreadSafe<SharedWriter>;
80 ~SharedWriter() {}
81
82 const mojo::ScopedDataPipeProducerHandle writer_;
83
84 DISALLOW_COPY_AND_ASSIGN(SharedWriter);
85};
86
87// This class is a IOBuffer subclass for data gotten from a
88// ScopedDataPipeProducerHandle.
89class MojoAsyncResourceHandler::WriterIOBuffer final
90 : public net::IOBufferWithSize {
91 public:
Reilly Grant789c63e2017-08-04 15:30:1692 // |data| and |size| should be gotten from |writer| via BeginWriteData.
yhirano72f62272016-08-13 12:50:0693 // They will be accesible via IOBuffer methods. As |writer| is stored in this
94 // instance, |data| will be kept valid as long as the following conditions
95 // hold:
96 // 1. |data| is not invalidated via EndWriteDataRaw.
97 // 2. |this| instance is alive.
98 WriterIOBuffer(scoped_refptr<SharedWriter> writer, void* data, size_t size)
99 : net::IOBufferWithSize(static_cast<char*>(data), size),
100 writer_(std::move(writer)) {}
101
102 private:
103 ~WriterIOBuffer() override {
104 // Avoid deleting |data_| in the IOBuffer destructor.
105 data_ = nullptr;
106 }
107
108 // This member is for keeping the writer alive.
109 scoped_refptr<SharedWriter> writer_;
110
111 DISALLOW_COPY_AND_ASSIGN(WriterIOBuffer);
112};
113
114MojoAsyncResourceHandler::MojoAsyncResourceHandler(
115 net::URLRequest* request,
116 ResourceDispatcherHostImpl* rdh,
Yutaka Hirano4f87e232017-07-25 08:13:52117 mojom::URLLoaderRequest mojo_request,
yhirano6f57b502017-03-01 03:44:20118 mojom::URLLoaderClientPtr url_loader_client,
tzikad092abe2017-01-24 02:34:17119 ResourceType resource_type)
yhirano72f62272016-08-13 12:50:06120 : ResourceHandler(request),
121 rdh_(rdh),
122 binding_(this, std::move(mojo_request)),
rockot9eadaba2017-03-15 23:57:47123 handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
yhiranobbc904d02016-11-26 05:59:26124 url_loader_client_(std::move(url_loader_client)),
125 weak_factory_(this) {
yhirano72f62272016-08-13 12:50:06126 DCHECK(url_loader_client_);
127 InitializeResourceBufferConstants();
yhirano59393702016-11-16 06:10:24128 // This unretained pointer is safe, because |binding_| is owned by |this| and
129 // the callback will never be called after |this| is destroyed.
tzik0f14f192017-08-15 02:43:33130 binding_.set_connection_error_handler(base::BindOnce(
131 &MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
yhiranobbc904d02016-11-26 05:59:26132
tzikad092abe2017-01-24 02:34:17133 if (IsResourceTypeFrame(resource_type)) {
134 GetRequestInfo()->set_on_transfer(base::Bind(
135 &MojoAsyncResourceHandler::OnTransfer, weak_factory_.GetWeakPtr()));
136 } else {
137 GetRequestInfo()->set_on_transfer(base::Bind(&NotReached));
138 }
yhirano72f62272016-08-13 12:50:06139}
140
141MojoAsyncResourceHandler::~MojoAsyncResourceHandler() {
142 if (has_checked_for_sufficient_resources_)
143 rdh_->FinishedWithResourcesForRequest(request());
144}
145
mmenke87f5c77a2017-01-31 16:11:26146void MojoAsyncResourceHandler::OnRequestRedirected(
yhirano72f62272016-08-13 12:50:06147 const net::RedirectInfo& redirect_info,
148 ResourceResponse* response,
mmenke87f5c77a2017-01-31 16:11:26149 std::unique_ptr<ResourceController> controller) {
yhirano7153dc472016-11-16 09:42:46150 // Unlike OnResponseStarted, OnRequestRedirected will NOT be preceded by
151 // OnWillRead.
mmenke87f5c77a2017-01-31 16:11:26152 DCHECK(!has_controller());
yhirano7153dc472016-11-16 09:42:46153 DCHECK(!shared_writer_);
154
yhirano7153dc472016-11-16 09:42:46155 request()->LogBlockedBy("MojoAsyncResourceHandler");
mmenke87f5c77a2017-01-31 16:11:26156 HoldController(std::move(controller));
yhirano7153dc472016-11-16 09:42:46157 did_defer_on_redirect_ = true;
158
yhirano7153dc472016-11-16 09:42:46159 response->head.encoded_data_length = request()->GetTotalReceivedBytes();
160 response->head.request_start = request()->creation_time();
161 response->head.response_start = base::TimeTicks::Now();
162 // TODO(davidben): Is it necessary to pass the new first party URL for
163 // cookies? The only case where it can change is top-level navigation requests
164 // and hopefully those will eventually all be owned by the browser. It's
165 // possible this is still needed while renderer-owned ones exist.
166 url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
yhirano72f62272016-08-13 12:50:06167}
168
mmenke87f5c77a2017-01-31 16:11:26169void MojoAsyncResourceHandler::OnResponseStarted(
170 ResourceResponse* response,
171 std::unique_ptr<ResourceController> controller) {
172 DCHECK(!has_controller());
173
tzikbedcbce2017-01-24 15:08:05174 if (upload_progress_tracker_) {
175 upload_progress_tracker_->OnUploadCompleted();
176 upload_progress_tracker_ = nullptr;
177 }
yhirano72f62272016-08-13 12:50:06178
tzikbedcbce2017-01-24 15:08:05179 const ResourceRequestInfoImpl* info = GetRequestInfo();
yhiranoa275b3c2016-12-20 03:58:40180 response->head.encoded_data_length = request()->raw_header_size();
181 reported_total_received_bytes_ = response->head.encoded_data_length;
yhirano72f62272016-08-13 12:50:06182
183 response->head.request_start = request()->creation_time();
184 response->head.response_start = base::TimeTicks::Now();
185 sent_received_response_message_ = true;
tzik47a9f9b2016-12-01 04:16:24186
yhirano6f57b502017-03-01 03:44:20187 mojom::DownloadedTempFilePtr downloaded_file_ptr;
tzik47a9f9b2016-12-01 04:16:24188 if (!response->head.download_file_path.empty()) {
yzshen20d075102017-02-16 21:36:44189 downloaded_file_ptr = DownloadedTempFileImpl::Create(info->GetChildID(),
190 info->GetRequestID());
tzik47a9f9b2016-12-01 04:16:24191 rdh_->RegisterDownloadedTempFile(info->GetChildID(), info->GetRequestID(),
192 response->head.download_file_path);
193 }
194
jam33d897e2017-04-14 21:28:46195 url_loader_client_->OnReceiveResponse(response->head, base::nullopt,
tzik47a9f9b2016-12-01 04:16:24196 std::move(downloaded_file_ptr));
yhirano2a525f92017-01-18 08:16:46197
198 net::IOBufferWithSize* metadata = GetResponseMetadata(request());
199 if (metadata) {
200 const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
201
202 url_loader_client_->OnReceiveCachedMetadata(
203 std::vector<uint8_t>(data, data + metadata->size()));
204 }
mmenke87f5c77a2017-01-31 16:11:26205
206 controller->Resume();
yhirano72f62272016-08-13 12:50:06207}
208
mmenke87f5c77a2017-01-31 16:11:26209void MojoAsyncResourceHandler::OnWillStart(
210 const GURL& url,
211 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05212 if (GetRequestInfo()->is_upload_progress_enabled() &&
213 request()->has_upload()) {
214 upload_progress_tracker_ = CreateUploadProgressTracker(
215 FROM_HERE,
216 base::BindRepeating(&MojoAsyncResourceHandler::SendUploadProgress,
217 base::Unretained(this)));
218 }
219
mmenke87f5c77a2017-01-31 16:11:26220 controller->Resume();
yhirano72f62272016-08-13 12:50:06221}
222
mmenke3c1d10c2017-03-09 16:25:45223void MojoAsyncResourceHandler::OnWillRead(
224 scoped_refptr<net::IOBuffer>* buf,
225 int* buf_size,
226 std::unique_ptr<ResourceController> controller) {
mmenke6add1722017-03-21 21:31:17227 // |buffer_| is set to nullptr on successful read completion (Except for the
228 // final 0-byte read, so this DCHECK will also catch OnWillRead being called
229 // after OnReadCompelted(0)).
230 DCHECK(!buffer_);
231 DCHECK_EQ(0u, buffer_offset_);
232
mmenke3c1d10c2017-03-09 16:25:45233 if (!CheckForSufficientResource()) {
234 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
235 return;
236 }
yhirano72f62272016-08-13 12:50:06237
mmenke6add1722017-03-21 21:31:17238 bool first_call = false;
yhirano72f62272016-08-13 12:50:06239 if (!shared_writer_) {
mmenke6add1722017-03-21 21:31:17240 first_call = true;
yhirano72f62272016-08-13 12:50:06241 MojoCreateDataPipeOptions options;
242 options.struct_size = sizeof(MojoCreateDataPipeOptions);
243 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
244 options.element_num_bytes = 1;
245 options.capacity_num_bytes = g_allocation_size;
Ken Rockotd61caeda2017-05-01 22:52:22246 mojo::ScopedDataPipeProducerHandle producer;
247 mojo::ScopedDataPipeConsumerHandle consumer;
yhirano72f62272016-08-13 12:50:06248
Ken Rockotd61caeda2017-05-01 22:52:22249 MojoResult result = mojo::CreateDataPipe(&options, &producer, &consumer);
250 if (result != MOJO_RESULT_OK) {
251 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
252 return;
253 }
254 DCHECK(producer.is_valid());
255 DCHECK(consumer.is_valid());
yhirano72f62272016-08-13 12:50:06256
Ken Rockotd61caeda2017-05-01 22:52:22257 response_body_consumer_handle_ = std::move(consumer);
258 shared_writer_ = new SharedWriter(std::move(producer));
rockot9eadaba2017-03-15 23:57:47259 handle_watcher_.Watch(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE,
yhirano72f62272016-08-13 12:50:06260 base::Bind(&MojoAsyncResourceHandler::OnWritable,
261 base::Unretained(this)));
rockot9eadaba2017-03-15 23:57:47262 handle_watcher_.ArmOrNotify();
mmenke6add1722017-03-21 21:31:17263 }
yhirano72f62272016-08-13 12:50:06264
mmenke6add1722017-03-21 21:31:17265 bool defer = false;
266 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
267 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
268 return;
269 }
270
271 if (defer) {
272 DCHECK(!buffer_);
273 parent_buffer_ = buf;
274 parent_buffer_size_ = buf_size;
275 HoldController(std::move(controller));
276 request()->LogBlockedBy("MojoAsyncResourceHandler");
277 did_defer_on_will_read_ = true;
278 return;
279 }
280
281 // The first call to OnWillRead must return a buffer of at least
282 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an
283 // intermediary buffer.
284 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) {
285 // The allocated buffer is too small, so need to create an intermediary one.
286 if (EndWrite(0) != MOJO_RESULT_OK) {
mmenke3c1d10c2017-03-09 16:25:45287 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
288 return;
289 }
yhirano72f62272016-08-13 12:50:06290 DCHECK(!is_using_io_buffer_not_from_writer_);
291 is_using_io_buffer_not_from_writer_ = true;
292 buffer_ = new net::IOBufferWithSize(kMinAllocationSize);
293 }
294
yhirano72f62272016-08-13 12:50:06295 *buf = buffer_;
296 *buf_size = buffer_->size();
mmenke3c1d10c2017-03-09 16:25:45297 controller->Resume();
yhirano72f62272016-08-13 12:50:06298}
299
mmenke87f5c77a2017-01-31 16:11:26300void MojoAsyncResourceHandler::OnReadCompleted(
301 int bytes_read,
302 std::unique_ptr<ResourceController> controller) {
303 DCHECK(!has_controller());
yhirano72f62272016-08-13 12:50:06304 DCHECK_GE(bytes_read, 0);
305 DCHECK(buffer_);
306
mmenke6add1722017-03-21 21:31:17307 if (bytes_read == 0) {
308 // Note that |buffer_| is not cleared here, which will cause a DCHECK on
309 // subsequent OnWillRead calls.
mmenke87f5c77a2017-01-31 16:11:26310 controller->Resume();
311 return;
312 }
yhirano72f62272016-08-13 12:50:06313
yhiranoa275b3c2016-12-20 03:58:40314 const ResourceRequestInfoImpl* info = GetRequestInfo();
315 if (info->ShouldReportRawHeaders()) {
316 auto transfer_size_diff = CalculateRecentlyReceivedBytes();
317 if (transfer_size_diff > 0)
318 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
319 }
320
yhirano246883ff62017-01-19 04:19:08321 if (response_body_consumer_handle_.is_valid()) {
322 // Send the data pipe on the first OnReadCompleted call.
323 url_loader_client_->OnStartLoadingResponseBody(
324 std::move(response_body_consumer_handle_));
325 response_body_consumer_handle_.reset();
326 }
327
yhirano72f62272016-08-13 12:50:06328 if (is_using_io_buffer_not_from_writer_) {
mmenke6add1722017-03-21 21:31:17329 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead.
yhirano72f62272016-08-13 12:50:06330 DCHECK_EQ(0u, buffer_bytes_read_);
331 buffer_bytes_read_ = bytes_read;
mmenke87f5c77a2017-01-31 16:11:26332 bool defer = false;
333 if (!CopyReadDataToDataPipe(&defer)) {
mmenke6add1722017-03-21 21:31:17334 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
mmenke87f5c77a2017-01-31 16:11:26335 return;
336 }
337 if (defer) {
yhirano7153dc472016-11-16 09:42:46338 request()->LogBlockedBy("MojoAsyncResourceHandler");
339 did_defer_on_writing_ = true;
mmenke87f5c77a2017-01-31 16:11:26340 HoldController(std::move(controller));
341 return;
yhirano7153dc472016-11-16 09:42:46342 }
mmenke87f5c77a2017-01-31 16:11:26343 controller->Resume();
344 return;
yhirano72f62272016-08-13 12:50:06345 }
346
mmenke87f5c77a2017-01-31 16:11:26347 if (EndWrite(bytes_read) != MOJO_RESULT_OK) {
348 controller->Cancel();
349 return;
350 }
mmenke87f5c77a2017-01-31 16:11:26351
mmenke6add1722017-03-21 21:31:17352 buffer_ = nullptr;
mmenke87f5c77a2017-01-31 16:11:26353 controller->Resume();
yhirano72f62272016-08-13 12:50:06354}
355
356void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
yhiranoa275b3c2016-12-20 03:58:40357 url_loader_client_->OnDataDownloaded(bytes_downloaded,
358 CalculateRecentlyReceivedBytes());
yhirano72f62272016-08-13 12:50:06359}
360
361void MojoAsyncResourceHandler::FollowRedirect() {
yhirano7153dc472016-11-16 09:42:46362 if (!request()->status().is_success()) {
363 DVLOG(1) << "FollowRedirect for invalid request";
364 return;
365 }
366 if (!did_defer_on_redirect_) {
367 DVLOG(1) << "Malformed FollowRedirect request";
368 ReportBadMessage("Malformed FollowRedirect request");
369 return;
370 }
371
mmenke6add1722017-03-21 21:31:17372 DCHECK(!did_defer_on_will_read_);
yhirano7153dc472016-11-16 09:42:46373 DCHECK(!did_defer_on_writing_);
374 did_defer_on_redirect_ = false;
375 request()->LogUnblocked();
mmenke87f5c77a2017-01-31 16:11:26376 Resume();
yhirano72f62272016-08-13 12:50:06377}
378
yhirano933ee582017-01-27 13:28:40379void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority,
380 int32_t intra_priority_value) {
381 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest(
382 request(), priority, intra_priority_value);
383}
384
yhirano7153dc472016-11-16 09:42:46385void MojoAsyncResourceHandler::OnWritableForTesting() {
386 OnWritable(MOJO_RESULT_OK);
yhirano72f62272016-08-13 12:50:06387}
388
389void MojoAsyncResourceHandler::SetAllocationSizeForTesting(size_t size) {
390 g_allocation_size = size;
391}
392
393MojoResult MojoAsyncResourceHandler::BeginWrite(void** data,
394 uint32_t* available) {
Reilly Grant789c63e2017-08-04 15:30:16395 MojoResult result = shared_writer_->writer().BeginWriteData(
396 data, available, MOJO_WRITE_DATA_FLAG_NONE);
yhirano72f62272016-08-13 12:50:06397 if (result == MOJO_RESULT_OK)
398 *available = std::min(*available, static_cast<uint32_t>(kMaxChunkSize));
rockot9eadaba2017-03-15 23:57:47399 else if (result == MOJO_RESULT_SHOULD_WAIT)
400 handle_watcher_.ArmOrNotify();
yhirano72f62272016-08-13 12:50:06401 return result;
402}
403
404MojoResult MojoAsyncResourceHandler::EndWrite(uint32_t written) {
Reilly Grant789c63e2017-08-04 15:30:16405 MojoResult result = shared_writer_->writer().EndWriteData(written);
horoe8442e62017-04-27 19:10:48406 if (result == MOJO_RESULT_OK) {
407 total_written_bytes_ += written;
rockot9eadaba2017-03-15 23:57:47408 handle_watcher_.ArmOrNotify();
horoe8442e62017-04-27 19:10:48409 }
rockot9eadaba2017-03-15 23:57:47410 return result;
yhirano72f62272016-08-13 12:50:06411}
412
yhirano2a525f92017-01-18 08:16:46413net::IOBufferWithSize* MojoAsyncResourceHandler::GetResponseMetadata(
414 net::URLRequest* request) {
415 return request->response_info().metadata.get();
416}
417
yhirano72f62272016-08-13 12:50:06418void MojoAsyncResourceHandler::OnResponseCompleted(
419 const net::URLRequestStatus& status,
mmenke87f5c77a2017-01-31 16:11:26420 std::unique_ptr<ResourceController> controller) {
tzikbedcbce2017-01-24 15:08:05421 // Ensure sending the final upload progress message here, since
422 // OnResponseCompleted can be called without OnResponseStarted on cancellation
423 // or error cases.
424 if (upload_progress_tracker_) {
425 upload_progress_tracker_->OnUploadCompleted();
426 upload_progress_tracker_ = nullptr;
427 }
428
yhirano72f62272016-08-13 12:50:06429 shared_writer_ = nullptr;
430 buffer_ = nullptr;
431 handle_watcher_.Cancel();
432
yhirano72f62272016-08-13 12:50:06433 // TODO(gavinp): Remove this CHECK when we figure out the cause of
434 // http://crbug.com/124680 . This check mirrors closely check in
435 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
436 // ResourceHandleInternal which asserts on its state and crashes. By crashing
437 // when the message is sent, we should get better crash reports.
438 CHECK(status.status() != net::URLRequestStatus::SUCCESS ||
439 sent_received_response_message_);
440
441 int error_code = status.error();
yhirano72f62272016-08-13 12:50:06442
443 DCHECK_NE(status.status(), net::URLRequestStatus::IO_PENDING);
yhirano72f62272016-08-13 12:50:06444
445 ResourceRequestCompletionStatus request_complete_data;
446 request_complete_data.error_code = error_code;
yhirano72f62272016-08-13 12:50:06447 request_complete_data.exists_in_cache = request()->response_info().was_cached;
yhirano72f62272016-08-13 12:50:06448 request_complete_data.completion_time = base::TimeTicks::Now();
449 request_complete_data.encoded_data_length =
450 request()->GetTotalReceivedBytes();
yhiranoefb9d782016-11-28 09:29:03451 request_complete_data.encoded_body_length = request()->GetRawBodyBytes();
horoe8442e62017-04-27 19:10:48452 request_complete_data.decoded_body_length = total_written_bytes_;
yhirano72f62272016-08-13 12:50:06453
454 url_loader_client_->OnComplete(request_complete_data);
mmenke87f5c77a2017-01-31 16:11:26455 controller->Resume();
yhirano72f62272016-08-13 12:50:06456}
457
458bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) {
mmenke6add1722017-03-21 21:31:17459 while (buffer_bytes_read_ > 0) {
yhirano72f62272016-08-13 12:50:06460 scoped_refptr<net::IOBufferWithSize> dest;
461 if (!AllocateWriterIOBuffer(&dest, defer))
462 return false;
463 if (*defer)
464 return true;
yhirano72f62272016-08-13 12:50:06465
466 size_t copied_size =
467 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size()));
468 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size);
469 buffer_offset_ += copied_size;
470 buffer_bytes_read_ -= copied_size;
471 if (EndWrite(copied_size) != MOJO_RESULT_OK)
472 return false;
yhirano4fede0f2017-03-21 03:33:15473 }
mmenke6add1722017-03-21 21:31:17474
475 // All bytes are copied.
476 buffer_ = nullptr;
477 buffer_offset_ = 0;
478 is_using_io_buffer_not_from_writer_ = false;
479 return true;
yhirano72f62272016-08-13 12:50:06480}
481
482bool MojoAsyncResourceHandler::AllocateWriterIOBuffer(
483 scoped_refptr<net::IOBufferWithSize>* buf,
484 bool* defer) {
485 void* data = nullptr;
486 uint32_t available = 0;
487 MojoResult result = BeginWrite(&data, &available);
488 if (result == MOJO_RESULT_SHOULD_WAIT) {
489 *defer = true;
490 return true;
491 }
492 if (result != MOJO_RESULT_OK)
493 return false;
mmenke6add1722017-03-21 21:31:17494 DCHECK_GT(available, 0u);
yhirano72f62272016-08-13 12:50:06495 *buf = new WriterIOBuffer(shared_writer_, data, available);
496 return true;
497}
498
yhirano72f62272016-08-13 12:50:06499bool MojoAsyncResourceHandler::CheckForSufficientResource() {
500 if (has_checked_for_sufficient_resources_)
501 return true;
502 has_checked_for_sufficient_resources_ = true;
503
504 if (rdh_->HasSufficientResourcesForRequest(request()))
505 return true;
506
yhirano72f62272016-08-13 12:50:06507 return false;
508}
509
yhirano7153dc472016-11-16 09:42:46510void MojoAsyncResourceHandler::OnWritable(MojoResult result) {
mmenke6add1722017-03-21 21:31:17511 if (did_defer_on_will_read_) {
512 DCHECK(has_controller());
513 DCHECK(!did_defer_on_writing_);
514 DCHECK(!did_defer_on_redirect_);
515
516 did_defer_on_will_read_ = false;
517
518 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_;
519 parent_buffer_ = nullptr;
520 int* parent_buffer_size = parent_buffer_size_;
521 parent_buffer_size_ = nullptr;
522
523 request()->LogUnblocked();
524 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController());
525 return;
526 }
527
yhirano7153dc472016-11-16 09:42:46528 if (!did_defer_on_writing_)
529 return;
mmenke87f5c77a2017-01-31 16:11:26530 DCHECK(has_controller());
yhirano7153dc472016-11-16 09:42:46531 DCHECK(!did_defer_on_redirect_);
532 did_defer_on_writing_ = false;
533
mmenke6add1722017-03-21 21:31:17534 DCHECK(is_using_io_buffer_not_from_writer_);
535 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
536 // to the data pipe.
537 DCHECK_GT(buffer_bytes_read_, 0u);
538 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
539 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
540 return;
yhirano7153dc472016-11-16 09:42:46541 }
542
543 if (did_defer_on_writing_) {
544 // Continue waiting.
545 return;
546 }
547 request()->LogUnblocked();
mmenke87f5c77a2017-01-31 16:11:26548 Resume();
yhirano72f62272016-08-13 12:50:06549}
550
yhirano59393702016-11-16 06:10:24551void MojoAsyncResourceHandler::Cancel() {
552 const ResourceRequestInfoImpl* info = GetRequestInfo();
553 ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer(
554 GlobalRequestID(info->GetChildID(), info->GetRequestID()));
555}
556
yhiranoa275b3c2016-12-20 03:58:40557int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() {
558 int64_t total_received_bytes = request()->GetTotalReceivedBytes();
559 int64_t bytes_to_report =
560 total_received_bytes - reported_total_received_bytes_;
561 reported_total_received_bytes_ = total_received_bytes;
562 DCHECK_LE(0, bytes_to_report);
563 return bytes_to_report;
564}
565
yhirano7153dc472016-11-16 09:42:46566void MojoAsyncResourceHandler::ReportBadMessage(const std::string& error) {
567 mojo::ReportBadMessage(error);
568}
569
tzikbedcbce2017-01-24 15:08:05570std::unique_ptr<UploadProgressTracker>
571MojoAsyncResourceHandler::CreateUploadProgressTracker(
Brett Wilson1c990022017-09-12 20:11:15572 const base::Location& from_here,
tzikbedcbce2017-01-24 15:08:05573 UploadProgressTracker::UploadProgressReportCallback callback) {
574 return base::MakeUnique<UploadProgressTracker>(from_here, std::move(callback),
575 request());
576}
577
yhiranobbc904d02016-11-26 05:59:26578void MojoAsyncResourceHandler::OnTransfer(
Yutaka Hirano4f87e232017-07-25 08:13:52579 mojom::URLLoaderRequest mojo_request,
yhirano6f57b502017-03-01 03:44:20580 mojom::URLLoaderClientPtr url_loader_client) {
yhiranobbc904d02016-11-26 05:59:26581 binding_.Unbind();
582 binding_.Bind(std::move(mojo_request));
tzik0f14f192017-08-15 02:43:33583 binding_.set_connection_error_handler(base::BindOnce(
584 &MojoAsyncResourceHandler::Cancel, base::Unretained(this)));
yhiranobbc904d02016-11-26 05:59:26585 url_loader_client_ = std::move(url_loader_client);
586}
587
tzikbedcbce2017-01-24 15:08:05588void MojoAsyncResourceHandler::SendUploadProgress(
589 const net::UploadProgress& progress) {
590 url_loader_client_->OnUploadProgress(
591 progress.position(), progress.size(),
tzik0f14f192017-08-15 02:43:33592 base::BindOnce(&MojoAsyncResourceHandler::OnUploadProgressACK,
593 weak_factory_.GetWeakPtr()));
tzikbedcbce2017-01-24 15:08:05594}
595
596void MojoAsyncResourceHandler::OnUploadProgressACK() {
597 if (upload_progress_tracker_)
598 upload_progress_tracker_->OnAckReceived();
599}
600
yhirano72f62272016-08-13 12:50:06601} // namespace content