OLD | NEW |
---|---|
(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 | |
OLD | NEW |