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/message_loop/message_loop.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/metrics/histogram.h"
14 #include "base/profiler/scoped_tracker.h"
15 #include "base/rand_util.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "net/base/net_errors.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/dns/host_resolver.h"
22 #include "net/dns/single_request_host_resolver.h"
23 #include "net/http/http_server_properties.h"
24 #include "net/quic/crypto/channel_id_chromium.h"
25 #include "net/quic/crypto/proof_verifier_chromium.h"
26 #include "net/quic/crypto/quic_random.h"
27 #include "net/quic/crypto/quic_server_info.h"
28 #include "net/quic/port_suggester.h"
29 #include "net/quic/quic_client_session.h"
30 #include "net/quic/quic_clock.h"
31 #include "net/quic/quic_connection.h"
32 #include "net/quic/quic_connection_helper.h"
33 #include "net/quic/quic_crypto_client_stream_factory.h"
34 #include "net/quic/quic_default_packet_writer.h"
35 #include "net/quic/quic_flags.h"
36 #include "net/quic/quic_http_stream.h"
37 #include "net/quic/quic_protocol.h"
38 #include "net/quic/quic_server_id.h"
39 #include "net/socket/client_socket_factory.h"
42 #include "base/win/windows_version.h"
49 enum CreateSessionFailure
{
50 CREATION_ERROR_CONNECTING_SOCKET
,
51 CREATION_ERROR_SETTING_RECEIVE_BUFFER
,
52 CREATION_ERROR_SETTING_SEND_BUFFER
,
56 // When a connection is idle for 30 seconds it will be closed.
57 const int kIdleConnectionTimeoutSeconds
= 30;
59 // The initial receive window size for both streams and sessions.
60 const int32 kInitialReceiveWindowSize
= 10 * 1024 * 1024; // 10MB
62 // Set the maximum number of undecryptable packets the connection will store.
63 const int32 kMaxUndecryptablePackets
= 100;
65 void HistogramCreateSessionFailure(enum CreateSessionFailure error
) {
66 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.CreationError", error
,
70 bool IsEcdsaSupported() {
72 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
79 QuicConfig
InitializeQuicConfig(const QuicTagVector
& connection_options
) {
81 config
.SetIdleConnectionStateLifetime(
82 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
),
83 QuicTime::Delta::FromSeconds(kIdleConnectionTimeoutSeconds
));
84 config
.SetConnectionOptionsToSend(connection_options
);
88 class DefaultPacketWriterFactory
: public QuicConnection::PacketWriterFactory
{
90 explicit DefaultPacketWriterFactory(DatagramClientSocket
* socket
)
92 ~DefaultPacketWriterFactory() override
{}
94 QuicPacketWriter
* Create(QuicConnection
* connection
) const override
;
97 DatagramClientSocket
* socket_
;
100 QuicPacketWriter
* DefaultPacketWriterFactory::Create(
101 QuicConnection
* connection
) const {
102 scoped_ptr
<QuicDefaultPacketWriter
> writer(
103 new QuicDefaultPacketWriter(socket_
));
104 writer
->SetConnection(connection
);
105 return writer
.release();
110 QuicStreamFactory::IpAliasKey::IpAliasKey() {}
112 QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint
,
114 : ip_endpoint(ip_endpoint
),
115 is_https(is_https
) {}
117 QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
119 bool QuicStreamFactory::IpAliasKey::operator<(
120 const QuicStreamFactory::IpAliasKey
& other
) const {
121 if (!(ip_endpoint
== other
.ip_endpoint
)) {
122 return ip_endpoint
< other
.ip_endpoint
;
124 return is_https
< other
.is_https
;
127 bool QuicStreamFactory::IpAliasKey::operator==(
128 const QuicStreamFactory::IpAliasKey
& other
) const {
129 return is_https
== other
.is_https
&&
130 ip_endpoint
== other
.ip_endpoint
;
133 // Responsible for creating a new QUIC session to the specified server, and
134 // for notifying any associated requests when complete.
135 class QuicStreamFactory::Job
{
137 Job(QuicStreamFactory
* factory
,
138 HostResolver
* host_resolver
,
139 const HostPortPair
& host_port_pair
,
141 bool was_alternate_protocol_recently_broken
,
142 PrivacyMode privacy_mode
,
144 QuicServerInfo
* server_info
,
145 const BoundNetLog
& net_log
);
147 // Creates a new job to handle the resumption of for connecting an
149 Job(QuicStreamFactory
* factory
,
150 HostResolver
* host_resolver
,
151 QuicClientSession
* session
,
152 QuicServerId server_id
);
156 int Run(const CompletionCallback
& callback
);
160 int DoResolveHostComplete(int rv
);
161 int DoLoadServerInfo();
162 int DoLoadServerInfoComplete(int rv
);
164 int DoResumeConnect();
165 int DoConnectComplete(int rv
);
167 void OnIOComplete(int rv
);
169 void RunAuxilaryJob();
173 void CancelWaitForDataReadyCallback();
175 const QuicServerId
server_id() const { return server_id_
; }
177 base::WeakPtr
<Job
> GetWeakPtr() { return weak_factory_
.GetWeakPtr(); }
183 STATE_RESOLVE_HOST_COMPLETE
,
184 STATE_LOAD_SERVER_INFO
,
185 STATE_LOAD_SERVER_INFO_COMPLETE
,
187 STATE_RESUME_CONNECT
,
188 STATE_CONNECT_COMPLETE
,
192 QuicStreamFactory
* factory_
;
193 SingleRequestHostResolver host_resolver_
;
194 QuicServerId server_id_
;
196 bool was_alternate_protocol_recently_broken_
;
197 scoped_ptr
<QuicServerInfo
> server_info_
;
198 bool started_another_job_
;
199 const BoundNetLog net_log_
;
200 QuicClientSession
* session_
;
201 CompletionCallback callback_
;
202 AddressList address_list_
;
203 base::TimeTicks disk_cache_load_start_time_
;
204 base::TimeTicks dns_resolution_start_time_
;
205 base::WeakPtrFactory
<Job
> weak_factory_
;
206 DISALLOW_COPY_AND_ASSIGN(Job
);
209 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
210 HostResolver
* host_resolver
,
211 const HostPortPair
& host_port_pair
,
213 bool was_alternate_protocol_recently_broken
,
214 PrivacyMode privacy_mode
,
216 QuicServerInfo
* server_info
,
217 const BoundNetLog
& net_log
)
218 : io_state_(STATE_RESOLVE_HOST
),
220 host_resolver_(host_resolver
),
221 server_id_(host_port_pair
, is_https
, privacy_mode
),
223 was_alternate_protocol_recently_broken_(
224 was_alternate_protocol_recently_broken
),
225 server_info_(server_info
),
226 started_another_job_(false),
229 weak_factory_(this) {
232 QuicStreamFactory::Job::Job(QuicStreamFactory
* factory
,
233 HostResolver
* host_resolver
,
234 QuicClientSession
* session
,
235 QuicServerId server_id
)
236 : io_state_(STATE_RESUME_CONNECT
),
238 host_resolver_(host_resolver
), // unused
239 server_id_(server_id
),
240 is_post_(false), // unused
241 was_alternate_protocol_recently_broken_(false), // unused
242 started_another_job_(false), // unused
243 net_log_(session
->net_log()), // unused
245 weak_factory_(this) {
248 QuicStreamFactory::Job::~Job() {
249 // If disk cache has a pending WaitForDataReadyCallback, cancel that callback.
251 server_info_
->ResetWaitForDataReadyCallback();
254 int QuicStreamFactory::Job::Run(const CompletionCallback
& callback
) {
256 if (rv
== ERR_IO_PENDING
)
257 callback_
= callback
;
259 return rv
> 0 ? OK
: rv
;
262 int QuicStreamFactory::Job::DoLoop(int rv
) {
264 IoState state
= io_state_
;
265 io_state_
= STATE_NONE
;
267 case STATE_RESOLVE_HOST
:
269 rv
= DoResolveHost();
271 case STATE_RESOLVE_HOST_COMPLETE
:
272 rv
= DoResolveHostComplete(rv
);
274 case STATE_LOAD_SERVER_INFO
:
276 rv
= DoLoadServerInfo();
278 case STATE_LOAD_SERVER_INFO_COMPLETE
:
279 rv
= DoLoadServerInfoComplete(rv
);
285 case STATE_RESUME_CONNECT
:
287 rv
= DoResumeConnect();
289 case STATE_CONNECT_COMPLETE
:
290 rv
= DoConnectComplete(rv
);
293 NOTREACHED() << "io_state_: " << io_state_
;
296 } while (io_state_
!= STATE_NONE
&& rv
!= ERR_IO_PENDING
);
300 void QuicStreamFactory::Job::OnIOComplete(int rv
) {
301 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
302 tracked_objects::ScopedTracker
tracking_profile1(
303 FROM_HERE_WITH_EXPLICIT_FUNCTION(
304 "422516 QuicStreamFactory::Job::OnIOComplete1"));
308 tracked_objects::ScopedTracker
tracking_profile2(
309 FROM_HERE_WITH_EXPLICIT_FUNCTION(
310 "422516 QuicStreamFactory::Job::OnIOComplete2"));
312 if (rv
!= ERR_IO_PENDING
&& !callback_
.is_null()) {
317 void QuicStreamFactory::Job::RunAuxilaryJob() {
318 int rv
= Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
319 base::Unretained(factory_
), this));
320 if (rv
!= ERR_IO_PENDING
)
321 factory_
->OnJobComplete(this, rv
);
324 void QuicStreamFactory::Job::Cancel() {
327 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED
);
330 void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() {
331 // If we are waiting for WaitForDataReadyCallback, then cancel the callback.
332 if (io_state_
!= STATE_LOAD_SERVER_INFO_COMPLETE
)
334 server_info_
->CancelWaitForDataReadyCallback();
338 int QuicStreamFactory::Job::DoResolveHost() {
339 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
340 tracked_objects::ScopedTracker
tracking_profile(
341 FROM_HERE_WITH_EXPLICIT_FUNCTION(
342 "422516 QuicStreamFactory::Job::DoResolveHost"));
344 // Start loading the data now, and wait for it after we resolve the host.
346 server_info_
->Start();
349 io_state_
= STATE_RESOLVE_HOST_COMPLETE
;
350 dns_resolution_start_time_
= base::TimeTicks::Now();
351 return host_resolver_
.Resolve(
352 HostResolver::RequestInfo(server_id_
.host_port_pair()), DEFAULT_PRIORITY
,
354 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()),
358 int QuicStreamFactory::Job::DoResolveHostComplete(int rv
) {
359 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
360 tracked_objects::ScopedTracker
tracking_profile(
361 FROM_HERE_WITH_EXPLICIT_FUNCTION(
362 "422516 QuicStreamFactory::Job::DoResolveHostComplete"));
364 UMA_HISTOGRAM_TIMES("Net.QuicSession.HostResolutionTime",
365 base::TimeTicks::Now() - dns_resolution_start_time_
);
369 DCHECK(!factory_
->HasActiveSession(server_id_
));
371 // Inform the factory of this resolution, which will set up
372 // a session alias, if possible.
373 if (factory_
->OnResolution(server_id_
, address_list_
)) {
378 io_state_
= STATE_LOAD_SERVER_INFO
;
380 io_state_
= STATE_CONNECT
;
384 int QuicStreamFactory::Job::DoLoadServerInfo() {
385 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
386 tracked_objects::ScopedTracker
tracking_profile(
387 FROM_HERE_WITH_EXPLICIT_FUNCTION(
388 "422516 QuicStreamFactory::Job::DoLoadServerInfo"));
390 io_state_
= STATE_LOAD_SERVER_INFO_COMPLETE
;
392 DCHECK(server_info_
);
394 // To mitigate the effects of disk cache taking too long to load QUIC server
395 // information, set up a timer to cancel WaitForDataReady's callback.
396 int64 load_server_info_timeout_ms
= factory_
->load_server_info_timeout_ms_
;
397 if (factory_
->load_server_info_timeout_srtt_multiplier_
> 0) {
398 DCHECK_EQ(0, load_server_info_timeout_ms
);
399 load_server_info_timeout_ms
=
400 (factory_
->load_server_info_timeout_srtt_multiplier_
*
401 factory_
->GetServerNetworkStatsSmoothedRttInMicroseconds(server_id_
)) /
404 if (load_server_info_timeout_ms
> 0) {
405 factory_
->task_runner_
->PostDelayedTask(
407 base::Bind(&QuicStreamFactory::Job::CancelWaitForDataReadyCallback
,
409 base::TimeDelta::FromMilliseconds(load_server_info_timeout_ms
));
412 disk_cache_load_start_time_
= base::TimeTicks::Now();
413 int rv
= server_info_
->WaitForDataReady(
414 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
415 if (rv
== ERR_IO_PENDING
&& factory_
->enable_connection_racing()) {
416 // If we are waiting to load server config from the disk cache, then start
418 started_another_job_
= true;
419 factory_
->CreateAuxilaryJob(server_id_
, is_post_
, net_log_
);
424 int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv
) {
425 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
426 tracked_objects::ScopedTracker
tracking_profile(
427 FROM_HERE_WITH_EXPLICIT_FUNCTION(
428 "422516 QuicStreamFactory::Job::DoLoadServerInfoComplete"));
430 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
431 base::TimeTicks::Now() - disk_cache_load_start_time_
);
434 server_info_
.reset();
436 if (started_another_job_
&&
437 (!server_info_
|| server_info_
->state().server_config
.empty() ||
438 !factory_
->CryptoConfigCacheIsEmpty(server_id_
))) {
439 // If we have started another job and if we didn't load the server config
440 // from the disk cache or if we have received a new server config from the
441 // server, then cancel the current job.
442 io_state_
= STATE_NONE
;
443 return ERR_CONNECTION_CLOSED
;
446 io_state_
= STATE_CONNECT
;
450 int QuicStreamFactory::Job::DoConnect() {
451 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
452 tracked_objects::ScopedTracker
tracking_profile(
453 FROM_HERE_WITH_EXPLICIT_FUNCTION(
454 "422516 QuicStreamFactory::Job::DoConnect"));
456 io_state_
= STATE_CONNECT_COMPLETE
;
458 int rv
= factory_
->CreateSession(server_id_
, server_info_
.Pass(),
459 address_list_
, net_log_
, &session_
);
461 DCHECK(rv
!= ERR_IO_PENDING
);
466 if (!session_
->connection()->connected()) {
467 return ERR_CONNECTION_CLOSED
;
470 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
471 tracked_objects::ScopedTracker
tracking_profile1(
472 FROM_HERE_WITH_EXPLICIT_FUNCTION(
473 "422516 QuicStreamFactory::Job::DoConnect1"));
475 session_
->StartReading();
476 if (!session_
->connection()->connected()) {
477 return ERR_QUIC_PROTOCOL_ERROR
;
479 bool require_confirmation
=
480 factory_
->require_confirmation() || is_post_
||
481 was_alternate_protocol_recently_broken_
;
483 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
484 tracked_objects::ScopedTracker
tracking_profile2(
485 FROM_HERE_WITH_EXPLICIT_FUNCTION(
486 "422516 QuicStreamFactory::Job::DoConnect2"));
488 rv
= session_
->CryptoConnect(
489 require_confirmation
,
490 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
494 int QuicStreamFactory::Job::DoResumeConnect() {
495 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
496 tracked_objects::ScopedTracker
tracking_profile(
497 FROM_HERE_WITH_EXPLICIT_FUNCTION(
498 "422516 QuicStreamFactory::Job::DoResumeConnect"));
500 io_state_
= STATE_CONNECT_COMPLETE
;
502 int rv
= session_
->ResumeCryptoConnect(
503 base::Bind(&QuicStreamFactory::Job::OnIOComplete
, GetWeakPtr()));
508 int QuicStreamFactory::Job::DoConnectComplete(int rv
) {
509 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
510 tracked_objects::ScopedTracker
tracking_profile(
511 FROM_HERE_WITH_EXPLICIT_FUNCTION(
512 "422516 QuicStreamFactory::Job::DoConnectComplete"));
517 DCHECK(!factory_
->HasActiveSession(server_id_
));
518 // There may well now be an active session for this IP. If so, use the
519 // existing session instead.
520 AddressList
address(session_
->connection()->peer_address());
521 if (factory_
->OnResolution(server_id_
, address
)) {
522 session_
->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED
);
527 factory_
->ActivateSession(server_id_
, session_
);
532 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory
* factory
)
533 : factory_(factory
) {}
535 QuicStreamRequest::~QuicStreamRequest() {
536 if (factory_
&& !callback_
.is_null())
537 factory_
->CancelRequest(this);
540 int QuicStreamRequest::Request(const HostPortPair
& host_port_pair
,
542 PrivacyMode privacy_mode
,
543 base::StringPiece method
,
544 const BoundNetLog
& net_log
,
545 const CompletionCallback
& callback
) {
547 DCHECK(callback_
.is_null());
549 int rv
= factory_
->Create(host_port_pair
, is_https
, privacy_mode
, method
,
551 if (rv
== ERR_IO_PENDING
) {
552 host_port_pair_
= host_port_pair
;
553 is_https_
= is_https
;
555 callback_
= callback
;
564 void QuicStreamRequest::set_stream(scoped_ptr
<QuicHttpStream
> stream
) {
566 stream_
= stream
.Pass();
569 void QuicStreamRequest::OnRequestComplete(int rv
) {
574 scoped_ptr
<QuicHttpStream
> QuicStreamRequest::ReleaseStream() {
576 return stream_
.Pass();
579 QuicStreamFactory::QuicStreamFactory(
580 HostResolver
* host_resolver
,
581 ClientSocketFactory
* client_socket_factory
,
582 base::WeakPtr
<HttpServerProperties
> http_server_properties
,
583 CertVerifier
* cert_verifier
,
584 ChannelIDService
* channel_id_service
,
585 TransportSecurityState
* transport_security_state
,
586 QuicCryptoClientStreamFactory
* quic_crypto_client_stream_factory
,
587 QuicRandom
* random_generator
,
589 size_t max_packet_length
,
590 const std::string
& user_agent_id
,
591 const QuicVersionVector
& supported_versions
,
592 bool enable_port_selection
,
593 bool always_require_handshake_confirmation
,
594 bool disable_connection_pooling
,
595 int load_server_info_timeout
,
596 float load_server_info_timeout_srtt_multiplier
,
597 bool enable_truncated_connection_ids
,
598 bool enable_connection_racing
,
599 bool disable_disk_cache
,
600 const QuicTagVector
& connection_options
)
601 : require_confirmation_(true),
602 host_resolver_(host_resolver
),
603 client_socket_factory_(client_socket_factory
),
604 http_server_properties_(http_server_properties
),
605 transport_security_state_(transport_security_state
),
606 quic_server_info_factory_(nullptr),
607 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory
),
608 random_generator_(random_generator
),
610 max_packet_length_(max_packet_length
),
611 config_(InitializeQuicConfig(connection_options
)),
612 supported_versions_(supported_versions
),
613 enable_port_selection_(enable_port_selection
),
614 always_require_handshake_confirmation_(
615 always_require_handshake_confirmation
),
616 disable_connection_pooling_(disable_connection_pooling
),
617 load_server_info_timeout_ms_(load_server_info_timeout
),
618 load_server_info_timeout_srtt_multiplier_(
619 load_server_info_timeout_srtt_multiplier
),
620 enable_truncated_connection_ids_(enable_truncated_connection_ids
),
621 enable_connection_racing_(enable_connection_racing
),
622 disable_disk_cache_(disable_disk_cache
),
623 port_seed_(random_generator_
->RandUint64()),
624 check_persisted_supports_quic_(true),
625 task_runner_(nullptr),
626 weak_factory_(this) {
627 DCHECK(transport_security_state_
);
628 // TODO(michaeln): Remove ScopedTracker below once crbug.com/454983 is fixed
629 tracked_objects::ScopedTracker
tracking_profile(
630 FROM_HERE_WITH_EXPLICIT_FUNCTION(
631 "454983 QuicStreamFactory::QuicStreamFactory"));
632 crypto_config_
.set_user_agent_id(user_agent_id
);
633 crypto_config_
.AddCanonicalSuffix(".c.youtube.com");
634 crypto_config_
.AddCanonicalSuffix(".googlevideo.com");
635 crypto_config_
.SetProofVerifier(
636 new ProofVerifierChromium(cert_verifier
, transport_security_state
));
637 crypto_config_
.SetChannelIDSource(
638 new ChannelIDSourceChromium(channel_id_service
));
640 if (cpu
.has_aesni() && cpu
.has_avx())
641 crypto_config_
.PreferAesGcm();
642 if (!IsEcdsaSupported())
643 crypto_config_
.DisableEcdsa();
646 QuicStreamFactory::~QuicStreamFactory() {
647 CloseAllSessions(ERR_ABORTED
);
648 while (!all_sessions_
.empty()) {
649 delete all_sessions_
.begin()->first
;
650 all_sessions_
.erase(all_sessions_
.begin());
652 while (!active_jobs_
.empty()) {
653 const QuicServerId server_id
= active_jobs_
.begin()->first
;
654 STLDeleteElements(&(active_jobs_
[server_id
]));
655 active_jobs_
.erase(server_id
);
659 void QuicStreamFactory::set_require_confirmation(bool require_confirmation
) {
660 require_confirmation_
= require_confirmation
;
661 if (http_server_properties_
&& (!(local_address_
== IPEndPoint()))) {
662 http_server_properties_
->SetSupportsQuic(!require_confirmation
,
663 local_address_
.address());
667 int QuicStreamFactory::Create(const HostPortPair
& host_port_pair
,
669 PrivacyMode privacy_mode
,
670 base::StringPiece method
,
671 const BoundNetLog
& net_log
,
672 QuicStreamRequest
* request
) {
673 QuicServerId
server_id(host_port_pair
, is_https
, privacy_mode
);
674 if (HasActiveSession(server_id
)) {
675 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
679 if (HasActiveJob(server_id
)) {
680 active_requests_
[request
] = server_id
;
681 job_requests_map_
[server_id
].insert(request
);
682 return ERR_IO_PENDING
;
685 // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
686 // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
688 task_runner_
= base::MessageLoop::current()->message_loop_proxy().get();
690 QuicServerInfo
* quic_server_info
= nullptr;
691 if (quic_server_info_factory_
) {
692 bool load_from_disk_cache
= !disable_disk_cache_
;
693 if (http_server_properties_
) {
694 const AlternateProtocolMap
& alternate_protocol_map
=
695 http_server_properties_
->alternate_protocol_map();
696 AlternateProtocolMap::const_iterator it
=
697 alternate_protocol_map
.Peek(server_id
.host_port_pair());
698 if (it
== alternate_protocol_map
.end() || it
->second
.protocol
!= QUIC
) {
699 // If there is no entry for QUIC, consider that as a new server and
700 // don't wait for Cache thread to load the data for that server.
701 load_from_disk_cache
= false;
704 if (load_from_disk_cache
&& CryptoConfigCacheIsEmpty(server_id
)) {
705 quic_server_info
= quic_server_info_factory_
->GetForServer(server_id
);
709 scoped_ptr
<Job
> job(new Job(this, host_resolver_
, host_port_pair
, is_https
,
710 WasAlternateProtocolRecentlyBroken(server_id
),
711 privacy_mode
, method
== "POST" /* is_post */,
712 quic_server_info
, net_log
));
713 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
714 base::Unretained(this), job
.get()));
715 if (rv
== ERR_IO_PENDING
) {
716 active_requests_
[request
] = server_id
;
717 job_requests_map_
[server_id
].insert(request
);
718 active_jobs_
[server_id
].insert(job
.release());
722 DCHECK(HasActiveSession(server_id
));
723 request
->set_stream(CreateIfSessionExists(server_id
, net_log
));
728 void QuicStreamFactory::CreateAuxilaryJob(const QuicServerId server_id
,
730 const BoundNetLog
& net_log
) {
731 Job
* aux_job
= new Job(this, host_resolver_
, server_id
.host_port_pair(),
732 server_id
.is_https(),
733 WasAlternateProtocolRecentlyBroken(server_id
),
734 server_id
.privacy_mode(), is_post
, nullptr, net_log
);
735 active_jobs_
[server_id
].insert(aux_job
);
736 task_runner_
->PostTask(FROM_HERE
,
737 base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob
,
738 aux_job
->GetWeakPtr()));
741 bool QuicStreamFactory::OnResolution(
742 const QuicServerId
& server_id
,
743 const AddressList
& address_list
) {
744 DCHECK(!HasActiveSession(server_id
));
745 if (disable_connection_pooling_
) {
748 for (const IPEndPoint
& address
: address_list
) {
749 const IpAliasKey
ip_alias_key(address
, server_id
.is_https());
750 if (!ContainsKey(ip_aliases_
, ip_alias_key
))
753 const SessionSet
& sessions
= ip_aliases_
[ip_alias_key
];
754 for (QuicClientSession
* session
: sessions
) {
755 if (!session
->CanPool(server_id
.host(), server_id
.privacy_mode()))
757 active_sessions_
[server_id
] = session
;
758 session_aliases_
[session
].insert(server_id
);
765 void QuicStreamFactory::OnJobComplete(Job
* job
, int rv
) {
766 QuicServerId server_id
= job
->server_id();
768 JobSet
* jobs
= &(active_jobs_
[server_id
]);
769 if (jobs
->size() > 1) {
770 // If there is another pending job, then we can delete this job and let
771 // the other job handle the request.
780 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
781 tracked_objects::ScopedTracker
tracking_profile1(
782 FROM_HERE_WITH_EXPLICIT_FUNCTION(
783 "422516 QuicStreamFactory::OnJobComplete1"));
785 if (!always_require_handshake_confirmation_
)
786 set_require_confirmation(false);
788 // Create all the streams, but do not notify them yet.
789 for (QuicStreamRequest
* request
: job_requests_map_
[server_id
]) {
790 DCHECK(HasActiveSession(server_id
));
791 request
->set_stream(CreateIfSessionExists(server_id
, request
->net_log()));
795 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
796 tracked_objects::ScopedTracker
tracking_profile2(
797 FROM_HERE_WITH_EXPLICIT_FUNCTION(
798 "422516 QuicStreamFactory::OnJobComplete2"));
800 while (!job_requests_map_
[server_id
].empty()) {
801 RequestSet::iterator it
= job_requests_map_
[server_id
].begin();
802 QuicStreamRequest
* request
= *it
;
803 job_requests_map_
[server_id
].erase(it
);
804 active_requests_
.erase(request
);
805 // Even though we're invoking callbacks here, we don't need to worry
806 // about |this| being deleted, because the factory is owned by the
807 // profile which can not be deleted via callbacks.
808 request
->OnRequestComplete(rv
);
811 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
812 tracked_objects::ScopedTracker
tracking_profile3(
813 FROM_HERE_WITH_EXPLICIT_FUNCTION(
814 "422516 QuicStreamFactory::OnJobComplete3"));
816 for (Job
* other_job
: active_jobs_
[server_id
]) {
817 if (other_job
!= job
)
821 STLDeleteElements(&(active_jobs_
[server_id
]));
822 active_jobs_
.erase(server_id
);
823 job_requests_map_
.erase(server_id
);
826 // Returns a newly created QuicHttpStream owned by the caller, if a
827 // matching session already exists. Returns nullptr otherwise.
828 scoped_ptr
<QuicHttpStream
> QuicStreamFactory::CreateIfSessionExists(
829 const QuicServerId
& server_id
,
830 const BoundNetLog
& net_log
) {
831 if (!HasActiveSession(server_id
)) {
832 DVLOG(1) << "No active session";
833 return scoped_ptr
<QuicHttpStream
>();
836 QuicClientSession
* session
= active_sessions_
[server_id
];
838 return scoped_ptr
<QuicHttpStream
>(
839 new QuicHttpStream(session
->GetWeakPtr()));
842 void QuicStreamFactory::OnIdleSession(QuicClientSession
* session
) {
845 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession
* session
) {
846 const AliasSet
& aliases
= session_aliases_
[session
];
847 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
849 DCHECK(active_sessions_
.count(*it
));
850 DCHECK_EQ(session
, active_sessions_
[*it
]);
851 // Track sessions which have recently gone away so that we can disable
853 if (session
->goaway_received()) {
854 gone_away_aliases_
.insert(*it
);
857 active_sessions_
.erase(*it
);
858 ProcessGoingAwaySession(session
, *it
, true);
860 ProcessGoingAwaySession(session
, all_sessions_
[session
], false);
861 if (!aliases
.empty()) {
862 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
863 aliases
.begin()->is_https());
864 ip_aliases_
[ip_alias_key
].erase(session
);
865 if (ip_aliases_
[ip_alias_key
].empty()) {
866 ip_aliases_
.erase(ip_alias_key
);
869 session_aliases_
.erase(session
);
872 void QuicStreamFactory::OnSessionClosed(QuicClientSession
* session
) {
873 DCHECK_EQ(0u, session
->GetNumOpenStreams());
874 OnSessionGoingAway(session
);
876 all_sessions_
.erase(session
);
879 void QuicStreamFactory::OnSessionConnectTimeout(
880 QuicClientSession
* session
) {
881 const AliasSet
& aliases
= session_aliases_
[session
];
882 for (AliasSet::const_iterator it
= aliases
.begin(); it
!= aliases
.end();
884 DCHECK(active_sessions_
.count(*it
));
885 DCHECK_EQ(session
, active_sessions_
[*it
]);
886 active_sessions_
.erase(*it
);
889 if (aliases
.empty()) {
893 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
894 aliases
.begin()->is_https());
895 ip_aliases_
[ip_alias_key
].erase(session
);
896 if (ip_aliases_
[ip_alias_key
].empty()) {
897 ip_aliases_
.erase(ip_alias_key
);
899 QuicServerId server_id
= *aliases
.begin();
900 session_aliases_
.erase(session
);
901 Job
* job
= new Job(this, host_resolver_
, session
, server_id
);
902 active_jobs_
[server_id
].insert(job
);
903 int rv
= job
->Run(base::Bind(&QuicStreamFactory::OnJobComplete
,
904 base::Unretained(this), job
));
905 DCHECK_EQ(ERR_IO_PENDING
, rv
);
908 void QuicStreamFactory::CancelRequest(QuicStreamRequest
* request
) {
909 DCHECK(ContainsKey(active_requests_
, request
));
910 QuicServerId server_id
= active_requests_
[request
];
911 job_requests_map_
[server_id
].erase(request
);
912 active_requests_
.erase(request
);
915 void QuicStreamFactory::CloseAllSessions(int error
) {
916 while (!active_sessions_
.empty()) {
917 size_t initial_size
= active_sessions_
.size();
918 active_sessions_
.begin()->second
->CloseSessionOnError(error
);
919 DCHECK_NE(initial_size
, active_sessions_
.size());
921 while (!all_sessions_
.empty()) {
922 size_t initial_size
= all_sessions_
.size();
923 all_sessions_
.begin()->first
->CloseSessionOnError(error
);
924 DCHECK_NE(initial_size
, all_sessions_
.size());
926 DCHECK(all_sessions_
.empty());
929 base::Value
* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
930 base::ListValue
* list
= new base::ListValue();
932 for (SessionMap::const_iterator it
= active_sessions_
.begin();
933 it
!= active_sessions_
.end(); ++it
) {
934 const QuicServerId
& server_id
= it
->first
;
935 QuicClientSession
* session
= it
->second
;
936 const AliasSet
& aliases
= session_aliases_
.find(session
)->second
;
937 // Only add a session to the list once.
938 if (server_id
== *aliases
.begin()) {
939 std::set
<HostPortPair
> hosts
;
940 for (AliasSet::const_iterator alias_it
= aliases
.begin();
941 alias_it
!= aliases
.end(); ++alias_it
) {
942 hosts
.insert(alias_it
->host_port_pair());
944 list
->Append(session
->GetInfoAsValue(hosts
));
950 void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
951 crypto_config_
.ClearCachedStates();
954 void QuicStreamFactory::OnIPAddressChanged() {
955 CloseAllSessions(ERR_NETWORK_CHANGED
);
956 set_require_confirmation(true);
959 void QuicStreamFactory::OnCertAdded(const X509Certificate
* cert
) {
960 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
963 void QuicStreamFactory::OnCACertChanged(const X509Certificate
* cert
) {
964 // We should flush the sessions if we removed trust from a
965 // cert, because a previously trusted server may have become
968 // We should not flush the sessions if we added trust to a cert.
970 // Since the OnCACertChanged method doesn't tell us what
971 // kind of change it is, we have to flush the socket
973 CloseAllSessions(ERR_CERT_DATABASE_CHANGED
);
976 bool QuicStreamFactory::HasActiveSession(
977 const QuicServerId
& server_id
) const {
978 return ContainsKey(active_sessions_
, server_id
);
981 bool QuicStreamFactory::HasActiveJob(const QuicServerId
& key
) const {
982 return ContainsKey(active_jobs_
, key
);
985 int QuicStreamFactory::CreateSession(
986 const QuicServerId
& server_id
,
987 scoped_ptr
<QuicServerInfo
> server_info
,
988 const AddressList
& address_list
,
989 const BoundNetLog
& net_log
,
990 QuicClientSession
** session
) {
991 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
992 tracked_objects::ScopedTracker
tracking_profile1(
993 FROM_HERE_WITH_EXPLICIT_FUNCTION(
994 "422516 QuicStreamFactory::CreateSession1"));
996 bool enable_port_selection
= enable_port_selection_
;
997 if (enable_port_selection
&&
998 ContainsKey(gone_away_aliases_
, server_id
)) {
999 // Disable port selection when the server is going away.
1000 // There is no point in trying to return to the same server, if
1001 // that server is no longer handling requests.
1002 enable_port_selection
= false;
1003 gone_away_aliases_
.erase(server_id
);
1006 QuicConnectionId connection_id
= random_generator_
->RandUint64();
1007 IPEndPoint addr
= *address_list
.begin();
1008 scoped_refptr
<PortSuggester
> port_suggester
=
1009 new PortSuggester(server_id
.host_port_pair(), port_seed_
);
1010 DatagramSocket::BindType bind_type
= enable_port_selection
?
1011 DatagramSocket::RANDOM_BIND
: // Use our callback.
1012 DatagramSocket::DEFAULT_BIND
; // Use OS to randomize.
1013 scoped_ptr
<DatagramClientSocket
> socket(
1014 client_socket_factory_
->CreateDatagramClientSocket(
1016 base::Bind(&PortSuggester::SuggestPort
, port_suggester
),
1017 net_log
.net_log(), net_log
.source()));
1019 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1020 tracked_objects::ScopedTracker
tracking_profile2(
1021 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1022 "422516 QuicStreamFactory::CreateSession2"));
1024 int rv
= socket
->Connect(addr
);
1026 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1027 tracked_objects::ScopedTracker
tracking_profile3(
1028 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1029 "422516 QuicStreamFactory::CreateSession3"));
1032 HistogramCreateSessionFailure(CREATION_ERROR_CONNECTING_SOCKET
);
1035 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
1036 port_suggester
->call_count());
1037 if (enable_port_selection
) {
1038 DCHECK_LE(1u, port_suggester
->call_count());
1040 DCHECK_EQ(0u, port_suggester
->call_count());
1043 // We should adaptively set this buffer size, but for now, we'll use a size
1044 // that is more than large enough for a full receive window, and yet
1045 // does not consume "too much" memory. If we see bursty packet loss, we may
1046 // revisit this setting and test for its impact.
1047 const int32 kSocketBufferSize
=
1048 static_cast<int32
>(kDefaultSocketReceiveBuffer
);
1049 rv
= socket
->SetReceiveBufferSize(kSocketBufferSize
);
1051 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER
);
1054 // Set a buffer large enough to contain the initial CWND's worth of packet
1055 // to work around the problem with CHLO packets being sent out with the
1056 // wrong encryption level, when the send buffer is full.
1057 rv
= socket
->SetSendBufferSize(kMaxPacketSize
* 20);
1059 HistogramCreateSessionFailure(CREATION_ERROR_SETTING_SEND_BUFFER
);
1063 socket
->GetLocalAddress(&local_address_
);
1064 if (check_persisted_supports_quic_
&& http_server_properties_
) {
1065 check_persisted_supports_quic_
= false;
1066 IPAddressNumber last_address
;
1067 if (http_server_properties_
->GetSupportsQuic(&last_address
) &&
1068 last_address
== local_address_
.address()) {
1069 require_confirmation_
= false;
1073 DefaultPacketWriterFactory
packet_writer_factory(socket
.get());
1075 if (!helper_
.get()) {
1076 helper_
.reset(new QuicConnectionHelper(
1077 base::MessageLoop::current()->message_loop_proxy().get(),
1078 clock_
.get(), random_generator_
));
1081 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1082 tracked_objects::ScopedTracker
tracking_profile4(
1083 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1084 "422516 QuicStreamFactory::CreateSession4"));
1086 QuicConnection
* connection
= new QuicConnection(connection_id
,
1089 packet_writer_factory
,
1090 true /* owns_writer */,
1091 false /* is_server */,
1092 server_id
.is_https(),
1093 supported_versions_
);
1094 connection
->set_max_packet_length(max_packet_length_
);
1096 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1097 tracked_objects::ScopedTracker
tracking_profile5(
1098 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1099 "422516 QuicStreamFactory::CreateSession5"));
1101 InitializeCachedStateInCryptoConfig(server_id
, server_info
);
1103 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1104 tracked_objects::ScopedTracker
tracking_profile51(
1105 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1106 "422516 QuicStreamFactory::CreateSession51"));
1108 QuicConfig config
= config_
;
1110 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1111 tracked_objects::ScopedTracker
tracking_profile52(
1112 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1113 "422516 QuicStreamFactory::CreateSession52"));
1115 config
.set_max_undecryptable_packets(kMaxUndecryptablePackets
);
1117 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1118 tracked_objects::ScopedTracker
tracking_profile53(
1119 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1120 "422516 QuicStreamFactory::CreateSession53"));
1122 config
.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize
);
1124 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1125 tracked_objects::ScopedTracker
tracking_profile54(
1126 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1127 "422516 QuicStreamFactory::CreateSession54"));
1129 config
.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize
);
1131 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1132 tracked_objects::ScopedTracker
tracking_profile55(
1133 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1134 "422516 QuicStreamFactory::CreateSession55"));
1136 int64 srtt
= GetServerNetworkStatsSmoothedRttInMicroseconds(server_id
);
1138 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1139 tracked_objects::ScopedTracker
tracking_profile56(
1140 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1141 "422516 QuicStreamFactory::CreateSession56"));
1144 config
.SetInitialRoundTripTimeUsToSend(static_cast<uint32
>(srtt
));
1146 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1147 tracked_objects::ScopedTracker
tracking_profile57(
1148 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1149 "422516 QuicStreamFactory::CreateSession57"));
1151 if (enable_truncated_connection_ids_
)
1152 config
.SetBytesForConnectionIdToSend(0);
1154 if (quic_server_info_factory_
&& !server_info
) {
1155 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1156 tracked_objects::ScopedTracker
tracking_profile6(
1157 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1158 "422516 QuicStreamFactory::CreateSession6"));
1160 // Start the disk cache loading so that we can persist the newer QUIC server
1161 // information and/or inform the disk cache that we have reused
1163 server_info
.reset(quic_server_info_factory_
->GetForServer(server_id
));
1164 server_info
->Start();
1167 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1168 tracked_objects::ScopedTracker
tracking_profile61(
1169 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1170 "422516 QuicStreamFactory::CreateSession61"));
1172 *session
= new QuicClientSession(
1173 connection
, socket
.Pass(), this, transport_security_state_
,
1174 server_info
.Pass(), config
, network_connection_
.GetDescription(),
1175 base::MessageLoop::current()->message_loop_proxy().get(),
1178 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
1179 tracked_objects::ScopedTracker
tracking_profile62(
1180 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1181 "422516 QuicStreamFactory::CreateSession62"));
1183 all_sessions_
[*session
] = server_id
; // owning pointer
1185 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1186 tracked_objects::ScopedTracker
tracking_profile7(
1187 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1188 "422516 QuicStreamFactory::CreateSession7"));
1190 (*session
)->InitializeSession(server_id
, &crypto_config_
,
1191 quic_crypto_client_stream_factory_
);
1192 bool closed_during_initialize
=
1193 !ContainsKey(all_sessions_
, *session
) ||
1194 !(*session
)->connection()->connected();
1195 UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.ClosedDuringInitializeSession",
1196 closed_during_initialize
);
1197 if (closed_during_initialize
) {
1198 DLOG(DFATAL
) << "Session closed during initialize";
1200 return ERR_CONNECTION_CLOSED
;
1205 void QuicStreamFactory::ActivateSession(
1206 const QuicServerId
& server_id
,
1207 QuicClientSession
* session
) {
1208 DCHECK(!HasActiveSession(server_id
));
1209 UMA_HISTOGRAM_COUNTS("Net.QuicActiveSessions", active_sessions_
.size());
1210 active_sessions_
[server_id
] = session
;
1211 session_aliases_
[session
].insert(server_id
);
1212 const IpAliasKey
ip_alias_key(session
->connection()->peer_address(),
1213 server_id
.is_https());
1214 DCHECK(!ContainsKey(ip_aliases_
[ip_alias_key
], session
));
1215 ip_aliases_
[ip_alias_key
].insert(session
);
1218 int64
QuicStreamFactory::GetServerNetworkStatsSmoothedRttInMicroseconds(
1219 const QuicServerId
& server_id
) const {
1220 if (!http_server_properties_
)
1222 const ServerNetworkStats
* stats
=
1223 http_server_properties_
->GetServerNetworkStats(
1224 server_id
.host_port_pair());
1225 if (stats
== nullptr)
1227 return stats
->srtt
.InMicroseconds();
1230 bool QuicStreamFactory::WasAlternateProtocolRecentlyBroken(
1231 const QuicServerId
& server_id
) const {
1232 return http_server_properties_
&&
1233 http_server_properties_
->WasAlternateProtocolRecentlyBroken(
1234 server_id
.host_port_pair());
1237 bool QuicStreamFactory::CryptoConfigCacheIsEmpty(
1238 const QuicServerId
& server_id
) {
1239 QuicCryptoClientConfig::CachedState
* cached
=
1240 crypto_config_
.LookupOrCreate(server_id
);
1241 return cached
->IsEmpty();
1244 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
1245 const QuicServerId
& server_id
,
1246 const scoped_ptr
<QuicServerInfo
>& server_info
) {
1247 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1248 tracked_objects::ScopedTracker
tracking_profile1(
1249 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1250 "422516 QuicStreamFactory::InitializeCachedStateInCryptoConfig1"));
1252 // |server_info| will be NULL, if a non-empty server config already exists in
1253 // the memory cache. This is a minor optimization to avoid LookupOrCreate.
1257 QuicCryptoClientConfig::CachedState
* cached
=
1258 crypto_config_
.LookupOrCreate(server_id
);
1259 if (!cached
->IsEmpty())
1262 if (http_server_properties_
) {
1263 if (quic_supported_servers_at_startup_
.empty()) {
1264 for (const std::pair
<const HostPortPair
, AlternateProtocolInfo
>&
1265 key_value
: http_server_properties_
->alternate_protocol_map()) {
1266 if (key_value
.second
.protocol
== QUIC
) {
1267 quic_supported_servers_at_startup_
.insert(key_value
.first
);
1272 // TODO(rtenneti): Delete the following histogram after collecting stats.
1273 // If the AlternateProtocolMap contained an entry for this host, check if
1274 // the disk cache contained an entry for it.
1275 if (ContainsKey(quic_supported_servers_at_startup_
,
1276 server_id
.host_port_pair())) {
1277 UMA_HISTOGRAM_BOOLEAN(
1278 "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
1279 server_info
->state().server_config
.empty());
1283 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
1284 tracked_objects::ScopedTracker
tracking_profile2(
1285 FROM_HERE_WITH_EXPLICIT_FUNCTION(
1286 "422516 QuicStreamFactory::InitializeCachedStateInCryptoConfig2"));
1288 if (!cached
->Initialize(server_info
->state().server_config
,
1289 server_info
->state().source_address_token
,
1290 server_info
->state().certs
,
1291 server_info
->state().server_config_sig
,
1295 if (!server_id
.is_https()) {
1296 // Don't check the certificates for insecure QUIC.
1297 cached
->SetProofValid();
1301 void QuicStreamFactory::ProcessGoingAwaySession(
1302 QuicClientSession
* session
,
1303 const QuicServerId
& server_id
,
1304 bool session_was_active
) {
1305 if (!http_server_properties_
)
1308 const QuicConnectionStats
& stats
= session
->connection()->GetStats();
1309 if (session
->IsCryptoHandshakeConfirmed()) {
1310 ServerNetworkStats network_stats
;
1311 network_stats
.srtt
= base::TimeDelta::FromMicroseconds(stats
.srtt_us
);
1312 network_stats
.bandwidth_estimate
= stats
.estimated_bandwidth
;
1313 http_server_properties_
->SetServerNetworkStats(server_id
.host_port_pair(),
1318 UMA_HISTOGRAM_COUNTS("Net.QuicHandshakeNotConfirmedNumPacketsReceived",
1319 stats
.packets_received
);
1321 if (!session_was_active
)
1324 const HostPortPair
& server
= server_id
.host_port_pair();
1325 // Don't try to change the alternate-protocol state, if the
1326 // alternate-protocol state is unknown.
1327 const AlternateProtocolInfo alternate
=
1328 http_server_properties_
->GetAlternateProtocol(server
);
1329 if (alternate
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
)
1332 // TODO(rch): In the special case where the session has received no
1333 // packets from the peer, we should consider blacklisting this
1334 // differently so that we still race TCP but we don't consider the
1335 // session connected until the handshake has been confirmed.
1336 HistogramBrokenAlternateProtocolLocation(
1337 BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY
);
1338 DCHECK_EQ(QUIC
, alternate
.protocol
);
1340 // Since the session was active, there's no longer an
1341 // HttpStreamFactoryImpl::Job running which can mark it broken, unless the
1342 // TCP job also fails. So to avoid not using QUIC when we otherwise could,
1343 // we mark it as broken, and then immediately re-enable it. This leaves
1344 // QUIC as "recently broken" which means that 0-RTT will be disabled but
1345 // we'll still race.
1346 http_server_properties_
->SetBrokenAlternateProtocol(server
);
1347 http_server_properties_
->ClearAlternateProtocol(server
);
1348 http_server_properties_
->SetAlternateProtocol(
1349 server
, alternate
.port
, alternate
.protocol
, 1);
1351 http_server_properties_
->GetAlternateProtocol(server
).protocol
);
1352 DCHECK(http_server_properties_
->WasAlternateProtocolRecentlyBroken(