| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "net/spdy/spdy_session_pool.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/ptr_util.h" | |
| 11 #include "base/metrics/histogram_macros.h" | |
| 12 #include "base/profiler/scoped_tracker.h" | |
| 13 #include "base/stl_util.h" | |
| 14 #include "base/trace_event/memory_allocator_dump.h" | |
| 15 #include "base/trace_event/process_memory_dump.h" | |
| 16 #include "base/trace_event/trace_event.h" | |
| 17 #include "base/values.h" | |
| 18 #include "net/base/address_list.h" | |
| 19 #include "net/base/trace_constants.h" | |
| 20 #include "net/http/http_network_session.h" | |
| 21 #include "net/http/http_server_properties.h" | |
| 22 #include "net/log/net_log_event_type.h" | |
| 23 #include "net/log/net_log_source.h" | |
| 24 #include "net/log/net_log_with_source.h" | |
| 25 #include "net/spdy/hpack/hpack_constants.h" | |
| 26 #include "net/spdy/hpack/hpack_huffman_table.h" | |
| 27 #include "net/spdy/hpack/hpack_static_table.h" | |
| 28 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h" | |
| 29 #include "net/spdy/platform/api/spdy_string_utils.h" | |
| 30 #include "net/spdy/spdy_session.h" | |
| 31 | |
| 32 namespace net { | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 enum SpdySessionGetTypes { | |
| 37 CREATED_NEW = 0, | |
| 38 FOUND_EXISTING = 1, | |
| 39 FOUND_EXISTING_FROM_IP_POOL = 2, | |
| 40 IMPORTED_FROM_SOCKET = 3, | |
| 41 SPDY_SESSION_GET_MAX = 4 | |
| 42 }; | |
| 43 | |
| 44 } // namespace | |
| 45 | |
| 46 SpdySessionPool::SpdySessionPool( | |
| 47 HostResolver* resolver, | |
| 48 SSLConfigService* ssl_config_service, | |
| 49 HttpServerProperties* http_server_properties, | |
| 50 TransportSecurityState* transport_security_state, | |
| 51 bool enable_ping_based_connection_checking, | |
| 52 size_t session_max_recv_window_size, | |
| 53 const SettingsMap& initial_settings, | |
| 54 SpdySessionPool::TimeFunc time_func, | |
| 55 ProxyDelegate* proxy_delegate) | |
| 56 : http_server_properties_(http_server_properties), | |
| 57 transport_security_state_(transport_security_state), | |
| 58 ssl_config_service_(ssl_config_service), | |
| 59 resolver_(resolver), | |
| 60 enable_sending_initial_data_(true), | |
| 61 enable_ping_based_connection_checking_( | |
| 62 enable_ping_based_connection_checking), | |
| 63 session_max_recv_window_size_(session_max_recv_window_size), | |
| 64 initial_settings_(initial_settings), | |
| 65 time_func_(time_func), | |
| 66 push_delegate_(nullptr), | |
| 67 proxy_delegate_(proxy_delegate) { | |
| 68 NetworkChangeNotifier::AddIPAddressObserver(this); | |
| 69 if (ssl_config_service_.get()) | |
| 70 ssl_config_service_->AddObserver(this); | |
| 71 CertDatabase::GetInstance()->AddObserver(this); | |
| 72 } | |
| 73 | |
| 74 SpdySessionPool::~SpdySessionPool() { | |
| 75 CloseAllSessions(); | |
| 76 | |
| 77 while (!sessions_.empty()) { | |
| 78 // Destroy sessions to enforce that lifetime is scoped to SpdySessionPool. | |
| 79 // Write callbacks queued upon session drain are not invoked. | |
| 80 RemoveUnavailableSession((*sessions_.begin())->GetWeakPtr()); | |
| 81 } | |
| 82 | |
| 83 if (ssl_config_service_.get()) | |
| 84 ssl_config_service_->RemoveObserver(this); | |
| 85 NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
| 86 CertDatabase::GetInstance()->RemoveObserver(this); | |
| 87 } | |
| 88 | |
| 89 base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket( | |
| 90 const SpdySessionKey& key, | |
| 91 std::unique_ptr<ClientSocketHandle> connection, | |
| 92 const NetLogWithSource& net_log, | |
| 93 bool is_secure) { | |
| 94 TRACE_EVENT0(kNetTracingCategory, | |
| 95 "SpdySessionPool::CreateAvailableSessionFromSocket"); | |
| 96 | |
| 97 UMA_HISTOGRAM_ENUMERATION( | |
| 98 "Net.SpdySessionGet", IMPORTED_FROM_SOCKET, SPDY_SESSION_GET_MAX); | |
| 99 | |
| 100 auto new_session = base::MakeUnique<SpdySession>( | |
| 101 key, http_server_properties_, transport_security_state_, | |
| 102 enable_sending_initial_data_, enable_ping_based_connection_checking_, | |
| 103 session_max_recv_window_size_, initial_settings_, time_func_, | |
| 104 push_delegate_, proxy_delegate_, net_log.net_log()); | |
| 105 | |
| 106 new_session->InitializeWithSocket(std::move(connection), this, is_secure); | |
| 107 | |
| 108 base::WeakPtr<SpdySession> available_session = new_session->GetWeakPtr(); | |
| 109 sessions_.insert(new_session.release()); | |
| 110 MapKeyToAvailableSession(key, available_session); | |
| 111 | |
| 112 net_log.AddEvent( | |
| 113 NetLogEventType::HTTP2_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET, | |
| 114 available_session->net_log().source().ToEventParametersCallback()); | |
| 115 | |
| 116 // Look up the IP address for this session so that we can match | |
| 117 // future sessions (potentially to different domains) which can | |
| 118 // potentially be pooled with this one. Because GetPeerAddress() | |
| 119 // reports the proxy's address instead of the origin server, check | |
| 120 // to see if this is a direct connection. | |
| 121 if (key.proxy_server().is_direct()) { | |
| 122 IPEndPoint address; | |
| 123 if (available_session->GetPeerAddress(&address) == OK) | |
| 124 aliases_[address] = key; | |
| 125 } | |
| 126 | |
| 127 return available_session; | |
| 128 } | |
| 129 | |
| 130 base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession( | |
| 131 const SpdySessionKey& key, | |
| 132 const GURL& url, | |
| 133 bool enable_ip_based_pooling, | |
| 134 const NetLogWithSource& net_log) { | |
| 135 UnclaimedPushedStreamMap::iterator url_it = | |
| 136 unclaimed_pushed_streams_.find(url); | |
| 137 if (!url.is_empty() && url_it != unclaimed_pushed_streams_.end()) { | |
| 138 DCHECK(url.SchemeIsCryptographic()); | |
| 139 for (WeakSessionList::iterator it = url_it->second.begin(); | |
| 140 it != url_it->second.end();) { | |
| 141 base::WeakPtr<SpdySession> spdy_session = *it; | |
| 142 // Lazy deletion of destroyed SpdySessions. | |
| 143 if (!spdy_session) { | |
| 144 it = url_it->second.erase(it); | |
| 145 continue; | |
| 146 } | |
| 147 ++it; | |
| 148 const SpdySessionKey& spdy_session_key = spdy_session->spdy_session_key(); | |
| 149 if (!(spdy_session_key.proxy_server() == key.proxy_server()) || | |
| 150 !(spdy_session_key.privacy_mode() == key.privacy_mode())) { | |
| 151 continue; | |
| 152 } | |
| 153 if (!spdy_session->VerifyDomainAuthentication( | |
| 154 key.host_port_pair().host())) { | |
| 155 continue; | |
| 156 } | |
| 157 return spdy_session; | |
| 158 } | |
| 159 if (url_it->second.empty()) { | |
| 160 unclaimed_pushed_streams_.erase(url_it); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 AvailableSessionMap::iterator it = LookupAvailableSessionByKey(key); | |
| 165 if (it != available_sessions_.end()) { | |
| 166 if (key.Equals(it->second->spdy_session_key())) { | |
| 167 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", FOUND_EXISTING, | |
| 168 SPDY_SESSION_GET_MAX); | |
| 169 net_log.AddEvent( | |
| 170 NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION, | |
| 171 it->second->net_log().source().ToEventParametersCallback()); | |
| 172 } else { | |
| 173 if (!enable_ip_based_pooling) { | |
| 174 // Remove session from available sessions and from aliases, and remove | |
| 175 // key from the session's pooled alias set, so that a new session can be | |
| 176 // created with this |key|. | |
| 177 it->second->RemovePooledAlias(key); | |
| 178 UnmapKey(key); | |
| 179 RemoveAliases(key); | |
| 180 return base::WeakPtr<SpdySession>(); | |
| 181 } | |
| 182 | |
| 183 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", | |
| 184 FOUND_EXISTING_FROM_IP_POOL, | |
| 185 SPDY_SESSION_GET_MAX); | |
| 186 net_log.AddEvent( | |
| 187 NetLogEventType:: | |
| 188 HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL, | |
| 189 it->second->net_log().source().ToEventParametersCallback()); | |
| 190 } | |
| 191 return it->second; | |
| 192 } | |
| 193 | |
| 194 if (!enable_ip_based_pooling) | |
| 195 return base::WeakPtr<SpdySession>(); | |
| 196 | |
| 197 // Look up IP addresses from resolver cache. | |
| 198 HostResolver::RequestInfo resolve_info(key.host_port_pair()); | |
| 199 AddressList addresses; | |
| 200 int rv = resolver_->ResolveFromCache(resolve_info, &addresses, net_log); | |
| 201 DCHECK_NE(rv, ERR_IO_PENDING); | |
| 202 if (rv != OK) | |
| 203 return base::WeakPtr<SpdySession>(); | |
| 204 | |
| 205 // Check if we have a session through a domain alias. | |
| 206 for (AddressList::const_iterator address_it = addresses.begin(); | |
| 207 address_it != addresses.end(); | |
| 208 ++address_it) { | |
| 209 AliasMap::const_iterator alias_it = aliases_.find(*address_it); | |
| 210 if (alias_it == aliases_.end()) | |
| 211 continue; | |
| 212 | |
| 213 // We found an alias. | |
| 214 const SpdySessionKey& alias_key = alias_it->second; | |
| 215 | |
| 216 // We can reuse this session only if the proxy and privacy | |
| 217 // settings match. | |
| 218 if (!(alias_key.proxy_server() == key.proxy_server()) || | |
| 219 !(alias_key.privacy_mode() == key.privacy_mode())) | |
| 220 continue; | |
| 221 | |
| 222 AvailableSessionMap::iterator available_session_it = | |
| 223 LookupAvailableSessionByKey(alias_key); | |
| 224 if (available_session_it == available_sessions_.end()) { | |
| 225 NOTREACHED(); // It shouldn't be in the aliases table if we can't get it! | |
| 226 continue; | |
| 227 } | |
| 228 | |
| 229 const base::WeakPtr<SpdySession>& available_session = | |
| 230 available_session_it->second; | |
| 231 DCHECK(base::ContainsKey(sessions_, available_session.get())); | |
| 232 // If the session is a secure one, we need to verify that the | |
| 233 // server is authenticated to serve traffic for |host_port_proxy_pair| too. | |
| 234 if (!available_session->VerifyDomainAuthentication( | |
| 235 key.host_port_pair().host())) { | |
| 236 UMA_HISTOGRAM_ENUMERATION("Net.SpdyIPPoolDomainMatch", 0, 2); | |
| 237 continue; | |
| 238 } | |
| 239 | |
| 240 UMA_HISTOGRAM_ENUMERATION("Net.SpdyIPPoolDomainMatch", 1, 2); | |
| 241 UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", | |
| 242 FOUND_EXISTING_FROM_IP_POOL, | |
| 243 SPDY_SESSION_GET_MAX); | |
| 244 net_log.AddEvent( | |
| 245 NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL, | |
| 246 available_session->net_log().source().ToEventParametersCallback()); | |
| 247 // Add this session to the map so that we can find it next time. | |
| 248 MapKeyToAvailableSession(key, available_session); | |
| 249 available_session->AddPooledAlias(key); | |
| 250 return available_session; | |
| 251 } | |
| 252 | |
| 253 return base::WeakPtr<SpdySession>(); | |
| 254 } | |
| 255 | |
| 256 void SpdySessionPool::MakeSessionUnavailable( | |
| 257 const base::WeakPtr<SpdySession>& available_session) { | |
| 258 UnmapKey(available_session->spdy_session_key()); | |
| 259 RemoveAliases(available_session->spdy_session_key()); | |
| 260 const std::set<SpdySessionKey>& aliases = available_session->pooled_aliases(); | |
| 261 for (std::set<SpdySessionKey>::const_iterator it = aliases.begin(); | |
| 262 it != aliases.end(); ++it) { | |
| 263 UnmapKey(*it); | |
| 264 RemoveAliases(*it); | |
| 265 } | |
| 266 DCHECK(!IsSessionAvailable(available_session)); | |
| 267 } | |
| 268 | |
| 269 void SpdySessionPool::RemoveUnavailableSession( | |
| 270 const base::WeakPtr<SpdySession>& unavailable_session) { | |
| 271 DCHECK(!IsSessionAvailable(unavailable_session)); | |
| 272 | |
| 273 unavailable_session->net_log().AddEvent( | |
| 274 NetLogEventType::HTTP2_SESSION_POOL_REMOVE_SESSION); | |
| 275 | |
| 276 SessionSet::iterator it = sessions_.find(unavailable_session.get()); | |
| 277 CHECK(it != sessions_.end()); | |
| 278 std::unique_ptr<SpdySession> owned_session(*it); | |
| 279 sessions_.erase(it); | |
| 280 } | |
| 281 | |
| 282 // Make a copy of |sessions_| in the Close* functions below to avoid | |
| 283 // reentrancy problems. Since arbitrary functions get called by close | |
| 284 // handlers, it doesn't suffice to simply increment the iterator | |
| 285 // before closing. | |
| 286 | |
| 287 void SpdySessionPool::CloseCurrentSessions(Error error) { | |
| 288 CloseCurrentSessionsHelper(error, "Closing current sessions.", | |
| 289 false /* idle_only */); | |
| 290 } | |
| 291 | |
| 292 void SpdySessionPool::CloseCurrentIdleSessions() { | |
| 293 CloseCurrentSessionsHelper(ERR_ABORTED, "Closing idle sessions.", | |
| 294 true /* idle_only */); | |
| 295 } | |
| 296 | |
| 297 void SpdySessionPool::CloseAllSessions() { | |
| 298 while (!available_sessions_.empty()) { | |
| 299 CloseCurrentSessionsHelper(ERR_ABORTED, "Closing all sessions.", | |
| 300 false /* idle_only */); | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 void SpdySessionPool::RegisterUnclaimedPushedStream( | |
| 305 GURL url, | |
| 306 base::WeakPtr<SpdySession> spdy_session) { | |
| 307 DCHECK(!url.is_empty()); | |
| 308 // This SpdySessionPool must own |spdy_session|. | |
| 309 DCHECK(base::ContainsKey(sessions_, spdy_session.get())); | |
| 310 UnclaimedPushedStreamMap::iterator url_it = | |
| 311 unclaimed_pushed_streams_.lower_bound(url); | |
| 312 if (url_it == unclaimed_pushed_streams_.end() || url_it->first != url) { | |
| 313 WeakSessionList list; | |
| 314 list.push_back(std::move(spdy_session)); | |
| 315 UnclaimedPushedStreamMap::value_type value(std::move(url), std::move(list)); | |
| 316 unclaimed_pushed_streams_.insert(url_it, std::move(value)); | |
| 317 return; | |
| 318 } | |
| 319 url_it->second.push_back(spdy_session); | |
| 320 } | |
| 321 | |
| 322 void SpdySessionPool::UnregisterUnclaimedPushedStream( | |
| 323 const GURL& url, | |
| 324 SpdySession* spdy_session) { | |
| 325 DCHECK(!url.is_empty()); | |
| 326 UnclaimedPushedStreamMap::iterator url_it = | |
| 327 unclaimed_pushed_streams_.find(url); | |
| 328 DCHECK(url_it != unclaimed_pushed_streams_.end()); | |
| 329 size_t removed = 0; | |
| 330 for (WeakSessionList::iterator it = url_it->second.begin(); | |
| 331 it != url_it->second.end();) { | |
| 332 // Lazy deletion of destroyed SpdySessions. | |
| 333 if (!*it) { | |
| 334 it = url_it->second.erase(it); | |
| 335 continue; | |
| 336 } | |
| 337 if (it->get() == spdy_session) { | |
| 338 it = url_it->second.erase(it); | |
| 339 ++removed; | |
| 340 break; | |
| 341 } | |
| 342 ++it; | |
| 343 } | |
| 344 if (url_it->second.empty()) { | |
| 345 unclaimed_pushed_streams_.erase(url_it); | |
| 346 } | |
| 347 DCHECK_EQ(1u, removed); | |
| 348 } | |
| 349 | |
| 350 std::unique_ptr<base::Value> SpdySessionPool::SpdySessionPoolInfoToValue() | |
| 351 const { | |
| 352 std::unique_ptr<base::ListValue> list(new base::ListValue()); | |
| 353 | |
| 354 for (AvailableSessionMap::const_iterator it = available_sessions_.begin(); | |
| 355 it != available_sessions_.end(); ++it) { | |
| 356 // Only add the session if the key in the map matches the main | |
| 357 // host_port_proxy_pair (not an alias). | |
| 358 const SpdySessionKey& key = it->first; | |
| 359 const SpdySessionKey& session_key = it->second->spdy_session_key(); | |
| 360 if (key.Equals(session_key)) | |
| 361 list->Append(it->second->GetInfoAsValue()); | |
| 362 } | |
| 363 return std::move(list); | |
| 364 } | |
| 365 | |
| 366 void SpdySessionPool::OnIPAddressChanged() { | |
| 367 WeakSessionList current_sessions = GetCurrentSessions(); | |
| 368 for (WeakSessionList::const_iterator it = current_sessions.begin(); | |
| 369 it != current_sessions.end(); ++it) { | |
| 370 if (!*it) | |
| 371 continue; | |
| 372 | |
| 373 // For OSs that terminate TCP connections upon relevant network changes, | |
| 374 // attempt to preserve active streams by marking all sessions as going | |
| 375 // away, rather than explicitly closing them. Streams may still fail due | |
| 376 // to a generated TCP reset. | |
| 377 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) | |
| 378 (*it)->MakeUnavailable(); | |
| 379 (*it)->StartGoingAway(kLastStreamId, ERR_NETWORK_CHANGED); | |
| 380 (*it)->MaybeFinishGoingAway(); | |
| 381 #else | |
| 382 (*it)->CloseSessionOnError(ERR_NETWORK_CHANGED, | |
| 383 "Closing current sessions."); | |
| 384 DCHECK((*it)->IsDraining()); | |
| 385 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) | |
| 386 DCHECK(!IsSessionAvailable(*it)); | |
| 387 } | |
| 388 } | |
| 389 | |
| 390 void SpdySessionPool::OnSSLConfigChanged() { | |
| 391 CloseCurrentSessions(ERR_NETWORK_CHANGED); | |
| 392 } | |
| 393 | |
| 394 void SpdySessionPool::OnCertDBChanged() { | |
| 395 CloseCurrentSessions(ERR_CERT_DATABASE_CHANGED); | |
| 396 } | |
| 397 | |
| 398 void SpdySessionPool::DumpMemoryStats( | |
| 399 base::trace_event::ProcessMemoryDump* pmd, | |
| 400 const SpdyString& parent_dump_absolute_name) const { | |
| 401 if (sessions_.empty()) | |
| 402 return; | |
| 403 size_t total_size = 0; | |
| 404 size_t buffer_size = 0; | |
| 405 size_t cert_count = 0; | |
| 406 size_t cert_size = 0; | |
| 407 size_t num_active_sessions = 0; | |
| 408 for (auto* session : sessions_) { | |
| 409 StreamSocket::SocketMemoryStats stats; | |
| 410 bool is_session_active = false; | |
| 411 total_size += session->DumpMemoryStats(&stats, &is_session_active); | |
| 412 buffer_size += stats.buffer_size; | |
| 413 cert_count += stats.cert_count; | |
| 414 cert_size += stats.cert_size; | |
| 415 if (is_session_active) | |
| 416 num_active_sessions++; | |
| 417 } | |
| 418 total_size += SpdyEstimateMemoryUsage(ObtainHpackHuffmanTable()) + | |
| 419 SpdyEstimateMemoryUsage(ObtainHpackStaticTable()); | |
| 420 base::trace_event::MemoryAllocatorDump* dump = | |
| 421 pmd->CreateAllocatorDump(SpdyStringPrintf( | |
| 422 "%s/spdy_session_pool", parent_dump_absolute_name.c_str())); | |
| 423 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | |
| 424 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| 425 total_size); | |
| 426 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount, | |
| 427 base::trace_event::MemoryAllocatorDump::kUnitsObjects, | |
| 428 sessions_.size()); | |
| 429 dump->AddScalar("active_session_count", | |
| 430 base::trace_event::MemoryAllocatorDump::kUnitsObjects, | |
| 431 num_active_sessions); | |
| 432 dump->AddScalar("buffer_size", | |
| 433 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| 434 buffer_size); | |
| 435 dump->AddScalar("cert_count", | |
| 436 base::trace_event::MemoryAllocatorDump::kUnitsObjects, | |
| 437 cert_count); | |
| 438 dump->AddScalar("cert_size", | |
| 439 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| 440 cert_size); | |
| 441 } | |
| 442 | |
| 443 bool SpdySessionPool::IsSessionAvailable( | |
| 444 const base::WeakPtr<SpdySession>& session) const { | |
| 445 for (AvailableSessionMap::const_iterator it = available_sessions_.begin(); | |
| 446 it != available_sessions_.end(); ++it) { | |
| 447 if (it->second.get() == session.get()) | |
| 448 return true; | |
| 449 } | |
| 450 return false; | |
| 451 } | |
| 452 | |
| 453 void SpdySessionPool::MapKeyToAvailableSession( | |
| 454 const SpdySessionKey& key, | |
| 455 const base::WeakPtr<SpdySession>& session) { | |
| 456 DCHECK(base::ContainsKey(sessions_, session.get())); | |
| 457 std::pair<AvailableSessionMap::iterator, bool> result = | |
| 458 available_sessions_.insert(std::make_pair(key, session)); | |
| 459 CHECK(result.second); | |
| 460 } | |
| 461 | |
| 462 SpdySessionPool::AvailableSessionMap::iterator | |
| 463 SpdySessionPool::LookupAvailableSessionByKey( | |
| 464 const SpdySessionKey& key) { | |
| 465 return available_sessions_.find(key); | |
| 466 } | |
| 467 | |
| 468 void SpdySessionPool::UnmapKey(const SpdySessionKey& key) { | |
| 469 AvailableSessionMap::iterator it = LookupAvailableSessionByKey(key); | |
| 470 CHECK(it != available_sessions_.end()); | |
| 471 available_sessions_.erase(it); | |
| 472 } | |
| 473 | |
| 474 void SpdySessionPool::RemoveAliases(const SpdySessionKey& key) { | |
| 475 // Walk the aliases map, find references to this pair. | |
| 476 // TODO(mbelshe): Figure out if this is too expensive. | |
| 477 for (AliasMap::iterator it = aliases_.begin(); it != aliases_.end(); ) { | |
| 478 if (it->second.Equals(key)) { | |
| 479 AliasMap::iterator old_it = it; | |
| 480 ++it; | |
| 481 aliases_.erase(old_it); | |
| 482 } else { | |
| 483 ++it; | |
| 484 } | |
| 485 } | |
| 486 } | |
| 487 | |
| 488 SpdySessionPool::WeakSessionList SpdySessionPool::GetCurrentSessions() const { | |
| 489 WeakSessionList current_sessions; | |
| 490 for (SessionSet::const_iterator it = sessions_.begin(); | |
| 491 it != sessions_.end(); ++it) { | |
| 492 current_sessions.push_back((*it)->GetWeakPtr()); | |
| 493 } | |
| 494 return current_sessions; | |
| 495 } | |
| 496 | |
| 497 void SpdySessionPool::CloseCurrentSessionsHelper(Error error, | |
| 498 const SpdyString& description, | |
| 499 bool idle_only) { | |
| 500 WeakSessionList current_sessions = GetCurrentSessions(); | |
| 501 for (WeakSessionList::const_iterator it = current_sessions.begin(); | |
| 502 it != current_sessions.end(); ++it) { | |
| 503 if (!*it) | |
| 504 continue; | |
| 505 | |
| 506 if (idle_only && (*it)->is_active()) | |
| 507 continue; | |
| 508 | |
| 509 (*it)->CloseSessionOnError(error, description); | |
| 510 DCHECK(!IsSessionAvailable(*it)); | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 } // namespace net | |
| OLD | NEW |