| Index: net/spdy/bidirectional_stream_spdy_impl.cc
|
| diff --git a/net/spdy/bidirectional_stream_spdy_impl.cc b/net/spdy/bidirectional_stream_spdy_impl.cc
|
| deleted file mode 100644
|
| index e926201edaa8a78847e6591de08cf59ae69bb5c0..0000000000000000000000000000000000000000
|
| --- a/net/spdy/bidirectional_stream_spdy_impl.cc
|
| +++ /dev/null
|
| @@ -1,424 +0,0 @@
|
| -// Copyright 2015 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 "net/spdy/bidirectional_stream_spdy_impl.h"
|
| -
|
| -#include <utility>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/location.h"
|
| -#include "base/logging.h"
|
| -#include "base/threading/thread_task_runner_handle.h"
|
| -#include "base/time/time.h"
|
| -#include "base/timer/timer.h"
|
| -#include "net/http/bidirectional_stream_request_info.h"
|
| -#include "net/spdy/spdy_buffer.h"
|
| -#include "net/spdy/spdy_header_block.h"
|
| -#include "net/spdy/spdy_http_utils.h"
|
| -#include "net/spdy/spdy_stream.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// Time to wait in millisecond to notify |delegate_| of data received.
|
| -// Handing small chunks of data to the caller creates measurable overhead.
|
| -// So buffer data in short time-spans and send a single read notification.
|
| -const int kBufferTimeMs = 1;
|
| -
|
| -} // namespace
|
| -
|
| -BidirectionalStreamSpdyImpl::BidirectionalStreamSpdyImpl(
|
| - const base::WeakPtr<SpdySession>& spdy_session,
|
| - NetLogSource source_dependency)
|
| - : spdy_session_(spdy_session),
|
| - request_info_(nullptr),
|
| - delegate_(nullptr),
|
| - source_dependency_(source_dependency),
|
| - negotiated_protocol_(kProtoUnknown),
|
| - more_read_data_pending_(false),
|
| - read_buffer_len_(0),
|
| - written_end_of_stream_(false),
|
| - write_pending_(false),
|
| - stream_closed_(false),
|
| - closed_stream_status_(ERR_FAILED),
|
| - closed_stream_received_bytes_(0),
|
| - closed_stream_sent_bytes_(0),
|
| - closed_has_load_timing_info_(false),
|
| - weak_factory_(this) {}
|
| -
|
| -BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() {
|
| - // Sends a RST to the remote if the stream is destroyed before it completes.
|
| - ResetStream();
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::Start(
|
| - const BidirectionalStreamRequestInfo* request_info,
|
| - const NetLogWithSource& net_log,
|
| - bool /*send_request_headers_automatically*/,
|
| - BidirectionalStreamImpl::Delegate* delegate,
|
| - std::unique_ptr<base::Timer> timer) {
|
| - DCHECK(!stream_);
|
| - DCHECK(timer);
|
| -
|
| - delegate_ = delegate;
|
| - timer_ = std::move(timer);
|
| -
|
| - if (!spdy_session_) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
|
| - weak_factory_.GetWeakPtr(), ERR_CONNECTION_CLOSED));
|
| - return;
|
| - }
|
| -
|
| - request_info_ = request_info;
|
| -
|
| - int rv = stream_request_.StartRequest(
|
| - SPDY_BIDIRECTIONAL_STREAM, spdy_session_, request_info_->url,
|
| - request_info_->priority, net_log,
|
| - base::Bind(&BidirectionalStreamSpdyImpl::OnStreamInitialized,
|
| - weak_factory_.GetWeakPtr()));
|
| - if (rv != ERR_IO_PENDING)
|
| - OnStreamInitialized(rv);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::SendRequestHeaders() {
|
| - // Request headers will be sent automatically.
|
| - NOTREACHED();
|
| -}
|
| -
|
| -int BidirectionalStreamSpdyImpl::ReadData(IOBuffer* buf, int buf_len) {
|
| - if (stream_)
|
| - DCHECK(!stream_->IsIdle());
|
| -
|
| - DCHECK(buf);
|
| - DCHECK(buf_len);
|
| - DCHECK(!timer_->IsRunning()) << "There should be only one ReadData in flight";
|
| -
|
| - // If there is data buffered, complete the IO immediately.
|
| - if (!read_data_queue_.IsEmpty()) {
|
| - return read_data_queue_.Dequeue(buf->data(), buf_len);
|
| - } else if (stream_closed_) {
|
| - return closed_stream_status_;
|
| - }
|
| - // Read will complete asynchronously and Delegate::OnReadCompleted will be
|
| - // called upon completion.
|
| - read_buffer_ = buf;
|
| - read_buffer_len_ = buf_len;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data,
|
| - int length,
|
| - bool end_stream) {
|
| - DCHECK(length > 0 || (length == 0 && end_stream));
|
| - DCHECK(!write_pending_);
|
| -
|
| - if (written_end_of_stream_) {
|
| - LOG(ERROR) << "Writing after end of stream is written.";
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
|
| - weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
|
| - return;
|
| - }
|
| -
|
| - write_pending_ = true;
|
| - written_end_of_stream_ = end_stream;
|
| - if (MaybeHandleStreamClosedInSendData())
|
| - return;
|
| -
|
| - DCHECK(!stream_closed_);
|
| - stream_->SendData(data.get(), length,
|
| - end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::SendvData(
|
| - const std::vector<scoped_refptr<IOBuffer>>& buffers,
|
| - const std::vector<int>& lengths,
|
| - bool end_stream) {
|
| - DCHECK_EQ(buffers.size(), lengths.size());
|
| - DCHECK(!write_pending_);
|
| -
|
| - if (written_end_of_stream_) {
|
| - LOG(ERROR) << "Writing after end of stream is written.";
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
|
| - weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
|
| - return;
|
| - }
|
| -
|
| - write_pending_ = true;
|
| - written_end_of_stream_ = end_stream;
|
| - if (MaybeHandleStreamClosedInSendData())
|
| - return;
|
| -
|
| - DCHECK(!stream_closed_);
|
| - int total_len = 0;
|
| - for (int len : lengths) {
|
| - total_len += len;
|
| - }
|
| -
|
| - pending_combined_buffer_ = new net::IOBuffer(total_len);
|
| - int len = 0;
|
| - // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames.
|
| - for (size_t i = 0; i < buffers.size(); ++i) {
|
| - memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(),
|
| - lengths[i]);
|
| - len += lengths[i];
|
| - }
|
| - stream_->SendData(pending_combined_buffer_.get(), total_len,
|
| - end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
|
| -}
|
| -
|
| -NextProto BidirectionalStreamSpdyImpl::GetProtocol() const {
|
| - return negotiated_protocol_;
|
| -}
|
| -
|
| -int64_t BidirectionalStreamSpdyImpl::GetTotalReceivedBytes() const {
|
| - if (stream_closed_)
|
| - return closed_stream_received_bytes_;
|
| -
|
| - if (!stream_)
|
| - return 0;
|
| -
|
| - return stream_->raw_received_bytes();
|
| -}
|
| -
|
| -int64_t BidirectionalStreamSpdyImpl::GetTotalSentBytes() const {
|
| - if (stream_closed_)
|
| - return closed_stream_sent_bytes_;
|
| -
|
| - if (!stream_)
|
| - return 0;
|
| -
|
| - return stream_->raw_sent_bytes();
|
| -}
|
| -
|
| -bool BidirectionalStreamSpdyImpl::GetLoadTimingInfo(
|
| - LoadTimingInfo* load_timing_info) const {
|
| - if (stream_closed_) {
|
| - if (!closed_has_load_timing_info_)
|
| - return false;
|
| - *load_timing_info = closed_load_timing_info_;
|
| - return true;
|
| - }
|
| -
|
| - // If |stream_| isn't created or has ID 0, return false. This is to match
|
| - // the implementation in SpdyHttpStream.
|
| - if (!stream_ || stream_->stream_id() == 0)
|
| - return false;
|
| -
|
| - return stream_->GetLoadTimingInfo(load_timing_info);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnHeadersSent() {
|
| - DCHECK(stream_);
|
| -
|
| - negotiated_protocol_ = kProtoHTTP2;
|
| - if (delegate_)
|
| - delegate_->OnStreamReady(/*request_headers_sent=*/true);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnHeadersReceived(
|
| - const SpdyHeaderBlock& response_headers) {
|
| - DCHECK(stream_);
|
| -
|
| - if (delegate_)
|
| - delegate_->OnHeadersReceived(response_headers);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnDataReceived(
|
| - std::unique_ptr<SpdyBuffer> buffer) {
|
| - DCHECK(stream_);
|
| - DCHECK(!stream_closed_);
|
| -
|
| - // If |buffer| is null, BidirectionalStreamSpdyImpl::OnClose will be invoked
|
| - // by SpdyStream to indicate the end of stream.
|
| - if (!buffer)
|
| - return;
|
| -
|
| - // When buffer is consumed, SpdyStream::OnReadBufferConsumed will adjust
|
| - // recv window size accordingly.
|
| - read_data_queue_.Enqueue(std::move(buffer));
|
| - if (read_buffer_) {
|
| - // Handing small chunks of data to the caller creates measurable overhead.
|
| - // So buffer data in short time-spans and send a single read notification.
|
| - ScheduleBufferedRead();
|
| - }
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnDataSent() {
|
| - DCHECK(write_pending_);
|
| -
|
| - pending_combined_buffer_ = nullptr;
|
| - write_pending_ = false;
|
| -
|
| - if (delegate_)
|
| - delegate_->OnDataSent();
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnTrailers(const SpdyHeaderBlock& trailers) {
|
| - DCHECK(stream_);
|
| - DCHECK(!stream_closed_);
|
| -
|
| - if (delegate_)
|
| - delegate_->OnTrailersReceived(trailers);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnClose(int status) {
|
| - DCHECK(stream_);
|
| -
|
| - stream_closed_ = true;
|
| - closed_stream_status_ = status;
|
| - closed_stream_received_bytes_ = stream_->raw_received_bytes();
|
| - closed_stream_sent_bytes_ = stream_->raw_sent_bytes();
|
| - closed_has_load_timing_info_ =
|
| - stream_->GetLoadTimingInfo(&closed_load_timing_info_);
|
| -
|
| - if (status != OK) {
|
| - NotifyError(status);
|
| - return;
|
| - }
|
| - ResetStream();
|
| - // Complete any remaining read, as all data has been buffered.
|
| - // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will
|
| - // do nothing.
|
| - timer_->Stop();
|
| -
|
| - // |this| might get destroyed after calling into |delegate_| in
|
| - // DoBufferedRead().
|
| - auto weak_this = weak_factory_.GetWeakPtr();
|
| - DoBufferedRead();
|
| - if (weak_this.get() && write_pending_)
|
| - OnDataSent();
|
| -}
|
| -
|
| -NetLogSource BidirectionalStreamSpdyImpl::source_dependency() const {
|
| - return source_dependency_;
|
| -}
|
| -
|
| -int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() {
|
| - SpdyHeaderBlock headers;
|
| - HttpRequestInfo http_request_info;
|
| - http_request_info.url = request_info_->url;
|
| - http_request_info.method = request_info_->method;
|
| - http_request_info.extra_headers = request_info_->extra_headers;
|
| -
|
| - CreateSpdyHeadersFromHttpRequest(
|
| - http_request_info, http_request_info.extra_headers, true, &headers);
|
| - written_end_of_stream_ = request_info_->end_stream_on_headers;
|
| - return stream_->SendRequestHeaders(std::move(headers),
|
| - request_info_->end_stream_on_headers
|
| - ? NO_MORE_DATA_TO_SEND
|
| - : MORE_DATA_TO_SEND);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) {
|
| - DCHECK_NE(ERR_IO_PENDING, rv);
|
| - if (rv == OK) {
|
| - stream_ = stream_request_.ReleaseStream();
|
| - stream_->SetDelegate(this);
|
| - rv = SendRequestHeadersHelper();
|
| - if (rv == OK) {
|
| - OnHeadersSent();
|
| - return;
|
| - } else if (rv == ERR_IO_PENDING) {
|
| - return;
|
| - }
|
| - }
|
| - NotifyError(rv);
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::NotifyError(int rv) {
|
| - ResetStream();
|
| - write_pending_ = false;
|
| - if (delegate_) {
|
| - BidirectionalStreamImpl::Delegate* delegate = delegate_;
|
| - delegate_ = nullptr;
|
| - // Cancel any pending callback.
|
| - weak_factory_.InvalidateWeakPtrs();
|
| - delegate->OnFailed(rv);
|
| - // |this| can be null when returned from delegate.
|
| - }
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::ResetStream() {
|
| - if (!stream_)
|
| - return;
|
| - if (!stream_->IsClosed()) {
|
| - // This sends a RST to the remote.
|
| - stream_->DetachDelegate();
|
| - DCHECK(!stream_);
|
| - } else {
|
| - // Stream is already closed, so it is not legal to call DetachDelegate.
|
| - stream_.reset();
|
| - }
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::ScheduleBufferedRead() {
|
| - // If there is already a scheduled DoBufferedRead, don't issue
|
| - // another one. Mark that we have received more data and return.
|
| - if (timer_->IsRunning()) {
|
| - more_read_data_pending_ = true;
|
| - return;
|
| - }
|
| -
|
| - more_read_data_pending_ = false;
|
| - timer_->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kBufferTimeMs),
|
| - base::Bind(&BidirectionalStreamSpdyImpl::DoBufferedRead,
|
| - weak_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void BidirectionalStreamSpdyImpl::DoBufferedRead() {
|
| - DCHECK(!timer_->IsRunning());
|
| - // Check to see that the stream has not errored out.
|
| - DCHECK(stream_ || stream_closed_);
|
| - DCHECK(!stream_closed_ || closed_stream_status_ == OK);
|
| -
|
| - // When |more_read_data_pending_| is true, it means that more data has arrived
|
| - // since started waiting. Wait a little longer and continue to buffer.
|
| - if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
|
| - ScheduleBufferedRead();
|
| - return;
|
| - }
|
| -
|
| - int rv = 0;
|
| - if (read_buffer_) {
|
| - rv = ReadData(read_buffer_.get(), read_buffer_len_);
|
| - DCHECK_NE(ERR_IO_PENDING, rv);
|
| - read_buffer_ = nullptr;
|
| - read_buffer_len_ = 0;
|
| - if (delegate_)
|
| - delegate_->OnDataRead(rv);
|
| - }
|
| -}
|
| -
|
| -bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const {
|
| - if (stream_closed_)
|
| - return false;
|
| - DCHECK_GT(read_buffer_len_, 0);
|
| - return read_data_queue_.GetTotalSize() <
|
| - static_cast<size_t>(read_buffer_len_);
|
| -}
|
| -
|
| -bool BidirectionalStreamSpdyImpl::MaybeHandleStreamClosedInSendData() {
|
| - if (stream_)
|
| - return false;
|
| - // If |stream_| is closed without an error before client half closes,
|
| - // blackhole any pending write data. crbug.com/650438.
|
| - if (stream_closed_ && closed_stream_status_ == OK) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::OnDataSent,
|
| - weak_factory_.GetWeakPtr()));
|
| - return true;
|
| - }
|
| - LOG(ERROR) << "Trying to send data after stream has been destroyed.";
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
|
| - weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
|
| - return true;
|
| -}
|
| -
|
| -} // namespace net
|
|
|