| 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 | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..33f2ef62baabfdc8ffc4f946e7d20f6f5b7fcccc | 
| --- /dev/null | 
| +++ b/net/http/http_pipelined_connection_impl.cc | 
| @@ -0,0 +1,612 @@ | 
| +// Copyright (c) 2011 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/message_loop.h" | 
| +#include "base/stl_util.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_stream_parser.h" | 
| +#include "net/socket/client_socket_handle.h" | 
| + | 
| +namespace net { | 
| + | 
| +HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl( | 
| +    ClientSocketHandle* connection, | 
| +    HttpPipelinedConnection::Delegate* delegate, | 
| +    const SSLConfig& used_ssl_config, | 
| +    const ProxyInfo& used_proxy_info, | 
| +    const BoundNetLog& net_log, | 
| +    bool was_npn_negotiated) | 
| +    : delegate_(delegate), | 
| +      connection_(connection), | 
| +      used_ssl_config_(used_ssl_config), | 
| +      used_proxy_info_(used_proxy_info), | 
| +      net_log_(net_log), | 
| +      was_npn_negotiated_(was_npn_negotiated), | 
| +      read_buf_(new GrowableIOBuffer()), | 
| +      next_pipeline_id_(1), | 
| +      active_(false), | 
| +      usable_(true), | 
| +      completed_one_request_(false), | 
| +      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), | 
| +      send_next_state_(SEND_STATE_NONE), | 
| +      ALLOW_THIS_IN_INITIALIZER_LIST(send_io_callback_( | 
| +          this, &HttpPipelinedConnectionImpl::OnSendIOCallback)), | 
| +      send_user_callback_(NULL), | 
| +      read_next_state_(READ_STATE_NONE), | 
| +      ALLOW_THIS_IN_INITIALIZER_LIST(read_io_callback_( | 
| +          this, &HttpPipelinedConnectionImpl::OnReadIOCallback)), | 
| +      read_user_callback_(NULL) { | 
| +  CHECK(connection_.get()); | 
| +} | 
| + | 
| +HttpPipelinedConnectionImpl::~HttpPipelinedConnectionImpl() { | 
| +  CHECK_EQ(depth(), 0); | 
| +  CHECK(stream_info_map_.empty()); | 
| +  CHECK(deferred_request_queue_.empty()); | 
| +  CHECK(request_order_.empty()); | 
| +  CHECK_EQ(send_next_state_, SEND_STATE_NONE); | 
| +  CHECK_EQ(read_next_state_, READ_STATE_NONE); | 
| +  CHECK(!send_user_callback_); | 
| +  CHECK(!read_user_callback_); | 
| +  if (!usable_) { | 
| +    connection_->socket()->Disconnect(); | 
| +  } | 
| +  connection_->Reset(); | 
| +} | 
| + | 
| +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)); | 
| + | 
| +  // In case our first stream doesn't SendRequest() immediately, we should still | 
| +  // allow others to use this pipeline. | 
| +  if (pipeline_id == 1) { | 
| +    MessageLoop::current()->PostTask( | 
| +        FROM_HERE, | 
| +        method_factory_.NewRunnableMethod( | 
| +            &HttpPipelinedConnectionImpl::ActivatePipeline)); | 
| +  } | 
| +} | 
| + | 
| +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()); | 
| +  CHECK(!stream_info_map_[pipeline_id].read_headers_callback); | 
| +  stream_info_map_.erase(pipeline_id); | 
| + | 
| +  delegate_->OnPipelineHasCapacity(this); | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::SendRequest(int pipeline_id, | 
| +                                             const std::string& request_line, | 
| +                                             const HttpRequestHeaders& headers, | 
| +                                             UploadDataStream* request_body, | 
| +                                             HttpResponseInfo* response, | 
| +                                             OldCompletionCallback* callback) { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_BOUND); | 
| +  if (!usable_) { | 
| +    return ERR_PIPELINE_EVICTION; | 
| +  } | 
| + | 
| +  DeferredSendRequest deferred_request; | 
| +  deferred_request.pipeline_id = pipeline_id; | 
| +  deferred_request.request_line = request_line; | 
| +  deferred_request.headers = headers; | 
| +  deferred_request.request_body = request_body; | 
| +  deferred_request.response = response; | 
| +  deferred_request.callback = callback; | 
| +  deferred_request_queue_.push(deferred_request); | 
| + | 
| +  int rv; | 
| +  if (send_next_state_ == SEND_STATE_NONE) { | 
| +    send_next_state_ = SEND_STATE_NEXT_REQUEST; | 
| +    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_NEXT_REQUEST: | 
| +        rv = DoSendNextRequest(rv); | 
| +        break; | 
| +      case SEND_STATE_COMPLETE: | 
| +        rv = DoSendComplete(rv); | 
| +        break; | 
| +      case SEND_STATE_UNUSABLE: | 
| +        rv = DoEvictPendingSendRequests(rv); | 
| +        break; | 
| +      default: | 
| +        NOTREACHED() << "bad send state: " << state; | 
| +        rv = ERR_FAILED; | 
| +        break; | 
| +    } | 
| +  } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE); | 
| +  return rv; | 
| +} | 
| + | 
| +void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) { | 
| +  CHECK(send_user_callback_); | 
| +  DoSendRequestLoop(result); | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoSendNextRequest(int result) { | 
| +  CHECK(!deferred_request_queue_.empty()); | 
| +  const DeferredSendRequest& deferred_request = deferred_request_queue_.front(); | 
| +  CHECK(ContainsKey(stream_info_map_, deferred_request.pipeline_id)); | 
| +  if (stream_info_map_[deferred_request.pipeline_id].state == STREAM_CLOSED) { | 
| +    deferred_request_queue_.pop(); | 
| +    if (deferred_request_queue_.empty()) { | 
| +      send_next_state_ = SEND_STATE_NONE; | 
| +    } else { | 
| +      send_next_state_ = SEND_STATE_NEXT_REQUEST; | 
| +    } | 
| +    return OK; | 
| +  } | 
| +  CHECK(stream_info_map_[deferred_request.pipeline_id].parser.get()); | 
| +  int rv = stream_info_map_[deferred_request.pipeline_id].parser->SendRequest( | 
| +      deferred_request.request_line, | 
| +      deferred_request.headers, | 
| +      deferred_request.request_body, | 
| +      deferred_request.response, | 
| +      &send_io_callback_); | 
| +  // |result| == ERR_IO_PENDING means this function was *not* called on the same | 
| +  // stack as SendRequest(). That means we returned ERR_IO_PENDING to | 
| +  // SendRequest() earlier and will need to invoke its callback. | 
| +  if (result == ERR_IO_PENDING || rv == ERR_IO_PENDING) { | 
| +    send_user_callback_ = deferred_request.callback; | 
| +  } | 
| +  stream_info_map_[deferred_request.pipeline_id].state = STREAM_SENDING; | 
| +  send_next_state_ = SEND_STATE_COMPLETE; | 
| +  return rv; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoSendComplete(int result) { | 
| +  CHECK(!deferred_request_queue_.empty()); | 
| +  const DeferredSendRequest& deferred_request = deferred_request_queue_.front(); | 
| +  CHECK_EQ(stream_info_map_[deferred_request.pipeline_id].state, | 
| +           STREAM_SENDING); | 
| +  request_order_.push(deferred_request.pipeline_id); | 
| +  stream_info_map_[deferred_request.pipeline_id].state = STREAM_SENT; | 
| +  deferred_request_queue_.pop(); | 
| +  if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) { | 
| +    result = ERR_PIPELINE_EVICTION; | 
| +  } | 
| +  if (result < OK) { | 
| +    send_next_state_ = SEND_STATE_UNUSABLE; | 
| +    usable_ = false; | 
| +  } | 
| +  if (send_user_callback_) { | 
| +    MessageLoop::current()->PostTask( | 
| +        FROM_HERE, | 
| +        method_factory_.NewRunnableMethod( | 
| +            &HttpPipelinedConnectionImpl::FireUserCallback, | 
| +            send_user_callback_, | 
| +            result)); | 
| +    send_user_callback_ = NULL; | 
| +  } | 
| +  if (result < OK) { | 
| +    return result; | 
| +  } | 
| +  if (deferred_request_queue_.empty()) { | 
| +    send_next_state_ = SEND_STATE_NONE; | 
| +    return OK; | 
| +  } | 
| +  send_next_state_ = SEND_STATE_NEXT_REQUEST; | 
| +  return OK; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoEvictPendingSendRequests(int result) { | 
| +  send_next_state_ = SEND_STATE_NONE; | 
| +  while (!deferred_request_queue_.empty()) { | 
| +    const DeferredSendRequest& evicted_send = deferred_request_queue_.front(); | 
| +    if (stream_info_map_[evicted_send.pipeline_id].state != STREAM_CLOSED) { | 
| +      evicted_send.callback->Run(ERR_PIPELINE_EVICTION); | 
| +    } | 
| +    deferred_request_queue_.pop(); | 
| +  } | 
| +  return result; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::ReadResponseHeaders( | 
| +    int pipeline_id, | 
| +    OldCompletionCallback* callback) { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_SENT); | 
| +  CHECK(!stream_info_map_[pipeline_id].read_headers_callback); | 
| +  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) { | 
| +    read_next_state_ = READ_STATE_NEXT_HEADERS; | 
| +    return DoReadHeadersLoop(OK); | 
| +  } else { | 
| +    return ERR_IO_PENDING; | 
| +  } | 
| +} | 
| + | 
| +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_NEXT_HEADERS: | 
| +        rv = DoReadNextHeaders(rv); | 
| +        break; | 
| +      case READ_STATE_COMPLETE: | 
| +        rv = DoReadHeadersComplete(rv); | 
| +        break; | 
| +      case READ_STATE_WAITING_FOR_CLOSE: | 
| +        rv = DoReadWaitingForClose(rv); | 
| +        return rv; | 
| +      case READ_STATE_STREAM_CLOSED: | 
| +        rv = DoReadStreamClosed(); | 
| +        break; | 
| +      case READ_STATE_UNUSABLE: | 
| +        rv = DoEvictPendingReadHeaders(rv); | 
| +        break; | 
| +      case READ_STATE_NONE: | 
| +        break; | 
| +      default: | 
| +        NOTREACHED() << "bad read state"; | 
| +        rv = ERR_FAILED; | 
| +        break; | 
| +    } | 
| +  } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE); | 
| +  return rv; | 
| +} | 
| + | 
| +void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) { | 
| +  CHECK(read_user_callback_); | 
| +  DoReadHeadersLoop(result); | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoReadNextHeaders(int result) { | 
| +  CHECK(!request_order_.empty()); | 
| +  int pipeline_id = request_order_.front(); | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  if (stream_info_map_[pipeline_id].state == 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_UNUSABLE; | 
| +    return OK; | 
| +  } | 
| +  if (stream_info_map_[pipeline_id].read_headers_callback == NULL) { | 
| +    return ERR_IO_PENDING; | 
| +  } | 
| +  CHECK(stream_info_map_[pipeline_id].parser.get()); | 
| + | 
| +  if (result == ERR_IO_PENDING) { | 
| +    CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_ACTIVE); | 
| +  } else { | 
| +    CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_READ_PENDING); | 
| +    stream_info_map_[pipeline_id].state = STREAM_ACTIVE; | 
| +  } | 
| + | 
| +  int rv = stream_info_map_[pipeline_id].parser->ReadResponseHeaders( | 
| +      &read_io_callback_); | 
| +  if (rv == ERR_IO_PENDING) { | 
| +    read_next_state_ = READ_STATE_COMPLETE; | 
| +    read_user_callback_ = stream_info_map_[pipeline_id].read_headers_callback; | 
| +  } else if (rv < OK) { | 
| +    read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 
| +    if (rv == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) | 
| +      rv = ERR_PIPELINE_EVICTION; | 
| +  } else { | 
| +    CHECK_LE(OK, rv); | 
| +    read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 
| +  } | 
| + | 
| +  // |result| == ERR_IO_PENDING means this function was *not* called on the same | 
| +  // stack as ReadResponseHeaders(). That means we returned ERR_IO_PENDING to | 
| +  // ReadResponseHeaders() earlier and now need to invoke its callback. | 
| +  if (rv != ERR_IO_PENDING && result == ERR_IO_PENDING) { | 
| +    read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 
| +    read_user_callback_ = stream_info_map_[pipeline_id].read_headers_callback; | 
| +    MessageLoop::current()->PostTask( | 
| +        FROM_HERE, | 
| +        method_factory_.NewRunnableMethod( | 
| +            &HttpPipelinedConnectionImpl::FireUserCallback, | 
| +            read_user_callback_, | 
| +            rv)); | 
| +  } | 
| +  return rv; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoReadHeadersComplete(int result) { | 
| +  read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 
| +  if (read_user_callback_) { | 
| +    MessageLoop::current()->PostTask( | 
| +        FROM_HERE, | 
| +        method_factory_.NewRunnableMethod( | 
| +            &HttpPipelinedConnectionImpl::FireUserCallback, | 
| +            read_user_callback_, | 
| +            result)); | 
| +    read_user_callback_ = NULL; | 
| +  } | 
| +  return result; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoReadWaitingForClose(int result) { | 
| +  read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; | 
| +  return result; | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::DoReadStreamClosed() { | 
| +  CHECK(!request_order_.empty()); | 
| +  int pipeline_id = request_order_.front(); | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_CLOSED); | 
| +  CHECK(stream_info_map_[pipeline_id].read_headers_callback); | 
| +  stream_info_map_[pipeline_id].read_headers_callback = NULL; | 
| +  request_order_.pop(); | 
| +  if (!usable_) { | 
| +    read_next_state_ = READ_STATE_UNUSABLE; | 
| +    return OK; | 
| +  } else { | 
| +    completed_one_request_ = true; | 
| +    if (!request_order_.empty()) { | 
| +      int next_pipeline_id = request_order_.front(); | 
| +      CHECK(ContainsKey(stream_info_map_, next_pipeline_id)); | 
| +      if (stream_info_map_[next_pipeline_id].read_headers_callback) { | 
| +        stream_info_map_[next_pipeline_id].state = STREAM_ACTIVE; | 
| +        read_next_state_ = READ_STATE_NEXT_HEADERS; | 
| +        MessageLoop::current()->PostTask( | 
| +            FROM_HERE, | 
| +            method_factory_.NewRunnableMethod( | 
| +                &HttpPipelinedConnectionImpl::DoReadHeadersLoop, | 
| +                ERR_IO_PENDING)); | 
| +        return ERR_IO_PENDING;  // Wait for the task to fire. | 
| +      } | 
| +    } | 
| +    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) || | 
| +        (stream_info_map_[evicted_id].read_headers_callback == NULL)) { | 
| +      continue; | 
| +    } | 
| +    if (stream_info_map_[evicted_id].state != STREAM_CLOSED) { | 
| +      MessageLoop::current()->PostTask( | 
| +          FROM_HERE, | 
| +          method_factory_.NewRunnableMethod( | 
| +              &HttpPipelinedConnectionImpl::FireUserCallback, | 
| +              stream_info_map_[evicted_id].read_headers_callback, | 
| +              ERR_PIPELINE_EVICTION)); | 
| +    } | 
| +    stream_info_map_[evicted_id].read_headers_callback = NULL; | 
| +  } | 
| +  read_next_state_ = READ_STATE_NONE; | 
| +  return result; | 
| +} | 
| + | 
| +void HttpPipelinedConnectionImpl::Close(int pipeline_id, | 
| +                                        bool not_reusable) { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  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; | 
| +      send_user_callback_ = NULL; | 
| +      send_next_state_ = SEND_STATE_UNUSABLE; | 
| +      DoSendRequestLoop(OK); | 
| +      break; | 
| + | 
| +    case STREAM_SENT: | 
| +    case STREAM_READ_PENDING: | 
| +      usable_ = false; | 
| +      stream_info_map_[pipeline_id].state = STREAM_CLOSED; | 
| +      stream_info_map_[pipeline_id].read_headers_callback = NULL; | 
| +      if (read_next_state_ == READ_STATE_NONE) { | 
| +        read_next_state_ = READ_STATE_UNUSABLE; | 
| +        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; | 
| +      read_user_callback_ = NULL; | 
| +      DoReadHeadersLoop(OK); | 
| +      break; | 
| + | 
| +    case STREAM_CLOSED: | 
| +    case STREAM_UNUSED: | 
| +      // TODO(simonjam): Why is Close() sometimes called twice? | 
| +      break; | 
| + | 
| +    default: | 
| +      NOTREACHED(); | 
| +      break; | 
| +  } | 
| +} | 
| + | 
| +int HttpPipelinedConnectionImpl::ReadResponseBody( | 
| +    int pipeline_id, | 
| +    IOBuffer* buf, | 
| +    int buf_len, | 
| +    OldCompletionCallback* callback) { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  CHECK(!request_order_.empty()); | 
| +  CHECK_EQ(pipeline_id, request_order_.front()); | 
| +  CHECK(stream_info_map_[pipeline_id].parser.get()); | 
| +  return stream_info_map_[pipeline_id].parser->ReadResponseBody( | 
| +      buf, buf_len, callback); | 
| +} | 
| + | 
| +uint64 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::IsMoreDataBuffered(int pipeline_id) const { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  return read_buf_->offset() != 0; | 
| +} | 
| + | 
| +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_is_reused(true); | 
| +} | 
| + | 
| +void HttpPipelinedConnectionImpl::GetSSLInfo(int pipeline_id, | 
| +                                             SSLInfo* ssl_info) { | 
| +  CHECK(ContainsKey(stream_info_map_, pipeline_id)); | 
| +  CHECK(stream_info_map_[pipeline_id].parser.get()); | 
| +  return 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()); | 
| +  return stream_info_map_[pipeline_id].parser->GetSSLCertRequestInfo( | 
| +      cert_request_info); | 
| +} | 
| + | 
| +void HttpPipelinedConnectionImpl::FireUserCallback( | 
| +    OldCompletionCallback* callback, | 
| +    int result) { | 
| +  CHECK(callback); | 
| +  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 NetLog::Source& HttpPipelinedConnectionImpl::source() const { | 
| +  return net_log_.source(); | 
| +} | 
| + | 
| +bool HttpPipelinedConnectionImpl::was_npn_negotiated() const { | 
| +  return was_npn_negotiated_; | 
| +} | 
| + | 
| +HttpPipelinedConnectionImpl::DeferredSendRequest::DeferredSendRequest() { | 
| +} | 
| + | 
| +HttpPipelinedConnectionImpl::DeferredSendRequest::~DeferredSendRequest() { | 
| +} | 
| + | 
| +HttpPipelinedConnectionImpl::StreamInfo::StreamInfo() | 
| +    : read_headers_callback(NULL), | 
| +      state(STREAM_CREATED) { | 
| +} | 
| + | 
| +HttpPipelinedConnectionImpl::StreamInfo::~StreamInfo() { | 
| +} | 
| + | 
| +}  // namespace net | 
|  |