Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / socket / client_socket_handle.cc
blobf38187b3f865c74d83262fc988bef37137735d90
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/logging.h"
11 #include "net/base/net_errors.h"
12 #include "net/socket/client_socket_pool.h"
14 namespace net {
16 ClientSocketHandle::ClientSocketHandle()
17 : is_initialized_(false),
18 pool_(NULL),
19 higher_pool_(NULL),
20 reuse_type_(ClientSocketHandle::UNUSED),
21 callback_(base::Bind(&ClientSocketHandle::OnIOComplete,
22 base::Unretained(this))),
23 is_ssl_error_(false),
24 ssl_failure_state_(SSL_FAILURE_NONE) {
27 ClientSocketHandle::~ClientSocketHandle() {
28 Reset();
31 void ClientSocketHandle::Reset() {
32 ResetInternal(true);
33 ResetErrorState();
36 void ClientSocketHandle::ResetInternal(bool cancel) {
37 // Was Init called?
38 if (!group_name_.empty()) {
39 // If so, we must have a pool.
40 CHECK(pool_);
41 if (is_initialized()) {
42 if (socket_) {
43 socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
44 // Release the socket back to the ClientSocketPool so it can be
45 // deleted or reused.
46 pool_->ReleaseSocket(group_name_, socket_.Pass(), pool_id_);
47 } else {
48 // If the handle has been initialized, we should still have a
49 // socket.
50 NOTREACHED();
52 } else if (cancel) {
53 // If we did not get initialized yet and we have a socket
54 // request pending, cancel it.
55 pool_->CancelRequest(group_name_, this);
58 is_initialized_ = false;
59 socket_.reset();
60 group_name_.clear();
61 reuse_type_ = ClientSocketHandle::UNUSED;
62 user_callback_.Reset();
63 if (higher_pool_)
64 RemoveHigherLayeredPool(higher_pool_);
65 pool_ = NULL;
66 idle_time_ = base::TimeDelta();
67 init_time_ = base::TimeTicks();
68 setup_time_ = base::TimeDelta();
69 connect_timing_ = LoadTimingInfo::ConnectTiming();
70 pool_id_ = -1;
73 void ClientSocketHandle::ResetErrorState() {
74 is_ssl_error_ = false;
75 ssl_error_response_info_ = HttpResponseInfo();
76 ssl_failure_state_ = SSL_FAILURE_NONE;
77 pending_http_proxy_connection_.reset();
80 LoadState ClientSocketHandle::GetLoadState() const {
81 CHECK(!is_initialized());
82 CHECK(!group_name_.empty());
83 // Because of http://crbug.com/37810 we may not have a pool, but have
84 // just a raw socket.
85 if (!pool_)
86 return LOAD_STATE_IDLE;
87 return pool_->GetLoadState(group_name_, this);
90 bool ClientSocketHandle::IsPoolStalled() const {
91 if (!pool_)
92 return false;
93 return pool_->IsStalled();
96 void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
97 CHECK(higher_pool);
98 CHECK(!higher_pool_);
99 // TODO(mmenke): |pool_| should only be NULL in tests. Maybe stop doing that
100 // so this be be made into a DCHECK, and the same can be done in
101 // RemoveHigherLayeredPool?
102 if (pool_) {
103 pool_->AddHigherLayeredPool(higher_pool);
104 higher_pool_ = higher_pool;
108 void ClientSocketHandle::RemoveHigherLayeredPool(
109 HigherLayeredPool* higher_pool) {
110 CHECK(higher_pool_);
111 CHECK_EQ(higher_pool_, higher_pool);
112 if (pool_) {
113 pool_->RemoveHigherLayeredPool(higher_pool);
114 higher_pool_ = NULL;
118 bool ClientSocketHandle::GetLoadTimingInfo(
119 bool is_reused,
120 LoadTimingInfo* load_timing_info) const {
121 // Only return load timing information when there's a socket.
122 if (!socket_)
123 return false;
125 load_timing_info->socket_log_id = socket_->NetLog().source().id;
126 load_timing_info->socket_reused = is_reused;
128 // No times if the socket is reused.
129 if (is_reused)
130 return true;
132 load_timing_info->connect_timing = connect_timing_;
133 return true;
136 void ClientSocketHandle::SetSocket(scoped_ptr<StreamSocket> s) {
137 socket_ = s.Pass();
140 void ClientSocketHandle::OnIOComplete(int result) {
141 CompletionCallback callback = user_callback_;
142 user_callback_.Reset();
143 HandleInitCompletion(result);
144 callback.Run(result);
147 scoped_ptr<StreamSocket> ClientSocketHandle::PassSocket() {
148 return socket_.Pass();
151 void ClientSocketHandle::HandleInitCompletion(int result) {
152 CHECK_NE(ERR_IO_PENDING, result);
153 if (result != OK) {
154 if (!socket_.get())
155 ResetInternal(false); // Nothing to cancel since the request failed.
156 else
157 is_initialized_ = true;
158 return;
160 is_initialized_ = true;
161 CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
162 setup_time_ = base::TimeTicks::Now() - init_time_;
164 // Broadcast that the socket has been acquired.
165 // TODO(eroman): This logging is not complete, in particular set_socket() and
166 // release() socket. It ends up working though, since those methods are being
167 // used to layer sockets (and the destination sources are the same).
168 DCHECK(socket_.get());
169 socket_->NetLog().BeginEvent(
170 NetLog::TYPE_SOCKET_IN_USE,
171 requesting_source_.ToEventParametersCallback());
174 } // namespace net