rAc - revert invalid suggestions to edit mode
[chromium-blink-merge.git] / net / quic / quic_stream_factory.cc
blobfdaeb0878c8710359ad92c9874d38aa13cc70da2
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"
7 #include <set>
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/metrics/histogram.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_util.h"
15 #include "base/values.h"
16 #include "net/base/net_errors.h"
17 #include "net/cert/cert_verifier.h"
18 #include "net/dns/host_resolver.h"
19 #include "net/dns/single_request_host_resolver.h"
20 #include "net/http/http_server_properties.h"
21 #include "net/quic/congestion_control/tcp_receiver.h"
22 #include "net/quic/crypto/proof_verifier_chromium.h"
23 #include "net/quic/crypto/quic_random.h"
24 #include "net/quic/crypto/quic_server_info.h"
25 #include "net/quic/port_suggester.h"
26 #include "net/quic/quic_client_session.h"
27 #include "net/quic/quic_clock.h"
28 #include "net/quic/quic_connection.h"
29 #include "net/quic/quic_connection_helper.h"
30 #include "net/quic/quic_crypto_client_stream_factory.h"
31 #include "net/quic/quic_default_packet_writer.h"
32 #include "net/quic/quic_http_stream.h"
33 #include "net/quic/quic_protocol.h"
34 #include "net/socket/client_socket_factory.h"
36 using std::string;
37 using std::vector;
39 namespace net {
41 // Responsible for creating a new QUIC session to the specified server, and
42 // for notifying any associated requests when complete.
43 class QuicStreamFactory::Job {
44 public:
45 Job(QuicStreamFactory* factory,
46 HostResolver* host_resolver,
47 const HostPortProxyPair& host_port_proxy_pair,
48 bool is_https,
49 base::StringPiece method,
50 CertVerifier* cert_verifier,
51 const BoundNetLog& net_log);
53 ~Job();
55 int Run(const CompletionCallback& callback);
57 int DoLoop(int rv);
58 int DoResolveHost();
59 int DoResolveHostComplete(int rv);
60 int DoConnect();
61 int DoConnectComplete(int rv);
63 void OnIOComplete(int rv);
65 CompletionCallback callback() {
66 return callback_;
69 const HostPortProxyPair& host_port_proxy_pair() const {
70 return host_port_proxy_pair_;
73 private:
74 enum IoState {
75 STATE_NONE,
76 STATE_RESOLVE_HOST,
77 STATE_RESOLVE_HOST_COMPLETE,
78 STATE_CONNECT,
79 STATE_CONNECT_COMPLETE,
81 IoState io_state_;
83 QuicStreamFactory* factory_;
84 SingleRequestHostResolver host_resolver_;
85 const HostPortProxyPair host_port_proxy_pair_;
86 bool is_https_;
87 bool is_post_;
88 CertVerifier* cert_verifier_;
89 const BoundNetLog net_log_;
90 QuicClientSession* session_;
91 CompletionCallback callback_;
92 AddressList address_list_;
93 DISALLOW_COPY_AND_ASSIGN(Job);
96 QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
97 HostResolver* host_resolver,
98 const HostPortProxyPair& host_port_proxy_pair,
99 bool is_https,
100 base::StringPiece method,
101 CertVerifier* cert_verifier,
102 const BoundNetLog& net_log)
103 : factory_(factory),
104 host_resolver_(host_resolver),
105 host_port_proxy_pair_(host_port_proxy_pair),
106 is_https_(is_https),
107 is_post_(method == "POST"),
108 cert_verifier_(cert_verifier),
109 net_log_(net_log),
110 session_(NULL) {}
112 QuicStreamFactory::Job::~Job() {
115 int QuicStreamFactory::Job::Run(const CompletionCallback& callback) {
116 io_state_ = STATE_RESOLVE_HOST;
117 int rv = DoLoop(OK);
118 if (rv == ERR_IO_PENDING)
119 callback_ = callback;
121 return rv > 0 ? OK : rv;
124 int QuicStreamFactory::Job::DoLoop(int rv) {
125 do {
126 IoState state = io_state_;
127 io_state_ = STATE_NONE;
128 switch (state) {
129 case STATE_RESOLVE_HOST:
130 CHECK_EQ(OK, rv);
131 rv = DoResolveHost();
132 break;
133 case STATE_RESOLVE_HOST_COMPLETE:
134 rv = DoResolveHostComplete(rv);
135 break;
136 case STATE_CONNECT:
137 CHECK_EQ(OK, rv);
138 rv = DoConnect();
139 break;
140 case STATE_CONNECT_COMPLETE:
141 rv = DoConnectComplete(rv);
142 break;
143 default:
144 NOTREACHED() << "io_state_: " << io_state_;
145 break;
147 } while (io_state_ != STATE_NONE && rv != ERR_IO_PENDING);
148 return rv;
151 void QuicStreamFactory::Job::OnIOComplete(int rv) {
152 rv = DoLoop(rv);
154 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
155 callback_.Run(rv);
159 int QuicStreamFactory::Job::DoResolveHost() {
160 io_state_ = STATE_RESOLVE_HOST_COMPLETE;
161 return host_resolver_.Resolve(
162 HostResolver::RequestInfo(host_port_proxy_pair_.first),
163 DEFAULT_PRIORITY,
164 &address_list_,
165 base::Bind(&QuicStreamFactory::Job::OnIOComplete, base::Unretained(this)),
166 net_log_);
169 int QuicStreamFactory::Job::DoResolveHostComplete(int rv) {
170 if (rv != OK)
171 return rv;
173 DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_));
175 // Inform the factory of this resolution, which will set up
176 // a session alias, if possible.
177 if (factory_->OnResolution(host_port_proxy_pair_, address_list_)) {
178 return OK;
181 io_state_ = STATE_CONNECT;
182 return OK;
185 QuicStreamRequest::QuicStreamRequest(QuicStreamFactory* factory)
186 : factory_(factory) {}
188 QuicStreamRequest::~QuicStreamRequest() {
189 if (factory_ && !callback_.is_null())
190 factory_->CancelRequest(this);
193 int QuicStreamRequest::Request(const HostPortProxyPair& host_port_proxy_pair,
194 bool is_https,
195 base::StringPiece method,
196 CertVerifier* cert_verifier,
197 const BoundNetLog& net_log,
198 const CompletionCallback& callback) {
199 DCHECK(!stream_);
200 DCHECK(callback_.is_null());
201 DCHECK(factory_);
202 int rv = factory_->Create(
203 host_port_proxy_pair, is_https, method, cert_verifier, net_log, this);
204 if (rv == ERR_IO_PENDING) {
205 host_port_proxy_pair_ = host_port_proxy_pair;
206 is_https_ = is_https;
207 cert_verifier_ = cert_verifier;
208 net_log_ = net_log;
209 callback_ = callback;
210 } else {
211 factory_ = NULL;
213 if (rv == OK)
214 DCHECK(stream_);
215 return rv;
218 void QuicStreamRequest::set_stream(scoped_ptr<QuicHttpStream> stream) {
219 DCHECK(stream);
220 stream_ = stream.Pass();
223 void QuicStreamRequest::OnRequestComplete(int rv) {
224 factory_ = NULL;
225 callback_.Run(rv);
228 scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() {
229 DCHECK(stream_);
230 return stream_.Pass();
233 int QuicStreamFactory::Job::DoConnect() {
234 io_state_ = STATE_CONNECT_COMPLETE;
236 int rv = factory_->CreateSession(host_port_proxy_pair_, is_https_,
237 cert_verifier_, address_list_, net_log_, &session_);
238 if (rv != OK) {
239 DCHECK(rv != ERR_IO_PENDING);
240 DCHECK(!session_);
241 return rv;
244 session_->StartReading();
245 if (!session_->connection()->connected()) {
246 return ERR_QUIC_PROTOCOL_ERROR;
248 rv = session_->CryptoConnect(
249 factory_->require_confirmation() || is_https_,
250 base::Bind(&QuicStreamFactory::Job::OnIOComplete,
251 base::Unretained(this)));
252 return rv;
255 int QuicStreamFactory::Job::DoConnectComplete(int rv) {
256 if (rv != OK)
257 return rv;
259 DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_));
260 // There may well now be an active session for this IP. If so, use the
261 // existing session instead.
262 AddressList address(session_->connection()->peer_address());
263 if (factory_->OnResolution(host_port_proxy_pair_, address)) {
264 session_->connection()->SendConnectionClose(QUIC_NO_ERROR);
265 session_ = NULL;
266 return OK;
269 factory_->ActivateSession(host_port_proxy_pair_, session_);
271 return OK;
274 QuicStreamFactory::QuicStreamFactory(
275 HostResolver* host_resolver,
276 ClientSocketFactory* client_socket_factory,
277 base::WeakPtr<HttpServerProperties> http_server_properties,
278 QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
279 QuicRandom* random_generator,
280 QuicClock* clock,
281 size_t max_packet_length,
282 const QuicVersionVector& supported_versions,
283 bool enable_port_selection,
284 bool enable_pacing)
285 : require_confirmation_(true),
286 host_resolver_(host_resolver),
287 client_socket_factory_(client_socket_factory),
288 http_server_properties_(http_server_properties),
289 quic_server_info_factory_(NULL),
290 quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory),
291 random_generator_(random_generator),
292 clock_(clock),
293 max_packet_length_(max_packet_length),
294 supported_versions_(supported_versions),
295 enable_port_selection_(enable_port_selection),
296 enable_pacing_(enable_pacing),
297 port_seed_(random_generator_->RandUint64()),
298 weak_factory_(this) {
299 config_.SetDefaults();
300 config_.EnablePacing(enable_pacing_);
301 config_.set_idle_connection_state_lifetime(
302 QuicTime::Delta::FromSeconds(30),
303 QuicTime::Delta::FromSeconds(30));
305 canoncial_suffixes_.push_back(string(".c.youtube.com"));
306 canoncial_suffixes_.push_back(string(".googlevideo.com"));
309 QuicStreamFactory::~QuicStreamFactory() {
310 CloseAllSessions(ERR_ABORTED);
311 STLDeleteElements(&all_sessions_);
312 STLDeleteValues(&active_jobs_);
313 STLDeleteValues(&all_crypto_configs_);
316 int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair,
317 bool is_https,
318 base::StringPiece method,
319 CertVerifier* cert_verifier,
320 const BoundNetLog& net_log,
321 QuicStreamRequest* request) {
322 if (HasActiveSession(host_port_proxy_pair)) {
323 request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log));
324 return OK;
327 if (HasActiveJob(host_port_proxy_pair)) {
328 Job* job = active_jobs_[host_port_proxy_pair];
329 active_requests_[request] = job;
330 job_requests_map_[job].insert(request);
331 return ERR_IO_PENDING;
334 // Create crypto config and start the process of loading QUIC server
335 // information from disk cache.
336 QuicCryptoClientConfig* crypto_config =
337 GetOrCreateCryptoConfig(host_port_proxy_pair);
338 DCHECK(crypto_config);
340 scoped_ptr<Job> job(new Job(this, host_resolver_, host_port_proxy_pair,
341 is_https, method, cert_verifier, net_log));
342 int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
343 base::Unretained(this), job.get()));
345 if (rv == ERR_IO_PENDING) {
346 active_requests_[request] = job.get();
347 job_requests_map_[job.get()].insert(request);
348 active_jobs_[host_port_proxy_pair] = job.release();
350 if (rv == OK) {
351 DCHECK(HasActiveSession(host_port_proxy_pair));
352 request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log));
354 return rv;
357 bool QuicStreamFactory::OnResolution(
358 const HostPortProxyPair& host_port_proxy_pair,
359 const AddressList& address_list) {
360 DCHECK(!HasActiveSession(host_port_proxy_pair));
361 for (size_t i = 0; i < address_list.size(); ++i) {
362 const IPEndPoint& address = address_list[i];
363 if (!ContainsKey(ip_aliases_, address))
364 continue;
366 const SessionSet& sessions = ip_aliases_[address];
367 for (SessionSet::const_iterator i = sessions.begin();
368 i != sessions.end(); ++i) {
369 QuicClientSession* session = *i;
370 if (!session->CanPool(host_port_proxy_pair.first.host()))
371 continue;
372 active_sessions_[host_port_proxy_pair] = session;
373 session_aliases_[session].insert(host_port_proxy_pair);
374 return true;
377 return false;
380 void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
381 if (rv == OK) {
382 require_confirmation_ = false;
384 // Create all the streams, but do not notify them yet.
385 for (RequestSet::iterator it = job_requests_map_[job].begin();
386 it != job_requests_map_[job].end() ; ++it) {
387 DCHECK(HasActiveSession(job->host_port_proxy_pair()));
388 (*it)->set_stream(CreateIfSessionExists(job->host_port_proxy_pair(),
389 (*it)->net_log()));
392 while (!job_requests_map_[job].empty()) {
393 RequestSet::iterator it = job_requests_map_[job].begin();
394 QuicStreamRequest* request = *it;
395 job_requests_map_[job].erase(it);
396 active_requests_.erase(request);
397 // Even though we're invoking callbacks here, we don't need to worry
398 // about |this| being deleted, because the factory is owned by the
399 // profile which can not be deleted via callbacks.
400 request->OnRequestComplete(rv);
402 active_jobs_.erase(job->host_port_proxy_pair());
403 job_requests_map_.erase(job);
404 delete job;
405 return;
408 // Returns a newly created QuicHttpStream owned by the caller, if a
409 // matching session already exists. Returns NULL otherwise.
410 scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists(
411 const HostPortProxyPair& host_port_proxy_pair,
412 const BoundNetLog& net_log) {
413 if (!HasActiveSession(host_port_proxy_pair)) {
414 DVLOG(1) << "No active session";
415 return scoped_ptr<QuicHttpStream>();
418 QuicClientSession* session = active_sessions_[host_port_proxy_pair];
419 DCHECK(session);
420 return scoped_ptr<QuicHttpStream>(
421 new QuicHttpStream(session->GetWeakPtr()));
424 void QuicStreamFactory::OnIdleSession(QuicClientSession* session) {
427 void QuicStreamFactory::OnSessionGoingAway(QuicClientSession* session) {
428 const AliasSet& aliases = session_aliases_[session];
429 for (AliasSet::const_iterator it = aliases.begin(); it != aliases.end();
430 ++it) {
431 DCHECK(active_sessions_.count(*it));
432 DCHECK_EQ(session, active_sessions_[*it]);
433 active_sessions_.erase(*it);
434 if (!http_server_properties_)
435 continue;
437 if (!session->IsCryptoHandshakeConfirmed()) {
438 // TODO(rch): In the special case where the session has received no
439 // packets from the peer, we should consider blacklisting this
440 // differently so that we still race TCP but we don't consider the
441 // session connected until the handshake has been confirmed.
442 http_server_properties_->SetBrokenAlternateProtocol(it->first);
443 } else {
444 QuicConnectionStats stats = session->connection()->GetStats();
445 HttpServerProperties::NetworkStats network_stats;
446 network_stats.rtt = base::TimeDelta::FromMicroseconds(stats.rtt);
447 network_stats.bandwidth_estimate = stats.estimated_bandwidth;
448 http_server_properties_->SetServerNetworkStats(
449 it->first, network_stats);
452 IPEndPoint peer_address = session->connection()->peer_address();
453 ip_aliases_[peer_address].erase(session);
454 if (ip_aliases_[peer_address].empty()) {
455 ip_aliases_.erase(peer_address);
457 session_aliases_.erase(session);
460 void QuicStreamFactory::OnSessionClosed(QuicClientSession* session) {
461 DCHECK_EQ(0u, session->GetNumOpenStreams());
462 OnSessionGoingAway(session);
463 all_sessions_.erase(session);
464 delete session;
467 void QuicStreamFactory::CancelRequest(QuicStreamRequest* request) {
468 DCHECK(ContainsKey(active_requests_, request));
469 Job* job = active_requests_[request];
470 job_requests_map_[job].erase(request);
471 active_requests_.erase(request);
474 void QuicStreamFactory::CloseAllSessions(int error) {
475 while (!active_sessions_.empty()) {
476 size_t initial_size = active_sessions_.size();
477 active_sessions_.begin()->second->CloseSessionOnError(error);
478 DCHECK_NE(initial_size, active_sessions_.size());
480 while (!all_sessions_.empty()) {
481 size_t initial_size = all_sessions_.size();
482 (*all_sessions_.begin())->CloseSessionOnError(error);
483 DCHECK_NE(initial_size, all_sessions_.size());
485 DCHECK(all_sessions_.empty());
488 base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
489 base::ListValue* list = new base::ListValue();
491 for (SessionMap::const_iterator it = active_sessions_.begin();
492 it != active_sessions_.end(); ++it) {
493 const HostPortProxyPair& pair = it->first;
494 QuicClientSession* session = it->second;
495 const AliasSet& aliases = session_aliases_.find(session)->second;
496 if (pair.first.Equals(aliases.begin()->first) &&
497 pair.second == aliases.begin()->second) {
498 list->Append(session->GetInfoAsValue(aliases));
501 return list;
504 void QuicStreamFactory::OnIPAddressChanged() {
505 CloseAllSessions(ERR_NETWORK_CHANGED);
506 require_confirmation_ = true;
509 void QuicStreamFactory::OnCertAdded(const X509Certificate* cert) {
510 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
513 void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
514 // We should flush the sessions if we removed trust from a
515 // cert, because a previously trusted server may have become
516 // untrusted.
518 // We should not flush the sessions if we added trust to a cert.
520 // Since the OnCACertChanged method doesn't tell us what
521 // kind of change it is, we have to flush the socket
522 // pools to be safe.
523 CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
526 bool QuicStreamFactory::HasActiveSession(
527 const HostPortProxyPair& host_port_proxy_pair) {
528 return ContainsKey(active_sessions_, host_port_proxy_pair);
531 int QuicStreamFactory::CreateSession(
532 const HostPortProxyPair& host_port_proxy_pair,
533 bool is_https,
534 CertVerifier* cert_verifier,
535 const AddressList& address_list,
536 const BoundNetLog& net_log,
537 QuicClientSession** session) {
538 QuicGuid guid = random_generator_->RandUint64();
539 IPEndPoint addr = *address_list.begin();
540 scoped_refptr<PortSuggester> port_suggester =
541 new PortSuggester(host_port_proxy_pair.first, port_seed_);
542 DatagramSocket::BindType bind_type = enable_port_selection_ ?
543 DatagramSocket::RANDOM_BIND : // Use our callback.
544 DatagramSocket::DEFAULT_BIND; // Use OS to randomize.
545 scoped_ptr<DatagramClientSocket> socket(
546 client_socket_factory_->CreateDatagramClientSocket(
547 bind_type,
548 base::Bind(&PortSuggester::SuggestPort, port_suggester),
549 net_log.net_log(), net_log.source()));
550 int rv = socket->Connect(addr);
551 if (rv != OK)
552 return rv;
553 UMA_HISTOGRAM_COUNTS("Net.QuicEphemeralPortsSuggested",
554 port_suggester->call_count());
555 if (enable_port_selection_) {
556 DCHECK_LE(1u, port_suggester->call_count());
557 } else {
558 DCHECK_EQ(0u, port_suggester->call_count());
561 // We should adaptively set this buffer size, but for now, we'll use a size
562 // that is more than large enough for a full receive window, and yet
563 // does not consume "too much" memory. If we see bursty packet loss, we may
564 // revisit this setting and test for its impact.
565 const int32 kSocketBufferSize(TcpReceiver::kReceiveWindowTCP);
566 socket->SetReceiveBufferSize(kSocketBufferSize);
567 // Set a buffer large enough to contain the initial CWND's worth of packet
568 // to work around the problem with CHLO packets being sent out with the
569 // wrong encryption level, when the send buffer is full.
570 socket->SetSendBufferSize(kMaxPacketSize * 20); // Support 20 packets.
572 scoped_ptr<QuicDefaultPacketWriter> writer(
573 new QuicDefaultPacketWriter(socket.get()));
575 if (!helper_.get()) {
576 helper_.reset(new QuicConnectionHelper(
577 base::MessageLoop::current()->message_loop_proxy().get(),
578 clock_.get(), random_generator_));
581 QuicConnection* connection = new QuicConnection(guid, addr, helper_.get(),
582 writer.get(), false,
583 supported_versions_);
584 writer->SetConnection(connection);
585 connection->options()->max_packet_length = max_packet_length_;
587 QuicCryptoClientConfig* crypto_config =
588 GetOrCreateCryptoConfig(host_port_proxy_pair);
589 DCHECK(crypto_config);
591 QuicConfig config = config_;
592 if (http_server_properties_) {
593 const HttpServerProperties::NetworkStats* stats =
594 http_server_properties_->GetServerNetworkStats(
595 host_port_proxy_pair.first);
596 if (stats != NULL) {
597 config.set_initial_round_trip_time_us(stats->rtt.InMicroseconds(),
598 stats->rtt.InMicroseconds());
602 *session = new QuicClientSession(
603 connection, socket.Pass(), writer.Pass(), this,
604 quic_crypto_client_stream_factory_, host_port_proxy_pair.first.host(),
605 config, crypto_config, net_log.net_log());
606 all_sessions_.insert(*session); // owning pointer
607 if (is_https) {
608 crypto_config->SetProofVerifier(
609 new ProofVerifierChromium(cert_verifier, net_log));
611 return OK;
614 bool QuicStreamFactory::HasActiveJob(
615 const HostPortProxyPair& host_port_proxy_pair) {
616 return ContainsKey(active_jobs_, host_port_proxy_pair);
619 void QuicStreamFactory::ActivateSession(
620 const HostPortProxyPair& host_port_proxy_pair,
621 QuicClientSession* session) {
622 DCHECK(!HasActiveSession(host_port_proxy_pair));
623 active_sessions_[host_port_proxy_pair] = session;
624 session_aliases_[session].insert(host_port_proxy_pair);
625 DCHECK(!ContainsKey(ip_aliases_[session->connection()->peer_address()],
626 session));
627 ip_aliases_[session->connection()->peer_address()].insert(session);
630 QuicCryptoClientConfig* QuicStreamFactory::GetOrCreateCryptoConfig(
631 const HostPortProxyPair& host_port_proxy_pair) {
632 QuicCryptoClientConfig* crypto_config;
634 if (ContainsKey(all_crypto_configs_, host_port_proxy_pair)) {
635 crypto_config = all_crypto_configs_[host_port_proxy_pair];
636 DCHECK(crypto_config);
637 } else {
638 // TODO(rtenneti): if two quic_sessions for the same host_port_proxy_pair
639 // share the same crypto_config, will it cause issues?
640 crypto_config = new QuicCryptoClientConfig();
641 if (quic_server_info_factory_) {
642 QuicCryptoClientConfig::CachedState* cached =
643 crypto_config->Create(host_port_proxy_pair.first.host(),
644 quic_server_info_factory_);
645 DCHECK(cached);
647 crypto_config->SetDefaults();
648 all_crypto_configs_[host_port_proxy_pair] = crypto_config;
649 PopulateFromCanonicalConfig(host_port_proxy_pair, crypto_config);
651 return crypto_config;
654 void QuicStreamFactory::PopulateFromCanonicalConfig(
655 const HostPortProxyPair& host_port_proxy_pair,
656 QuicCryptoClientConfig* crypto_config) {
657 const string server_hostname = host_port_proxy_pair.first.host();
659 unsigned i = 0;
660 for (; i < canoncial_suffixes_.size(); ++i) {
661 if (EndsWith(server_hostname, canoncial_suffixes_[i], false)) {
662 break;
665 if (i == canoncial_suffixes_.size())
666 return;
668 HostPortPair canonical_host_port(canoncial_suffixes_[i],
669 host_port_proxy_pair.first.port());
670 if (!ContainsKey(canonical_hostname_to_origin_map_, canonical_host_port)) {
671 // This is the first host we've seen which matches the suffix, so make it
672 // canonical.
673 canonical_hostname_to_origin_map_[canonical_host_port] =
674 host_port_proxy_pair;
675 return;
678 const HostPortProxyPair& canonical_host_port_proxy_pair =
679 canonical_hostname_to_origin_map_[canonical_host_port];
680 QuicCryptoClientConfig* canonical_crypto_config =
681 all_crypto_configs_[canonical_host_port_proxy_pair];
682 DCHECK(canonical_crypto_config);
684 // Copy the CachedState for the canonical server from canonical_crypto_config
685 // as the initial CachedState for the server_hostname in crypto_config.
686 crypto_config->InitializeFrom(server_hostname,
687 canonical_host_port_proxy_pair.first.host(),
688 canonical_crypto_config);
689 // Update canonical version to point at the "most recent" crypto_config.
690 canonical_hostname_to_origin_map_[canonical_host_port] = host_port_proxy_pair;
693 } // namespace net