Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Side by Side Diff: content/browser/loader/mojo_async_resource_handler.cc

Issue 2738973002: Allow MojoAsyncResourceHandler::OnWillRead to complete asyncronously (Closed)
Patch Set: Cleanup Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/loader/mojo_async_resource_handler.h" 5 #include "content/browser/loader/mojo_async_resource_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 11 matching lines...) Expand all
22 #include "content/browser/loader/resource_dispatcher_host_impl.h" 22 #include "content/browser/loader/resource_dispatcher_host_impl.h"
23 #include "content/browser/loader/resource_request_info_impl.h" 23 #include "content/browser/loader/resource_request_info_impl.h"
24 #include "content/browser/loader/resource_scheduler.h" 24 #include "content/browser/loader/resource_scheduler.h"
25 #include "content/browser/loader/upload_progress_tracker.h" 25 #include "content/browser/loader/upload_progress_tracker.h"
26 #include "content/common/resource_request_completion_status.h" 26 #include "content/common/resource_request_completion_status.h"
27 #include "content/public/browser/global_request_id.h" 27 #include "content/public/browser/global_request_id.h"
28 #include "content/public/browser/resource_dispatcher_host_delegate.h" 28 #include "content/public/browser/resource_dispatcher_host_delegate.h"
29 #include "content/public/common/resource_response.h" 29 #include "content/public/common/resource_response.h"
30 #include "mojo/public/c/system/data_pipe.h" 30 #include "mojo/public/c/system/data_pipe.h"
31 #include "mojo/public/cpp/bindings/message.h" 31 #include "mojo/public/cpp/bindings/message.h"
32 #include "net/base/io_buffer.h"
33 #include "net/base/mime_sniffer.h" 32 #include "net/base/mime_sniffer.h"
33 #include "net/base/net_errors.h"
34 #include "net/url_request/redirect_info.h" 34 #include "net/url_request/redirect_info.h"
35 35
36 namespace content { 36 namespace content {
37 namespace { 37 namespace {
38 38
39 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize; 39 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize;
40 40
41 // MimeTypeResourceHandler *implicitly* requires that the buffer size 41 // MimeTypeResourceHandler *implicitly* requires that the buffer size
42 // returned from OnWillRead should be larger than certain size. 42 // returned from OnWillRead should be larger than certain size.
43 // TODO(yhirano): Fix MimeTypeResourceHandler. 43 // TODO(yhirano): Fix MimeTypeResourceHandler.
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 base::Unretained(this))); 226 base::Unretained(this)));
227 } 227 }
228 228
229 controller->Resume(); 229 controller->Resume();
230 } 230 }
231 231
232 void MojoAsyncResourceHandler::OnWillRead( 232 void MojoAsyncResourceHandler::OnWillRead(
233 scoped_refptr<net::IOBuffer>* buf, 233 scoped_refptr<net::IOBuffer>* buf,
234 int* buf_size, 234 int* buf_size,
235 std::unique_ptr<ResourceController> controller) { 235 std::unique_ptr<ResourceController> controller) {
236 DCHECK(!buffer_);
237 DCHECK_EQ(0u, buffer_offset_);
238
236 if (!CheckForSufficientResource()) { 239 if (!CheckForSufficientResource()) {
237 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); 240 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
238 return; 241 return;
239 } 242 }
240 243
244 bool first_call = false;
241 if (!shared_writer_) { 245 if (!shared_writer_) {
246 first_call = true;
242 MojoCreateDataPipeOptions options; 247 MojoCreateDataPipeOptions options;
243 options.struct_size = sizeof(MojoCreateDataPipeOptions); 248 options.struct_size = sizeof(MojoCreateDataPipeOptions);
244 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; 249 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
245 options.element_num_bytes = 1; 250 options.element_num_bytes = 1;
246 options.capacity_num_bytes = g_allocation_size; 251 options.capacity_num_bytes = g_allocation_size;
247 mojo::DataPipe data_pipe(options); 252 mojo::DataPipe data_pipe(options);
248 253
249 DCHECK(data_pipe.producer_handle.is_valid()); 254 DCHECK(data_pipe.producer_handle.is_valid());
250 DCHECK(data_pipe.consumer_handle.is_valid()); 255 DCHECK(data_pipe.consumer_handle.is_valid());
251 256
252 response_body_consumer_handle_ = std::move(data_pipe.consumer_handle); 257 response_body_consumer_handle_ = std::move(data_pipe.consumer_handle);
253 shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle)); 258 shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle));
254 handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, 259 handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE,
255 base::Bind(&MojoAsyncResourceHandler::OnWritable, 260 base::Bind(&MojoAsyncResourceHandler::OnWritable,
256 base::Unretained(this))); 261 base::Unretained(this)));
262 }
257 263
258 bool defer = false; 264 bool defer = false;
259 scoped_refptr<net::IOBufferWithSize> buffer; 265 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
260 if (!AllocateWriterIOBuffer(&buffer, &defer)) { 266 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
267 return;
268 }
269
270 if (defer) {
271 DCHECK(!buffer_);
272 parent_buffer_ = buf;
273 parent_buffer_size_ = buf_size;
274 HoldController(std::move(controller));
275 request()->LogBlockedBy("MojoAsyncResourceHandler");
276 did_defer_on_will_read_ = true;
277 return;
278 }
279
280 // The first call to OnWillRead must return a buffer of at least
281 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an
282 // intermediary buffer.
283 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) {
284 // The allocated buffer is too small, so need to create an intermediary one.
285 if (EndWrite(0) != MOJO_RESULT_OK) {
261 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); 286 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
262 return; 287 return;
263 } 288 }
264 if (!defer) {
265 if (static_cast<size_t>(buffer->size()) >= kMinAllocationSize) {
266 *buf = buffer_ = buffer;
267 *buf_size = buffer_->size();
268 controller->Resume();
269 return;
270 }
271
272 // The allocated buffer is too small.
273 if (EndWrite(0) != MOJO_RESULT_OK) {
274 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
275 return;
276 }
277 }
278 DCHECK(!is_using_io_buffer_not_from_writer_); 289 DCHECK(!is_using_io_buffer_not_from_writer_);
279 is_using_io_buffer_not_from_writer_ = true; 290 is_using_io_buffer_not_from_writer_ = true;
280 buffer_ = new net::IOBufferWithSize(kMinAllocationSize); 291 buffer_ = new net::IOBufferWithSize(kMinAllocationSize);
281 } 292 }
282 293
283 DCHECK_EQ(0u, buffer_offset_);
284 *buf = buffer_; 294 *buf = buffer_;
285 *buf_size = buffer_->size(); 295 *buf_size = buffer_->size();
286 controller->Resume(); 296 controller->Resume();
287 } 297 }
288 298
289 void MojoAsyncResourceHandler::OnReadCompleted( 299 void MojoAsyncResourceHandler::OnReadCompleted(
290 int bytes_read, 300 int bytes_read,
291 std::unique_ptr<ResourceController> controller) { 301 std::unique_ptr<ResourceController> controller) {
292 DCHECK(!has_controller()); 302 DCHECK(!has_controller());
293 DCHECK_GE(bytes_read, 0); 303 DCHECK_GE(bytes_read, 0);
294 DCHECK(buffer_); 304 DCHECK(buffer_);
295 305
296 if (!bytes_read) { 306 if (bytes_read == 0) {
307 // Note that |buffer_| is not cleared here, which will cause a DCHECK on
308 // subsequent OnWillRead calls.
Randy Smith (Not in Mondays) 2017/03/17 20:06:06 Confirming: It seems what this means is that you'r
mmenke 2017/03/17 22:29:39 It's mostly because a buffer_ = nullptr here didn'
297 controller->Resume(); 309 controller->Resume();
298 return; 310 return;
299 } 311 }
300 312
301 const ResourceRequestInfoImpl* info = GetRequestInfo(); 313 const ResourceRequestInfoImpl* info = GetRequestInfo();
302 if (info->ShouldReportRawHeaders()) { 314 if (info->ShouldReportRawHeaders()) {
303 auto transfer_size_diff = CalculateRecentlyReceivedBytes(); 315 auto transfer_size_diff = CalculateRecentlyReceivedBytes();
304 if (transfer_size_diff > 0) 316 if (transfer_size_diff > 0)
305 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff); 317 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
306 } 318 }
307 319
308 if (response_body_consumer_handle_.is_valid()) { 320 if (response_body_consumer_handle_.is_valid()) {
309 // Send the data pipe on the first OnReadCompleted call. 321 // Send the data pipe on the first OnReadCompleted call.
310 url_loader_client_->OnStartLoadingResponseBody( 322 url_loader_client_->OnStartLoadingResponseBody(
311 std::move(response_body_consumer_handle_)); 323 std::move(response_body_consumer_handle_));
312 response_body_consumer_handle_.reset(); 324 response_body_consumer_handle_.reset();
313 } 325 }
314 326
315 if (is_using_io_buffer_not_from_writer_) { 327 if (is_using_io_buffer_not_from_writer_) {
316 // Couldn't allocate a buffer on the data pipe in OnWillRead. 328 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead.
317 DCHECK_EQ(0u, buffer_bytes_read_); 329 DCHECK_EQ(0u, buffer_bytes_read_);
318 buffer_bytes_read_ = bytes_read; 330 buffer_bytes_read_ = bytes_read;
319 bool defer = false; 331 bool defer = false;
320 if (!CopyReadDataToDataPipe(&defer)) { 332 if (!CopyReadDataToDataPipe(&defer)) {
321 controller->Cancel(); 333 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
322 return; 334 return;
323 } 335 }
324 if (defer) { 336 if (defer) {
325 request()->LogBlockedBy("MojoAsyncResourceHandler"); 337 request()->LogBlockedBy("MojoAsyncResourceHandler");
326 did_defer_on_writing_ = true; 338 did_defer_on_writing_ = true;
327 HoldController(std::move(controller)); 339 HoldController(std::move(controller));
328 return; 340 return;
329 } 341 }
330 controller->Resume(); 342 controller->Resume();
331 return; 343 return;
332 } 344 }
333 345
334 if (EndWrite(bytes_read) != MOJO_RESULT_OK) { 346 if (EndWrite(bytes_read) != MOJO_RESULT_OK) {
335 controller->Cancel(); 347 controller->Cancel();
336 return; 348 return;
337 } 349 }
338 // Allocate a buffer for the next OnWillRead call here, because OnWillRead
339 // doesn't have |defer| parameter.
340 bool defer = false;
341 if (!AllocateWriterIOBuffer(&buffer_, &defer)) {
342 controller->Cancel();
343 return;
344 }
345 if (defer) {
346 request()->LogBlockedBy("MojoAsyncResourceHandler");
347 did_defer_on_writing_ = true;
348 HoldController(std::move(controller));
349 return;
350 }
351 350
351 buffer_ = nullptr;
352 controller->Resume(); 352 controller->Resume();
353 } 353 }
354 354
355 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { 355 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
356 url_loader_client_->OnDataDownloaded(bytes_downloaded, 356 url_loader_client_->OnDataDownloaded(bytes_downloaded,
357 CalculateRecentlyReceivedBytes()); 357 CalculateRecentlyReceivedBytes());
358 } 358 }
359 359
360 void MojoAsyncResourceHandler::FollowRedirect() { 360 void MojoAsyncResourceHandler::FollowRedirect() {
361 if (!request()->status().is_success()) { 361 if (!request()->status().is_success()) {
362 DVLOG(1) << "FollowRedirect for invalid request"; 362 DVLOG(1) << "FollowRedirect for invalid request";
363 return; 363 return;
364 } 364 }
365 if (!did_defer_on_redirect_) { 365 if (!did_defer_on_redirect_) {
366 DVLOG(1) << "Malformed FollowRedirect request"; 366 DVLOG(1) << "Malformed FollowRedirect request";
367 ReportBadMessage("Malformed FollowRedirect request"); 367 ReportBadMessage("Malformed FollowRedirect request");
368 return; 368 return;
369 } 369 }
370 370
371 DCHECK(!did_defer_on_will_read_);
371 DCHECK(!did_defer_on_writing_); 372 DCHECK(!did_defer_on_writing_);
372 did_defer_on_redirect_ = false; 373 did_defer_on_redirect_ = false;
373 request()->LogUnblocked(); 374 request()->LogUnblocked();
374 Resume(); 375 Resume();
375 } 376 }
376 377
377 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority, 378 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority,
378 int32_t intra_priority_value) { 379 int32_t intra_priority_value) {
379 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest( 380 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest(
380 request(), priority, intra_priority_value); 381 request(), priority, intra_priority_value);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 request_complete_data.completion_time = base::TimeTicks::Now(); 448 request_complete_data.completion_time = base::TimeTicks::Now();
448 request_complete_data.encoded_data_length = 449 request_complete_data.encoded_data_length =
449 request()->GetTotalReceivedBytes(); 450 request()->GetTotalReceivedBytes();
450 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); 451 request_complete_data.encoded_body_length = request()->GetRawBodyBytes();
451 452
452 url_loader_client_->OnComplete(request_complete_data); 453 url_loader_client_->OnComplete(request_complete_data);
453 controller->Resume(); 454 controller->Resume();
454 } 455 }
455 456
456 bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { 457 bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) {
457 while (true) { 458 while (buffer_bytes_read_ > 0) {
458 scoped_refptr<net::IOBufferWithSize> dest; 459 scoped_refptr<net::IOBufferWithSize> dest;
459 if (!AllocateWriterIOBuffer(&dest, defer)) 460 if (!AllocateWriterIOBuffer(&dest, defer))
460 return false; 461 return false;
461 if (*defer) 462 if (*defer)
462 return true; 463 return true;
463 if (buffer_bytes_read_ == 0) {
464 // All bytes are copied. Save the buffer for the next OnWillRead call.
465 buffer_ = std::move(dest);
466 return true;
467 }
468 464
469 size_t copied_size = 465 size_t copied_size =
470 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size())); 466 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size()));
471 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size); 467 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size);
472 buffer_offset_ += copied_size; 468 buffer_offset_ += copied_size;
473 buffer_bytes_read_ -= copied_size; 469 buffer_bytes_read_ -= copied_size;
474 if (EndWrite(copied_size) != MOJO_RESULT_OK) 470 if (EndWrite(copied_size) != MOJO_RESULT_OK)
475 return false; 471 return false;
472 }
476 473
477 if (buffer_bytes_read_ == 0) { 474 // All bytes are copied.
478 // All bytes are copied. 475 buffer_ = nullptr;
479 buffer_offset_ = 0; 476 buffer_offset_ = 0;
480 is_using_io_buffer_not_from_writer_ = false; 477 is_using_io_buffer_not_from_writer_ = false;
481 } 478 return true;
482 }
483 } 479 }
484 480
485 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( 481 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer(
486 scoped_refptr<net::IOBufferWithSize>* buf, 482 scoped_refptr<net::IOBufferWithSize>* buf,
487 bool* defer) { 483 bool* defer) {
488 void* data = nullptr; 484 void* data = nullptr;
489 uint32_t available = 0; 485 uint32_t available = 0;
490 MojoResult result = BeginWrite(&data, &available); 486 MojoResult result = BeginWrite(&data, &available);
491 if (result == MOJO_RESULT_SHOULD_WAIT) { 487 if (result == MOJO_RESULT_SHOULD_WAIT) {
492 *defer = true; 488 *defer = true;
493 return true; 489 return true;
494 } 490 }
495 if (result != MOJO_RESULT_OK) 491 if (result != MOJO_RESULT_OK)
496 return false; 492 return false;
493 DCHECK_GT(available, 0u);
497 *buf = new WriterIOBuffer(shared_writer_, data, available); 494 *buf = new WriterIOBuffer(shared_writer_, data, available);
498 return true; 495 return true;
499 } 496 }
500 497
501 bool MojoAsyncResourceHandler::CheckForSufficientResource() { 498 bool MojoAsyncResourceHandler::CheckForSufficientResource() {
502 if (has_checked_for_sufficient_resources_) 499 if (has_checked_for_sufficient_resources_)
503 return true; 500 return true;
504 has_checked_for_sufficient_resources_ = true; 501 has_checked_for_sufficient_resources_ = true;
505 502
506 if (rdh_->HasSufficientResourcesForRequest(request())) 503 if (rdh_->HasSufficientResourcesForRequest(request()))
507 return true; 504 return true;
508 505
509 return false; 506 return false;
510 } 507 }
511 508
512 void MojoAsyncResourceHandler::OnWritable(MojoResult result) { 509 void MojoAsyncResourceHandler::OnWritable(MojoResult result) {
510 if (did_defer_on_will_read_) {
511 DCHECK(has_controller());
512 DCHECK(!did_defer_on_writing_);
513 DCHECK(!did_defer_on_redirect_);
514
515 did_defer_on_will_read_ = false;
516
517 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_;
518 parent_buffer_ = nullptr;
519 int* parent_buffer_size = parent_buffer_size_;
520 parent_buffer_size_ = nullptr;
521 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController());
522 return;
523 }
524
513 if (!did_defer_on_writing_) 525 if (!did_defer_on_writing_)
514 return; 526 return;
515 DCHECK(has_controller()); 527 DCHECK(has_controller());
516 DCHECK(!did_defer_on_redirect_); 528 DCHECK(!did_defer_on_redirect_);
517 did_defer_on_writing_ = false; 529 did_defer_on_writing_ = false;
518 530
519 if (is_using_io_buffer_not_from_writer_) { 531 DCHECK(is_using_io_buffer_not_from_writer_);
520 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents 532 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents
521 // to the data pipe. 533 // to the data pipe.
522 DCHECK_GT(buffer_bytes_read_, 0u); 534 DCHECK_GT(buffer_bytes_read_, 0u);
523 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { 535 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) {
524 CancelWithError(net::ERR_FAILED); 536 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
525 return; 537 return;
526 }
527 } else {
528 // Allocate a buffer for the next OnWillRead call here.
529 if (!AllocateWriterIOBuffer(&buffer_, &did_defer_on_writing_)) {
530 CancelWithError(net::ERR_FAILED);
531 return;
532 }
533 } 538 }
534 539
535 if (did_defer_on_writing_) { 540 if (did_defer_on_writing_) {
536 // Continue waiting. 541 // Continue waiting.
537 return; 542 return;
538 } 543 }
539 request()->LogUnblocked(); 544 request()->LogUnblocked();
540 Resume(); 545 Resume();
541 } 546 }
542 547
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK, 589 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK,
585 weak_factory_.GetWeakPtr())); 590 weak_factory_.GetWeakPtr()));
586 } 591 }
587 592
588 void MojoAsyncResourceHandler::OnUploadProgressACK() { 593 void MojoAsyncResourceHandler::OnUploadProgressACK() {
589 if (upload_progress_tracker_) 594 if (upload_progress_tracker_)
590 upload_progress_tracker_->OnAckReceived(); 595 upload_progress_tracker_->OnAckReceived();
591 } 596 }
592 597
593 } // namespace content 598 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698