| Index: net/spdy/spdy_http_stream.cc
|
| diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
|
| deleted file mode 100644
|
| index 25be33212ec057870d6377fb177d0669dbf2bd3b..0000000000000000000000000000000000000000
|
| --- a/net/spdy/spdy_http_stream.cc
|
| +++ /dev/null
|
| @@ -1,538 +0,0 @@
|
| -// Copyright (c) 2012 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/spdy_http_stream.h"
|
| -
|
| -#include <algorithm>
|
| -#include <list>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/logging.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "net/base/host_port_pair.h"
|
| -#include "net/base/net_log.h"
|
| -#include "net/base/net_util.h"
|
| -#include "net/base/upload_data_stream.h"
|
| -#include "net/http/http_request_headers.h"
|
| -#include "net/http/http_request_info.h"
|
| -#include "net/http/http_response_info.h"
|
| -#include "net/spdy/spdy_header_block.h"
|
| -#include "net/spdy/spdy_http_utils.h"
|
| -#include "net/spdy/spdy_protocol.h"
|
| -#include "net/spdy/spdy_session.h"
|
| -
|
| -namespace net {
|
| -
|
| -SpdyHttpStream::SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session,
|
| - bool direct)
|
| - : spdy_session_(spdy_session),
|
| - is_reused_(spdy_session_->IsReused()),
|
| - stream_closed_(false),
|
| - closed_stream_status_(ERR_FAILED),
|
| - closed_stream_id_(0),
|
| - closed_stream_received_bytes_(0),
|
| - request_info_(NULL),
|
| - response_info_(NULL),
|
| - response_headers_status_(RESPONSE_HEADERS_ARE_INCOMPLETE),
|
| - user_buffer_len_(0),
|
| - request_body_buf_size_(0),
|
| - buffered_read_callback_pending_(false),
|
| - more_read_data_pending_(false),
|
| - direct_(direct),
|
| - weak_factory_(this) {
|
| - DCHECK(spdy_session_.get());
|
| -}
|
| -
|
| -SpdyHttpStream::~SpdyHttpStream() {
|
| - if (stream_.get()) {
|
| - stream_->DetachDelegate();
|
| - DCHECK(!stream_.get());
|
| - }
|
| -}
|
| -
|
| -int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
|
| - RequestPriority priority,
|
| - const BoundNetLog& stream_net_log,
|
| - const CompletionCallback& callback) {
|
| - DCHECK(!stream_);
|
| - if (!spdy_session_)
|
| - return ERR_CONNECTION_CLOSED;
|
| -
|
| - request_info_ = request_info;
|
| - if (request_info_->method == "GET") {
|
| - int error = spdy_session_->GetPushStream(request_info_->url, &stream_,
|
| - stream_net_log);
|
| - if (error != OK)
|
| - return error;
|
| -
|
| - // |stream_| may be NULL even if OK was returned.
|
| - if (stream_.get()) {
|
| - DCHECK_EQ(stream_->type(), SPDY_PUSH_STREAM);
|
| - stream_->SetDelegate(this);
|
| - return OK;
|
| - }
|
| - }
|
| -
|
| - int rv = stream_request_.StartRequest(
|
| - SPDY_REQUEST_RESPONSE_STREAM, spdy_session_, request_info_->url,
|
| - priority, stream_net_log,
|
| - base::Bind(&SpdyHttpStream::OnStreamCreated,
|
| - weak_factory_.GetWeakPtr(), callback));
|
| -
|
| - if (rv == OK) {
|
| - stream_ = stream_request_.ReleaseStream();
|
| - stream_->SetDelegate(this);
|
| - }
|
| -
|
| - return rv;
|
| -}
|
| -
|
| -UploadProgress SpdyHttpStream::GetUploadProgress() const {
|
| - if (!request_info_ || !HasUploadData())
|
| - return UploadProgress();
|
| -
|
| - return UploadProgress(request_info_->upload_data_stream->position(),
|
| - request_info_->upload_data_stream->size());
|
| -}
|
| -
|
| -int SpdyHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
|
| - CHECK(!callback.is_null());
|
| - if (stream_closed_)
|
| - return closed_stream_status_;
|
| -
|
| - CHECK(stream_.get());
|
| -
|
| - // Check if we already have the response headers. If so, return synchronously.
|
| - if (response_headers_status_ == RESPONSE_HEADERS_ARE_COMPLETE) {
|
| - CHECK(!stream_->IsIdle());
|
| - return OK;
|
| - }
|
| -
|
| - // Still waiting for the response, return IO_PENDING.
|
| - CHECK(callback_.is_null());
|
| - callback_ = callback;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -int SpdyHttpStream::ReadResponseBody(
|
| - IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
|
| - if (stream_.get())
|
| - CHECK(!stream_->IsIdle());
|
| -
|
| - CHECK(buf);
|
| - CHECK(buf_len);
|
| - CHECK(!callback.is_null());
|
| -
|
| - // If we have data buffered, complete the IO immediately.
|
| - if (!response_body_queue_.IsEmpty()) {
|
| - return response_body_queue_.Dequeue(buf->data(), buf_len);
|
| - } else if (stream_closed_) {
|
| - return closed_stream_status_;
|
| - }
|
| -
|
| - CHECK(callback_.is_null());
|
| - CHECK(!user_buffer_.get());
|
| - CHECK_EQ(0, user_buffer_len_);
|
| -
|
| - callback_ = callback;
|
| - user_buffer_ = buf;
|
| - user_buffer_len_ = buf_len;
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void SpdyHttpStream::Close(bool not_reusable) {
|
| - // Note: the not_reusable flag has no meaning for SPDY streams.
|
| -
|
| - Cancel();
|
| - DCHECK(!stream_.get());
|
| -}
|
| -
|
| -HttpStream* SpdyHttpStream::RenewStreamForAuth() {
|
| - return NULL;
|
| -}
|
| -
|
| -bool SpdyHttpStream::IsResponseBodyComplete() const {
|
| - return stream_closed_;
|
| -}
|
| -
|
| -bool SpdyHttpStream::CanFindEndOfResponse() const {
|
| - return true;
|
| -}
|
| -
|
| -bool SpdyHttpStream::IsConnectionReused() const {
|
| - return is_reused_;
|
| -}
|
| -
|
| -void SpdyHttpStream::SetConnectionReused() {
|
| - // SPDY doesn't need an indicator here.
|
| -}
|
| -
|
| -bool SpdyHttpStream::IsConnectionReusable() const {
|
| - // SPDY streams aren't considered reusable.
|
| - return false;
|
| -}
|
| -
|
| -int64 SpdyHttpStream::GetTotalReceivedBytes() const {
|
| - if (stream_closed_)
|
| - return closed_stream_received_bytes_;
|
| -
|
| - if (!stream_)
|
| - return 0;
|
| -
|
| - return stream_->raw_received_bytes();
|
| -}
|
| -
|
| -bool SpdyHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
|
| - if (stream_closed_) {
|
| - if (!closed_stream_has_load_timing_info_)
|
| - return false;
|
| - *load_timing_info = closed_stream_load_timing_info_;
|
| - return true;
|
| - }
|
| -
|
| - // If |stream_| has yet to be created, or does not yet have an ID, fail.
|
| - // The reused flag can only be correctly set once a stream has an ID. Streams
|
| - // get their IDs once the request has been successfully sent, so this does not
|
| - // behave that differently from other stream types.
|
| - if (!stream_ || stream_->stream_id() == 0)
|
| - return false;
|
| -
|
| - return stream_->GetLoadTimingInfo(load_timing_info);
|
| -}
|
| -
|
| -int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
|
| - HttpResponseInfo* response,
|
| - const CompletionCallback& callback) {
|
| - if (stream_closed_) {
|
| - return closed_stream_status_;
|
| - }
|
| -
|
| - base::Time request_time = base::Time::Now();
|
| - CHECK(stream_.get());
|
| -
|
| - stream_->SetRequestTime(request_time);
|
| - // This should only get called in the case of a request occurring
|
| - // during server push that has already begun but hasn't finished,
|
| - // so we set the response's request time to be the actual one
|
| - if (response_info_)
|
| - response_info_->request_time = request_time;
|
| -
|
| - CHECK(!request_body_buf_.get());
|
| - if (HasUploadData()) {
|
| - // Use kMaxSpdyFrameChunkSize as the buffer size, since the request
|
| - // body data is written with this size at a time.
|
| - request_body_buf_ = new IOBufferWithSize(kMaxSpdyFrameChunkSize);
|
| - // The request body buffer is empty at first.
|
| - request_body_buf_size_ = 0;
|
| - }
|
| -
|
| - CHECK(!callback.is_null());
|
| - CHECK(response);
|
| -
|
| - // SendRequest can be called in two cases.
|
| - //
|
| - // a) A client initiated request. In this case, |response_info_| should be
|
| - // NULL to start with.
|
| - // b) A client request which matches a response that the server has already
|
| - // pushed.
|
| - if (push_response_info_.get()) {
|
| - *response = *(push_response_info_.get());
|
| - push_response_info_.reset();
|
| - } else {
|
| - DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_);
|
| - }
|
| -
|
| - response_info_ = response;
|
| -
|
| - // Put the peer's IP address and port into the response.
|
| - IPEndPoint address;
|
| - int result = stream_->GetPeerAddress(&address);
|
| - if (result != OK)
|
| - return result;
|
| - response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
|
| -
|
| - if (stream_->type() == SPDY_PUSH_STREAM) {
|
| - // Pushed streams do not send any data, and should always be
|
| - // idle. However, we still want to return ERR_IO_PENDING to mimic
|
| - // non-push behavior. The callback will be called when the
|
| - // response is received.
|
| - result = ERR_IO_PENDING;
|
| - } else {
|
| - scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
|
| - CreateSpdyHeadersFromHttpRequest(
|
| - *request_info_, request_headers,
|
| - stream_->GetProtocolVersion(), direct_,
|
| - headers.get());
|
| - stream_->net_log().AddEvent(
|
| - NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS,
|
| - base::Bind(&SpdyHeaderBlockNetLogCallback, headers.get()));
|
| - result =
|
| - stream_->SendRequestHeaders(
|
| - headers.Pass(),
|
| - HasUploadData() ? MORE_DATA_TO_SEND : NO_MORE_DATA_TO_SEND);
|
| - }
|
| -
|
| - if (result == ERR_IO_PENDING) {
|
| - CHECK(callback_.is_null());
|
| - callback_ = callback;
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -void SpdyHttpStream::Cancel() {
|
| - callback_.Reset();
|
| - if (stream_.get()) {
|
| - stream_->Cancel();
|
| - DCHECK(!stream_.get());
|
| - }
|
| -}
|
| -
|
| -void SpdyHttpStream::OnRequestHeadersSent() {
|
| - if (!callback_.is_null())
|
| - DoCallback(OK);
|
| -
|
| - // TODO(akalin): Do this immediately after sending the request
|
| - // headers.
|
| - if (HasUploadData())
|
| - ReadAndSendRequestBodyData();
|
| -}
|
| -
|
| -SpdyResponseHeadersStatus SpdyHttpStream::OnResponseHeadersUpdated(
|
| - const SpdyHeaderBlock& response_headers) {
|
| - CHECK_EQ(response_headers_status_, RESPONSE_HEADERS_ARE_INCOMPLETE);
|
| -
|
| - if (!response_info_) {
|
| - DCHECK_EQ(stream_->type(), SPDY_PUSH_STREAM);
|
| - push_response_info_.reset(new HttpResponseInfo);
|
| - response_info_ = push_response_info_.get();
|
| - }
|
| -
|
| - if (!SpdyHeadersToHttpResponse(
|
| - response_headers, stream_->GetProtocolVersion(), response_info_)) {
|
| - // We do not have complete headers yet.
|
| - return RESPONSE_HEADERS_ARE_INCOMPLETE;
|
| - }
|
| -
|
| - response_info_->response_time = stream_->response_time();
|
| - response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
|
| - // Don't store the SSLInfo in the response here, HttpNetworkTransaction
|
| - // will take care of that part.
|
| - SSLInfo ssl_info;
|
| - NextProto protocol_negotiated = kProtoUnknown;
|
| - stream_->GetSSLInfo(&ssl_info,
|
| - &response_info_->was_npn_negotiated,
|
| - &protocol_negotiated);
|
| - response_info_->npn_negotiated_protocol =
|
| - SSLClientSocket::NextProtoToString(protocol_negotiated);
|
| - response_info_->request_time = stream_->GetRequestTime();
|
| - response_info_->connection_info =
|
| - HttpResponseInfo::ConnectionInfoFromNextProto(stream_->GetProtocol());
|
| - response_info_->vary_data
|
| - .Init(*request_info_, *response_info_->headers.get());
|
| -
|
| - if (!callback_.is_null())
|
| - DoCallback(OK);
|
| -
|
| - return RESPONSE_HEADERS_ARE_COMPLETE;
|
| -}
|
| -
|
| -void SpdyHttpStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
|
| - CHECK_EQ(response_headers_status_, RESPONSE_HEADERS_ARE_COMPLETE);
|
| -
|
| - // Note that data may be received for a SpdyStream prior to the user calling
|
| - // ReadResponseBody(), therefore user_buffer_ may be NULL. This may often
|
| - // happen for server initiated streams.
|
| - DCHECK(stream_.get());
|
| - DCHECK(!stream_->IsClosed() || stream_->type() == SPDY_PUSH_STREAM);
|
| - if (buffer) {
|
| - response_body_queue_.Enqueue(buffer.Pass());
|
| -
|
| - if (user_buffer_.get()) {
|
| - // Handing small chunks of data to the caller creates measurable overhead.
|
| - // We buffer data in short time-spans and send a single read notification.
|
| - ScheduleBufferedReadCallback();
|
| - }
|
| - }
|
| -}
|
| -
|
| -void SpdyHttpStream::OnDataSent() {
|
| - request_body_buf_size_ = 0;
|
| - ReadAndSendRequestBodyData();
|
| -}
|
| -
|
| -void SpdyHttpStream::OnClose(int status) {
|
| - if (stream_.get()) {
|
| - stream_closed_ = true;
|
| - closed_stream_status_ = status;
|
| - closed_stream_id_ = stream_->stream_id();
|
| - closed_stream_has_load_timing_info_ =
|
| - stream_->GetLoadTimingInfo(&closed_stream_load_timing_info_);
|
| - closed_stream_received_bytes_ = stream_->raw_received_bytes();
|
| - }
|
| - stream_.reset();
|
| - bool invoked_callback = false;
|
| - if (status == net::OK) {
|
| - // We need to complete any pending buffered read now.
|
| - invoked_callback = DoBufferedReadCallback();
|
| - }
|
| - if (!invoked_callback && !callback_.is_null())
|
| - DoCallback(status);
|
| -}
|
| -
|
| -bool SpdyHttpStream::HasUploadData() const {
|
| - CHECK(request_info_);
|
| - return
|
| - request_info_->upload_data_stream &&
|
| - ((request_info_->upload_data_stream->size() > 0) ||
|
| - request_info_->upload_data_stream->is_chunked());
|
| -}
|
| -
|
| -void SpdyHttpStream::OnStreamCreated(
|
| - const CompletionCallback& callback,
|
| - int rv) {
|
| - if (rv == OK) {
|
| - stream_ = stream_request_.ReleaseStream();
|
| - stream_->SetDelegate(this);
|
| - }
|
| - callback.Run(rv);
|
| -}
|
| -
|
| -void SpdyHttpStream::ReadAndSendRequestBodyData() {
|
| - CHECK(HasUploadData());
|
| - CHECK_EQ(request_body_buf_size_, 0);
|
| -
|
| - if (request_info_->upload_data_stream->IsEOF())
|
| - return;
|
| -
|
| - // Read the data from the request body stream.
|
| - const int rv = request_info_->upload_data_stream
|
| - ->Read(request_body_buf_.get(),
|
| - request_body_buf_->size(),
|
| - base::Bind(&SpdyHttpStream::OnRequestBodyReadCompleted,
|
| - weak_factory_.GetWeakPtr()));
|
| -
|
| - if (rv != ERR_IO_PENDING) {
|
| - // ERR_IO_PENDING is the only possible error.
|
| - CHECK_GE(rv, 0);
|
| - OnRequestBodyReadCompleted(rv);
|
| - }
|
| -}
|
| -
|
| -void SpdyHttpStream::OnRequestBodyReadCompleted(int status) {
|
| - CHECK_GE(status, 0);
|
| - request_body_buf_size_ = status;
|
| - const bool eof = request_info_->upload_data_stream->IsEOF();
|
| - // Only the final fame may have a length of 0.
|
| - if (eof) {
|
| - CHECK_GE(request_body_buf_size_, 0);
|
| - } else {
|
| - CHECK_GT(request_body_buf_size_, 0);
|
| - }
|
| - stream_->SendData(request_body_buf_.get(),
|
| - request_body_buf_size_,
|
| - eof ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
|
| -}
|
| -
|
| -void SpdyHttpStream::ScheduleBufferedReadCallback() {
|
| - // If there is already a scheduled DoBufferedReadCallback, don't issue
|
| - // another one. Mark that we have received more data and return.
|
| - if (buffered_read_callback_pending_) {
|
| - more_read_data_pending_ = true;
|
| - return;
|
| - }
|
| -
|
| - more_read_data_pending_ = false;
|
| - buffered_read_callback_pending_ = true;
|
| - const base::TimeDelta kBufferTime = base::TimeDelta::FromMilliseconds(1);
|
| - base::MessageLoop::current()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(base::IgnoreResult(&SpdyHttpStream::DoBufferedReadCallback),
|
| - weak_factory_.GetWeakPtr()),
|
| - kBufferTime);
|
| -}
|
| -
|
| -// Checks to see if we should wait for more buffered data before notifying
|
| -// the caller. Returns true if we should wait, false otherwise.
|
| -bool SpdyHttpStream::ShouldWaitForMoreBufferedData() const {
|
| - // If the response is complete, there is no point in waiting.
|
| - if (stream_closed_)
|
| - return false;
|
| -
|
| - DCHECK_GT(user_buffer_len_, 0);
|
| - return response_body_queue_.GetTotalSize() <
|
| - static_cast<size_t>(user_buffer_len_);
|
| -}
|
| -
|
| -bool SpdyHttpStream::DoBufferedReadCallback() {
|
| - buffered_read_callback_pending_ = false;
|
| -
|
| - // If the transaction is cancelled or errored out, we don't need to complete
|
| - // the read.
|
| - if (!stream_.get() && !stream_closed_)
|
| - return false;
|
| -
|
| - int stream_status =
|
| - stream_closed_ ? closed_stream_status_ : stream_->response_status();
|
| - if (stream_status != OK)
|
| - return false;
|
| -
|
| - // When more_read_data_pending_ is true, it means that more data has
|
| - // arrived since we started waiting. Wait a little longer and continue
|
| - // to buffer.
|
| - if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
|
| - ScheduleBufferedReadCallback();
|
| - return false;
|
| - }
|
| -
|
| - int rv = 0;
|
| - if (user_buffer_.get()) {
|
| - rv = ReadResponseBody(user_buffer_.get(), user_buffer_len_, callback_);
|
| - CHECK_NE(rv, ERR_IO_PENDING);
|
| - user_buffer_ = NULL;
|
| - user_buffer_len_ = 0;
|
| - DoCallback(rv);
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void SpdyHttpStream::DoCallback(int rv) {
|
| - CHECK_NE(rv, ERR_IO_PENDING);
|
| - CHECK(!callback_.is_null());
|
| -
|
| - // Since Run may result in being called back, clear user_callback_ in advance.
|
| - CompletionCallback c = callback_;
|
| - callback_.Reset();
|
| - c.Run(rv);
|
| -}
|
| -
|
| -void SpdyHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
|
| - DCHECK(stream_.get());
|
| - bool using_npn;
|
| - NextProto protocol_negotiated = kProtoUnknown;
|
| - stream_->GetSSLInfo(ssl_info, &using_npn, &protocol_negotiated);
|
| -}
|
| -
|
| -void SpdyHttpStream::GetSSLCertRequestInfo(
|
| - SSLCertRequestInfo* cert_request_info) {
|
| - DCHECK(stream_.get());
|
| - stream_->GetSSLCertRequestInfo(cert_request_info);
|
| -}
|
| -
|
| -bool SpdyHttpStream::IsSpdyHttpStream() const {
|
| - return true;
|
| -}
|
| -
|
| -void SpdyHttpStream::Drain(HttpNetworkSession* session) {
|
| - Close(false);
|
| - delete this;
|
| -}
|
| -
|
| -void SpdyHttpStream::SetPriority(RequestPriority priority) {
|
| - // TODO(akalin): Plumb this through to |stream_request_| and
|
| - // |stream_|.
|
| -}
|
| -
|
| -} // namespace net
|
|
|