Patch 3/3 to get WebScheduler via WebThread
[chromium-blink-merge.git] / net / socket / client_socket_handle.cc
blob734e58aeffff7369f6547ec84a98d8307d10d26e
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/socket/client_socket_handle.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/metrics/histogram.h"
11 #include "base/logging.h"
12 #include "net/base/net_errors.h"
13 #include "net/socket/client_socket_pool.h"
15 namespace net {
17 ClientSocketHandle::ClientSocketHandle()
18 : is_initialized_(false),
19 pool_(NULL),
20 higher_pool_(NULL),
21 reuse_type_(ClientSocketHandle::UNUSED),
22 callback_(base::Bind(&ClientSocketHandle::OnIOComplete,
23 base::Unretained(this))),
24 is_ssl_error_(false) {}
26 ClientSocketHandle::~ClientSocketHandle() {
27 Reset();
30 void ClientSocketHandle::Reset() {
31 ResetInternal(true);
32 ResetErrorState();
35 void ClientSocketHandle::ResetInternal(bool cancel) {
36 // Was Init called?
37 if (!group_name_.empty()) {
38 // If so, we must have a pool.
39 CHECK(pool_);
40 if (is_initialized()) {
41 if (socket_) {
42 socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
43 // Release the socket back to the ClientSocketPool so it can be
44 // deleted or reused.
45 pool_->ReleaseSocket(group_name_, socket_.Pass(), pool_id_);
46 } else {
47 // If the handle has been initialized, we should still have a
48 // socket.
49 NOTREACHED();
51 } else if (cancel) {
52 // If we did not get initialized yet and we have a socket
53 // request pending, cancel it.
54 pool_->CancelRequest(group_name_, this);
57 is_initialized_ = false;
58 socket_.reset();
59 group_name_.clear();
60 reuse_type_ = ClientSocketHandle::UNUSED;
61 user_callback_.Reset();
62 if (higher_pool_)
63 RemoveHigherLayeredPool(higher_pool_);
64 pool_ = NULL;
65 idle_time_ = base::TimeDelta();
66 init_time_ = base::TimeTicks();
67 setup_time_ = base::TimeDelta();
68 connect_timing_ = LoadTimingInfo::ConnectTiming();
69 pool_id_ = -1;
72 void ClientSocketHandle::ResetErrorState() {
73 is_ssl_error_ = false;
74 ssl_error_response_info_ = HttpResponseInfo();
75 pending_http_proxy_connection_.reset();
78 LoadState ClientSocketHandle::GetLoadState() const {
79 CHECK(!is_initialized());
80 CHECK(!group_name_.empty());
81 // Because of http://crbug.com/37810 we may not have a pool, but have
82 // just a raw socket.
83 if (!pool_)
84 return LOAD_STATE_IDLE;
85 return pool_->GetLoadState(group_name_, this);
88 bool ClientSocketHandle::IsPoolStalled() const {
89 if (!pool_)
90 return false;
91 return pool_->IsStalled();
94 void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
95 CHECK(higher_pool);
96 CHECK(!higher_pool_);
97 // TODO(mmenke): |pool_| should only be NULL in tests. Maybe stop doing that
98 // so this be be made into a DCHECK, and the same can be done in
99 // RemoveHigherLayeredPool?
100 if (pool_) {
101 pool_->AddHigherLayeredPool(higher_pool);
102 higher_pool_ = higher_pool;
106 void ClientSocketHandle::RemoveHigherLayeredPool(
107 HigherLayeredPool* higher_pool) {
108 CHECK(higher_pool_);
109 CHECK_EQ(higher_pool_, higher_pool);
110 if (pool_) {
111 pool_->RemoveHigherLayeredPool(higher_pool);
112 higher_pool_ = NULL;
116 bool ClientSocketHandle::GetLoadTimingInfo(
117 bool is_reused,
118 LoadTimingInfo* load_timing_info) const {
119 // Only return load timing information when there's a socket.
120 if (!socket_)
121 return false;
123 load_timing_info->socket_log_id = socket_->NetLog().source().id;
124 load_timing_info->socket_reused = is_reused;
126 // No times if the socket is reused.
127 if (is_reused)
128 return true;
130 load_timing_info->connect_timing = connect_timing_;
131 return true;
134 void ClientSocketHandle::SetSocket(scoped_ptr<StreamSocket> s) {
135 socket_ = s.Pass();
138 void ClientSocketHandle::OnIOComplete(int result) {
139 CompletionCallback callback = user_callback_;
140 user_callback_.Reset();
141 HandleInitCompletion(result);
142 callback.Run(result);
145 scoped_ptr<StreamSocket> ClientSocketHandle::PassSocket() {
146 return socket_.Pass();
149 void ClientSocketHandle::HandleInitCompletion(int result) {
150 CHECK_NE(ERR_IO_PENDING, result);
151 if (result != OK) {
152 if (!socket_.get())
153 ResetInternal(false); // Nothing to cancel since the request failed.
154 else
155 is_initialized_ = true;
156 return;
158 is_initialized_ = true;
159 CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
160 setup_time_ = base::TimeTicks::Now() - init_time_;
162 // Broadcast that the socket has been acquired.
163 // TODO(eroman): This logging is not complete, in particular set_socket() and
164 // release() socket. It ends up working though, since those methods are being
165 // used to layer sockets (and the destination sources are the same).
166 DCHECK(socket_.get());
167 socket_->NetLog().BeginEvent(
168 NetLog::TYPE_SOCKET_IN_USE,
169 requesting_source_.ToEventParametersCallback());
172 } // namespace net