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/quic/quic_stream_factory.h"
10 #include "base/location.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/metrics/sparse_histogram.h"
14 #include "base/rand_util.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/values.h"
21 #include "net/base/net_errors.h"
22 #include "net/cert/cert_verifier.h"
23 #include "net/dns/host_resolver.h"
24 #include "net/dns/single_request_host_resolver.h"
25 #include "net/http/http_server_properties.h"
26 #include "net/quic/crypto/channel_id_chromium.h"
27 #include "net/quic/crypto/proof_verifier_chromium.h"
28 #include "net/quic/crypto/quic_random.h"
29 #include "net/quic/crypto/quic_server_info.h"
30 #include "net/quic/port_suggester.h"
31 #include "net/quic/quic_chromium_client_session.h"
32 #include "net/quic/quic_clock.h"
33 #include "net/quic/quic_connection.h"
34 #include "net/quic/quic_connection_helper.h"
35 #include "net/quic/quic_crypto_client_stream_factory.h"
36 #include "net/quic/quic_default_packet_writer.h"
37 #include "net/quic/quic_flags.h"
38 #include "net/quic/quic_http_stream.h"
39 #include "net/quic/quic_protocol.h"
40 #include "net/quic/quic_server_id.h"
41 #include "net/socket/client_socket_factory.h"
42 #include "net/udp/udp_client_socket.h"
45 #include "base/win/windows_version.h"
48 #if defined(USE_OPENSSL)
49 #include <openssl/aead.h>
50 #include "crypto/openssl_util.h"
61 enum CreateSessionFailure
{
62 CREATION_ERROR_CONNECTING_SOCKET
,
63 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
64 CREATION_ERROR_SETTING_SEND_BUFFER
,
68 // When a connection is idle for 30 seconds it will be closed.
69 const int kIdleConnectionTimeoutSeconds
= 30;
71 // The maximum receive window sizes for QUIC sessions and streams.
72 const int32 kQuicSessionMaxRecvWindowSize
= 15 * 1024 * 1024; // 15 MB
73 const int32 kQuicStreamMaxRecvWindowSize
= 6 * 1024 * 1024; // 6 MB
75 // Set the maximum number of undecryptable packets the connection will store.
76 const int32 kMaxUndecryptablePackets
= 100;
78 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
79 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
83 bool IsEcdsaSupported() {
85 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
92 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
94 config
.SetIdleConnectionStateLifetime(
95 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
96 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
97 config
.SetConnectionOptionsToSend(connection_options
);
101 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
103 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
105 ~DefaultPacketWriterFactory() override
{}
107 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
110 DatagramClientSocket
* socket_
;
113 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
114 QuicConnection
* connection
) const {
115 scoped_ptr
<QuicDefaultPacketWriter
> writer(
116 new QuicDefaultPacketWriter(socket_
));
117 writer
->SetConnection(connection
);
118 return writer
.release();
123 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
125 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
127 : ip_endpoint(ip_endpoint
),
128 is_https(is_https
) {}
130 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
132 bool QuicStreamFactory::IpAliasKey::operator<(
133 const QuicStreamFactory::IpAliasKey
& other
) const {
134 if (!(ip_endpoint
== other
.ip_endpoint
)) {
135 return ip_endpoint
< other
.ip_endpoint
;
137 return is_https
< other
.is_https
;
140 bool QuicStreamFactory::IpAliasKey::operator==(
141 const QuicStreamFactory::IpAliasKey
& other
) const {
142 return is_https
== other
.is_https
&&
143 ip_endpoint
== other
.ip_endpoint
;
146 // Responsible for creating a new QUIC session to the specified server, and
147 // for notifying any associated requests when complete.
148 class QuicStreamFactory::Job
{
150 Job(QuicStreamFactory
* factory
,
151 HostResolver
* host_resolver
,
152 const HostPortPair
& host_port_pair
,
153 bool server_and_origin_have_same_host
,
155 bool was_alternative_service_recently_broken
,
156 PrivacyMode privacy_mode
,
157 int cert_verify_flags
,
159 QuicServerInfo
* server_info
,
160 const BoundNetLog
& net_log
);
162 // Creates a new job to handle the resumption of for connecting an
164 Job(QuicStreamFactory
* factory
,
165 HostResolver
* host_resolver
,
166 QuicChromiumClientSession
* session
,
167 QuicServerId server_id
);
171 int Run(const CompletionCallback
& callback
);
175 int DoResolveHostComplete(int rv
);
176 int DoLoadServerInfo();
177 int DoLoadServerInfoComplete(int rv
);
179 int DoResumeConnect();
180 int DoConnectComplete(int rv
);
182 void OnIOComplete(int rv
);
184 void RunAuxilaryJob();
188 void CancelWaitForDataReadyCallback();
190 const QuicServerId
server_id() const { return server_id_
; }
192 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
198 STATE_RESOLVE_HOST_COMPLETE
,
199 STATE_LOAD_SERVER_INFO
,
200 STATE_LOAD_SERVER_INFO_COMPLETE
,
202 STATE_RESUME_CONNECT
,
203 STATE_CONNECT_COMPLETE
,
207 QuicStreamFactory
* factory_
;
208 SingleRequestHostResolver host_resolver_
;
209 QuicServerId server_id_
;
210 int cert_verify_flags_
;
211 // True if and only if server and origin have the same hostname.
212 bool server_and_origin_have_same_host_
;
214 bool was_alternative_service_recently_broken_
;
215 scoped_ptr
<QuicServerInfo
> server_info_
;
216 bool started_another_job_
;
217 const BoundNetLog net_log_
;
218 QuicChromiumClientSession
* session_
;
219 CompletionCallback callback_
;
220 AddressList address_list_
;
221 base::TimeTicks dns_resolution_start_time_
;
222 base::TimeTicks dns_resolution_end_time_
;
223 base::WeakPtrFactory
<Job
> weak_factory_
;
224 DISALLOW_COPY_AND_ASSIGN(Job
);
227 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
228 HostResolver
* host_resolver
,
229 const HostPortPair
& host_port_pair
,
230 bool server_and_origin_have_same_host
,
232 bool was_alternative_service_recently_broken
,
233 PrivacyMode privacy_mode
,
234 int cert_verify_flags
,
236 QuicServerInfo
* server_info
,
237 const BoundNetLog
& net_log
)
238 : io_state_(STATE_RESOLVE_HOST
),
240 host_resolver_(host_resolver
),
241 server_id_(host_port_pair
, is_https
, privacy_mode
),
242 cert_verify_flags_(cert_verify_flags
),
243 server_and_origin_have_same_host_(server_and_origin_have_same_host
),
245 was_alternative_service_recently_broken_(
246 was_alternative_service_recently_broken
),
247 server_info_(server_info
),
248 started_another_job_(false),
251 weak_factory_(this) {
254 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
255 HostResolver
* host_resolver
,
256 QuicChromiumClientSession
* session
,
257 QuicServerId server_id
)
258 : io_state_(STATE_RESUME_CONNECT
),
260 host_resolver_(host_resolver
), // unused
261 server_id_(server_id
),
262 cert_verify_flags_(0), // unused
263 server_and_origin_have_same_host_(false), // unused
264 is_post_(false), // unused
265 was_alternative_service_recently_broken_(false), // unused
266 started_another_job_(false), // unused
267 net_log_(session
->net_log()), // unused
269 weak_factory_(this) {}
271 QuicStreamFactory::Job::~Job() {
272 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
274 server_info_
->ResetWaitForDataReadyCallback();
277 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
279 if (rv
== ERR_IO_PENDING
)
280 callback_
= callback
;
282 return rv
> 0 ? OK
: rv
;
285 int QuicStreamFactory::Job::DoLoop(int rv
) {
287 IoState state
= io_state_
;
288 io_state_
= STATE_NONE
;
290 case STATE_RESOLVE_HOST
:
292 rv
= DoResolveHost();
294 case STATE_RESOLVE_HOST_COMPLETE
:
295 rv
= DoResolveHostComplete(rv
);
297 case STATE_LOAD_SERVER_INFO
:
299 rv
= DoLoadServerInfo();
301 case STATE_LOAD_SERVER_INFO_COMPLETE
:
302 rv
= DoLoadServerInfoComplete(rv
);
308 case STATE_RESUME_CONNECT
:
310 rv
= DoResumeConnect();
312 case STATE_CONNECT_COMPLETE
:
313 rv
= DoConnectComplete(rv
);
316 NOTREACHED() << "io_state_: " << io_state_
;
319 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
323 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
325 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
330 void QuicStreamFactory::Job::RunAuxilaryJob() {
331 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
332 base::Unretained(factory_
), this));
333 if (rv
!= ERR_IO_PENDING
)
334 factory_
->OnJobComplete(this, rv
);
337 void QuicStreamFactory::Job::Cancel() {
340 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
343 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
344 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
345 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
347 server_info_
->CancelWaitForDataReadyCallback();
351 int QuicStreamFactory::Job::DoResolveHost() {
352 // Start loading the data now, and wait for it after we resolve the host.
354 server_info_
->Start();
357 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
358 dns_resolution_start_time_
= base::TimeTicks::Now();
359 return host_resolver_
.Resolve(
360 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
362 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
366 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
367 dns_resolution_end_time_
= base::TimeTicks::Now();
368 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
369 dns_resolution_end_time_
- dns_resolution_start_time_
);
373 DCHECK(!factory_
->HasActiveSession(server_id_
));
375 // Inform the factory of this resolution, which will set up
376 // a session alias, if possible.
377 if (factory_
->OnResolution(server_id_
, address_list_
)) {
382 io_state_
= STATE_LOAD_SERVER_INFO
;
384 io_state_
= STATE_CONNECT
;
388 int QuicStreamFactory::Job::DoLoadServerInfo() {
389 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
391 DCHECK(server_info_
);
393 // To mitigate the effects of disk cache taking too long to load QUIC server
394 // information, set up a timer to cancel WaitForDataReady's callback.
395 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
396 const int kMaxLoadServerInfoTimeoutMs
= 50;
397 // Wait for DiskCache a maximum of 50ms.
398 int64 load_server_info_timeout_ms
=
399 min(static_cast<int>(
400 (factory_
->load_server_info_timeout_srtt_multiplier_
*
401 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(
404 kMaxLoadServerInfoTimeoutMs
);
405 if (load_server_info_timeout_ms
> 0) {
406 factory_
->task_runner_
->PostDelayedTask(
408 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
410 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
414 int rv
= server_info_
->WaitForDataReady(
415 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
416 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
417 // If we are waiting to load server config from the disk cache, then start
419 started_another_job_
= true;
420 factory_
->CreateAuxilaryJob(server_id_
, cert_verify_flags_
,
421 server_and_origin_have_same_host_
, is_post_
,
427 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
428 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
429 base::TimeTicks::Now() - dns_resolution_end_time_
);
432 server_info_
.reset();
434 if (started_another_job_
&&
435 (!server_info_
|| server_info_
->state().server_config
.empty() ||
436 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
437 // If we have started another job and if we didn't load the server config
438 // from the disk cache or if we have received a new server config from the
439 // server, then cancel the current job.
440 io_state_
= STATE_NONE
;
441 return ERR_CONNECTION_CLOSED
;
444 io_state_
= STATE_CONNECT
;
448 int QuicStreamFactory::Job::DoConnect() {
449 io_state_
= STATE_CONNECT_COMPLETE
;
451 int rv
= factory_
->CreateSession(
452 server_id_
, cert_verify_flags_
, server_info_
.Pass(), address_list_
,
453 dns_resolution_end_time_
, net_log_
, &session_
);
455 DCHECK(rv
!= ERR_IO_PENDING
);
460 if (!session_
->connection()->connected()) {
461 return ERR_CONNECTION_CLOSED
;
464 session_
->StartReading();
465 if (!session_
->connection()->connected()) {
466 return ERR_QUIC_PROTOCOL_ERROR
;
468 bool require_confirmation
= factory_
->require_confirmation() ||
469 !server_and_origin_have_same_host_
|| is_post_
||
470 was_alternative_service_recently_broken_
;
472 rv
= session_
->CryptoConnect(
473 require_confirmation
,
474 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
478 int QuicStreamFactory::Job::DoResumeConnect() {
479 io_state_
= STATE_CONNECT_COMPLETE
;
481 int rv
= session_
->ResumeCryptoConnect(
482 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
487 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
491 DCHECK(!factory_
->HasActiveSession(server_id_
));
492 // There may well now be an active session for this IP. If so, use the
493 // existing session instead.
494 AddressList
address(session_
->connection()->peer_address());
495 if (factory_
->OnResolution(server_id_
, address
)) {
496 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
501 factory_
->ActivateSession(server_id_
, session_
);
506 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
507 : factory_(factory
) {}
509 QuicStreamRequest::~QuicStreamRequest() {
510 if (factory_
&& !callback_
.is_null())
511 factory_
->CancelRequest(this);
514 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
516 PrivacyMode privacy_mode
,
517 int cert_verify_flags
,
518 base::StringPiece origin_host
,
519 base::StringPiece method
,
520 const BoundNetLog
& net_log
,
521 const CompletionCallback
& callback
) {
523 DCHECK(callback_
.is_null());
525 origin_host_
= origin_host
.as_string();
526 privacy_mode_
= privacy_mode
;
528 factory_
->Create(host_port_pair
, is_https
, privacy_mode
,
529 cert_verify_flags
, origin_host
, method
, net_log
, this);
530 if (rv
== ERR_IO_PENDING
) {
531 host_port_pair_
= host_port_pair
;
532 is_https_
= is_https
;
534 callback_
= callback
;
543 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
545 stream_
= stream
.Pass();
548 void QuicStreamRequest::OnRequestComplete(int rv
) {
553 base::TimeDelta
QuicStreamRequest::GetTimeDelayForWaitingJob() const {
555 return base::TimeDelta();
556 return factory_
->GetTimeDelayForWaitingJob(
557 QuicServerId(host_port_pair_
, is_https_
, privacy_mode_
));
560 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
562 return stream_
.Pass();
565 QuicStreamFactory::QuicStreamFactory(
566 HostResolver
* host_resolver
,
567 ClientSocketFactory
* client_socket_factory
,
568 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
569 CertVerifier
* cert_verifier
,
570 CertPolicyEnforcer
* cert_policy_enforcer
,
571 ChannelIDService
* channel_id_service
,
572 TransportSecurityState
* transport_security_state
,
573 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
574 QuicRandom
* random_generator
,
576 size_t max_packet_length
,
577 const std::string
& user_agent_id
,
578 const QuicVersionVector
& supported_versions
,
579 bool enable_port_selection
,
580 bool always_require_handshake_confirmation
,
581 bool disable_connection_pooling
,
582 float load_server_info_timeout_srtt_multiplier
,
583 bool enable_connection_racing
,
584 bool enable_non_blocking_io
,
585 bool disable_disk_cache
,
587 int max_number_of_lossy_connections
,
588 float packet_loss_threshold
,
589 int max_disabled_reasons
,
590 int threshold_public_resets_post_handshake
,
591 int threshold_timeouts_with_open_streams
,
592 int socket_receive_buffer_size
,
594 const QuicTagVector
& connection_options
)
595 : require_confirmation_(true),
596 host_resolver_(host_resolver
),
597 client_socket_factory_(client_socket_factory
),
598 http_server_properties_(http_server_properties
),
599 transport_security_state_(transport_security_state
),
600 quic_server_info_factory_(nullptr),
601 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
602 random_generator_(random_generator
),
604 max_packet_length_(max_packet_length
),
605 config_(InitializeQuicConfig(connection_options
)),
606 supported_versions_(supported_versions
),
607 enable_port_selection_(enable_port_selection
),
608 always_require_handshake_confirmation_(
609 always_require_handshake_confirmation
),
610 disable_connection_pooling_(disable_connection_pooling
),
611 load_server_info_timeout_srtt_multiplier_(
612 load_server_info_timeout_srtt_multiplier
),
613 enable_connection_racing_(enable_connection_racing
),
614 enable_non_blocking_io_(enable_non_blocking_io
),
615 disable_disk_cache_(disable_disk_cache
),
616 prefer_aes_(prefer_aes
),
617 max_number_of_lossy_connections_(max_number_of_lossy_connections
),
618 packet_loss_threshold_(packet_loss_threshold
),
619 max_disabled_reasons_(max_disabled_reasons
),
620 num_public_resets_post_handshake_(0),
621 num_timeouts_with_open_streams_(0),
622 max_public_resets_post_handshake_(0),
623 max_timeouts_with_open_streams_(0),
624 threshold_timeouts_with_open_streams_(
625 threshold_timeouts_with_open_streams
),
626 threshold_public_resets_post_handshake_(
627 threshold_public_resets_post_handshake
),
628 socket_receive_buffer_size_(socket_receive_buffer_size
),
629 delay_tcp_race_(delay_tcp_race
),
630 port_seed_(random_generator_
->RandUint64()),
631 check_persisted_supports_quic_(true),
632 quic_supported_servers_at_startup_initialzied_(false),
633 task_runner_(nullptr),
634 weak_factory_(this) {
635 DCHECK(transport_security_state_
);
636 crypto_config_
.set_user_agent_id(user_agent_id
);
637 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
638 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
639 crypto_config_
.AddCanonicalSuffix(".googleusercontent.com");
640 crypto_config_
.SetProofVerifier(new ProofVerifierChromium(
641 cert_verifier
, cert_policy_enforcer
, transport_security_state
));
642 // TODO(rtenneti): http://crbug.com/487355. Temporary fix for b/20760730 until
643 // channel_id_service is supported in cronet.
644 if (channel_id_service
) {
645 crypto_config_
.SetChannelIDSource(
646 new ChannelIDSourceChromium(channel_id_service
));
648 #if defined(USE_OPENSSL)
649 crypto::EnsureOpenSSLInit();
650 bool has_aes_hardware_support
= !!EVP_has_aes_hardware();
653 bool has_aes_hardware_support
= cpu
.has_aesni() && cpu
.has_avx();
655 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
656 has_aes_hardware_support
);
657 if (has_aes_hardware_support
|| prefer_aes_
)
658 crypto_config_
.PreferAesGcm();
659 if (!IsEcdsaSupported())
660 crypto_config_
.DisableEcdsa();
663 QuicStreamFactory::~QuicStreamFactory() {
664 CloseAllSessions(ERR_ABORTED
);
665 while (!all_sessions_
.empty()) {
666 delete all_sessions_
.begin()->first
;
667 all_sessions_
.erase(all_sessions_
.begin());
669 while (!active_jobs_
.empty()) {
670 const QuicServerId server_id
= active_jobs_
.begin()->first
;
671 STLDeleteElements(&(active_jobs_
[server_id
]));
672 active_jobs_
.erase(server_id
);
676 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
677 require_confirmation_
= require_confirmation
;
678 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
679 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
680 local_address_
.address());
684 base::TimeDelta
QuicStreamFactory::GetTimeDelayForWaitingJob(
685 const QuicServerId
& server_id
) {
686 if (!delay_tcp_race_
|| require_confirmation_
)
687 return base::TimeDelta();
688 int64 srtt
= 1.5 * GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
689 // Picked 300ms based on mean time from
690 // Net.QuicSession.HostResolution.HandshakeConfirmedTime histogram.
691 const int kDefaultRTT
= 300 * kNumMicrosPerMilli
;
694 return base::TimeDelta::FromMicroseconds(srtt
);
697 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
699 PrivacyMode privacy_mode
,
700 int cert_verify_flags
,
701 base::StringPiece origin_host
,
702 base::StringPiece method
,
703 const BoundNetLog
& net_log
,
704 QuicStreamRequest
* request
) {
705 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
706 SessionMap::iterator it
= active_sessions_
.find(server_id
);
707 if (it
!= active_sessions_
.end()) {
708 QuicChromiumClientSession
* session
= it
->second
;
709 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
710 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
711 request
->set_stream(CreateFromSession(session
));
715 if (HasActiveJob(server_id
)) {
716 active_requests_
[request
] = server_id
;
717 job_requests_map_
[server_id
].insert(request
);
718 return ERR_IO_PENDING
;
721 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
722 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
724 task_runner_
= base::ThreadTaskRunnerHandle::Get().get();
726 QuicServerInfo
* quic_server_info
= nullptr;
727 if (quic_server_info_factory_
) {
728 bool load_from_disk_cache
= !disable_disk_cache_
;
729 if (http_server_properties_
) {
730 if (!quic_supported_servers_at_startup_initialzied_
)
731 InitializeQuicSupportedServersAtStartup();
732 if (!ContainsKey(quic_supported_servers_at_startup_
,
733 server_id
.host_port_pair())) {
734 // If there is no entry for QUIC, consider that as a new server and
735 // don't wait for Cache thread to load the data for that server.
736 load_from_disk_cache
= false;
739 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
740 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
744 bool server_and_origin_have_same_host
= host_port_pair
.host() == origin_host
;
745 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
,
746 server_and_origin_have_same_host
, is_https
,
747 WasQuicRecentlyBroken(server_id
), privacy_mode
,
748 cert_verify_flags
, method
== "POST" /* is_post */,
749 quic_server_info
, net_log
));
750 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
751 base::Unretained(this), job
.get()));
752 if (rv
== ERR_IO_PENDING
) {
753 active_requests_
[request
] = server_id
;
754 job_requests_map_
[server_id
].insert(request
);
755 active_jobs_
[server_id
].insert(job
.release());
759 it
= active_sessions_
.find(server_id
);
760 DCHECK(it
!= active_sessions_
.end());
761 QuicChromiumClientSession
* session
= it
->second
;
762 if (!session
->CanPool(origin_host
.as_string(), privacy_mode
))
763 return ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
;
764 request
->set_stream(CreateFromSession(session
));
769 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
770 int cert_verify_flags
,
771 bool server_and_origin_have_same_host
,
773 const BoundNetLog
& net_log
) {
775 new Job(this, host_resolver_
, server_id
.host_port_pair(),
776 server_and_origin_have_same_host
, server_id
.is_https(),
777 WasQuicRecentlyBroken(server_id
), server_id
.privacy_mode(),
778 cert_verify_flags
, is_post
, nullptr, net_log
);
779 active_jobs_
[server_id
].insert(aux_job
);
780 task_runner_
->PostTask(FROM_HERE
,
781 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
782 aux_job
->GetWeakPtr()));
785 bool QuicStreamFactory::OnResolution(
786 const QuicServerId
& server_id
,
787 const AddressList
& address_list
) {
788 DCHECK(!HasActiveSession(server_id
));
789 if (disable_connection_pooling_
) {
792 for (const IPEndPoint
& address
: address_list
) {
793 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
794 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
797 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
798 for (QuicChromiumClientSession
* session
: sessions
) {
799 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
801 active_sessions_
[server_id
] = session
;
802 session_aliases_
[session
].insert(server_id
);
809 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
810 QuicServerId server_id
= job
->server_id();
812 JobSet
* jobs
= &(active_jobs_
[server_id
]);
813 if (jobs
->size() > 1) {
814 // If there is another pending job, then we can delete this job and let
815 // the other job handle the request.
824 if (!always_require_handshake_confirmation_
)
825 set_require_confirmation(false);
827 // Create all the streams, but do not notify them yet.
828 SessionMap::iterator session_it
= active_sessions_
.find(server_id
);
829 for (RequestSet::iterator request_it
= job_requests_map_
[server_id
].begin();
830 request_it
!= job_requests_map_
[server_id
].end();) {
831 DCHECK(session_it
!= active_sessions_
.end());
832 QuicChromiumClientSession
* session
= session_it
->second
;
833 QuicStreamRequest
* request
= *request_it
;
834 if (!session
->CanPool(request
->origin_host(), request
->privacy_mode())) {
835 RequestSet::iterator old_request_it
= request_it
;
837 // Remove request from containers so that OnRequestComplete() is not
838 // called later again on the same request.
839 job_requests_map_
[server_id
].erase(old_request_it
);
840 active_requests_
.erase(request
);
841 // Notify request of certificate error.
842 request
->OnRequestComplete(ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN
);
845 request
->set_stream(CreateFromSession(session
));
850 while (!job_requests_map_
[server_id
].empty()) {
851 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
852 QuicStreamRequest
* request
= *it
;
853 job_requests_map_
[server_id
].erase(it
);
854 active_requests_
.erase(request
);
855 // Even though we're invoking callbacks here, we don't need to worry
856 // about |this| being deleted, because the factory is owned by the
857 // profile which can not be deleted via callbacks.
858 request
->OnRequestComplete(rv
);
861 for (Job
* other_job
: active_jobs_
[server_id
]) {
862 if (other_job
!= job
)
866 STLDeleteElements(&(active_jobs_
[server_id
]));
867 active_jobs_
.erase(server_id
);
868 job_requests_map_
.erase(server_id
);
871 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateFromSession(
872 QuicChromiumClientSession
* session
) {
873 return scoped_ptr
<QuicHttpStream
>(new QuicHttpStream(session
->GetWeakPtr()));
876 QuicChromiumClientSession::QuicDisabledReason
877 QuicStreamFactory::QuicDisabledReason(uint16 port
) const {
878 if (max_number_of_lossy_connections_
> 0 &&
879 number_of_lossy_connections_
.find(port
) !=
880 number_of_lossy_connections_
.end() &&
881 number_of_lossy_connections_
.at(port
) >=
882 max_number_of_lossy_connections_
) {
883 return QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE
;
885 if (threshold_public_resets_post_handshake_
> 0 &&
886 num_public_resets_post_handshake_
>=
887 threshold_public_resets_post_handshake_
) {
888 return QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE
;
890 if (threshold_timeouts_with_open_streams_
> 0 &&
891 num_timeouts_with_open_streams_
>=
892 threshold_timeouts_with_open_streams_
) {
893 return QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS
;
895 return QuicChromiumClientSession::QUIC_DISABLED_NOT
;
898 const char* QuicStreamFactory::QuicDisabledReasonString() const {
899 // TODO(ckrasic) - better solution for port/lossy connections?
900 const uint16 port
= 443;
901 switch (QuicDisabledReason(port
)) {
902 case QuicChromiumClientSession::QUIC_DISABLED_BAD_PACKET_LOSS_RATE
:
903 return "Bad packet loss rate.";
904 case QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE
:
905 return "Public resets after successful handshakes.";
906 case QuicChromiumClientSession::QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS
:
907 return "Connection timeouts with streams open.";
913 bool QuicStreamFactory::IsQuicDisabled(uint16 port
) {
914 return QuicDisabledReason(port
) !=
915 QuicChromiumClientSession::QUIC_DISABLED_NOT
;
918 bool QuicStreamFactory::OnHandshakeConfirmed(QuicChromiumClientSession
* session
,
919 float packet_loss_rate
) {
921 uint16 port
= session
->server_id().port();
922 if (packet_loss_rate
< packet_loss_threshold_
) {
923 number_of_lossy_connections_
[port
] = 0;
927 if (http_server_properties_
) {
928 // We mark it as recently broken, which means that 0-RTT will be disabled
929 // but we'll still race.
930 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
931 AlternativeService(QUIC
, session
->server_id().host(), port
));
934 bool was_quic_disabled
= IsQuicDisabled(port
);
935 ++number_of_lossy_connections_
[port
];
937 // Collect data for port 443 for packet loss events.
938 if (port
== 443 && max_number_of_lossy_connections_
> 0) {
939 UMA_HISTOGRAM_SPARSE_SLOWLY(
940 base::StringPrintf("Net.QuicStreamFactory.BadPacketLossEvents%d",
941 max_number_of_lossy_connections_
),
942 std::min(number_of_lossy_connections_
[port
],
943 max_number_of_lossy_connections_
));
946 bool is_quic_disabled
= IsQuicDisabled(port
);
947 if (is_quic_disabled
) {
948 // Close QUIC connection if Quic is disabled for this port.
949 session
->CloseSessionOnErrorAndNotifyFactoryLater(
950 ERR_ABORTED
, QUIC_BAD_PACKET_LOSS_RATE
);
952 // If this bad packet loss rate disabled the QUIC, then record it.
953 if (!was_quic_disabled
)
954 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicStreamFactory.QuicIsDisabled", port
);
956 return is_quic_disabled
;
959 void QuicStreamFactory::OnIdleSession(QuicChromiumClientSession
* session
) {}
961 void QuicStreamFactory::OnSessionGoingAway(QuicChromiumClientSession
* session
) {
962 const AliasSet
& aliases
= session_aliases_
[session
];
963 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
965 DCHECK(active_sessions_
.count(*it
));
966 DCHECK_EQ(session
, active_sessions_
[*it
]);
967 // Track sessions which have recently gone away so that we can disable
969 if (session
->goaway_received()) {
970 gone_away_aliases_
.insert(*it
);
973 active_sessions_
.erase(*it
);
974 ProcessGoingAwaySession(session
, *it
, true);
976 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
977 if (!aliases
.empty()) {
978 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
979 aliases
.begin()->is_https());
980 ip_aliases_
[ip_alias_key
].erase(session
);
981 if (ip_aliases_
[ip_alias_key
].empty()) {
982 ip_aliases_
.erase(ip_alias_key
);
985 session_aliases_
.erase(session
);
988 void QuicStreamFactory::MaybeDisableQuic(QuicChromiumClientSession
* session
) {
990 uint16 port
= session
->server_id().port();
991 if (IsQuicDisabled(port
))
994 // Expire the oldest disabled_reason if appropriate. This enforces that we
995 // only consider the max_disabled_reasons_ most recent sessions.
996 QuicChromiumClientSession::QuicDisabledReason disabled_reason
;
997 if (static_cast<int>(disabled_reasons_
.size()) == max_disabled_reasons_
) {
998 disabled_reason
= disabled_reasons_
.front();
999 disabled_reasons_
.pop_front();
1000 if (disabled_reason
==
1001 QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE
) {
1002 --num_public_resets_post_handshake_
;
1003 } else if (disabled_reason
== QuicChromiumClientSession::
1004 QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS
) {
1005 --num_timeouts_with_open_streams_
;
1008 disabled_reason
= session
->disabled_reason();
1009 disabled_reasons_
.push_back(disabled_reason
);
1010 if (disabled_reason
==
1011 QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE
) {
1012 ++num_public_resets_post_handshake_
;
1013 } else if (disabled_reason
== QuicChromiumClientSession::
1014 QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS
) {
1015 ++num_timeouts_with_open_streams_
;
1017 if (num_timeouts_with_open_streams_
> max_timeouts_with_open_streams_
) {
1018 max_timeouts_with_open_streams_
= num_timeouts_with_open_streams_
;
1019 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicStreamFactory.TimeoutsWithOpenStreams",
1020 num_timeouts_with_open_streams_
, 0, 20, 10);
1023 if (num_public_resets_post_handshake_
> max_public_resets_post_handshake_
) {
1024 max_public_resets_post_handshake_
= num_public_resets_post_handshake_
;
1025 UMA_HISTOGRAM_CUSTOM_COUNTS(
1026 "Net.QuicStreamFactory.PublicResetsPostHandshake",
1027 num_public_resets_post_handshake_
, 0, 20, 10);
1030 if (IsQuicDisabled(port
)) {
1031 if (disabled_reason
==
1032 QuicChromiumClientSession::QUIC_DISABLED_PUBLIC_RESET_POST_HANDSHAKE
) {
1033 session
->CloseSessionOnErrorAndNotifyFactoryLater(
1034 ERR_ABORTED
, QUIC_PUBLIC_RESETS_POST_HANDSHAKE
);
1035 } else if (disabled_reason
== QuicChromiumClientSession::
1036 QUIC_DISABLED_TIMEOUT_WITH_OPEN_STREAMS
) {
1037 session
->CloseSessionOnErrorAndNotifyFactoryLater(
1038 ERR_ABORTED
, QUIC_TIMEOUTS_WITH_OPEN_STREAMS
);
1040 UMA_HISTOGRAM_ENUMERATION("Net.QuicStreamFactory.DisabledReasons",
1042 QuicChromiumClientSession::QUIC_DISABLED_MAX
);
1046 void QuicStreamFactory::OnSessionClosed(QuicChromiumClientSession
* session
) {
1047 DCHECK_EQ(0u, session
->GetNumOpenStreams());
1048 MaybeDisableQuic(session
);
1049 OnSessionGoingAway(session
);
1051 all_sessions_
.erase(session
);
1054 void QuicStreamFactory::OnSessionConnectTimeout(
1055 QuicChromiumClientSession
* session
) {
1056 const AliasSet
& aliases
= session_aliases_
[session
];
1057 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
1059 DCHECK(active_sessions_
.count(*it
));
1060 DCHECK_EQ(session
, active_sessions_
[*it
]);
1061 active_sessions_
.erase(*it
);
1064 if (aliases
.empty()) {
1068 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1069 aliases
.begin()->is_https());
1070 ip_aliases_
[ip_alias_key
].erase(session
);
1071 if (ip_aliases_
[ip_alias_key
].empty()) {
1072 ip_aliases_
.erase(ip_alias_key
);
1074 QuicServerId server_id
= *aliases
.begin();
1075 session_aliases_
.erase(session
);
1076 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
1077 active_jobs_
[server_id
].insert(job
);
1078 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
1079 base::Unretained(this), job
));
1080 DCHECK_EQ(ERR_IO_PENDING
, rv
);
1083 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
1084 DCHECK(ContainsKey(active_requests_
, request
));
1085 QuicServerId server_id
= active_requests_
[request
];
1086 job_requests_map_
[server_id
].erase(request
);
1087 active_requests_
.erase(request
);
1090 void QuicStreamFactory::CloseAllSessions(int error
) {
1091 while (!active_sessions_
.empty()) {
1092 size_t initial_size
= active_sessions_
.size();
1093 active_sessions_
.begin()->second
->CloseSessionOnError(error
,
1094 QUIC_INTERNAL_ERROR
);
1095 DCHECK_NE(initial_size
, active_sessions_
.size());
1097 while (!all_sessions_
.empty()) {
1098 size_t initial_size
= all_sessions_
.size();
1099 all_sessions_
.begin()->first
->CloseSessionOnError(error
,
1100 QUIC_INTERNAL_ERROR
);
1101 DCHECK_NE(initial_size
, all_sessions_
.size());
1103 DCHECK(all_sessions_
.empty());
1106 scoped_ptr
<base::Value
> QuicStreamFactory::QuicStreamFactoryInfoToValue()
1108 scoped_ptr
<base::ListValue
> list(new base::ListValue());
1110 for (SessionMap::const_iterator it
= active_sessions_
.begin();
1111 it
!= active_sessions_
.end(); ++it
) {
1112 const QuicServerId
& server_id
= it
->first
;
1113 QuicChromiumClientSession
* session
= it
->second
;
1114 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
1115 // Only add a session to the list once.
1116 if (server_id
== *aliases
.begin()) {
1117 std::set
<HostPortPair
> hosts
;
1118 for (AliasSet::const_iterator alias_it
= aliases
.begin();
1119 alias_it
!= aliases
.end(); ++alias_it
) {
1120 hosts
.insert(alias_it
->host_port_pair());
1122 list
->Append(session
->GetInfoAsValue(hosts
));
1128 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
1129 crypto_config_
.ClearCachedStates();
1132 void QuicStreamFactory::OnIPAddressChanged() {
1133 CloseAllSessions(ERR_NETWORK_CHANGED
);
1134 set_require_confirmation(true);
1137 void QuicStreamFactory::OnSSLConfigChanged() {
1138 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
1141 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
1142 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
1145 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
1146 // We should flush the sessions if we removed trust from a
1147 // cert, because a previously trusted server may have become
1150 // We should not flush the sessions if we added trust to a cert.
1152 // Since the OnCACertChanged method doesn't tell us what
1153 // kind of change it is, we have to flush the socket
1154 // pools to be safe.
1155 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
1158 bool QuicStreamFactory::HasActiveSession(
1159 const QuicServerId
& server_id
) const {
1160 return ContainsKey(active_sessions_
, server_id
);
1163 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
1164 return ContainsKey(active_jobs_
, key
);
1167 int QuicStreamFactory::CreateSession(const QuicServerId
& server_id
,
1168 int cert_verify_flags
,
1169 scoped_ptr
<QuicServerInfo
> server_info
,
1170 const AddressList
& address_list
,
1171 base::TimeTicks dns_resolution_end_time
,
1172 const BoundNetLog
& net_log
,
1173 QuicChromiumClientSession
** session
) {
1174 bool enable_port_selection
= enable_port_selection_
;
1175 if (enable_port_selection
&&
1176 ContainsKey(gone_away_aliases_
, server_id
)) {
1177 // Disable port selection when the server is going away.
1178 // There is no point in trying to return to the same server, if
1179 // that server is no longer handling requests.
1180 enable_port_selection
= false;
1181 gone_away_aliases_
.erase(server_id
);
1184 QuicConnectionId connection_id
= random_generator_
->RandUint64();
1185 IPEndPoint addr
= *address_list
.begin();
1186 scoped_refptr
<PortSuggester
> port_suggester
=
1187 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
1188 DatagramSocket::BindType bind_type
= enable_port_selection
?
1189 DatagramSocket::RANDOM_BIND
: // Use our callback.
1190 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
1191 scoped_ptr
<DatagramClientSocket
> socket(
1192 client_socket_factory_
->CreateDatagramClientSocket(
1194 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
1195 net_log
.net_log(), net_log
.source()));
1197 if (enable_non_blocking_io_
&&
1198 client_socket_factory_
== ClientSocketFactory::GetDefaultFactory()) {
1200 static_cast<UDPClientSocket
*>(socket
.get())->UseNonBlockingIO();
1204 int rv
= socket
->Connect(addr
);
1207 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
1210 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1211 port_suggester
->call_count());
1212 if (enable_port_selection
) {
1213 DCHECK_LE(1u, port_suggester
->call_count());
1215 DCHECK_EQ(0u, port_suggester
->call_count());
1218 rv
= socket
->SetReceiveBufferSize(socket_receive_buffer_size_
);
1220 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
1223 // Set a buffer large enough to contain the initial CWND's worth of packet
1224 // to work around the problem with CHLO packets being sent out with the
1225 // wrong encryption level, when the send buffer is full.
1226 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
1228 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
1232 socket
->GetLocalAddress(&local_address_
);
1233 if (check_persisted_supports_quic_
&& http_server_properties_
) {
1234 check_persisted_supports_quic_
= false;
1235 IPAddressNumber last_address
;
1236 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
1237 last_address
== local_address_
.address()) {
1238 require_confirmation_
= false;
1242 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
1244 if (!helper_
.get()) {
1246 new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
1247 clock_
.get(), random_generator_
));
1250 QuicConnection
* connection
= new QuicConnection(
1251 connection_id
, addr
, helper_
.get(), packet_writer_factory
,
1252 true /* owns_writer */, Perspective::IS_CLIENT
, server_id
.is_https(),
1253 supported_versions_
);
1254 connection
->SetMaxPacketLength(max_packet_length_
);
1256 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
1258 QuicConfig config
= config_
;
1259 config
.SetSocketReceiveBufferToSend(socket_receive_buffer_size_
);
1260 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1261 config
.SetInitialSessionFlowControlWindowToSend(
1262 kQuicSessionMaxRecvWindowSize
);
1263 config
.SetInitialStreamFlowControlWindowToSend(kQuicStreamMaxRecvWindowSize
);
1264 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1266 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1267 config
.SetBytesForConnectionIdToSend(0);
1269 if (quic_server_info_factory_
&& !server_info
) {
1270 // Start the disk cache loading so that we can persist the newer QUIC server
1271 // information and/or inform the disk cache that we have reused
1273 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1274 server_info
->Start();
1277 *session
= new QuicChromiumClientSession(
1278 connection
, socket
.Pass(), this, quic_crypto_client_stream_factory_
,
1279 transport_security_state_
, server_info
.Pass(), server_id
,
1280 cert_verify_flags
, config
, &crypto_config_
,
1281 network_connection_
.GetDescription(), dns_resolution_end_time
,
1282 base::ThreadTaskRunnerHandle::Get().get(), net_log
.net_log());
1284 all_sessions_
[*session
] = server_id
; // owning pointer
1286 (*session
)->Initialize();
1287 bool closed_during_initialize
=
1288 !ContainsKey(all_sessions_
, *session
) ||
1289 !(*session
)->connection()->connected();
1290 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1291 closed_during_initialize
);
1292 if (closed_during_initialize
) {
1293 DLOG(DFATAL
) << "Session closed during initialize";
1295 return ERR_CONNECTION_CLOSED
;
1300 void QuicStreamFactory::ActivateSession(const QuicServerId
& server_id
,
1301 QuicChromiumClientSession
* session
) {
1302 DCHECK(!HasActiveSession(server_id
));
1303 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1304 active_sessions_
[server_id
] = session
;
1305 session_aliases_
[session
].insert(server_id
);
1306 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1307 server_id
.is_https());
1308 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1309 ip_aliases_
[ip_alias_key
].insert(session
);
1312 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1313 const QuicServerId
& server_id
) const {
1314 if (!http_server_properties_
)
1316 const ServerNetworkStats
* stats
=
1317 http_server_properties_
->GetServerNetworkStats(
1318 server_id
.host_port_pair());
1319 if (stats
== nullptr)
1321 return stats
->srtt
.InMicroseconds();
1324 bool QuicStreamFactory::WasQuicRecentlyBroken(
1325 const QuicServerId
& server_id
) const {
1326 if (!http_server_properties_
)
1328 const AlternativeService
alternative_service(QUIC
,
1329 server_id
.host_port_pair());
1330 return http_server_properties_
->WasAlternativeServiceRecentlyBroken(
1331 alternative_service
);
1334 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1335 const QuicServerId
& server_id
) {
1336 QuicCryptoClientConfig::CachedState
* cached
=
1337 crypto_config_
.LookupOrCreate(server_id
);
1338 return cached
->IsEmpty();
1341 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1342 const QuicServerId
& server_id
,
1343 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1344 // |server_info| will be NULL, if a non-empty server config already exists in
1345 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1349 QuicCryptoClientConfig::CachedState
* cached
=
1350 crypto_config_
.LookupOrCreate(server_id
);
1351 if (!cached
->IsEmpty())
1354 if (http_server_properties_
) {
1355 DCHECK(quic_supported_servers_at_startup_initialzied_
);
1356 // TODO(rtenneti): Delete the following histogram after collecting stats.
1357 // If the AlternativeServiceMap contained an entry for this host, check if
1358 // the disk cache contained an entry for it.
1359 if (ContainsKey(quic_supported_servers_at_startup_
,
1360 server_id
.host_port_pair())) {
1361 UMA_HISTOGRAM_BOOLEAN(
1362 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1363 server_info
->state().server_config
.empty());
1367 if (!cached
->Initialize(server_info
->state().server_config
,
1368 server_info
->state().source_address_token
,
1369 server_info
->state().certs
,
1370 server_info
->state().server_config_sig
,
1374 if (!server_id
.is_https()) {
1375 // Don't check the certificates for insecure QUIC.
1376 cached
->SetProofValid();
1380 void QuicStreamFactory::InitializeQuicSupportedServersAtStartup() {
1381 DCHECK(http_server_properties_
);
1382 DCHECK(!quic_supported_servers_at_startup_initialzied_
);
1383 quic_supported_servers_at_startup_initialzied_
= true;
1384 for (const std::pair
<const HostPortPair
, AlternativeServiceInfoVector
>&
1385 key_value
: http_server_properties_
->alternative_service_map()) {
1386 for (const AlternativeServiceInfo
& alternative_service_info
:
1388 if (alternative_service_info
.alternative_service
.protocol
== QUIC
) {
1389 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1396 void QuicStreamFactory::ProcessGoingAwaySession(
1397 QuicChromiumClientSession
* session
,
1398 const QuicServerId
& server_id
,
1399 bool session_was_active
) {
1400 if (!http_server_properties_
)
1403 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1404 const AlternativeService
alternative_service(QUIC
,
1405 server_id
.host_port_pair());
1406 if (session
->IsCryptoHandshakeConfirmed()) {
1407 http_server_properties_
->ConfirmAlternativeService(alternative_service
);
1408 ServerNetworkStats network_stats
;
1409 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1410 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1411 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1416 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1417 stats
.packets_received
);
1419 if (!session_was_active
)
1422 // TODO(rch): In the special case where the session has received no
1423 // packets from the peer, we should consider blacklisting this
1424 // differently so that we still race TCP but we don't consider the
1425 // session connected until the handshake has been confirmed.
1426 HistogramBrokenAlternateProtocolLocation(
1427 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1429 // Since the session was active, there's no longer an
1430 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the TCP
1431 // job also fails. So to avoid not using QUIC when we otherwise could, we mark
1432 // it as recently broken, which means that 0-RTT will be disabled but we'll
1434 http_server_properties_
->MarkAlternativeServiceRecentlyBroken(
1435 alternative_service
);