Chromium Code Reviews| Index: content/browser/loader/mojo_async_resource_handler.cc |
| diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc |
| index 8f14d599510dd16a63e7ae5a2f2b187dcd21c217..ed25d1fc0fb1d2d794746c7cedccffd458a9a3c0 100644 |
| --- a/content/browser/loader/mojo_async_resource_handler.cc |
| +++ b/content/browser/loader/mojo_async_resource_handler.cc |
| @@ -29,8 +29,8 @@ |
| #include "content/public/common/resource_response.h" |
| #include "mojo/public/c/system/data_pipe.h" |
| #include "mojo/public/cpp/bindings/message.h" |
| -#include "net/base/io_buffer.h" |
| #include "net/base/mime_sniffer.h" |
| +#include "net/base/net_errors.h" |
| #include "net/url_request/redirect_info.h" |
| namespace content { |
| @@ -233,12 +233,17 @@ void MojoAsyncResourceHandler::OnWillRead( |
| scoped_refptr<net::IOBuffer>* buf, |
| int* buf_size, |
| std::unique_ptr<ResourceController> controller) { |
| + DCHECK(!buffer_); |
| + DCHECK_EQ(0u, buffer_offset_); |
| + |
| if (!CheckForSufficientResource()) { |
| controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| return; |
| } |
| + bool first_call = false; |
| if (!shared_writer_) { |
| + first_call = true; |
| MojoCreateDataPipeOptions options; |
| options.struct_size = sizeof(MojoCreateDataPipeOptions); |
| options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; |
| @@ -254,33 +259,38 @@ void MojoAsyncResourceHandler::OnWillRead( |
| handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, |
| base::Bind(&MojoAsyncResourceHandler::OnWritable, |
| base::Unretained(this))); |
| + } |
| - bool defer = false; |
| - scoped_refptr<net::IOBufferWithSize> buffer; |
| - if (!AllocateWriterIOBuffer(&buffer, &defer)) { |
| + bool defer = false; |
| + if (!AllocateWriterIOBuffer(&buffer_, &defer)) { |
| + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| + return; |
| + } |
| + |
| + if (defer) { |
| + DCHECK(!buffer_); |
| + parent_buffer_ = buf; |
| + parent_buffer_size_ = buf_size; |
| + HoldController(std::move(controller)); |
| + request()->LogBlockedBy("MojoAsyncResourceHandler"); |
| + did_defer_on_will_read_ = true; |
| + return; |
| + } |
| + |
| + // The first call to OnWillRead must return a buffer of at least |
| + // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an |
| + // intermediary buffer. |
| + if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) { |
| + // The allocated buffer is too small, so need to create an intermediary one. |
| + if (EndWrite(0) != MOJO_RESULT_OK) { |
| controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| return; |
| } |
| - if (!defer) { |
| - if (static_cast<size_t>(buffer->size()) >= kMinAllocationSize) { |
| - *buf = buffer_ = buffer; |
| - *buf_size = buffer_->size(); |
| - controller->Resume(); |
| - return; |
| - } |
| - |
| - // The allocated buffer is too small. |
| - if (EndWrite(0) != MOJO_RESULT_OK) { |
| - controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| - return; |
| - } |
| - } |
| DCHECK(!is_using_io_buffer_not_from_writer_); |
| is_using_io_buffer_not_from_writer_ = true; |
| buffer_ = new net::IOBufferWithSize(kMinAllocationSize); |
| } |
| - DCHECK_EQ(0u, buffer_offset_); |
| *buf = buffer_; |
| *buf_size = buffer_->size(); |
| controller->Resume(); |
| @@ -293,7 +303,9 @@ void MojoAsyncResourceHandler::OnReadCompleted( |
| DCHECK_GE(bytes_read, 0); |
| DCHECK(buffer_); |
| - if (!bytes_read) { |
| + if (bytes_read == 0) { |
| + // Note that |buffer_| is not cleared here, which will cause a DCHECK on |
| + // 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'
|
| controller->Resume(); |
| return; |
| } |
| @@ -313,12 +325,12 @@ void MojoAsyncResourceHandler::OnReadCompleted( |
| } |
| if (is_using_io_buffer_not_from_writer_) { |
| - // Couldn't allocate a buffer on the data pipe in OnWillRead. |
| + // Couldn't allocate a large enough buffer on the data pipe in OnWillRead. |
| DCHECK_EQ(0u, buffer_bytes_read_); |
| buffer_bytes_read_ = bytes_read; |
| bool defer = false; |
| if (!CopyReadDataToDataPipe(&defer)) { |
| - controller->Cancel(); |
| + controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| return; |
| } |
| if (defer) { |
| @@ -335,20 +347,8 @@ void MojoAsyncResourceHandler::OnReadCompleted( |
| controller->Cancel(); |
| return; |
| } |
| - // Allocate a buffer for the next OnWillRead call here, because OnWillRead |
| - // doesn't have |defer| parameter. |
| - bool defer = false; |
| - if (!AllocateWriterIOBuffer(&buffer_, &defer)) { |
| - controller->Cancel(); |
| - return; |
| - } |
| - if (defer) { |
| - request()->LogBlockedBy("MojoAsyncResourceHandler"); |
| - did_defer_on_writing_ = true; |
| - HoldController(std::move(controller)); |
| - return; |
| - } |
| + buffer_ = nullptr; |
| controller->Resume(); |
| } |
| @@ -368,6 +368,7 @@ void MojoAsyncResourceHandler::FollowRedirect() { |
| return; |
| } |
| + DCHECK(!did_defer_on_will_read_); |
| DCHECK(!did_defer_on_writing_); |
| did_defer_on_redirect_ = false; |
| request()->LogUnblocked(); |
| @@ -454,17 +455,12 @@ void MojoAsyncResourceHandler::OnResponseCompleted( |
| } |
| bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { |
| - while (true) { |
| + while (buffer_bytes_read_ > 0) { |
| scoped_refptr<net::IOBufferWithSize> dest; |
| if (!AllocateWriterIOBuffer(&dest, defer)) |
| return false; |
| if (*defer) |
| return true; |
| - if (buffer_bytes_read_ == 0) { |
| - // All bytes are copied. Save the buffer for the next OnWillRead call. |
| - buffer_ = std::move(dest); |
| - return true; |
| - } |
| size_t copied_size = |
| std::min(buffer_bytes_read_, static_cast<size_t>(dest->size())); |
| @@ -473,13 +469,13 @@ bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { |
| buffer_bytes_read_ -= copied_size; |
| if (EndWrite(copied_size) != MOJO_RESULT_OK) |
| return false; |
| - |
| - if (buffer_bytes_read_ == 0) { |
| - // All bytes are copied. |
| - buffer_offset_ = 0; |
| - is_using_io_buffer_not_from_writer_ = false; |
| - } |
| } |
| + |
| + // All bytes are copied. |
| + buffer_ = nullptr; |
| + buffer_offset_ = 0; |
| + is_using_io_buffer_not_from_writer_ = false; |
| + return true; |
| } |
| bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( |
| @@ -494,6 +490,7 @@ bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( |
| } |
| if (result != MOJO_RESULT_OK) |
| return false; |
| + DCHECK_GT(available, 0u); |
| *buf = new WriterIOBuffer(shared_writer_, data, available); |
| return true; |
| } |
| @@ -510,26 +507,34 @@ bool MojoAsyncResourceHandler::CheckForSufficientResource() { |
| } |
| void MojoAsyncResourceHandler::OnWritable(MojoResult result) { |
| + if (did_defer_on_will_read_) { |
| + DCHECK(has_controller()); |
| + DCHECK(!did_defer_on_writing_); |
| + DCHECK(!did_defer_on_redirect_); |
| + |
| + did_defer_on_will_read_ = false; |
| + |
| + scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_; |
| + parent_buffer_ = nullptr; |
| + int* parent_buffer_size = parent_buffer_size_; |
| + parent_buffer_size_ = nullptr; |
| + OnWillRead(parent_buffer, parent_buffer_size, ReleaseController()); |
| + return; |
| + } |
| + |
| if (!did_defer_on_writing_) |
| return; |
| DCHECK(has_controller()); |
| DCHECK(!did_defer_on_redirect_); |
| did_defer_on_writing_ = false; |
| - if (is_using_io_buffer_not_from_writer_) { |
| - // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents |
| - // to the data pipe. |
| - DCHECK_GT(buffer_bytes_read_, 0u); |
| - if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { |
| - CancelWithError(net::ERR_FAILED); |
| - return; |
| - } |
| - } else { |
| - // Allocate a buffer for the next OnWillRead call here. |
| - if (!AllocateWriterIOBuffer(&buffer_, &did_defer_on_writing_)) { |
| - CancelWithError(net::ERR_FAILED); |
| - return; |
| - } |
| + DCHECK(is_using_io_buffer_not_from_writer_); |
| + // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents |
| + // to the data pipe. |
| + DCHECK_GT(buffer_bytes_read_, 0u); |
| + if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { |
| + CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
| + return; |
| } |
| if (did_defer_on_writing_) { |