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 |