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

Unified Diff: content/browser/loader/intercepting_resource_handler.cc

Issue 2668603003: Make ResourceHandler::OnWillRead able to complete asynchronously. (Closed)
Patch Set: One bot doesn't like 256 day timers. :( Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/loader/intercepting_resource_handler.cc
diff --git a/content/browser/loader/intercepting_resource_handler.cc b/content/browser/loader/intercepting_resource_handler.cc
index 902ba302c55db4aa2b4211277936a4f711fa6623..b9fffc8c50dd85d0ff87f2e9683eb26d006d0472 100644
--- a/content/browser/loader/intercepting_resource_handler.cc
+++ b/content/browser/loader/intercepting_resource_handler.cc
@@ -92,21 +92,27 @@ void InterceptingResourceHandler::OnResponseStarted(
DoLoop();
}
-bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size) {
- if (state_ == State::PASS_THROUGH)
- return next_handler_->OnWillRead(buf, buf_size);
+void InterceptingResourceHandler::OnWillRead(
+ scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ std::unique_ptr<ResourceController> controller) {
+ if (state_ == State::PASS_THROUGH) {
+ next_handler_->OnWillRead(buf, buf_size, std::move(controller));
+ return;
+ }
DCHECK_EQ(State::STARTING, state_);
+ DCHECK(!first_read_buffer_);
+ DCHECK_EQ(0, first_read_buffer_size_);
+ DCHECK(!parent_read_buffer_);
+ DCHECK(!parent_read_buffer_size_);
- if (!next_handler_->OnWillRead(buf, buf_size))
- return false;
+ parent_read_buffer_ = buf;
+ parent_read_buffer_size_ = buf_size;
- first_read_buffer_ = *buf;
- first_read_buffer_size_ = *buf_size;
- first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size));
- *buf = first_read_buffer_double_;
- return true;
+ state_ = State::SENDING_ON_WILL_READ_TO_OLD_HANDLER;
+ HoldController(std::move(controller));
+ DoLoop();
}
void InterceptingResourceHandler::OnReadCompleted(
@@ -191,6 +197,12 @@ void InterceptingResourceHandler::DoLoop() {
case State::PASS_THROUGH:
NOTREACHED();
break;
+ case State::SENDING_ON_WILL_READ_TO_OLD_HANDLER:
+ SendOnWillReadToOldHandler();
+ break;
+ case State::WAITING_FOR_OLD_HANDLERS_BUFFER:
+ OnBufferReceived();
+ break;
case State::SENDING_ON_WILL_START_TO_NEW_HANDLER:
SendOnResponseStartedToNewHandler();
break;
@@ -213,9 +225,15 @@ void InterceptingResourceHandler::DoLoop() {
case State::SENDING_PAYLOAD_TO_OLD_HANDLER:
SendPayloadToOldHandler();
break;
+ case State::RECEIVING_BUFFER_FROM_OLD_HANDLER:
+ ReceivedBufferFromOldHandler();
+ break;
case State::SENDING_BUFFER_TO_NEW_HANDLER:
SendFirstReadBufferToNewHandler();
break;
+ case State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER:
+ ReceivedBufferFromNewHandler();
+ break;
}
}
}
@@ -245,6 +263,36 @@ void InterceptingResourceHandler::ResumeInternal() {
weak_ptr_factory_.GetWeakPtr()));
}
+void InterceptingResourceHandler::SendOnWillReadToOldHandler() {
+ DCHECK_EQ(State::SENDING_ON_WILL_READ_TO_OLD_HANDLER, state_);
+
+ state_ = State::WAITING_FOR_OLD_HANDLERS_BUFFER;
+ next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
+ base::MakeUnique<Controller>(this));
+}
+
+void InterceptingResourceHandler::OnBufferReceived() {
+ DCHECK_EQ(State::WAITING_FOR_OLD_HANDLERS_BUFFER, state_);
+
+ // TODO(mmenke): If this method is just going to allocate a double buffer
+ // anyways, can the call to the old handler's OnWillRead be removed? That
+ // would mean handling replaying data in the case that |next_handler_|'s
+ // buffer is smaller than the double buffer, but SendPayloadToOldHandler
+ // already handles that case, anyways, so could share that code with the
+ // no-swap path as well. Or better, just have MimeSniffingResourceHandler
+ // create and manage the buffer itself.
+ first_read_buffer_double_ =
+ new net::IOBuffer(static_cast<size_t>(first_read_buffer_size_));
+ *parent_read_buffer_ = first_read_buffer_double_;
+ *parent_read_buffer_size_ = first_read_buffer_size_;
+
+ parent_read_buffer_ = nullptr;
+ parent_read_buffer_size_ = nullptr;
+
+ state_ = State::STARTING;
+ Resume();
+}
+
void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() {
state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
next_handler_->OnResponseStarted(response_.get(),
@@ -253,7 +301,9 @@ void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() {
void InterceptingResourceHandler::SendPayloadToOldHandler() {
DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_);
- if (payload_bytes_written_ == payload_for_old_handler_.size()) {
+
+ if (static_cast<size_t>(payload_bytes_written_) ==
+ payload_for_old_handler_.size()) {
net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
if (payload_for_old_handler_.empty()) {
// If there is no payload, just finalize the request on the old handler.
@@ -273,29 +323,43 @@ void InterceptingResourceHandler::SendPayloadToOldHandler() {
return;
}
+ state_ = State::RECEIVING_BUFFER_FROM_OLD_HANDLER;
+
scoped_refptr<net::IOBuffer> buffer;
- int size = 0;
+ // If |first_read_buffer_| is non-NULL, it was already received from
+ // |next_handler_| via OnWillRead. Can just use the buffer.
if (first_read_buffer_) {
- // |first_read_buffer_| is a buffer gotten from |next_handler_| via
- // OnWillRead. Use the buffer.
- buffer = first_read_buffer_;
- size = first_read_buffer_size_;
-
- first_read_buffer_ = nullptr;
- first_read_buffer_size_ = 0;
- } else {
- if (!next_handler_->OnWillRead(&buffer, &size)) {
- Cancel();
- return;
- }
+ DCHECK_GT(first_read_buffer_size_, 0);
+
+ ResumeInternal();
+ return;
}
- size = std::min(size, static_cast<int>(payload_for_old_handler_.size() -
- payload_bytes_written_));
- memcpy(buffer->data(),
- payload_for_old_handler_.data() + payload_bytes_written_, size);
- payload_bytes_written_ += size;
- next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this));
+ DCHECK(!first_read_buffer_size_);
+ next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
+ base::MakeUnique<Controller>(this));
+}
+
+void InterceptingResourceHandler::ReceivedBufferFromOldHandler() {
+ DCHECK_EQ(State::RECEIVING_BUFFER_FROM_OLD_HANDLER, state_);
+ DCHECK(first_read_buffer_);
+ DCHECK_GT(first_read_buffer_size_, 0);
+
+ int bytes_to_copy =
+ std::min(first_read_buffer_size_,
+ static_cast<int>(payload_for_old_handler_.size() -
+ payload_bytes_written_));
+ memcpy(first_read_buffer_->data(),
+ payload_for_old_handler_.data() + payload_bytes_written_,
+ bytes_to_copy);
+ payload_bytes_written_ += bytes_to_copy;
+
+ first_read_buffer_ = nullptr;
+ first_read_buffer_size_ = 0;
+
+ state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
+ next_handler_->OnReadCompleted(bytes_to_copy,
+ base::MakeUnique<Controller>(this));
}
void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() {
@@ -306,6 +370,8 @@ void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() {
void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() {
DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER);
+ DCHECK(!new_handler_read_buffer_);
+ DCHECK(!new_handler_read_buffer_size_);
if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) {
state_ = State::PASS_THROUGH;
@@ -314,19 +380,32 @@ void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() {
return;
}
- scoped_refptr<net::IOBuffer> buf;
- int size = 0;
- if (!next_handler_->OnWillRead(&buf, &size)) {
- Cancel();
- return;
- }
- size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ -
- first_read_buffer_bytes_written_));
- memcpy(buf->data(),
+ next_handler_->OnWillRead(&new_handler_read_buffer_,
+ &new_handler_read_buffer_size_,
+ base::MakeUnique<Controller>(this));
+ state_ = State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER;
Charlie Harrison 2017/02/16 21:25:04 Shouldn't this go above the OnWillReadCall?
mmenke 2017/03/08 19:16:07 Done. Doesn't matter for correctness, but it's mo
+}
+
+void InterceptingResourceHandler::ReceivedBufferFromNewHandler() {
+ DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER);
+ DCHECK(new_handler_read_buffer_);
+ DCHECK(new_handler_read_buffer_size_);
+
+ int bytes_to_copy =
+ std::min(new_handler_read_buffer_size_,
+ static_cast<int>(first_read_buffer_bytes_read_ -
+ first_read_buffer_bytes_written_));
+ memcpy(new_handler_read_buffer_->data(),
first_read_buffer_double_->data() + first_read_buffer_bytes_written_,
- size);
- first_read_buffer_bytes_written_ += size;
- next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this));
+ bytes_to_copy);
+ first_read_buffer_bytes_written_ += bytes_to_copy;
+
+ new_handler_read_buffer_ = nullptr;
+ new_handler_read_buffer_size_ = 0;
+
+ state_ = State::SENDING_BUFFER_TO_NEW_HANDLER;
+ next_handler_->OnReadCompleted(bytes_to_copy,
+ base::MakeUnique<Controller>(this));
}
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698