Chromium Code Reviews| Index: content/child/url_response_body_consumer.cc |
| diff --git a/content/child/url_response_body_consumer.cc b/content/child/url_response_body_consumer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fed2006f4f44391e303ab02d84ff2e250687886a |
| --- /dev/null |
| +++ b/content/child/url_response_body_consumer.cc |
| @@ -0,0 +1,132 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/child/url_response_body_consumer.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/macros.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "content/child/resource_dispatcher.h" |
| +#include "content/common/resource_messages.h" |
| +#include "content/common/resource_request_completion_status.h" |
| +#include "content/public/child/request_peer.h" |
| + |
| +namespace content { |
| + |
| +class URLResponseBodyConsumer::ReceivedData final |
| + : public RequestPeer::ReceivedData { |
| + public: |
| + ReceivedData(const char* payload, |
| + int length, |
| + scoped_refptr<URLResponseBodyConsumer> consumer) |
| + : payload_(payload), length_(length), consumer_(consumer) {} |
| + |
| + ~ReceivedData() override { consumer_->Reclaim(length_); } |
| + |
| + const char* payload() const override { return payload_; } |
| + int length() const override { return length_; } |
| + // TODO(yhirano): These return incorrect values. Remove these from |
| + // ReceivedData before enabling Mojo-Loading. |
| + int encoded_data_length() const override { return length_; } |
| + int encoded_body_length() const override { return length_; } |
| + |
| + private: |
| + const char* const payload_; |
| + const uint32_t length_; |
| + |
| + scoped_refptr<URLResponseBodyConsumer> consumer_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ReceivedData); |
| +}; |
| + |
| +URLResponseBodyConsumer::URLResponseBodyConsumer( |
| + int request_id, |
| + ResourceDispatcher* resource_dispatcher, |
| + mojo::ScopedDataPipeConsumerHandle handle) |
| + : request_id_(request_id), |
| + resource_dispatcher_(resource_dispatcher), |
| + handle_(std::move(handle)), |
| + has_seen_end_of_data_(!handle_.is_valid()) { |
| + StartWatching(); |
| +} |
| + |
| +URLResponseBodyConsumer::~URLResponseBodyConsumer() {} |
| + |
| +void URLResponseBodyConsumer::OnComplete( |
| + const ResourceRequestCompletionStatus& status) { |
| + if (has_been_cancelled_) |
| + return; |
| + has_received_completion_ = true; |
| + completion_status_ = status; |
| + NotifyCompletionIfAppropriate(); |
| +} |
| + |
| +void URLResponseBodyConsumer::Cancel() { |
| + has_been_cancelled_ = true; |
| + handle_watcher_.Stop(); |
| +} |
| + |
| +void URLResponseBodyConsumer::Reclaim(uint32_t size) { |
| + MojoResult result = mojo::EndReadDataRaw(handle_.get(), size); |
| + DCHECK_EQ(MOJO_RESULT_OK, result); |
| + StartWatching(); |
| +} |
| + |
| +void URLResponseBodyConsumer::OnReadable(MojoResult unused) { |
| + DCHECK(!has_been_cancelled_); |
| + |
| + // TODO(yhirano): Suppress notification when deferred. |
| + // TODO(yhirano): Run this operation on the loading task runner. |
| + const void* buffer = nullptr; |
| + uint32_t available = 0; |
| + MojoResult result = mojo::BeginReadDataRaw(handle_.get(), &buffer, &available, |
| + MOJO_READ_DATA_FLAG_NONE); |
| + if (result == MOJO_RESULT_OK) { |
| + ResourceDispatcher::PendingRequestInfo* request_info = |
| + resource_dispatcher_->GetPendingRequestInfo(request_id_); |
| + DCHECK(request_info); |
| + request_info->peer->OnReceivedData(base::WrapUnique( |
| + new ReceivedData(static_cast<const char*>(buffer), available, this))); |
| + // |this| may be deleted. |
| + return; |
| + } |
| + if (result == MOJO_RESULT_FAILED_PRECONDITION) { |
| + has_seen_end_of_data_ = true; |
| + NotifyCompletionIfAppropriate(); |
| + // |this| may be deleted. |
| + return; |
| + } |
| + if (result == MOJO_RESULT_SHOULD_WAIT) { |
| + StartWatching(); |
| + return; |
| + } |
| + completion_status_.error_code = net::ERR_FAILED; |
| + has_seen_end_of_data_ = true; |
| + has_received_completion_ = true; |
| + NotifyCompletionIfAppropriate(); |
| + // |this| may be deleted. |
| +} |
| + |
| +void URLResponseBodyConsumer::StartWatching() { |
| + if (has_been_cancelled_ || has_seen_end_of_data_) |
| + return; |
| + handle_watcher_.Start( |
| + handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, |
| + base::Bind(&URLResponseBodyConsumer::OnReadable, base::Unretained(this))); |
| +} |
| + |
| +void URLResponseBodyConsumer::NotifyCompletionIfAppropriate() { |
| + if (has_been_cancelled_) |
| + return; |
| + if (has_received_completion_ && has_seen_end_of_data_) { |
|
kinuko
2016/08/04 16:07:03
nit: maybe early return in the other way instead
yhirano
2016/08/05 12:21:40
Done.
|
| + // Cancel this instance in order not to notify twice. |
| + Cancel(); |
| + |
| + resource_dispatcher_->OnMessageReceived( |
| + ResourceMsg_RequestComplete(request_id_, completion_status_)); |
| + // |this| may be deleted. |
| + } |
| +} |
| + |
| +} // namespace content |