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

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

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

Powered by Google App Engine
This is Rietveld 408576698