| Index: net/http/http_pipelined_connection_impl.cc
|
| diff --git a/net/http/http_pipelined_connection_impl.cc b/net/http/http_pipelined_connection_impl.cc
|
| deleted file mode 100644
|
| index ebd73f24ab7fcf8119c3e7db3b6f47cee2636ad2..0000000000000000000000000000000000000000
|
| --- a/net/http/http_pipelined_connection_impl.cc
|
| +++ /dev/null
|
| @@ -1,846 +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/http/http_pipelined_connection_impl.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/bind_helpers.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/stl_util.h"
|
| -#include "base/values.h"
|
| -#include "net/base/io_buffer.h"
|
| -#include "net/http/http_pipelined_stream.h"
|
| -#include "net/http/http_request_info.h"
|
| -#include "net/http/http_response_body_drainer.h"
|
| -#include "net/http/http_response_headers.h"
|
| -#include "net/http/http_stream_parser.h"
|
| -#include "net/http/http_version.h"
|
| -#include "net/socket/client_socket_handle.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -base::Value* NetLogReceivedHeadersCallback(const NetLog::Source& source,
|
| - const std::string* feedback,
|
| - NetLog::LogLevel /* log_level */) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue;
|
| - source.AddToEventParameters(dict);
|
| - dict->SetString("feedback", *feedback);
|
| - return dict;
|
| -}
|
| -
|
| -base::Value* NetLogStreamClosedCallback(const NetLog::Source& source,
|
| - bool not_reusable,
|
| - NetLog::LogLevel /* log_level */) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue;
|
| - source.AddToEventParameters(dict);
|
| - dict->SetBoolean("not_reusable", not_reusable);
|
| - return dict;
|
| -}
|
| -
|
| -base::Value* NetLogHostPortPairCallback(const HostPortPair* host_port_pair,
|
| - NetLog::LogLevel /* log_level */) {
|
| - base::DictionaryValue* dict = new base::DictionaryValue;
|
| - dict->SetString("host_and_port", host_port_pair->ToString());
|
| - return dict;
|
| -}
|
| -
|
| -} // anonymous namespace
|
| -
|
| -HttpPipelinedConnection*
|
| -HttpPipelinedConnectionImpl::Factory::CreateNewPipeline(
|
| - ClientSocketHandle* connection,
|
| - HttpPipelinedConnection::Delegate* delegate,
|
| - const HostPortPair& origin,
|
| - const SSLConfig& used_ssl_config,
|
| - const ProxyInfo& used_proxy_info,
|
| - const BoundNetLog& net_log,
|
| - bool was_npn_negotiated,
|
| - NextProto protocol_negotiated) {
|
| - return new HttpPipelinedConnectionImpl(connection, delegate, origin,
|
| - used_ssl_config, used_proxy_info,
|
| - net_log, was_npn_negotiated,
|
| - protocol_negotiated);
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl(
|
| - ClientSocketHandle* connection,
|
| - HttpPipelinedConnection::Delegate* delegate,
|
| - const HostPortPair& origin,
|
| - const SSLConfig& used_ssl_config,
|
| - const ProxyInfo& used_proxy_info,
|
| - const BoundNetLog& net_log,
|
| - bool was_npn_negotiated,
|
| - NextProto protocol_negotiated)
|
| - : delegate_(delegate),
|
| - connection_(connection),
|
| - used_ssl_config_(used_ssl_config),
|
| - used_proxy_info_(used_proxy_info),
|
| - net_log_(BoundNetLog::Make(net_log.net_log(),
|
| - NetLog::SOURCE_HTTP_PIPELINED_CONNECTION)),
|
| - was_npn_negotiated_(was_npn_negotiated),
|
| - protocol_negotiated_(protocol_negotiated),
|
| - read_buf_(new GrowableIOBuffer()),
|
| - next_pipeline_id_(1),
|
| - active_(false),
|
| - usable_(true),
|
| - completed_one_request_(false),
|
| - weak_factory_(this),
|
| - send_next_state_(SEND_STATE_NONE),
|
| - send_still_on_call_stack_(false),
|
| - read_next_state_(READ_STATE_NONE),
|
| - active_read_id_(0),
|
| - read_still_on_call_stack_(false) {
|
| - CHECK(connection_.get());
|
| - net_log_.BeginEvent(
|
| - NetLog::TYPE_HTTP_PIPELINED_CONNECTION,
|
| - base::Bind(&NetLogHostPortPairCallback, &origin));
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::~HttpPipelinedConnectionImpl() {
|
| - CHECK_EQ(depth(), 0);
|
| - CHECK(stream_info_map_.empty());
|
| - CHECK(pending_send_request_queue_.empty());
|
| - CHECK(request_order_.empty());
|
| - CHECK_EQ(send_next_state_, SEND_STATE_NONE);
|
| - CHECK_EQ(read_next_state_, READ_STATE_NONE);
|
| - CHECK(!active_send_request_.get());
|
| - CHECK(!active_read_id_);
|
| - if (!usable_) {
|
| - connection_->socket()->Disconnect();
|
| - }
|
| - connection_->Reset();
|
| - net_log_.EndEvent(NetLog::TYPE_HTTP_PIPELINED_CONNECTION);
|
| -}
|
| -
|
| -HttpPipelinedStream* HttpPipelinedConnectionImpl::CreateNewStream() {
|
| - int pipeline_id = next_pipeline_id_++;
|
| - CHECK(pipeline_id);
|
| - HttpPipelinedStream* stream = new HttpPipelinedStream(this, pipeline_id);
|
| - stream_info_map_.insert(std::make_pair(pipeline_id, StreamInfo()));
|
| - return stream;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::InitializeParser(
|
| - int pipeline_id,
|
| - const HttpRequestInfo* request,
|
| - const BoundNetLog& net_log) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(!stream_info_map_[pipeline_id].parser.get());
|
| - stream_info_map_[pipeline_id].state = STREAM_BOUND;
|
| - stream_info_map_[pipeline_id].parser.reset(new HttpStreamParser(
|
| - connection_.get(), request, read_buf_.get(), net_log));
|
| - stream_info_map_[pipeline_id].source = net_log.source();
|
| -
|
| - // In case our first stream doesn't SendRequest() immediately, we should still
|
| - // allow others to use this pipeline.
|
| - if (pipeline_id == 1) {
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&HttpPipelinedConnectionImpl::ActivatePipeline,
|
| - weak_factory_.GetWeakPtr()));
|
| - }
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::ActivatePipeline() {
|
| - if (!active_) {
|
| - active_ = true;
|
| - delegate_->OnPipelineHasCapacity(this);
|
| - }
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::OnStreamDeleted(int pipeline_id) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - Close(pipeline_id, false);
|
| -
|
| - if (stream_info_map_[pipeline_id].state != STREAM_CREATED &&
|
| - stream_info_map_[pipeline_id].state != STREAM_UNUSED) {
|
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_CLOSED);
|
| - CHECK(stream_info_map_[pipeline_id].parser.get());
|
| - stream_info_map_[pipeline_id].parser.reset();
|
| - }
|
| - CHECK(!stream_info_map_[pipeline_id].parser.get());
|
| - stream_info_map_.erase(pipeline_id);
|
| -
|
| - delegate_->OnPipelineHasCapacity(this);
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::SendRequest(
|
| - int pipeline_id,
|
| - const std::string& request_line,
|
| - const HttpRequestHeaders& headers,
|
| - HttpResponseInfo* response,
|
| - const CompletionCallback& callback) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_BOUND);
|
| - if (!usable_) {
|
| - return ERR_PIPELINE_EVICTION;
|
| - }
|
| -
|
| - PendingSendRequest* send_request = new PendingSendRequest;
|
| - send_request->pipeline_id = pipeline_id;
|
| - send_request->request_line = request_line;
|
| - send_request->headers = headers;
|
| - send_request->response = response;
|
| - send_request->callback = callback;
|
| - pending_send_request_queue_.push(send_request);
|
| -
|
| - int rv;
|
| - if (send_next_state_ == SEND_STATE_NONE) {
|
| - send_next_state_ = SEND_STATE_START_IMMEDIATELY;
|
| - rv = DoSendRequestLoop(OK);
|
| - } else {
|
| - rv = ERR_IO_PENDING;
|
| - }
|
| - ActivatePipeline();
|
| - return rv;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoSendRequestLoop(int result) {
|
| - int rv = result;
|
| - do {
|
| - SendRequestState state = send_next_state_;
|
| - send_next_state_ = SEND_STATE_NONE;
|
| - switch (state) {
|
| - case SEND_STATE_START_IMMEDIATELY:
|
| - rv = DoStartRequestImmediately(rv);
|
| - break;
|
| - case SEND_STATE_START_NEXT_DEFERRED_REQUEST:
|
| - rv = DoStartNextDeferredRequest(rv);
|
| - break;
|
| - case SEND_STATE_SEND_ACTIVE_REQUEST:
|
| - rv = DoSendActiveRequest(rv);
|
| - break;
|
| - case SEND_STATE_COMPLETE:
|
| - rv = DoSendComplete(rv);
|
| - break;
|
| - case SEND_STATE_EVICT_PENDING_REQUESTS:
|
| - rv = DoEvictPendingSendRequests(rv);
|
| - break;
|
| - default:
|
| - CHECK(false) << "bad send state: " << state;
|
| - rv = ERR_FAILED;
|
| - break;
|
| - }
|
| - } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE);
|
| - send_still_on_call_stack_ = false;
|
| - return rv;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) {
|
| - CHECK(active_send_request_.get());
|
| - DoSendRequestLoop(result);
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoStartRequestImmediately(int result) {
|
| - CHECK(!active_send_request_.get());
|
| - CHECK_EQ(static_cast<size_t>(1), pending_send_request_queue_.size());
|
| - // If SendRequest() completes synchronously, then we need to return the value
|
| - // directly to the caller. |send_still_on_call_stack_| will track this.
|
| - // Otherwise, asynchronous completions will notify the caller via callback.
|
| - send_still_on_call_stack_ = true;
|
| - active_send_request_.reset(pending_send_request_queue_.front());
|
| - pending_send_request_queue_.pop();
|
| - send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST;
|
| - return OK;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoStartNextDeferredRequest(int result) {
|
| - CHECK(!send_still_on_call_stack_);
|
| - CHECK(!active_send_request_.get());
|
| -
|
| - while (!pending_send_request_queue_.empty()) {
|
| - scoped_ptr<PendingSendRequest> next_request(
|
| - pending_send_request_queue_.front());
|
| - pending_send_request_queue_.pop();
|
| - CHECK(ContainsKey(stream_info_map_, next_request->pipeline_id));
|
| - if (stream_info_map_[next_request->pipeline_id].state != STREAM_CLOSED) {
|
| - active_send_request_.reset(next_request.release());
|
| - send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST;
|
| - return OK;
|
| - }
|
| - }
|
| -
|
| - send_next_state_ = SEND_STATE_NONE;
|
| - return OK;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoSendActiveRequest(int result) {
|
| - CHECK(stream_info_map_[active_send_request_->pipeline_id].parser.get());
|
| - int rv = stream_info_map_[active_send_request_->pipeline_id].parser->
|
| - SendRequest(active_send_request_->request_line,
|
| - active_send_request_->headers,
|
| - active_send_request_->response,
|
| - base::Bind(&HttpPipelinedConnectionImpl::OnSendIOCallback,
|
| - base::Unretained(this)));
|
| - stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENDING;
|
| - send_next_state_ = SEND_STATE_COMPLETE;
|
| - return rv;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoSendComplete(int result) {
|
| - CHECK(active_send_request_.get());
|
| - CHECK_EQ(STREAM_SENDING,
|
| - stream_info_map_[active_send_request_->pipeline_id].state);
|
| -
|
| - request_order_.push(active_send_request_->pipeline_id);
|
| - stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENT;
|
| - net_log_.AddEvent(
|
| - NetLog::TYPE_HTTP_PIPELINED_CONNECTION_SENT_REQUEST,
|
| - stream_info_map_[active_send_request_->pipeline_id].source.
|
| - ToEventParametersCallback());
|
| -
|
| - if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) {
|
| - result = ERR_PIPELINE_EVICTION;
|
| - }
|
| - if (result < OK) {
|
| - usable_ = false;
|
| - }
|
| -
|
| - if (!send_still_on_call_stack_) {
|
| - QueueUserCallback(active_send_request_->pipeline_id,
|
| - active_send_request_->callback, result, FROM_HERE);
|
| - }
|
| -
|
| - active_send_request_.reset();
|
| -
|
| - if (send_still_on_call_stack_) {
|
| - // It should be impossible for another request to appear on the queue while
|
| - // this send was on the call stack.
|
| - CHECK(pending_send_request_queue_.empty());
|
| - send_next_state_ = SEND_STATE_NONE;
|
| - } else if (!usable_) {
|
| - send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS;
|
| - } else {
|
| - send_next_state_ = SEND_STATE_START_NEXT_DEFERRED_REQUEST;
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoEvictPendingSendRequests(int result) {
|
| - while (!pending_send_request_queue_.empty()) {
|
| - scoped_ptr<PendingSendRequest> evicted_send(
|
| - pending_send_request_queue_.front());
|
| - pending_send_request_queue_.pop();
|
| - if (ContainsKey(stream_info_map_, evicted_send->pipeline_id) &&
|
| - stream_info_map_[evicted_send->pipeline_id].state != STREAM_CLOSED) {
|
| - evicted_send->callback.Run(ERR_PIPELINE_EVICTION);
|
| - }
|
| - }
|
| - send_next_state_ = SEND_STATE_NONE;
|
| - return result;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::ReadResponseHeaders(
|
| - int pipeline_id, const CompletionCallback& callback) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK_EQ(STREAM_SENT, stream_info_map_[pipeline_id].state);
|
| - CHECK(stream_info_map_[pipeline_id].read_headers_callback.is_null());
|
| -
|
| - if (!usable_)
|
| - return ERR_PIPELINE_EVICTION;
|
| -
|
| - stream_info_map_[pipeline_id].state = STREAM_READ_PENDING;
|
| - stream_info_map_[pipeline_id].read_headers_callback = callback;
|
| - if (read_next_state_ == READ_STATE_NONE &&
|
| - pipeline_id == request_order_.front()) {
|
| - read_next_state_ = READ_STATE_START_IMMEDIATELY;
|
| - return DoReadHeadersLoop(OK);
|
| - }
|
| - return ERR_IO_PENDING;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::StartNextDeferredRead() {
|
| - if (read_next_state_ == READ_STATE_NONE) {
|
| - read_next_state_ = READ_STATE_START_NEXT_DEFERRED_READ;
|
| - DoReadHeadersLoop(OK);
|
| - }
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoReadHeadersLoop(int result) {
|
| - int rv = result;
|
| - do {
|
| - ReadHeadersState state = read_next_state_;
|
| - read_next_state_ = READ_STATE_NONE;
|
| - switch (state) {
|
| - case READ_STATE_START_IMMEDIATELY:
|
| - rv = DoStartReadImmediately(rv);
|
| - break;
|
| - case READ_STATE_START_NEXT_DEFERRED_READ:
|
| - rv = DoStartNextDeferredRead(rv);
|
| - break;
|
| - case READ_STATE_READ_HEADERS:
|
| - rv = DoReadHeaders(rv);
|
| - break;
|
| - case READ_STATE_READ_HEADERS_COMPLETE:
|
| - rv = DoReadHeadersComplete(rv);
|
| - break;
|
| - case READ_STATE_WAITING_FOR_CLOSE:
|
| - // This is a holding state. We return instead of continuing to run hte
|
| - // loop. The state will advance when the stream calls Close().
|
| - rv = DoReadWaitForClose(rv);
|
| - read_still_on_call_stack_ = false;
|
| - return rv;
|
| - case READ_STATE_STREAM_CLOSED:
|
| - rv = DoReadStreamClosed();
|
| - break;
|
| - case READ_STATE_EVICT_PENDING_READS:
|
| - rv = DoEvictPendingReadHeaders(rv);
|
| - break;
|
| - case READ_STATE_NONE:
|
| - break;
|
| - default:
|
| - CHECK(false) << "bad read state";
|
| - rv = ERR_FAILED;
|
| - break;
|
| - }
|
| - } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE);
|
| - read_still_on_call_stack_ = false;
|
| - return rv;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) {
|
| - DoReadHeadersLoop(result);
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoStartReadImmediately(int result) {
|
| - CHECK(!active_read_id_);
|
| - CHECK(!read_still_on_call_stack_);
|
| - CHECK(!request_order_.empty());
|
| - // If ReadResponseHeaders() completes synchronously, then we need to return
|
| - // the value directly to the caller. |read_still_on_call_stack_| will track
|
| - // this. Otherwise, asynchronous completions will notify the caller via
|
| - // callback.
|
| - read_still_on_call_stack_ = true;
|
| - read_next_state_ = READ_STATE_READ_HEADERS;
|
| - active_read_id_ = request_order_.front();
|
| - request_order_.pop();
|
| - return OK;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoStartNextDeferredRead(int result) {
|
| - CHECK(!active_read_id_);
|
| - CHECK(!read_still_on_call_stack_);
|
| -
|
| - if (request_order_.empty()) {
|
| - read_next_state_ = READ_STATE_NONE;
|
| - return OK;
|
| - }
|
| -
|
| - int next_id = request_order_.front();
|
| - CHECK(ContainsKey(stream_info_map_, next_id));
|
| - switch (stream_info_map_[next_id].state) {
|
| - case STREAM_READ_PENDING:
|
| - read_next_state_ = READ_STATE_READ_HEADERS;
|
| - active_read_id_ = next_id;
|
| - request_order_.pop();
|
| - break;
|
| -
|
| - case STREAM_CLOSED:
|
| - // Since nobody will read whatever data is on the pipeline associated with
|
| - // this closed request, we must shut down the rest of the pipeline.
|
| - read_next_state_ = READ_STATE_EVICT_PENDING_READS;
|
| - break;
|
| -
|
| - case STREAM_SENT:
|
| - read_next_state_ = READ_STATE_NONE;
|
| - break;
|
| -
|
| - default:
|
| - CHECK(false) << "Unexpected read state: "
|
| - << stream_info_map_[next_id].state;
|
| - }
|
| -
|
| - return OK;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoReadHeaders(int result) {
|
| - CHECK(active_read_id_);
|
| - CHECK(ContainsKey(stream_info_map_, active_read_id_));
|
| - CHECK_EQ(STREAM_READ_PENDING, stream_info_map_[active_read_id_].state);
|
| - stream_info_map_[active_read_id_].state = STREAM_ACTIVE;
|
| - int rv = stream_info_map_[active_read_id_].parser->ReadResponseHeaders(
|
| - base::Bind(&HttpPipelinedConnectionImpl::OnReadIOCallback,
|
| - base::Unretained(this)));
|
| - read_next_state_ = READ_STATE_READ_HEADERS_COMPLETE;
|
| - return rv;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoReadHeadersComplete(int result) {
|
| - CHECK(active_read_id_);
|
| - CHECK(ContainsKey(stream_info_map_, active_read_id_));
|
| - CHECK_EQ(STREAM_ACTIVE, stream_info_map_[active_read_id_].state);
|
| -
|
| - read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
|
| - if (result < OK) {
|
| - if (completed_one_request_ &&
|
| - (result == ERR_CONNECTION_CLOSED ||
|
| - result == ERR_EMPTY_RESPONSE ||
|
| - result == ERR_SOCKET_NOT_CONNECTED)) {
|
| - // These usually indicate that pipelining failed on the server side. In
|
| - // that case, we should retry without pipelining.
|
| - result = ERR_PIPELINE_EVICTION;
|
| - }
|
| - usable_ = false;
|
| - }
|
| -
|
| - CheckHeadersForPipelineCompatibility(active_read_id_, result);
|
| -
|
| - if (!read_still_on_call_stack_) {
|
| - QueueUserCallback(active_read_id_,
|
| - stream_info_map_[active_read_id_].read_headers_callback,
|
| - result, FROM_HERE);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoReadWaitForClose(int result) {
|
| - read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
|
| - return result;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoReadStreamClosed() {
|
| - CHECK(active_read_id_);
|
| - CHECK(ContainsKey(stream_info_map_, active_read_id_));
|
| - CHECK_EQ(stream_info_map_[active_read_id_].state, STREAM_CLOSED);
|
| - active_read_id_ = 0;
|
| - if (!usable_) {
|
| - // TODO(simonjam): Don't wait this long to evict.
|
| - read_next_state_ = READ_STATE_EVICT_PENDING_READS;
|
| - return OK;
|
| - }
|
| - completed_one_request_ = true;
|
| - base::MessageLoop::current()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&HttpPipelinedConnectionImpl::StartNextDeferredRead,
|
| - weak_factory_.GetWeakPtr()));
|
| - read_next_state_ = READ_STATE_NONE;
|
| - return OK;
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::DoEvictPendingReadHeaders(int result) {
|
| - while (!request_order_.empty()) {
|
| - int evicted_id = request_order_.front();
|
| - request_order_.pop();
|
| - if (!ContainsKey(stream_info_map_, evicted_id)) {
|
| - continue;
|
| - }
|
| - if (stream_info_map_[evicted_id].state == STREAM_READ_PENDING) {
|
| - stream_info_map_[evicted_id].state = STREAM_READ_EVICTED;
|
| - stream_info_map_[evicted_id].read_headers_callback.Run(
|
| - ERR_PIPELINE_EVICTION);
|
| - }
|
| - }
|
| - read_next_state_ = READ_STATE_NONE;
|
| - return result;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::Close(int pipeline_id,
|
| - bool not_reusable) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - net_log_.AddEvent(
|
| - NetLog::TYPE_HTTP_PIPELINED_CONNECTION_STREAM_CLOSED,
|
| - base::Bind(&NetLogStreamClosedCallback,
|
| - stream_info_map_[pipeline_id].source, not_reusable));
|
| - switch (stream_info_map_[pipeline_id].state) {
|
| - case STREAM_CREATED:
|
| - stream_info_map_[pipeline_id].state = STREAM_UNUSED;
|
| - break;
|
| -
|
| - case STREAM_BOUND:
|
| - stream_info_map_[pipeline_id].state = STREAM_CLOSED;
|
| - break;
|
| -
|
| - case STREAM_SENDING:
|
| - usable_ = false;
|
| - stream_info_map_[pipeline_id].state = STREAM_CLOSED;
|
| - active_send_request_.reset();
|
| - send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS;
|
| - DoSendRequestLoop(OK);
|
| - break;
|
| -
|
| - case STREAM_SENT:
|
| - case STREAM_READ_PENDING:
|
| - usable_ = false;
|
| - stream_info_map_[pipeline_id].state = STREAM_CLOSED;
|
| - if (!request_order_.empty() &&
|
| - pipeline_id == request_order_.front() &&
|
| - read_next_state_ == READ_STATE_NONE) {
|
| - read_next_state_ = READ_STATE_EVICT_PENDING_READS;
|
| - DoReadHeadersLoop(OK);
|
| - }
|
| - break;
|
| -
|
| - case STREAM_ACTIVE:
|
| - stream_info_map_[pipeline_id].state = STREAM_CLOSED;
|
| - if (not_reusable) {
|
| - usable_ = false;
|
| - }
|
| - read_next_state_ = READ_STATE_STREAM_CLOSED;
|
| - DoReadHeadersLoop(OK);
|
| - break;
|
| -
|
| - case STREAM_READ_EVICTED:
|
| - stream_info_map_[pipeline_id].state = STREAM_CLOSED;
|
| - break;
|
| -
|
| - case STREAM_CLOSED:
|
| - case STREAM_UNUSED:
|
| - // TODO(simonjam): Why is Close() sometimes called twice?
|
| - break;
|
| -
|
| - default:
|
| - CHECK(false);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::ReadResponseBody(
|
| - int pipeline_id, IOBuffer* buf, int buf_len,
|
| - const CompletionCallback& callback) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK_EQ(active_read_id_, pipeline_id);
|
| - CHECK(stream_info_map_[pipeline_id].parser.get());
|
| - return stream_info_map_[pipeline_id].parser->ReadResponseBody(
|
| - buf, buf_len, callback);
|
| -}
|
| -
|
| -UploadProgress HttpPipelinedConnectionImpl::GetUploadProgress(
|
| - int pipeline_id) const {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
|
| - return stream_info_map_.find(pipeline_id)->second.parser->GetUploadProgress();
|
| -}
|
| -
|
| -HttpResponseInfo* HttpPipelinedConnectionImpl::GetResponseInfo(
|
| - int pipeline_id) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
|
| - return stream_info_map_.find(pipeline_id)->second.parser->GetResponseInfo();
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::IsResponseBodyComplete(
|
| - int pipeline_id) const {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
|
| - return stream_info_map_.find(pipeline_id)->second.parser->
|
| - IsResponseBodyComplete();
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::CanFindEndOfResponse(int pipeline_id) const {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
|
| - return stream_info_map_.find(pipeline_id)->second.parser->
|
| - CanFindEndOfResponse();
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::IsConnectionReused(int pipeline_id) const {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - if (pipeline_id > 1) {
|
| - return true;
|
| - }
|
| - ClientSocketHandle::SocketReuseType reuse_type = connection_->reuse_type();
|
| - return connection_->is_reused() ||
|
| - reuse_type == ClientSocketHandle::UNUSED_IDLE;
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::SetConnectionReused(int pipeline_id) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - connection_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
|
| -}
|
| -
|
| -int64 HttpPipelinedConnectionImpl::GetTotalReceivedBytes(
|
| - int pipeline_id) const {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - if (stream_info_map_.find(pipeline_id)->second.parser.get())
|
| - return stream_info_map_.find(pipeline_id)->second.parser->received_bytes();
|
| - return 0;
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::GetLoadTimingInfo(
|
| - int pipeline_id, LoadTimingInfo* load_timing_info) const {
|
| - return connection_->GetLoadTimingInfo(IsConnectionReused(pipeline_id),
|
| - load_timing_info);
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::GetSSLInfo(int pipeline_id,
|
| - SSLInfo* ssl_info) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_[pipeline_id].parser.get());
|
| - stream_info_map_[pipeline_id].parser->GetSSLInfo(ssl_info);
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::GetSSLCertRequestInfo(
|
| - int pipeline_id,
|
| - SSLCertRequestInfo* cert_request_info) {
|
| - CHECK(ContainsKey(stream_info_map_, pipeline_id));
|
| - CHECK(stream_info_map_[pipeline_id].parser.get());
|
| - stream_info_map_[pipeline_id].parser->GetSSLCertRequestInfo(
|
| - cert_request_info);
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::Drain(HttpPipelinedStream* stream,
|
| - HttpNetworkSession* session) {
|
| - HttpResponseHeaders* headers = stream->GetResponseInfo()->headers.get();
|
| - if (!stream->CanFindEndOfResponse() || headers->IsChunkEncoded() ||
|
| - !usable_) {
|
| - // TODO(simonjam): Drain chunk-encoded responses if they're relatively
|
| - // common.
|
| - stream->Close(true);
|
| - delete stream;
|
| - return;
|
| - }
|
| - HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(stream);
|
| - drainer->StartWithSize(session, headers->GetContentLength());
|
| - // |drainer| will delete itself when done.
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::CheckHeadersForPipelineCompatibility(
|
| - int pipeline_id,
|
| - int result) {
|
| - if (result < OK) {
|
| - switch (result) {
|
| - // TODO(simonjam): Ignoring specific errors like this may not work.
|
| - // Collect metrics to see if this code is useful.
|
| - case ERR_ABORTED:
|
| - case ERR_INTERNET_DISCONNECTED:
|
| - case ERR_NETWORK_CHANGED:
|
| - // These errors are no fault of the server.
|
| - break;
|
| -
|
| - default:
|
| - ReportPipelineFeedback(pipeline_id, PIPELINE_SOCKET_ERROR);
|
| - break;
|
| - }
|
| - return;
|
| - }
|
| - HttpResponseInfo* info = GetResponseInfo(pipeline_id);
|
| - const HttpVersion required_version(1, 1);
|
| - if (info->headers->GetParsedHttpVersion() < required_version) {
|
| - ReportPipelineFeedback(pipeline_id, OLD_HTTP_VERSION);
|
| - return;
|
| - }
|
| - if (!info->headers->IsKeepAlive() || !CanFindEndOfResponse(pipeline_id)) {
|
| - usable_ = false;
|
| - ReportPipelineFeedback(pipeline_id, MUST_CLOSE_CONNECTION);
|
| - return;
|
| - }
|
| - if (info->headers->HasHeader(
|
| - HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_SERVER))) {
|
| - ReportPipelineFeedback(pipeline_id, AUTHENTICATION_REQUIRED);
|
| - return;
|
| - }
|
| - ReportPipelineFeedback(pipeline_id, OK);
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::ReportPipelineFeedback(int pipeline_id,
|
| - Feedback feedback) {
|
| - std::string feedback_str;
|
| - switch (feedback) {
|
| - case OK:
|
| - feedback_str = "OK";
|
| - break;
|
| -
|
| - case PIPELINE_SOCKET_ERROR:
|
| - feedback_str = "PIPELINE_SOCKET_ERROR";
|
| - break;
|
| -
|
| - case OLD_HTTP_VERSION:
|
| - feedback_str = "OLD_HTTP_VERSION";
|
| - break;
|
| -
|
| - case MUST_CLOSE_CONNECTION:
|
| - feedback_str = "MUST_CLOSE_CONNECTION";
|
| - break;
|
| -
|
| - case AUTHENTICATION_REQUIRED:
|
| - feedback_str = "AUTHENTICATION_REQUIRED";
|
| - break;
|
| -
|
| - default:
|
| - NOTREACHED();
|
| - feedback_str = "UNKNOWN";
|
| - break;
|
| - }
|
| - net_log_.AddEvent(
|
| - NetLog::TYPE_HTTP_PIPELINED_CONNECTION_RECEIVED_HEADERS,
|
| - base::Bind(&NetLogReceivedHeadersCallback,
|
| - stream_info_map_[pipeline_id].source, &feedback_str));
|
| - delegate_->OnPipelineFeedback(this, feedback);
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::QueueUserCallback(
|
| - int pipeline_id, const CompletionCallback& callback, int rv,
|
| - const tracked_objects::Location& from_here) {
|
| - CHECK(stream_info_map_[pipeline_id].pending_user_callback.is_null());
|
| - stream_info_map_[pipeline_id].pending_user_callback = callback;
|
| - base::MessageLoop::current()->PostTask(
|
| - from_here,
|
| - base::Bind(&HttpPipelinedConnectionImpl::FireUserCallback,
|
| - weak_factory_.GetWeakPtr(), pipeline_id, rv));
|
| -}
|
| -
|
| -void HttpPipelinedConnectionImpl::FireUserCallback(int pipeline_id,
|
| - int result) {
|
| - if (ContainsKey(stream_info_map_, pipeline_id)) {
|
| - CHECK(!stream_info_map_[pipeline_id].pending_user_callback.is_null());
|
| - CompletionCallback callback =
|
| - stream_info_map_[pipeline_id].pending_user_callback;
|
| - stream_info_map_[pipeline_id].pending_user_callback.Reset();
|
| - callback.Run(result);
|
| - }
|
| -}
|
| -
|
| -int HttpPipelinedConnectionImpl::depth() const {
|
| - return stream_info_map_.size();
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::usable() const {
|
| - return usable_;
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::active() const {
|
| - return active_;
|
| -}
|
| -
|
| -const SSLConfig& HttpPipelinedConnectionImpl::used_ssl_config() const {
|
| - return used_ssl_config_;
|
| -}
|
| -
|
| -const ProxyInfo& HttpPipelinedConnectionImpl::used_proxy_info() const {
|
| - return used_proxy_info_;
|
| -}
|
| -
|
| -const BoundNetLog& HttpPipelinedConnectionImpl::net_log() const {
|
| - return net_log_;
|
| -}
|
| -
|
| -bool HttpPipelinedConnectionImpl::was_npn_negotiated() const {
|
| - return was_npn_negotiated_;
|
| -}
|
| -
|
| -NextProto HttpPipelinedConnectionImpl::protocol_negotiated()
|
| - const {
|
| - return protocol_negotiated_;
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::PendingSendRequest::PendingSendRequest()
|
| - : pipeline_id(0),
|
| - response(NULL) {
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::PendingSendRequest::~PendingSendRequest() {
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::StreamInfo::StreamInfo()
|
| - : state(STREAM_CREATED) {
|
| -}
|
| -
|
| -HttpPipelinedConnectionImpl::StreamInfo::~StreamInfo() {
|
| -}
|
| -
|
| -} // namespace net
|
|
|