| 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..a9c83db06c4c2e7bdfe9caef82b2a718a4b0bb79
|
| --- /dev/null
|
| +++ b/content/child/url_response_body_consumer.cc
|
| @@ -0,0 +1,129 @@
|
| +// 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_; }
|
| + int encoded_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_) {
|
| + // 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
|
|
|