| Index: net/quic/quic_stream_factory.cc
|
| diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
|
| index f445cd3e8f7a07579cc0fe7e5cab6cf3fa55ea5f..c92f184e42d187463950df7bfe762855fd9f96a7 100644
|
| --- a/net/quic/quic_stream_factory.cc
|
| +++ b/net/quic/quic_stream_factory.cc
|
| @@ -38,6 +38,57 @@ using std::vector;
|
|
|
| namespace net {
|
|
|
| +QuicStreamFactory::SessionKey::SessionKey() {}
|
| +
|
| +QuicStreamFactory::SessionKey::SessionKey(
|
| + HostPortProxyPair host_port_proxy_pair,
|
| + bool is_https)
|
| + : host_port_proxy_pair(host_port_proxy_pair),
|
| + is_https(is_https) {}
|
| +
|
| +QuicStreamFactory::SessionKey::~SessionKey() {}
|
| +
|
| +bool QuicStreamFactory::SessionKey::operator<(
|
| + const QuicStreamFactory::SessionKey &other) const {
|
| + if (!host_port_proxy_pair.first.Equals(other.host_port_proxy_pair.first)) {
|
| + return host_port_proxy_pair.first < other.host_port_proxy_pair.first;
|
| + }
|
| + if (!(host_port_proxy_pair.second == other.host_port_proxy_pair.second)) {
|
| + return host_port_proxy_pair.second < other.host_port_proxy_pair.second;
|
| + }
|
| + return is_https < other.is_https;
|
| +}
|
| +
|
| +bool QuicStreamFactory::SessionKey::operator==(
|
| + const QuicStreamFactory::SessionKey& other) const {
|
| + return is_https == other.is_https &&
|
| + host_port_proxy_pair.second == other.host_port_proxy_pair.second &&
|
| + host_port_proxy_pair.first.Equals(other.host_port_proxy_pair.first);
|
| +};
|
| +
|
| +QuicStreamFactory::IpAliasKey::IpAliasKey() {}
|
| +
|
| +QuicStreamFactory::IpAliasKey::IpAliasKey(IPEndPoint ip_endpoint,
|
| + bool is_https)
|
| + : ip_endpoint(ip_endpoint),
|
| + is_https(is_https) {}
|
| +
|
| +QuicStreamFactory::IpAliasKey::~IpAliasKey() {}
|
| +
|
| +bool QuicStreamFactory::IpAliasKey::operator<(
|
| + const QuicStreamFactory::IpAliasKey& other) const {
|
| + if (!(ip_endpoint == other.ip_endpoint)) {
|
| + return ip_endpoint < other.ip_endpoint;
|
| + }
|
| + return is_https < other.is_https;
|
| +}
|
| +
|
| +bool QuicStreamFactory::IpAliasKey::operator==(
|
| + const QuicStreamFactory::IpAliasKey& other) const {
|
| + return is_https == other.is_https &&
|
| + ip_endpoint == other.ip_endpoint;
|
| +};
|
| +
|
| // Responsible for creating a new QUIC session to the specified server, and
|
| // for notifying any associated requests when complete.
|
| class QuicStreamFactory::Job {
|
| @@ -66,8 +117,8 @@ class QuicStreamFactory::Job {
|
| return callback_;
|
| }
|
|
|
| - const HostPortProxyPair& host_port_proxy_pair() const {
|
| - return host_port_proxy_pair_;
|
| + const SessionKey session_key() const {
|
| + return session_key_;
|
| }
|
|
|
| private:
|
| @@ -82,8 +133,8 @@ class QuicStreamFactory::Job {
|
|
|
| QuicStreamFactory* factory_;
|
| SingleRequestHostResolver host_resolver_;
|
| - const HostPortProxyPair host_port_proxy_pair_;
|
| bool is_https_;
|
| + SessionKey session_key_;
|
| bool is_post_;
|
| CertVerifier* cert_verifier_;
|
| const BoundNetLog net_log_;
|
| @@ -102,8 +153,8 @@ QuicStreamFactory::Job::Job(QuicStreamFactory* factory,
|
| const BoundNetLog& net_log)
|
| : factory_(factory),
|
| host_resolver_(host_resolver),
|
| - host_port_proxy_pair_(host_port_proxy_pair),
|
| is_https_(is_https),
|
| + session_key_(host_port_proxy_pair, is_https),
|
| is_post_(method == "POST"),
|
| cert_verifier_(cert_verifier),
|
| net_log_(net_log),
|
| @@ -159,7 +210,7 @@ void QuicStreamFactory::Job::OnIOComplete(int rv) {
|
| int QuicStreamFactory::Job::DoResolveHost() {
|
| io_state_ = STATE_RESOLVE_HOST_COMPLETE;
|
| return host_resolver_.Resolve(
|
| - HostResolver::RequestInfo(host_port_proxy_pair_.first),
|
| + HostResolver::RequestInfo(session_key_.host_port_proxy_pair.first),
|
| DEFAULT_PRIORITY,
|
| &address_list_,
|
| base::Bind(&QuicStreamFactory::Job::OnIOComplete, base::Unretained(this)),
|
| @@ -170,11 +221,11 @@ int QuicStreamFactory::Job::DoResolveHostComplete(int rv) {
|
| if (rv != OK)
|
| return rv;
|
|
|
| - DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_));
|
| + DCHECK(!factory_->HasActiveSession(session_key_));
|
|
|
| // Inform the factory of this resolution, which will set up
|
| // a session alias, if possible.
|
| - if (factory_->OnResolution(host_port_proxy_pair_, address_list_)) {
|
| + if (factory_->OnResolution(session_key_, address_list_)) {
|
| return OK;
|
| }
|
|
|
| @@ -199,8 +250,8 @@ int QuicStreamRequest::Request(const HostPortProxyPair& host_port_proxy_pair,
|
| DCHECK(!stream_);
|
| DCHECK(callback_.is_null());
|
| DCHECK(factory_);
|
| - int rv = factory_->Create(
|
| - host_port_proxy_pair, is_https, method, cert_verifier, net_log, this);
|
| + int rv = factory_->Create(host_port_proxy_pair, is_https,
|
| + method, cert_verifier, net_log, this);
|
| if (rv == ERR_IO_PENDING) {
|
| host_port_proxy_pair_ = host_port_proxy_pair;
|
| is_https_ = is_https;
|
| @@ -233,7 +284,7 @@ scoped_ptr<QuicHttpStream> QuicStreamRequest::ReleaseStream() {
|
| int QuicStreamFactory::Job::DoConnect() {
|
| io_state_ = STATE_CONNECT_COMPLETE;
|
|
|
| - int rv = factory_->CreateSession(host_port_proxy_pair_, is_https_,
|
| + int rv = factory_->CreateSession(session_key_.host_port_proxy_pair, is_https_,
|
| cert_verifier_, address_list_, net_log_, &session_);
|
| if (rv != OK) {
|
| DCHECK(rv != ERR_IO_PENDING);
|
| @@ -256,17 +307,18 @@ int QuicStreamFactory::Job::DoConnectComplete(int rv) {
|
| if (rv != OK)
|
| return rv;
|
|
|
| - DCHECK(!factory_->HasActiveSession(host_port_proxy_pair_));
|
| + DCHECK(!factory_->HasActiveSession(session_key_));
|
| // There may well now be an active session for this IP. If so, use the
|
| // existing session instead.
|
| AddressList address(session_->connection()->peer_address());
|
| - if (factory_->OnResolution(host_port_proxy_pair_, address)) {
|
| + if (factory_->OnResolution(session_key_, address)) {
|
| +
|
| session_->connection()->SendConnectionClose(QUIC_NO_ERROR);
|
| session_ = NULL;
|
| return OK;
|
| }
|
|
|
| - factory_->ActivateSession(host_port_proxy_pair_, session_);
|
| + factory_->ActivateSession(session_key_, session_);
|
|
|
| return OK;
|
| }
|
| @@ -319,13 +371,14 @@ int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair,
|
| CertVerifier* cert_verifier,
|
| const BoundNetLog& net_log,
|
| QuicStreamRequest* request) {
|
| - if (HasActiveSession(host_port_proxy_pair)) {
|
| - request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log));
|
| + SessionKey key(host_port_proxy_pair, is_https);
|
| + if (HasActiveSession(key)) {
|
| + request->set_stream(CreateIfSessionExists(key, net_log));
|
| return OK;
|
| }
|
|
|
| - if (HasActiveJob(host_port_proxy_pair)) {
|
| - Job* job = active_jobs_[host_port_proxy_pair];
|
| + if (HasActiveJob(key)) {
|
| + Job* job = active_jobs_[key];
|
| active_requests_[request] = job;
|
| job_requests_map_[job].insert(request);
|
| return ERR_IO_PENDING;
|
| @@ -345,32 +398,33 @@ int QuicStreamFactory::Create(const HostPortProxyPair& host_port_proxy_pair,
|
| if (rv == ERR_IO_PENDING) {
|
| active_requests_[request] = job.get();
|
| job_requests_map_[job.get()].insert(request);
|
| - active_jobs_[host_port_proxy_pair] = job.release();
|
| + active_jobs_[key] = job.release();
|
| }
|
| if (rv == OK) {
|
| - DCHECK(HasActiveSession(host_port_proxy_pair));
|
| - request->set_stream(CreateIfSessionExists(host_port_proxy_pair, net_log));
|
| + DCHECK(HasActiveSession(key));
|
| + request->set_stream(CreateIfSessionExists(key, net_log));
|
| }
|
| return rv;
|
| }
|
|
|
| bool QuicStreamFactory::OnResolution(
|
| - const HostPortProxyPair& host_port_proxy_pair,
|
| + const SessionKey& session_key,
|
| const AddressList& address_list) {
|
| - DCHECK(!HasActiveSession(host_port_proxy_pair));
|
| + DCHECK(!HasActiveSession(session_key));
|
| for (size_t i = 0; i < address_list.size(); ++i) {
|
| const IPEndPoint& address = address_list[i];
|
| - if (!ContainsKey(ip_aliases_, address))
|
| + const IpAliasKey ip_alias_key(address, session_key.is_https);
|
| + if (!ContainsKey(ip_aliases_, ip_alias_key))
|
| continue;
|
|
|
| - const SessionSet& sessions = ip_aliases_[address];
|
| + const SessionSet& sessions = ip_aliases_[ip_alias_key];
|
| for (SessionSet::const_iterator i = sessions.begin();
|
| i != sessions.end(); ++i) {
|
| QuicClientSession* session = *i;
|
| - if (!session->CanPool(host_port_proxy_pair.first.host()))
|
| + if (!session->CanPool(session_key.host_port_proxy_pair.first.host()))
|
| continue;
|
| - active_sessions_[host_port_proxy_pair] = session;
|
| - session_aliases_[session].insert(host_port_proxy_pair);
|
| + active_sessions_[session_key] = session;
|
| + session_aliases_[session].insert(session_key);
|
| return true;
|
| }
|
| }
|
| @@ -384,8 +438,8 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
|
| // Create all the streams, but do not notify them yet.
|
| for (RequestSet::iterator it = job_requests_map_[job].begin();
|
| it != job_requests_map_[job].end() ; ++it) {
|
| - DCHECK(HasActiveSession(job->host_port_proxy_pair()));
|
| - (*it)->set_stream(CreateIfSessionExists(job->host_port_proxy_pair(),
|
| + DCHECK(HasActiveSession(job->session_key()));
|
| + (*it)->set_stream(CreateIfSessionExists(job->session_key(),
|
| (*it)->net_log()));
|
| }
|
| }
|
| @@ -399,7 +453,7 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
|
| // profile which can not be deleted via callbacks.
|
| request->OnRequestComplete(rv);
|
| }
|
| - active_jobs_.erase(job->host_port_proxy_pair());
|
| + active_jobs_.erase(job->session_key());
|
| job_requests_map_.erase(job);
|
| delete job;
|
| return;
|
| @@ -408,14 +462,14 @@ void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
|
| // Returns a newly created QuicHttpStream owned by the caller, if a
|
| // matching session already exists. Returns NULL otherwise.
|
| scoped_ptr<QuicHttpStream> QuicStreamFactory::CreateIfSessionExists(
|
| - const HostPortProxyPair& host_port_proxy_pair,
|
| + const SessionKey& session_key,
|
| const BoundNetLog& net_log) {
|
| - if (!HasActiveSession(host_port_proxy_pair)) {
|
| + if (!HasActiveSession(session_key)) {
|
| DVLOG(1) << "No active session";
|
| return scoped_ptr<QuicHttpStream>();
|
| }
|
|
|
| - QuicClientSession* session = active_sessions_[host_port_proxy_pair];
|
| + QuicClientSession* session = active_sessions_[session_key];
|
| DCHECK(session);
|
| return scoped_ptr<QuicHttpStream>(
|
| new QuicHttpStream(session->GetWeakPtr()));
|
| @@ -445,20 +499,24 @@ void QuicStreamFactory::OnSessionGoingAway(QuicClientSession* session) {
|
| // packets from the peer, we should consider blacklisting this
|
| // differently so that we still race TCP but we don't consider the
|
| // session connected until the handshake has been confirmed.
|
| - http_server_properties_->SetBrokenAlternateProtocol(it->first);
|
| + http_server_properties_->SetBrokenAlternateProtocol(
|
| + it->host_port_proxy_pair.first);
|
| } else {
|
| QuicConnectionStats stats = session->connection()->GetStats();
|
| HttpServerProperties::NetworkStats network_stats;
|
| network_stats.rtt = base::TimeDelta::FromMicroseconds(stats.rtt);
|
| network_stats.bandwidth_estimate = stats.estimated_bandwidth;
|
| http_server_properties_->SetServerNetworkStats(
|
| - it->first, network_stats);
|
| + it->host_port_proxy_pair.first, network_stats);
|
| }
|
| }
|
| - IPEndPoint peer_address = session->connection()->peer_address();
|
| - ip_aliases_[peer_address].erase(session);
|
| - if (ip_aliases_[peer_address].empty()) {
|
| - ip_aliases_.erase(peer_address);
|
| + if (!aliases.empty()) {
|
| + const IpAliasKey ip_alias_key(session->connection()->peer_address(),
|
| + aliases.begin()->is_https);
|
| + ip_aliases_[ip_alias_key].erase(session);
|
| + if (ip_aliases_[ip_alias_key].empty()) {
|
| + ip_aliases_.erase(ip_alias_key);
|
| + }
|
| }
|
| session_aliases_.erase(session);
|
| }
|
| @@ -496,12 +554,17 @@ base::Value* QuicStreamFactory::QuicStreamFactoryInfoToValue() const {
|
|
|
| for (SessionMap::const_iterator it = active_sessions_.begin();
|
| it != active_sessions_.end(); ++it) {
|
| - const HostPortProxyPair& pair = it->first;
|
| + const SessionKey& session_key = it->first;
|
| QuicClientSession* session = it->second;
|
| const AliasSet& aliases = session_aliases_.find(session)->second;
|
| - if (pair.first.Equals(aliases.begin()->first) &&
|
| - pair.second == aliases.begin()->second) {
|
| - list->Append(session->GetInfoAsValue(aliases));
|
| + // Only add a session to the list once.
|
| + if (session_key == *aliases.begin()) {
|
| + std::set<HostPortProxyPair> hosts;
|
| + for (AliasSet::const_iterator alias_it = aliases.begin();
|
| + alias_it != aliases.end(); ++alias_it) {
|
| + hosts.insert(alias_it->host_port_proxy_pair);
|
| + }
|
| + list->Append(session->GetInfoAsValue(hosts));
|
| }
|
| }
|
| return list;
|
| @@ -529,9 +592,8 @@ void QuicStreamFactory::OnCACertChanged(const X509Certificate* cert) {
|
| CloseAllSessions(ERR_CERT_DATABASE_CHANGED);
|
| }
|
|
|
| -bool QuicStreamFactory::HasActiveSession(
|
| - const HostPortProxyPair& host_port_proxy_pair) {
|
| - return ContainsKey(active_sessions_, host_port_proxy_pair);
|
| +bool QuicStreamFactory::HasActiveSession(const SessionKey& session_key) const {
|
| + return ContainsKey(active_sessions_, session_key);
|
| }
|
|
|
| int QuicStreamFactory::CreateSession(
|
| @@ -542,13 +604,14 @@ int QuicStreamFactory::CreateSession(
|
| const BoundNetLog& net_log,
|
| QuicClientSession** session) {
|
| bool enable_port_selection = enable_port_selection_;
|
| + SessionKey session_key(host_port_proxy_pair, is_https);
|
| if (enable_port_selection &&
|
| - ContainsKey(gone_away_aliases_, host_port_proxy_pair)) {
|
| + ContainsKey(gone_away_aliases_, session_key)) {
|
| // Disable port selection when the server is going away.
|
| // There is no point in trying to return to the same server, if
|
| // that server is no longer handling requests.
|
| enable_port_selection = false;
|
| - gone_away_aliases_.erase(host_port_proxy_pair);
|
| + gone_away_aliases_.erase(session_key);
|
| }
|
|
|
| QuicConnectionId connection_id = random_generator_->RandUint64();
|
| @@ -628,20 +691,20 @@ int QuicStreamFactory::CreateSession(
|
| return OK;
|
| }
|
|
|
| -bool QuicStreamFactory::HasActiveJob(
|
| - const HostPortProxyPair& host_port_proxy_pair) {
|
| - return ContainsKey(active_jobs_, host_port_proxy_pair);
|
| +bool QuicStreamFactory::HasActiveJob(const SessionKey& key) const {
|
| + return ContainsKey(active_jobs_, key);
|
| }
|
|
|
| void QuicStreamFactory::ActivateSession(
|
| - const HostPortProxyPair& host_port_proxy_pair,
|
| + const SessionKey& session_key,
|
| QuicClientSession* session) {
|
| - DCHECK(!HasActiveSession(host_port_proxy_pair));
|
| - active_sessions_[host_port_proxy_pair] = session;
|
| - session_aliases_[session].insert(host_port_proxy_pair);
|
| - DCHECK(!ContainsKey(ip_aliases_[session->connection()->peer_address()],
|
| - session));
|
| - ip_aliases_[session->connection()->peer_address()].insert(session);
|
| + DCHECK(!HasActiveSession(session_key));
|
| + active_sessions_[session_key] = session;
|
| + session_aliases_[session].insert(session_key);
|
| + const IpAliasKey ip_alias_key(session->connection()->peer_address(),
|
| + session_key.is_https);
|
| + DCHECK(!ContainsKey(ip_aliases_[ip_alias_key], session));
|
| + ip_aliases_[ip_alias_key].insert(session);
|
| }
|
|
|
| QuicCryptoClientConfig* QuicStreamFactory::GetOrCreateCryptoConfig(
|
|
|