Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Side by Side Diff: net/socket/ssl_client_socket_pool.cc

Issue 2870030: Implement SSLClientSocketPool. (Closed)
Patch Set: Rebase and fix mac compile error Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2010 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.
4
5 #include "net/socket/ssl_client_socket_pool.h"
6
7 #include "net/base/net_errors.h"
8 #include "net/socket/client_socket_factory.h"
9 #include "net/socket/client_socket_handle.h"
10
11 namespace net {
12
13 SSLSocketParams::SSLSocketParams(
14 const scoped_refptr<TCPSocketParams>& tcp_params,
15 const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
16 const scoped_refptr<SOCKSSocketParams>& socks_params,
17 ProxyServer::Scheme proxy,
18 const std::string& hostname,
19 const SSLConfig& ssl_config,
20 int load_flags,
21 bool want_spdy)
22 : tcp_params_(tcp_params),
23 http_proxy_params_(http_proxy_params),
24 socks_params_(socks_params),
25 proxy_(proxy),
26 hostname_(hostname),
27 ssl_config_(ssl_config),
28 load_flags_(load_flags),
29 want_spdy_(want_spdy) {
30 switch (proxy_) {
31 case ProxyServer::SCHEME_DIRECT:
32 DCHECK(tcp_params_.get() != NULL);
33 DCHECK(http_proxy_params_.get() == NULL);
34 DCHECK(socks_params_.get() == NULL);
35 break;
36 case ProxyServer::SCHEME_HTTP:
37 DCHECK(tcp_params_.get() == NULL);
38 DCHECK(http_proxy_params_.get() != NULL);
39 DCHECK(socks_params_.get() == NULL);
40 break;
41 case ProxyServer::SCHEME_SOCKS4:
42 case ProxyServer::SCHEME_SOCKS5:
43 DCHECK(tcp_params_.get() == NULL);
44 DCHECK(http_proxy_params_.get() == NULL);
45 DCHECK(socks_params_.get() != NULL);
46 break;
47 default:
48 LOG(DFATAL) << "unknown proxy type";
49 break;
50 }
51 }
52
53 SSLSocketParams::~SSLSocketParams() {}
54
55 // Timeout for the SSL handshake portion of the connect.
56 static const int kSSLHandshakeTimeoutInSeconds = 30;
57
58 SSLConnectJob::SSLConnectJob(
59 const std::string& group_name,
60 const scoped_refptr<SSLSocketParams>& params,
61 const base::TimeDelta& timeout_duration,
62 const scoped_refptr<TCPClientSocketPool>& tcp_pool,
63 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
64 const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
65 ClientSocketFactory* client_socket_factory,
66 const scoped_refptr<HostResolver>& host_resolver,
67 Delegate* delegate,
68 NetLog* net_log)
69 : ConnectJob(group_name, timeout_duration, delegate,
70 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
71 params_(params),
72 tcp_pool_(tcp_pool),
73 http_proxy_pool_(http_proxy_pool),
74 socks_pool_(socks_pool),
75 client_socket_factory_(client_socket_factory),
76 resolver_(host_resolver),
Nico 2015/03/08 02:31:18 This constructor sets all fields except next_state
wrong vandebo 2015/03/08 03:57:15 Looks like it could have been set to STATE_NONE
77 ALLOW_THIS_IN_INITIALIZER_LIST(
78 callback_(this, &SSLConnectJob::OnIOComplete)) {}
79
80 SSLConnectJob::~SSLConnectJob() {}
81
82 LoadState SSLConnectJob::GetLoadState() const {
83 switch (next_state_) {
84 case STATE_TCP_CONNECT:
85 case STATE_TCP_CONNECT_COMPLETE:
86 case STATE_SOCKS_CONNECT:
87 case STATE_SOCKS_CONNECT_COMPLETE:
88 case STATE_TUNNEL_CONNECT:
89 case STATE_TUNNEL_CONNECT_COMPLETE:
90 return transport_socket_handle_->GetLoadState();
91 case STATE_SSL_CONNECT:
92 case STATE_SSL_CONNECT_COMPLETE:
93 return LOAD_STATE_SSL_HANDSHAKE;
94 default:
95 NOTREACHED();
96 return LOAD_STATE_IDLE;
97 }
98 }
99
100 int SSLConnectJob::ConnectInternal() {
101 DetermineFirstState();
102 return DoLoop(OK);
103 }
104
105 void SSLConnectJob::DetermineFirstState() {
106 switch (params_->proxy()) {
107 case ProxyServer::SCHEME_DIRECT:
108 next_state_ = STATE_TCP_CONNECT;
109 break;
110 case ProxyServer::SCHEME_HTTP:
111 next_state_ = STATE_TUNNEL_CONNECT;
112 break;
113 case ProxyServer::SCHEME_SOCKS4:
114 case ProxyServer::SCHEME_SOCKS5:
115 next_state_ = STATE_SOCKS_CONNECT;
116 break;
117 default:
118 NOTREACHED() << "unknown proxy type";
119 break;
120 }
121 }
122
123 void SSLConnectJob::OnIOComplete(int result) {
124 int rv = DoLoop(result);
125 if (rv != ERR_IO_PENDING)
126 NotifyDelegateOfCompletion(rv); // Deletes |this|.
127 }
128
129 int SSLConnectJob::DoLoop(int result) {
130 DCHECK_NE(next_state_, STATE_NONE);
131
132 int rv = result;
133 do {
134 State state = next_state_;
135 next_state_ = STATE_NONE;
136 switch (state) {
137 case STATE_TCP_CONNECT:
138 DCHECK_EQ(OK, rv);
139 rv = DoTCPConnect();
140 break;
141 case STATE_TCP_CONNECT_COMPLETE:
142 rv = DoTCPConnectComplete(rv);
143 break;
144 case STATE_SOCKS_CONNECT:
145 DCHECK_EQ(OK, rv);
146 rv = DoSOCKSConnect();
147 break;
148 case STATE_SOCKS_CONNECT_COMPLETE:
149 rv = DoSOCKSConnectComplete(rv);
150 break;
151 case STATE_TUNNEL_CONNECT:
152 DCHECK_EQ(OK, rv);
153 rv = DoTunnelConnect();
154 break;
155 case STATE_TUNNEL_CONNECT_COMPLETE:
156 rv = DoTunnelConnectComplete(rv);
157 break;
158 case STATE_SSL_CONNECT:
159 DCHECK_EQ(OK, rv);
160 rv = DoSSLConnect();
161 break;
162 case STATE_SSL_CONNECT_COMPLETE:
163 rv = DoSSLConnectComplete(rv);
164 break;
165 default:
166 NOTREACHED() << "bad state";
167 rv = ERR_FAILED;
168 break;
169 }
170 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
171
172 return rv;
173 }
174
175 int SSLConnectJob::DoTCPConnect() {
176 DCHECK(tcp_pool_.get());
177 next_state_ = STATE_TCP_CONNECT_COMPLETE;
178 transport_socket_handle_.reset(new ClientSocketHandle());
179 scoped_refptr<TCPSocketParams> tcp_params = params_->tcp_params();
180 return transport_socket_handle_->Init(group_name(), tcp_params,
181 tcp_params->destination().priority(),
182 &callback_, tcp_pool_, net_log());
183 }
184
185 int SSLConnectJob::DoTCPConnectComplete(int result) {
186 if (result == OK)
187 next_state_ = STATE_SSL_CONNECT;
188
189 return result;
190 }
191
192 int SSLConnectJob::DoSOCKSConnect() {
193 DCHECK(socks_pool_.get());
194 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
195 transport_socket_handle_.reset(new ClientSocketHandle());
196 scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params();
197 return transport_socket_handle_->Init(group_name(), socks_params,
198 socks_params->destination().priority(),
199 &callback_, socks_pool_, net_log());
200 }
201
202 int SSLConnectJob::DoSOCKSConnectComplete(int result) {
203 if (result == OK)
204 next_state_ = STATE_SSL_CONNECT;
205
206 return result;
207 }
208
209 int SSLConnectJob::DoTunnelConnect() {
210 DCHECK(http_proxy_pool_.get());
211 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
212 transport_socket_handle_.reset(new ClientSocketHandle());
213 scoped_refptr<HttpProxySocketParams> http_proxy_params =
214 params_->http_proxy_params();
215 return transport_socket_handle_->Init(
216 group_name(), http_proxy_params,
217 http_proxy_params->tcp_params()->destination().priority(), &callback_,
218 http_proxy_pool_, net_log());
219 }
220
221 int SSLConnectJob::DoTunnelConnectComplete(int result) {
222 ClientSocket* socket = transport_socket_handle_->socket();
223 HttpProxyClientSocket* tunnel_socket =
224 static_cast<HttpProxyClientSocket*>(socket);
225
226 if (result == ERR_RETRY_CONNECTION) {
227 DetermineFirstState();
228 transport_socket_handle_->socket()->Disconnect();
229 return OK;
230 }
231
232 if (result == ERR_PROXY_AUTH_REQUESTED) {
233 // Extract the information needed to prompt for the proxy authentication.
234 // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|,
235 // we can easily set the state.
236 const HttpResponseInfo* tunnel_response = tunnel_socket->GetResponseInfo();
237
238 http_auth_response_headers_ = tunnel_response->headers;
239 http_auth_auth_challenge_ = tunnel_response->auth_challenge;
240 }
241
242 if (result < 0)
243 return result;
244
245 if (tunnel_socket->NeedsRestartWithAuth()) {
246 // We must have gotten an 'idle' tunnel socket that is waiting for auth.
247 // The HttpAuthController should have new credentials, we just need
248 // to retry.
249 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
250 return tunnel_socket->RestartWithAuth(&callback_);
251 }
252
253 next_state_ = STATE_SSL_CONNECT;
254 return result;
255 }
256
257 void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) {
258 if (http_auth_response_headers_.get() != NULL)
259 handle->set_tunnel_auth_response_info(http_auth_response_headers_,
260 http_auth_auth_challenge_);
261 if (!ssl_connect_start_time_.is_null())
262 handle->set_is_ssl_error(true);
263 }
264
265 int SSLConnectJob::DoSSLConnect() {
266 next_state_ = STATE_SSL_CONNECT_COMPLETE;
267 // Reset the timeout to just the time allowed for the SSL handshake.
268 ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds));
269 ssl_connect_start_time_ = base::TimeTicks::Now();
270
271 ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
272 transport_socket_handle_.release(), params_->hostname(),
273 params_->ssl_config()));
274 return ssl_socket_->Connect(&callback_);
275 }
276
277 int SSLConnectJob::DoSSLConnectComplete(int result) {
278 SSLClientSocket::NextProtoStatus status =
279 SSLClientSocket::kNextProtoUnsupported;
280 std::string proto;
281 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
282 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
283 // here, then we know that we called SSL_ImportFD.
284 if (result == OK || IsCertificateError(result))
285 status = ssl_socket_->GetNextProto(&proto);
286
287 bool using_spdy = false;
288 if (status == SSLClientSocket::kNextProtoNegotiated) {
289 ssl_socket_->setWasNpnNegotiated(true);
290 if (SSLClientSocket::NextProtoFromString(proto) ==
291 SSLClientSocket::kProtoSPDY1) {
292 using_spdy = true;
293 }
294 }
295 if (params_->want_spdy() && !using_spdy)
296 return ERR_NPN_NEGOTIATION_FAILED;
297
298 if (result == OK ||
299 ssl_socket_->IgnoreCertError(result, params_->load_flags())) {
300 DCHECK(ssl_connect_start_time_ != base::TimeTicks());
301 base::TimeDelta connect_duration =
302 base::TimeTicks::Now() - ssl_connect_start_time_;
303 if (using_spdy)
304 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency",
305 connect_duration,
306 base::TimeDelta::FromMilliseconds(1),
307 base::TimeDelta::FromMinutes(10),
308 100);
309 else
310 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency",
311 connect_duration,
312 base::TimeDelta::FromMilliseconds(1),
313 base::TimeDelta::FromMinutes(10),
314 100);
315 }
316 if (result == OK || IsCertificateError(result))
317 set_socket(ssl_socket_.release());
318
319 return result;
320 }
321
322 ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
323 const std::string& group_name,
324 const PoolBase::Request& request,
325 ConnectJob::Delegate* delegate) const {
326 return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(),
327 tcp_pool_, http_proxy_pool_, socks_pool_,
328 client_socket_factory_, host_resolver_, delegate,
329 net_log_);
330 }
331
332 SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
333 const scoped_refptr<TCPClientSocketPool>& tcp_pool,
334 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
335 const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
336 ClientSocketFactory* client_socket_factory,
337 HostResolver* host_resolver,
338 NetLog* net_log)
339 : tcp_pool_(tcp_pool),
340 http_proxy_pool_(http_proxy_pool),
341 socks_pool_(socks_pool),
342 client_socket_factory_(client_socket_factory),
343 host_resolver_(host_resolver),
344 net_log_(net_log) {
345 base::TimeDelta max_transport_timeout = base::TimeDelta();
346 base::TimeDelta pool_timeout;
347 if (tcp_pool_)
348 max_transport_timeout = tcp_pool_->ConnectionTimeout();
349 if (socks_pool_) {
350 pool_timeout = socks_pool_->ConnectionTimeout();
351 if (pool_timeout > max_transport_timeout)
352 max_transport_timeout = pool_timeout;
353 }
354 if (http_proxy_pool_) {
355 pool_timeout = http_proxy_pool_->ConnectionTimeout();
356 if (pool_timeout > max_transport_timeout)
357 max_transport_timeout = pool_timeout;
358 }
359 timeout_ = max_transport_timeout +
360 base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds);
361 }
362
363 SSLClientSocketPool::SSLClientSocketPool(
364 int max_sockets,
365 int max_sockets_per_group,
366 const scoped_refptr<ClientSocketPoolHistograms>& histograms,
367 const scoped_refptr<HostResolver>& host_resolver,
368 ClientSocketFactory* client_socket_factory,
369 const scoped_refptr<TCPClientSocketPool>& tcp_pool,
370 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool,
371 const scoped_refptr<SOCKSClientSocketPool>& socks_pool,
372 NetLog* net_log)
373 : base_(max_sockets, max_sockets_per_group, histograms,
374 base::TimeDelta::FromSeconds(
375 ClientSocketPool::unused_idle_socket_timeout()),
376 base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout),
377 new SSLConnectJobFactory(tcp_pool, http_proxy_pool, socks_pool,
378 client_socket_factory, host_resolver,
379 net_log)) {}
380
381 SSLClientSocketPool::~SSLClientSocketPool() {}
382
383 int SSLClientSocketPool::RequestSocket(const std::string& group_name,
384 const void* socket_params,
385 RequestPriority priority,
386 ClientSocketHandle* handle,
387 CompletionCallback* callback,
388 const BoundNetLog& net_log) {
389 const scoped_refptr<SSLSocketParams>* casted_socket_params =
390 static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params);
391
392 return base_.RequestSocket(group_name, *casted_socket_params, priority,
393 handle, callback, net_log);
394 }
395
396 void SSLClientSocketPool::CancelRequest(const std::string& group_name,
397 const ClientSocketHandle* handle) {
398 base_.CancelRequest(group_name, handle);
399 }
400
401 void SSLClientSocketPool::ReleaseSocket(const std::string& group_name,
402 ClientSocket* socket, int id) {
403 base_.ReleaseSocket(group_name, socket, id);
404 }
405
406 void SSLClientSocketPool::Flush() {
407 base_.Flush();
408 }
409
410 void SSLClientSocketPool::CloseIdleSockets() {
411 base_.CloseIdleSockets();
412 }
413
414 int SSLClientSocketPool::IdleSocketCountInGroup(
415 const std::string& group_name) const {
416 return base_.IdleSocketCountInGroup(group_name);
417 }
418
419 LoadState SSLClientSocketPool::GetLoadState(
420 const std::string& group_name, const ClientSocketHandle* handle) const {
421 return base_.GetLoadState(group_name, handle);
422 }
423
424 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698