| Index: net/base/client_socket_pool.cc | 
| diff --git a/net/base/client_socket_pool.cc b/net/base/client_socket_pool.cc | 
| index 9f14fe76d06f6d86fbcd6dea42b9899a2e844d3e..4171b0c3d07de2d76f4819675ec0c00cf7bf5a2a 100644 | 
| --- a/net/base/client_socket_pool.cc | 
| +++ b/net/base/client_socket_pool.cc | 
| @@ -4,16 +4,10 @@ | 
|  | 
| #include "net/base/client_socket_pool.h" | 
|  | 
| -#include "base/compiler_specific.h" | 
| -#include "base/field_trial.h" | 
| #include "base/message_loop.h" | 
| -#include "base/time.h" | 
| -#include "base/stl_util-inl.h" | 
| -#include "net/base/client_socket_factory.h" | 
| +#include "net/base/client_socket.h" | 
| #include "net/base/client_socket_handle.h" | 
| -#include "net/base/dns_resolution_observer.h" | 
| #include "net/base/net_errors.h" | 
| -#include "net/base/tcp_client_socket.h" | 
|  | 
| using base::TimeDelta; | 
|  | 
| @@ -34,123 +28,8 @@ const int kIdleTimeout = 300;  // 5 minutes. | 
|  | 
| namespace net { | 
|  | 
| -ClientSocketPool::ConnectingSocket::ConnectingSocket( | 
| -    const std::string& group_name, | 
| -    const ClientSocketHandle* handle, | 
| -    ClientSocketFactory* client_socket_factory, | 
| -    ClientSocketPool* pool) | 
| -    : group_name_(group_name), | 
| -      handle_(handle), | 
| -      client_socket_factory_(client_socket_factory), | 
| -      ALLOW_THIS_IN_INITIALIZER_LIST( | 
| -          callback_(this, | 
| -                    &ClientSocketPool::ConnectingSocket::OnIOComplete)), | 
| -      pool_(pool) {} | 
| - | 
| -ClientSocketPool::ConnectingSocket::~ConnectingSocket() {} | 
| - | 
| -int ClientSocketPool::ConnectingSocket::Connect( | 
| -    const std::string& host, | 
| -    int port, | 
| -    CompletionCallback* callback) { | 
| -  DidStartDnsResolution(host, this); | 
| -  int rv = resolver_.Resolve(host, port, &addresses_, &callback_); | 
| -  if (rv == OK) { | 
| -    // TODO(willchan): This code is broken.  It should be fixed, but the code | 
| -    // path is impossible in the current implementation since the host resolver | 
| -    // always dumps the request to a worker pool, so it cannot complete | 
| -    // synchronously. | 
| -    connect_start_time_ = base::Time::Now(); | 
| -    rv = socket_->Connect(&callback_); | 
| -  } | 
| -  return rv; | 
| -} | 
| - | 
| -ClientSocket* ClientSocketPool::ConnectingSocket::ReleaseSocket() { | 
| -  return socket_.release(); | 
| -} | 
| - | 
| -void ClientSocketPool::ConnectingSocket::OnIOComplete(int result) { | 
| -  DCHECK_NE(result, ERR_IO_PENDING); | 
| - | 
| -  GroupMap::iterator group_it = pool_->group_map_.find(group_name_); | 
| -  if (group_it == pool_->group_map_.end()) { | 
| -    // The request corresponding to this ConnectingSocket has been canceled. | 
| -    // Stop bothering with it. | 
| -    delete this; | 
| -    return; | 
| -  } | 
| - | 
| -  Group& group = group_it->second; | 
| - | 
| -  RequestMap* request_map = &group.connecting_requests; | 
| -  RequestMap::iterator it = request_map->find(handle_); | 
| -  if (it == request_map->end()) { | 
| -    // The request corresponding to this ConnectingSocket has been canceled. | 
| -    // Stop bothering with it. | 
| -    group.active_socket_count--; | 
| - | 
| -    // Delete group if no longer needed. | 
| -    if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| -      DCHECK(group.pending_requests.empty()); | 
| -      DCHECK(group.connecting_requests.empty()); | 
| -      pool_->group_map_.erase(group_it); | 
| -    } | 
| -    delete this; | 
| -    return; | 
| -  } | 
| - | 
| -  if (result == OK) { | 
| -    if (it->second.load_state == LOAD_STATE_RESOLVING_HOST) { | 
| -      it->second.load_state = LOAD_STATE_CONNECTING; | 
| -      socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_)); | 
| -      connect_start_time_ = base::Time::Now(); | 
| -      result = socket_->Connect(&callback_); | 
| -      if (result == ERR_IO_PENDING) | 
| -        return; | 
| -    } else { | 
| -      DCHECK(connect_start_time_ != base::Time()); | 
| -      base::TimeDelta connect_duration = | 
| -          base::Time::Now() - connect_start_time_; | 
| - | 
| -      UMA_HISTOGRAM_CLIPPED_TIMES( | 
| -          FieldTrial::MakeName( | 
| -              "Net.TCP_Connection_Latency", "DnsImpact").data(), | 
| -          connect_duration, | 
| -          base::TimeDelta::FromMilliseconds(1), | 
| -          base::TimeDelta::FromMinutes(10), | 
| -          100); | 
| -    } | 
| -  } | 
| - | 
| -  // Now, we either succeeded at Connect()'ing, or we failed at host resolution | 
| -  // or Connect()'ing.  Either way, we'll run the callback to alert the client. | 
| - | 
| -  Request request = it->second; | 
| -  request_map->erase(it); | 
| - | 
| -  if (result == OK) { | 
| -    request.handle->set_socket(socket_.release()); | 
| -    request.handle->set_is_reused(false); | 
| -  } else { | 
| -    group.active_socket_count--; | 
| - | 
| -    // Delete group if no longer needed. | 
| -    if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| -      DCHECK(group.pending_requests.empty()); | 
| -      DCHECK(group.connecting_requests.empty()); | 
| -      pool_->group_map_.erase(group_it); | 
| -    } | 
| -  } | 
| - | 
| -  request.callback->Run(result); | 
| -  delete this; | 
| -} | 
| - | 
| -ClientSocketPool::ClientSocketPool(int max_sockets_per_group, | 
| -                                   ClientSocketFactory* client_socket_factory) | 
| -    : client_socket_factory_(client_socket_factory), | 
| -      idle_socket_count_(0), | 
| +ClientSocketPool::ClientSocketPool(int max_sockets_per_group) | 
| +    : idle_socket_count_(0), | 
| max_sockets_per_group_(max_sockets_per_group) { | 
| } | 
|  | 
| @@ -175,15 +54,10 @@ void ClientSocketPool::InsertRequestIntoQueue(const Request& r, | 
| pending_requests->insert(it, r); | 
| } | 
|  | 
| -int ClientSocketPool::RequestSocket(const std::string& group_name, | 
| -                                    const std::string& host, | 
| -                                    int port, | 
| +int ClientSocketPool::RequestSocket(ClientSocketHandle* handle, | 
| int priority, | 
| -                                    ClientSocketHandle* handle, | 
| CompletionCallback* callback) { | 
| -  DCHECK(!host.empty()); | 
| -  DCHECK_GE(priority, 0); | 
| -  Group& group = group_map_[group_name]; | 
| +  Group& group = group_map_[handle->group_name_]; | 
|  | 
| // Can we make another active socket now? | 
| if (group.active_socket_count == max_sockets_per_group_) { | 
| @@ -192,9 +66,6 @@ int ClientSocketPool::RequestSocket(const std::string& group_name, | 
| DCHECK(callback); | 
| r.callback = callback; | 
| r.priority = priority; | 
| -    r.host = host; | 
| -    r.port = port; | 
| -    r.load_state = LOAD_STATE_IDLE; | 
| InsertRequestIntoQueue(r, &group.pending_requests); | 
| return ERR_IO_PENDING; | 
| } | 
| @@ -202,91 +73,49 @@ int ClientSocketPool::RequestSocket(const std::string& group_name, | 
| // OK, we are going to activate one. | 
| group.active_socket_count++; | 
|  | 
| +  // Use idle sockets in LIFO order because they're more likely to be | 
| +  // still reusable. | 
| while (!group.idle_sockets.empty()) { | 
| IdleSocket idle_socket = group.idle_sockets.back(); | 
| group.idle_sockets.pop_back(); | 
| DecrementIdleCount(); | 
| -    if (idle_socket.socket->IsConnectedAndIdle()) { | 
| +    if ((*idle_socket.ptr)->IsConnectedAndIdle()) { | 
| // We found one we can reuse! | 
| -      handle->set_socket(idle_socket.socket); | 
| -      handle->set_is_reused(true); | 
| +      handle->socket_ = idle_socket.ptr; | 
| return OK; | 
| } | 
| -    delete idle_socket.socket; | 
| +    delete idle_socket.ptr; | 
| } | 
|  | 
| -  // We couldn't find a socket to reuse, so allocate and connect a new one. | 
| -  scoped_ptr<ConnectingSocket> connecting_socket( | 
| -      new ConnectingSocket(group_name, handle, client_socket_factory_, this)); | 
| -  int rv = connecting_socket->Connect(host, port, callback); | 
| -  if (rv == OK) { | 
| -    handle->set_socket(connecting_socket->ReleaseSocket()); | 
| -    handle->set_is_reused(false); | 
| -  } else if (rv == ERR_IO_PENDING) { | 
| -    // The ConnectingSocket will delete itself. | 
| -    connecting_socket.release(); | 
| -    Request r; | 
| -    r.handle = handle; | 
| -    DCHECK(callback); | 
| -    r.callback = callback; | 
| -    r.priority = priority; | 
| -    r.host = host; | 
| -    r.port = port; | 
| -    r.load_state = LOAD_STATE_RESOLVING_HOST; | 
| -    group_map_[group_name].connecting_requests[handle] = r; | 
| -  } else { | 
| -    group.active_socket_count--; | 
| - | 
| -    // Delete group if no longer needed. | 
| -    if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| -      DCHECK(group.pending_requests.empty()); | 
| -      DCHECK(group.connecting_requests.empty()); | 
| -      group_map_.erase(group_name); | 
| -    } | 
| -  } | 
| - | 
| -  return rv; | 
| +  handle->socket_ = new ClientSocketPtr(); | 
| +  return OK; | 
| } | 
|  | 
| -void ClientSocketPool::CancelRequest(const std::string& group_name, | 
| -                                     const ClientSocketHandle* handle) { | 
| -  DCHECK(ContainsKey(group_map_, group_name)); | 
| +void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) { | 
| +  Group& group = group_map_[handle->group_name_]; | 
|  | 
| -  Group& group = group_map_[group_name]; | 
| +  // In order for us to be canceling a pending request, we must have active | 
| +  // sockets equaling the limit.  NOTE: The correctness of the code doesn't | 
| +  // require this assertion. | 
| +  DCHECK(group.active_socket_count == max_sockets_per_group_); | 
|  | 
| // Search pending_requests for matching handle. | 
| -  RequestQueue::iterator it = group.pending_requests.begin(); | 
| +  std::deque<Request>::iterator it = group.pending_requests.begin(); | 
| for (; it != group.pending_requests.end(); ++it) { | 
| if (it->handle == handle) { | 
| group.pending_requests.erase(it); | 
| -      return; | 
| -    } | 
| -  } | 
| - | 
| -  // It's invalid to cancel a non-existent request. | 
| -  DCHECK(ContainsKey(group.connecting_requests, handle)); | 
| - | 
| -  RequestMap::iterator map_it = group.connecting_requests.find(handle); | 
| -  if (map_it != group.connecting_requests.end()) { | 
| -    group.connecting_requests.erase(map_it); | 
| -    group.active_socket_count--; | 
| - | 
| -    // Delete group if no longer needed. | 
| -    if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| -      DCHECK(group.pending_requests.empty()); | 
| -      DCHECK(group.connecting_requests.empty()); | 
| -      group_map_.erase(group_name); | 
| +      break; | 
| } | 
| } | 
| } | 
|  | 
| -void ClientSocketPool::ReleaseSocket(const std::string& group_name, | 
| -                                     ClientSocket* socket) { | 
| +void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) { | 
| // Run this asynchronously to allow the caller to finish before we let | 
| // another to begin doing work.  This also avoids nasty recursion issues. | 
| // NOTE: We cannot refer to the handle argument after this method returns. | 
| MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | 
| -      this, &ClientSocketPool::DoReleaseSocket, group_name, socket)); | 
| +      this, &ClientSocketPool::DoReleaseSocket, handle->group_name_, | 
| +      handle->socket_)); | 
| } | 
|  | 
| void ClientSocketPool::CloseIdleSockets() { | 
| @@ -301,42 +130,10 @@ int ClientSocketPool::IdleSocketCountInGroup( | 
| return i->second.idle_sockets.size(); | 
| } | 
|  | 
| -LoadState ClientSocketPool::GetLoadState( | 
| -    const std::string& group_name, | 
| -    const ClientSocketHandle* handle) const { | 
| -  DCHECK(ContainsKey(group_map_, group_name)) << group_name; | 
| - | 
| -  // Can't use operator[] since it is non-const. | 
| -  const Group& group = group_map_.find(group_name)->second; | 
| - | 
| -  // Search connecting_requests for matching handle. | 
| -  RequestMap::const_iterator map_it = group.connecting_requests.find(handle); | 
| -  if (map_it != group.connecting_requests.end()) { | 
| -    const LoadState load_state = map_it->second.load_state; | 
| -    DCHECK(load_state == LOAD_STATE_RESOLVING_HOST || | 
| -           load_state == LOAD_STATE_CONNECTING); | 
| -    return load_state; | 
| -  } | 
| - | 
| -  // Search pending_requests for matching handle. | 
| -  RequestQueue::const_iterator it = group.pending_requests.begin(); | 
| -  for (; it != group.pending_requests.end(); ++it) { | 
| -    if (it->handle == handle) { | 
| -      DCHECK_EQ(LOAD_STATE_IDLE, it->load_state); | 
| -      // TODO(wtc): Add a state for being on the wait list. | 
| -      // See http://www.crbug.com/5077. | 
| -      return LOAD_STATE_IDLE; | 
| -    } | 
| -  } | 
| - | 
| -  NOTREACHED(); | 
| -  return LOAD_STATE_IDLE; | 
| -} | 
| - | 
| bool ClientSocketPool::IdleSocket::ShouldCleanup(base::TimeTicks now) const { | 
| bool timed_out = (now - start_time) >= | 
| base::TimeDelta::FromSeconds(kIdleTimeout); | 
| -  return timed_out || !socket->IsConnectedAndIdle(); | 
| +  return timed_out || !(*ptr)->IsConnectedAndIdle(); | 
| } | 
|  | 
| void ClientSocketPool::CleanupIdleSockets(bool force) { | 
| @@ -354,7 +151,7 @@ void ClientSocketPool::CleanupIdleSockets(bool force) { | 
| std::deque<IdleSocket>::iterator j = group.idle_sockets.begin(); | 
| while (j != group.idle_sockets.end()) { | 
| if (force || j->ShouldCleanup(now)) { | 
| -        delete j->socket; | 
| +        delete j->ptr; | 
| j = group.idle_sockets.erase(j); | 
| DecrementIdleCount(); | 
| } else { | 
| @@ -365,7 +162,6 @@ void ClientSocketPool::CleanupIdleSockets(bool force) { | 
| // Delete group if no longer needed. | 
| if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| DCHECK(group.pending_requests.empty()); | 
| -      DCHECK(group.connecting_requests.empty()); | 
| group_map_.erase(i++); | 
| } else { | 
| ++i; | 
| @@ -385,43 +181,40 @@ void ClientSocketPool::DecrementIdleCount() { | 
| } | 
|  | 
| void ClientSocketPool::DoReleaseSocket(const std::string& group_name, | 
| -                                       ClientSocket* socket) { | 
| +                                       ClientSocketPtr* ptr) { | 
| GroupMap::iterator i = group_map_.find(group_name); | 
| DCHECK(i != group_map_.end()); | 
|  | 
| Group& group = i->second; | 
|  | 
| -  DCHECK_GT(group.active_socket_count, 0); | 
| +  DCHECK(group.active_socket_count > 0); | 
| group.active_socket_count--; | 
|  | 
| -  const bool can_reuse = socket->IsConnectedAndIdle(); | 
| +  bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle(); | 
| if (can_reuse) { | 
| IdleSocket idle_socket; | 
| -    idle_socket.socket = socket; | 
| +    idle_socket.ptr = ptr; | 
| idle_socket.start_time = base::TimeTicks::Now(); | 
|  | 
| group.idle_sockets.push_back(idle_socket); | 
| IncrementIdleCount(); | 
| } else { | 
| -    delete socket; | 
| +    delete ptr; | 
| } | 
|  | 
| // Process one pending request. | 
| if (!group.pending_requests.empty()) { | 
| Request r = group.pending_requests.front(); | 
| group.pending_requests.pop_front(); | 
| - | 
| -    int rv = RequestSocket( | 
| -        group_name, r.host, r.port, r.priority, r.handle, r.callback); | 
| -    if (rv != ERR_IO_PENDING) | 
| -      r.callback->Run(rv); | 
| +    int rv = RequestSocket(r.handle, r.priority, NULL); | 
| +    DCHECK(rv == OK); | 
| +    r.callback->Run(rv); | 
| return; | 
| } | 
|  | 
| // Delete group if no longer needed. | 
| if (group.active_socket_count == 0 && group.idle_sockets.empty()) { | 
| DCHECK(group.pending_requests.empty()); | 
| -    DCHECK(group.connecting_requests.empty()); | 
| group_map_.erase(i); | 
| } | 
| } | 
|  |