• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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/http/http_network_session.h"
6 
7 #include <inttypes.h>
8 
9 #include <utility>
10 
11 #include "base/atomic_sequence_num.h"
12 #include "base/check_op.h"
13 #include "base/compiler_specific.h"
14 #include "base/containers/contains.h"
15 #include "base/feature_list.h"
16 #include "base/notreached.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/values.h"
20 #include "build/build_config.h"
21 #include "net/base/features.h"
22 #include "net/dns/host_resolver.h"
23 #include "net/http/http_auth_handler_factory.h"
24 #include "net/http/http_response_body_drainer.h"
25 #include "net/http/http_stream_factory.h"
26 #include "net/http/http_stream_pool.h"
27 #include "net/http/url_security_manager.h"
28 #include "net/proxy_resolution/proxy_resolution_service.h"
29 #include "net/quic/platform/impl/quic_chromium_clock.h"
30 #include "net/quic/quic_crypto_client_stream_factory.h"
31 #include "net/quic/quic_session_pool.h"
32 #include "net/socket/client_socket_factory.h"
33 #include "net/socket/client_socket_pool_manager_impl.h"
34 #include "net/socket/next_proto.h"
35 #include "net/socket/ssl_client_socket.h"
36 #include "net/spdy/spdy_session.h"
37 #include "net/spdy/spdy_session_pool.h"
38 #include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_random.h"
39 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
40 #include "net/third_party/quiche/src/quiche/quic/core/quic_tag.h"
41 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
42 #include "url/scheme_host_port.h"
43 
44 namespace net {
45 
46 // The maximum receive window sizes for HTTP/2 sessions and streams.
47 const int32_t kSpdySessionMaxRecvWindowSize = 15 * 1024 * 1024;  // 15 MB
48 const int32_t kSpdyStreamMaxRecvWindowSize = 6 * 1024 * 1024;    //  6 MB
49 
50 // Value of SETTINGS_ENABLE_PUSH reflecting that server push is not supported.
51 const uint32_t kSpdyDisablePush = 0;
52 
53 namespace {
54 
55 // Keep all HTTP2 parameters in |http2_settings|, even the ones that are not
56 // implemented, to be sent to the server.
57 // Set default values for settings that |http2_settings| does not specify.
AddDefaultHttp2Settings(spdy::SettingsMap http2_settings)58 spdy::SettingsMap AddDefaultHttp2Settings(spdy::SettingsMap http2_settings) {
59   // Server push is not supported.
60   http2_settings[spdy::SETTINGS_ENABLE_PUSH] = kSpdyDisablePush;
61 
62   // For other setting parameters, set default values only if |http2_settings|
63   // does not have a value set for given setting.
64   auto it = http2_settings.find(spdy::SETTINGS_HEADER_TABLE_SIZE);
65   if (it == http2_settings.end()) {
66     http2_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
67   }
68 
69   it = http2_settings.find(spdy::SETTINGS_INITIAL_WINDOW_SIZE);
70   if (it == http2_settings.end()) {
71     http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
72         kSpdyStreamMaxRecvWindowSize;
73   }
74 
75   it = http2_settings.find(spdy::SETTINGS_MAX_HEADER_LIST_SIZE);
76   if (it == http2_settings.end()) {
77     http2_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
78         kSpdyMaxHeaderListSize;
79   }
80 
81   return http2_settings;
82 }
83 
OriginToForceQuicOnInternal(const QuicParams & quic_params,const url::SchemeHostPort & destination)84 bool OriginToForceQuicOnInternal(const QuicParams& quic_params,
85                                  const url::SchemeHostPort& destination) {
86   // TODO(crbug.com/40181080): Consider converting `origins_to_force_quic_on` to
87   // use url::SchemeHostPort.
88   return (
89       base::Contains(quic_params.origins_to_force_quic_on, HostPortPair()) ||
90       base::Contains(quic_params.origins_to_force_quic_on,
91                      HostPortPair::FromSchemeHostPort(destination)));
92 }
93 
94 }  // unnamed namespace
95 
HttpNetworkSessionParams()96 HttpNetworkSessionParams::HttpNetworkSessionParams()
97     : spdy_session_max_recv_window_size(kSpdySessionMaxRecvWindowSize),
98       spdy_session_max_queued_capped_frames(kSpdySessionMaxQueuedCappedFrames),
99       time_func(&base::TimeTicks::Now) {
100   enable_early_data =
101       base::FeatureList::IsEnabled(features::kEnableTLS13EarlyData);
102   use_dns_https_svcb_alpn =
103       base::FeatureList::IsEnabled(features::kUseDnsHttpsSvcbAlpn);
104 }
105 
106 HttpNetworkSessionParams::HttpNetworkSessionParams(
107     const HttpNetworkSessionParams& other) = default;
108 
109 HttpNetworkSessionParams::~HttpNetworkSessionParams() = default;
110 
HttpNetworkSessionContext()111 HttpNetworkSessionContext::HttpNetworkSessionContext()
112     : client_socket_factory(nullptr),
113       host_resolver(nullptr),
114       cert_verifier(nullptr),
115       transport_security_state(nullptr),
116       sct_auditing_delegate(nullptr),
117       proxy_resolution_service(nullptr),
118       proxy_delegate(nullptr),
119       http_user_agent_settings(nullptr),
120       ssl_config_service(nullptr),
121       http_auth_handler_factory(nullptr),
122       net_log(nullptr),
123       socket_performance_watcher_factory(nullptr),
124       network_quality_estimator(nullptr),
125       quic_context(nullptr),
126 #if BUILDFLAG(ENABLE_REPORTING)
127       reporting_service(nullptr),
128       network_error_logging_service(nullptr),
129 #endif
130       quic_crypto_client_stream_factory(
131           QuicCryptoClientStreamFactory::GetDefaultFactory()) {
132 }
133 
134 HttpNetworkSessionContext::HttpNetworkSessionContext(
135     const HttpNetworkSessionContext& other) = default;
136 
137 HttpNetworkSessionContext::~HttpNetworkSessionContext() = default;
138 
139 // TODO(mbelshe): Move the socket factories into HttpStreamFactory.
HttpNetworkSession(const HttpNetworkSessionParams & params,const HttpNetworkSessionContext & context)140 HttpNetworkSession::HttpNetworkSession(const HttpNetworkSessionParams& params,
141                                        const HttpNetworkSessionContext& context)
142     : net_log_(context.net_log),
143       http_server_properties_(context.http_server_properties),
144       cert_verifier_(context.cert_verifier),
145       http_auth_handler_factory_(context.http_auth_handler_factory),
146       host_resolver_(context.host_resolver),
147 #if BUILDFLAG(ENABLE_REPORTING)
148       reporting_service_(context.reporting_service),
149       network_error_logging_service_(context.network_error_logging_service),
150 #endif
151       proxy_resolution_service_(context.proxy_resolution_service),
152       ssl_config_service_(context.ssl_config_service),
153       http_auth_cache_(
154           params.key_auth_cache_server_entries_by_network_anonymization_key),
155       ssl_client_session_cache_(SSLClientSessionCache::Config()),
156       ssl_client_context_(context.ssl_config_service,
157                           context.cert_verifier,
158                           context.transport_security_state,
159                           &ssl_client_session_cache_,
160                           context.sct_auditing_delegate),
161       quic_session_pool_(context.net_log,
162                          context.host_resolver,
163                          context.ssl_config_service,
164                          context.client_socket_factory,
165                          context.http_server_properties,
166                          context.cert_verifier,
167                          context.transport_security_state,
168                          context.proxy_delegate,
169                          context.sct_auditing_delegate,
170                          context.socket_performance_watcher_factory,
171                          context.quic_crypto_client_stream_factory,
172                          context.quic_context),
173       spdy_session_pool_(context.host_resolver,
174                          &ssl_client_context_,
175                          context.http_server_properties,
176                          context.transport_security_state,
177                          context.quic_context->params()->supported_versions,
178                          params.enable_spdy_ping_based_connection_checking,
179                          params.enable_http2,
180                          params.enable_quic,
181                          params.spdy_session_max_recv_window_size,
182                          params.spdy_session_max_queued_capped_frames,
183                          AddDefaultHttp2Settings(params.http2_settings),
184                          params.enable_http2_settings_grease,
185                          params.greased_http2_frame,
186                          params.http2_end_stream_with_data_frame,
187                          params.enable_priority_update,
188                          params.spdy_go_away_on_ip_change,
189                          params.time_func,
190                          context.network_quality_estimator,
191                          // cleanup_sessions_on_ip_address_changed
192                          !params.ignore_ip_address_changes),
193       http_stream_factory_(std::make_unique<HttpStreamFactory>(this)),
194       params_(params),
195       context_(context) {
196   DCHECK(proxy_resolution_service_);
197   DCHECK(ssl_config_service_);
198   CHECK(http_server_properties_);
199   DCHECK(context_.client_socket_factory);
200 
201   normal_socket_pool_manager_ = std::make_unique<ClientSocketPoolManagerImpl>(
202       CreateCommonConnectJobParams(false /* for_websockets */),
203       CreateCommonConnectJobParams(true /* for_websockets */),
204       NORMAL_SOCKET_POOL,
205       // cleanup_on_ip_address_change
206       !params.ignore_ip_address_changes);
207   websocket_socket_pool_manager_ =
208       std::make_unique<ClientSocketPoolManagerImpl>(
209           CreateCommonConnectJobParams(false /* for_websockets */),
210           CreateCommonConnectJobParams(true /* for_websockets */),
211           WEBSOCKET_SOCKET_POOL,
212           // cleanup_on_ip_address_change
213           !params.ignore_ip_address_changes);
214 
215   if (params_.enable_http2) {
216     next_protos_.push_back(kProtoHTTP2);
217     if (base::FeatureList::IsEnabled(features::kAlpsForHttp2)) {
218       // Enable ALPS for HTTP/2 with empty data.
219       application_settings_[kProtoHTTP2] = {};
220     }
221   }
222 
223   next_protos_.push_back(kProtoHTTP11);
224 
225   http_server_properties_->SetMaxServerConfigsStoredInProperties(
226       context.quic_context->params()->max_server_configs_stored_in_properties);
227   http_server_properties_->SetBrokenAlternativeServicesDelayParams(
228       context.quic_context->params()
229           ->initial_delay_for_broken_alternative_service,
230       context.quic_context->params()->exponential_backoff_on_initial_delay);
231 
232   if (!params_.disable_idle_sockets_close_on_memory_pressure) {
233     memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
234         FROM_HERE, base::BindRepeating(&HttpNetworkSession::OnMemoryPressure,
235                                        base::Unretained(this)));
236   }
237 
238   if (base::FeatureList::IsEnabled(features::kHappyEyeballsV3)) {
239     http_stream_pool_ = std::make_unique<HttpStreamPool>(
240         this,
241         /*cleanup_on_ip_address_change=*/!params.ignore_ip_address_changes);
242   }
243 }
244 
~HttpNetworkSession()245 HttpNetworkSession::~HttpNetworkSession() {
246   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
247   if (http_stream_pool_) {
248     http_stream_pool_->OnShuttingDown();
249   }
250   response_drainers_.clear();
251   // TODO(bnc): CloseAllSessions() is also called in SpdySessionPool destructor,
252   // one of the two calls should be removed.
253   spdy_session_pool_.CloseAllSessions();
254 }
255 
StartResponseDrainer(std::unique_ptr<HttpResponseBodyDrainer> drainer)256 void HttpNetworkSession::StartResponseDrainer(
257     std::unique_ptr<HttpResponseBodyDrainer> drainer) {
258   DCHECK(!base::Contains(response_drainers_, drainer.get()));
259   HttpResponseBodyDrainer* drainer_ptr = drainer.get();
260   response_drainers_.insert(std::move(drainer));
261   drainer_ptr->Start(this);
262 }
263 
RemoveResponseDrainer(HttpResponseBodyDrainer * drainer)264 void HttpNetworkSession::RemoveResponseDrainer(
265     HttpResponseBodyDrainer* drainer) {
266   DCHECK(base::Contains(response_drainers_, drainer));
267 
268   response_drainers_.erase(response_drainers_.find(drainer));
269 }
270 
GetSocketPool(SocketPoolType pool_type,const ProxyChain & proxy_chain)271 ClientSocketPool* HttpNetworkSession::GetSocketPool(
272     SocketPoolType pool_type,
273     const ProxyChain& proxy_chain) {
274   return GetSocketPoolManager(pool_type)->GetSocketPool(proxy_chain);
275 }
276 
SocketPoolInfoToValue() const277 base::Value HttpNetworkSession::SocketPoolInfoToValue() const {
278   // TODO(yutak): Should merge values from normal pools and WebSocket pools.
279   return normal_socket_pool_manager_->SocketPoolInfoToValue();
280 }
281 
SpdySessionPoolInfoToValue() const282 std::unique_ptr<base::Value> HttpNetworkSession::SpdySessionPoolInfoToValue()
283     const {
284   return spdy_session_pool_.SpdySessionPoolInfoToValue();
285 }
286 
QuicInfoToValue() const287 base::Value HttpNetworkSession::QuicInfoToValue() const {
288   base::Value::Dict dict;
289   dict.Set("sessions", quic_session_pool_.QuicSessionPoolInfoToValue());
290   dict.Set("quic_enabled", IsQuicEnabled());
291 
292   const QuicParams* quic_params = context_.quic_context->params();
293 
294   base::Value::List connection_options;
295   for (const auto& option : quic_params->connection_options) {
296     connection_options.Append(quic::QuicTagToString(option));
297   }
298   dict.Set("connection_options", std::move(connection_options));
299 
300   base::Value::List supported_versions;
301   for (const auto& version : quic_params->supported_versions) {
302     supported_versions.Append(ParsedQuicVersionToString(version));
303   }
304   dict.Set("supported_versions", std::move(supported_versions));
305 
306   base::Value::List origins_to_force_quic_on;
307   for (const auto& origin : quic_params->origins_to_force_quic_on) {
308     origins_to_force_quic_on.Append(origin.ToString());
309   }
310   dict.Set("origins_to_force_quic_on", std::move(origins_to_force_quic_on));
311 
312   dict.Set("max_packet_length",
313            static_cast<int>(quic_params->max_packet_length));
314   dict.Set(
315       "max_server_configs_stored_in_properties",
316       static_cast<int>(quic_params->max_server_configs_stored_in_properties));
317   dict.Set("idle_connection_timeout_seconds",
318            static_cast<int>(quic_params->idle_connection_timeout.InSeconds()));
319   dict.Set("reduced_ping_timeout_seconds",
320            static_cast<int>(quic_params->reduced_ping_timeout.InSeconds()));
321   dict.Set("retry_without_alt_svc_on_quic_errors",
322            quic_params->retry_without_alt_svc_on_quic_errors);
323   dict.Set("close_sessions_on_ip_change",
324            quic_params->close_sessions_on_ip_change);
325   dict.Set("goaway_sessions_on_ip_change",
326            quic_params->goaway_sessions_on_ip_change);
327   dict.Set("migrate_sessions_on_network_change_v2",
328            quic_params->migrate_sessions_on_network_change_v2);
329   dict.Set("migrate_sessions_early_v2", quic_params->migrate_sessions_early_v2);
330   dict.Set("retransmittable_on_wire_timeout_milliseconds",
331            static_cast<int>(
332                quic_params->retransmittable_on_wire_timeout.InMilliseconds()));
333   dict.Set("retry_on_alternate_network_before_handshake",
334            quic_params->retry_on_alternate_network_before_handshake);
335   dict.Set("migrate_idle_sessions", quic_params->migrate_idle_sessions);
336   dict.Set(
337       "idle_session_migration_period_seconds",
338       static_cast<int>(quic_params->idle_session_migration_period.InSeconds()));
339   dict.Set("max_time_on_non_default_network_seconds",
340            static_cast<int>(
341                quic_params->max_time_on_non_default_network.InSeconds()));
342   dict.Set("max_num_migrations_to_non_default_network_on_write_error",
343            quic_params->max_migrations_to_non_default_network_on_write_error);
344   dict.Set(
345       "max_num_migrations_to_non_default_network_on_path_degrading",
346       quic_params->max_migrations_to_non_default_network_on_path_degrading);
347   dict.Set("allow_server_migration", quic_params->allow_server_migration);
348   dict.Set("estimate_initial_rtt", quic_params->estimate_initial_rtt);
349   dict.Set("initial_rtt_for_handshake_milliseconds",
350            static_cast<int>(
351                quic_params->initial_rtt_for_handshake.InMilliseconds()));
352 
353   return base::Value(std::move(dict));
354 }
355 
CloseAllConnections(int net_error,const char * net_log_reason_utf8)356 void HttpNetworkSession::CloseAllConnections(int net_error,
357                                              const char* net_log_reason_utf8) {
358   normal_socket_pool_manager_->FlushSocketPoolsWithError(net_error,
359                                                          net_log_reason_utf8);
360   websocket_socket_pool_manager_->FlushSocketPoolsWithError(
361       net_error, net_log_reason_utf8);
362   if (http_stream_pool_) {
363     http_stream_pool_->FlushWithError(
364         net_error, HttpStreamPool::StreamCloseReason::kCloseAllConnections,
365         net_log_reason_utf8);
366   }
367   spdy_session_pool_.CloseCurrentSessions(static_cast<Error>(net_error));
368   quic_session_pool_.CloseAllSessions(net_error, quic::QUIC_PEER_GOING_AWAY);
369 }
370 
CloseIdleConnections(const char * net_log_reason_utf8)371 void HttpNetworkSession::CloseIdleConnections(const char* net_log_reason_utf8) {
372   normal_socket_pool_manager_->CloseIdleSockets(net_log_reason_utf8);
373   websocket_socket_pool_manager_->CloseIdleSockets(net_log_reason_utf8);
374   if (http_stream_pool_) {
375     http_stream_pool_->CloseIdleStreams(net_log_reason_utf8);
376   }
377   spdy_session_pool_.CloseCurrentIdleSessions(net_log_reason_utf8);
378 }
379 
IsQuicEnabled() const380 bool HttpNetworkSession::IsQuicEnabled() const {
381   return params_.enable_quic;
382 }
383 
DisableQuic()384 void HttpNetworkSession::DisableQuic() {
385   params_.enable_quic = false;
386 }
387 
ShouldForceQuic(const url::SchemeHostPort & destination,const ProxyInfo & proxy_info,bool is_websocket)388 bool HttpNetworkSession::ShouldForceQuic(const url::SchemeHostPort& destination,
389                                          const ProxyInfo& proxy_info,
390                                          bool is_websocket) {
391   if (!IsQuicEnabled()) {
392     return false;
393   }
394   if (is_websocket) {
395     return false;
396   }
397   // If a proxy is being used, the last proxy in the chain must be QUIC if we
398   // are to use QUIC on top of it.
399   if (!proxy_info.is_direct() && !proxy_info.proxy_chain().Last().is_quic()) {
400     return false;
401   }
402   return OriginToForceQuicOnInternal(*context_.quic_context->params(),
403                                      destination) &&
404          GURL::SchemeIsCryptographic(destination.scheme());
405 }
406 
IgnoreCertificateErrorsForTesting()407 void HttpNetworkSession::IgnoreCertificateErrorsForTesting() {
408   params_.ignore_certificate_errors = true;
409 }
410 
ClearSSLSessionCache()411 void HttpNetworkSession::ClearSSLSessionCache() {
412   ssl_client_session_cache_.Flush();
413 }
414 
CreateCommonConnectJobParams(bool for_websockets)415 CommonConnectJobParams HttpNetworkSession::CreateCommonConnectJobParams(
416     bool for_websockets) {
417   // Use null websocket_endpoint_lock_manager, which is only set for WebSockets,
418   // and only when not using a proxy.
419   return CommonConnectJobParams(
420       context_.client_socket_factory, context_.host_resolver, &http_auth_cache_,
421       context_.http_auth_handler_factory, &spdy_session_pool_,
422       &context_.quic_context->params()->supported_versions, &quic_session_pool_,
423       context_.proxy_delegate, context_.http_user_agent_settings,
424       &ssl_client_context_, context_.socket_performance_watcher_factory,
425       context_.network_quality_estimator, context_.net_log,
426       for_websockets ? &websocket_endpoint_lock_manager_ : nullptr,
427       context_.http_server_properties, &next_protos_, &application_settings_,
428       &params_.ignore_certificate_errors, &params_.enable_early_data);
429 }
430 
ApplyTestingFixedPort(url::SchemeHostPort & endpoint) const431 void HttpNetworkSession::ApplyTestingFixedPort(
432     url::SchemeHostPort& endpoint) const {
433   bool using_ssl = GURL::SchemeIsCryptographic(endpoint.scheme());
434   if (!using_ssl && params().testing_fixed_http_port != 0) {
435     endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
436                                    params().testing_fixed_http_port);
437   } else if (using_ssl && params().testing_fixed_https_port != 0) {
438     endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
439                                    params().testing_fixed_https_port);
440   }
441 }
442 
GetSocketPoolManager(SocketPoolType pool_type)443 ClientSocketPoolManager* HttpNetworkSession::GetSocketPoolManager(
444     SocketPoolType pool_type) {
445   switch (pool_type) {
446     case NORMAL_SOCKET_POOL:
447       return normal_socket_pool_manager_.get();
448     case WEBSOCKET_SOCKET_POOL:
449       return websocket_socket_pool_manager_.get();
450     default:
451       NOTREACHED();
452   }
453 }
454 
OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level)455 void HttpNetworkSession::OnMemoryPressure(
456     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
457   DCHECK(!params_.disable_idle_sockets_close_on_memory_pressure);
458 
459   switch (memory_pressure_level) {
460     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
461       break;
462 
463     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
464     case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
465       CloseIdleConnections("Low memory");
466       break;
467   }
468 }
469 
470 }  // namespace net
471