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 ¶ms_.ignore_certificate_errors, ¶ms_.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