#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "net/spdy/spdy_session.h"
#include <limits>
#include <map>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/memory_usage_estimator.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/proxy_chain.h"
#include "net/base/proxy_string_util.h"
#include "net/base/tracing.h"
#include "net/base/url_util.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/ct_policy_status.h"
#include "net/http/http_network_session.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_util.h"
#include "net/http/http_vary_data.h"
#include "net/http/transport_security_state.h"
#include "net/log/net_log.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_event_type.h"
#include "net/log/net_log_source_type.h"
#include "net/log/net_log_with_source.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/quic/quic_http_utils.h"
#include "net/socket/socket.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/alps_decoder.h"
#include "net/spdy/header_coalescer.h"
#include "net/spdy/spdy_buffer_producer.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_log_util.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/spdy/spdy_stream.h"
#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/third_party/quiche/src/quiche/spdy/core/spdy_frame_builder.h"
#include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
#include "url/scheme_host_port.h"
#include "url/url_constants.h"
namespace net {
namespace {
constexpr net::NetworkTrafficAnnotationTag
kSpdySessionCommandsTrafficAnnotation = …;
const int kReadBufferSize = …;
const int kDefaultConnectionAtRiskOfLossSeconds = …;
const int kHungIntervalSeconds = …;
const uint32_t kDefaultInitialHeaderTableSize = …;
const uint32_t kDefaultInitialEnablePush = …;
const uint32_t kDefaultInitialInitialWindowSize = …;
const uint32_t kDefaultInitialMaxFrameSize = …;
enum class SpdyAcceptChEntries { … };
class GreasedBufferProducer : public SpdyBufferProducer { … };
bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,
uint32_t value) { … }
void LogSpdyAcceptChForOriginHistogram(bool value) { … }
base::Value::Dict NetLogSpdyHeadersSentParams(
const quiche::HttpHeaderBlock* headers,
bool fin,
spdy::SpdyStreamId stream_id,
bool has_priority,
int weight,
spdy::SpdyStreamId parent_stream_id,
bool exclusive,
NetLogSource source_dependency,
NetLogCaptureMode capture_mode) { … }
base::Value::Dict NetLogSpdyHeadersReceivedParams(
const quiche::HttpHeaderBlock* headers,
bool fin,
spdy::SpdyStreamId stream_id,
NetLogCaptureMode capture_mode) { … }
base::Value::Dict NetLogSpdySessionCloseParams(int net_error,
const std::string& description) { … }
base::Value::Dict NetLogSpdySessionParams(const HostPortProxyPair& host_pair) { … }
base::Value::Dict NetLogSpdyInitializedParams(NetLogSource source) { … }
base::Value::Dict NetLogSpdySendSettingsParams(
const spdy::SettingsMap* settings) { … }
base::Value::Dict NetLogSpdyRecvAcceptChParams(
spdy::AcceptChOriginValuePair entry) { … }
base::Value::Dict NetLogSpdyRecvSettingParams(spdy::SpdySettingsId id,
uint32_t value) { … }
base::Value::Dict NetLogSpdyWindowUpdateFrameParams(
spdy::SpdyStreamId stream_id,
uint32_t delta) { … }
base::Value::Dict NetLogSpdySessionWindowUpdateParams(int32_t delta,
int32_t window_size) { … }
base::Value::Dict NetLogSpdyDataParams(spdy::SpdyStreamId stream_id,
int size,
bool fin) { … }
base::Value::Dict NetLogSpdyRecvRstStreamParams(
spdy::SpdyStreamId stream_id,
spdy::SpdyErrorCode error_code) { … }
base::Value::Dict NetLogSpdySendRstStreamParams(
spdy::SpdyStreamId stream_id,
spdy::SpdyErrorCode error_code,
const std::string& description) { … }
base::Value::Dict NetLogSpdyPingParams(spdy::SpdyPingId unique_id,
bool is_ack,
const char* type) { … }
base::Value::Dict NetLogSpdyRecvGoAwayParams(spdy::SpdyStreamId last_stream_id,
int active_streams,
spdy::SpdyErrorCode error_code,
std::string_view debug_data,
NetLogCaptureMode capture_mode) { … }
base::Value::Dict NetLogSpdySessionStalledParams(size_t num_active_streams,
size_t num_created_streams,
size_t max_concurrent_streams,
const std::string& url) { … }
base::Value::Dict NetLogSpdyPriorityParams(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId parent_stream_id,
int weight,
bool exclusive) { … }
base::Value::Dict NetLogSpdyGreasedFrameParams(spdy::SpdyStreamId stream_id,
uint8_t type,
uint8_t flags,
size_t length,
RequestPriority priority) { … }
template <typename T, size_t N>
size_t GetTotalSize(const T (&arr)[N]) { … }
const size_t kMaxConcurrentStreamLimit = …;
}
SpdyProtocolErrorDetails MapFramerErrorToProtocolError(
http2::Http2DecoderAdapter::SpdyFramerError err) { … }
Error MapFramerErrorToNetError(
http2::Http2DecoderAdapter::SpdyFramerError err) { … }
SpdyProtocolErrorDetails MapRstStreamStatusToProtocolError(
spdy::SpdyErrorCode error_code) { … }
spdy::SpdyErrorCode MapNetErrorToGoAwayStatus(Error err) { … }
SpdyStreamRequest::SpdyStreamRequest() { … }
SpdyStreamRequest::~SpdyStreamRequest() { … }
int SpdyStreamRequest::StartRequest(
SpdyStreamType type,
const base::WeakPtr<SpdySession>& session,
const GURL& url,
bool can_send_early,
RequestPriority priority,
const SocketTag& socket_tag,
const NetLogWithSource& net_log,
CompletionOnceCallback callback,
const NetworkTrafficAnnotationTag& traffic_annotation,
bool detect_broken_connection,
base::TimeDelta heartbeat_interval) { … }
void SpdyStreamRequest::CancelRequest() { … }
base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() { … }
void SpdyStreamRequest::SetPriority(RequestPriority priority) { … }
void SpdyStreamRequest::OnRequestCompleteSuccess(
const base::WeakPtr<SpdyStream>& stream) { … }
void SpdyStreamRequest::OnRequestCompleteFailure(int rv) { … }
void SpdyStreamRequest::Reset() { … }
void SpdyStreamRequest::OnConfirmHandshakeComplete(int rv) { … }
bool SpdySession::CanPool(TransportSecurityState* transport_security_state,
const SSLInfo& ssl_info,
const SSLConfigService& ssl_config_service,
std::string_view old_hostname,
std::string_view new_hostname) { … }
SpdySession::SpdySession(
const SpdySessionKey& spdy_session_key,
HttpServerProperties* http_server_properties,
TransportSecurityState* transport_security_state,
SSLConfigService* ssl_config_service,
const quic::ParsedQuicVersionVector& quic_supported_versions,
bool enable_sending_initial_data,
bool enable_ping_based_connection_checking,
bool is_http2_enabled,
bool is_quic_enabled,
size_t session_max_recv_window_size,
int session_max_queued_capped_frames,
const spdy::SettingsMap& initial_settings,
bool enable_http2_settings_grease,
const std::optional<SpdySessionPool::GreasedHttp2Frame>&
greased_http2_frame,
bool http2_end_stream_with_data_frame,
bool enable_priority_update,
TimeFunc time_func,
NetworkQualityEstimator* network_quality_estimator,
NetLog* net_log)
: … { … }
SpdySession::~SpdySession() { … }
void SpdySession::InitializeWithSocketHandle(
std::unique_ptr<StreamSocketHandle> stream_socket_handle,
SpdySessionPool* pool) { … }
void SpdySession::InitializeWithSocket(
std::unique_ptr<StreamSocket> stream_socket,
const LoadTimingInfo::ConnectTiming& connect_timing,
SpdySessionPool* pool) { … }
int SpdySession::ParseAlps() { … }
bool SpdySession::VerifyDomainAuthentication(std::string_view domain) const { … }
void SpdySession::EnqueueStreamWrite(
const base::WeakPtr<SpdyStream>& stream,
spdy::SpdyFrameType frame_type,
std::unique_ptr<SpdyBufferProducer> producer) { … }
bool SpdySession::GreasedFramesEnabled() const { … }
void SpdySession::EnqueueGreasedFrame(const base::WeakPtr<SpdyStream>& stream) { … }
bool SpdySession::ShouldSendHttp2Priority() const { … }
bool SpdySession::ShouldSendPriorityUpdate() const { … }
int SpdySession::ConfirmHandshake(CompletionOnceCallback callback) { … }
std::unique_ptr<spdy::SpdySerializedFrame> SpdySession::CreateHeaders(
spdy::SpdyStreamId stream_id,
RequestPriority priority,
spdy::SpdyControlFlags flags,
quiche::HttpHeaderBlock block,
NetLogSource source_dependency) { … }
std::unique_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(
spdy::SpdyStreamId stream_id,
IOBuffer* data,
int len,
spdy::SpdyDataFlags flags,
int* effective_len,
bool* end_stream) { … }
void SpdySession::UpdateStreamPriority(SpdyStream* stream,
RequestPriority old_priority,
RequestPriority new_priority) { … }
void SpdySession::CloseActiveStream(spdy::SpdyStreamId stream_id, int status) { … }
void SpdySession::CloseCreatedStream(const base::WeakPtr<SpdyStream>& stream,
int status) { … }
void SpdySession::ResetStream(spdy::SpdyStreamId stream_id,
int error,
const std::string& description) { … }
bool SpdySession::IsStreamActive(spdy::SpdyStreamId stream_id) const { … }
LoadState SpdySession::GetLoadState() const { … }
int SpdySession::GetRemoteEndpoint(IPEndPoint* endpoint) { … }
bool SpdySession::GetSSLInfo(SSLInfo* ssl_info) const { … }
std::string_view SpdySession::GetAcceptChViaAlps(
const url::SchemeHostPort& scheme_host_port) const { … }
NextProto SpdySession::GetNegotiatedProtocol() const { … }
void SpdySession::SendStreamWindowUpdate(spdy::SpdyStreamId stream_id,
uint32_t delta_window_size) { … }
void SpdySession::CloseSessionOnError(Error err,
const std::string& description) { … }
void SpdySession::MakeUnavailable() { … }
void SpdySession::StartGoingAway(spdy::SpdyStreamId last_good_stream_id,
Error status) { … }
void SpdySession::MaybeFinishGoingAway() { … }
base::Value::Dict SpdySession::GetInfoAsValue() const { … }
bool SpdySession::IsReused() const { … }
bool SpdySession::GetLoadTimingInfo(spdy::SpdyStreamId stream_id,
LoadTimingInfo* load_timing_info) const { … }
int SpdySession::GetPeerAddress(IPEndPoint* address) const { … }
int SpdySession::GetLocalAddress(IPEndPoint* address) const { … }
void SpdySession::AddPooledAlias(const SpdySessionKey& alias_key) { … }
void SpdySession::RemovePooledAlias(const SpdySessionKey& alias_key) { … }
bool SpdySession::HasAcceptableTransportSecurity() const { … }
base::WeakPtr<SpdySession> SpdySession::GetWeakPtr() { … }
bool SpdySession::CloseOneIdleConnection() { … }
bool SpdySession::ChangeSocketTag(const SocketTag& new_tag) { … }
void SpdySession::EnableBrokenConnectionDetection(
base::TimeDelta heartbeat_interval) { … }
bool SpdySession::IsBrokenConnectionDetectionEnabled() const { … }
void SpdySession::InitializeInternal(SpdySessionPool* pool) { … }
int SpdySession::TryCreateStream(
const base::WeakPtr<SpdyStreamRequest>& request,
base::WeakPtr<SpdyStream>* stream) { … }
int SpdySession::CreateStream(const SpdyStreamRequest& request,
base::WeakPtr<SpdyStream>* stream) { … }
bool SpdySession::CancelStreamRequest(
const base::WeakPtr<SpdyStreamRequest>& request) { … }
void SpdySession::ChangeStreamRequestPriority(
const base::WeakPtr<SpdyStreamRequest>& request,
RequestPriority priority) { … }
base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() { … }
void SpdySession::ProcessPendingStreamRequests() { … }
void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
int status) { … }
void SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
int status) { … }
void SpdySession::ResetStreamIterator(ActiveStreamMap::iterator it,
int error,
const std::string& description) { … }
void SpdySession::EnqueueResetStreamFrame(spdy::SpdyStreamId stream_id,
RequestPriority priority,
spdy::SpdyErrorCode error_code,
const std::string& description) { … }
void SpdySession::EnqueuePriorityFrame(spdy::SpdyStreamId stream_id,
spdy::SpdyStreamId dependency_id,
int weight,
bool exclusive) { … }
void SpdySession::PumpReadLoop(ReadState expected_read_state, int result) { … }
int SpdySession::DoReadLoop(ReadState expected_read_state, int result) { … }
int SpdySession::DoRead() { … }
int SpdySession::DoReadComplete(int result) { … }
void SpdySession::PumpWriteLoop(WriteState expected_write_state, int result) { … }
void SpdySession::MaybePostWriteLoop() { … }
int SpdySession::DoWriteLoop(WriteState expected_write_state, int result) { … }
int SpdySession::DoWrite() { … }
int SpdySession::DoWriteComplete(int result) { … }
void SpdySession::NotifyRequestsOfConfirmation(int rv) { … }
void SpdySession::SendInitialData() { … }
void SpdySession::HandleSetting(uint32_t id, uint32_t value) { … }
void SpdySession::UpdateStreamsSendWindowSize(int32_t delta_window_size) { … }
void SpdySession::MaybeCheckConnectionStatus() { … }
void SpdySession::MaybeSendPrefacePing() { … }
void SpdySession::SendWindowUpdateFrame(spdy::SpdyStreamId stream_id,
uint32_t delta_window_size,
RequestPriority priority) { … }
void SpdySession::WritePingFrame(spdy::SpdyPingId unique_id, bool is_ack) { … }
void SpdySession::PlanToCheckPingStatus() { … }
void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) { … }
spdy::SpdyStreamId SpdySession::GetNewStreamId() { … }
void SpdySession::EnqueueSessionWrite(
RequestPriority priority,
spdy::SpdyFrameType frame_type,
std::unique_ptr<spdy::SpdySerializedFrame> frame) { … }
void SpdySession::EnqueueWrite(
RequestPriority priority,
spdy::SpdyFrameType frame_type,
std::unique_ptr<SpdyBufferProducer> producer,
const base::WeakPtr<SpdyStream>& stream,
const NetworkTrafficAnnotationTag& traffic_annotation) { … }
void SpdySession::InsertCreatedStream(std::unique_ptr<SpdyStream> stream) { … }
std::unique_ptr<SpdyStream> SpdySession::ActivateCreatedStream(
SpdyStream* stream) { … }
void SpdySession::InsertActivatedStream(std::unique_ptr<SpdyStream> stream) { … }
void SpdySession::DeleteStream(std::unique_ptr<SpdyStream> stream, int status) { … }
void SpdySession::RecordHistograms() { … }
void SpdySession::RecordProtocolErrorHistogram(
SpdyProtocolErrorDetails details) { … }
void SpdySession::DcheckGoingAway() const { … }
void SpdySession::DcheckDraining() const { … }
void SpdySession::DoDrainSession(Error err, const std::string& description) { … }
void SpdySession::LogAbandonedStream(SpdyStream* stream, Error status) { … }
void SpdySession::LogAbandonedActiveStream(ActiveStreamMap::const_iterator it,
Error status) { … }
void SpdySession::CompleteStreamRequest(
const base::WeakPtr<SpdyStreamRequest>& pending_request) { … }
void SpdySession::OnError(
http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) { … }
void SpdySession::OnStreamError(spdy::SpdyStreamId stream_id,
const std::string& description) { … }
void SpdySession::OnPing(spdy::SpdyPingId unique_id, bool is_ack) { … }
void SpdySession::OnRstStream(spdy::SpdyStreamId stream_id,
spdy::SpdyErrorCode error_code) { … }
void SpdySession::OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
spdy::SpdyErrorCode error_code,
std::string_view debug_data) { … }
void SpdySession::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
size_t length,
bool fin) { … }
void SpdySession::OnStreamFrameData(spdy::SpdyStreamId stream_id,
const char* data,
size_t len) { … }
void SpdySession::OnStreamEnd(spdy::SpdyStreamId stream_id) { … }
void SpdySession::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) { … }
void SpdySession::OnSettings() { … }
void SpdySession::OnSettingsAck() { … }
void SpdySession::OnSetting(spdy::SpdySettingsId id, uint32_t value) { … }
void SpdySession::OnSettingsEnd() { … }
void SpdySession::OnWindowUpdate(spdy::SpdyStreamId stream_id,
int delta_window_size) { … }
void SpdySession::OnPushPromise(spdy::SpdyStreamId ,
spdy::SpdyStreamId ,
quiche::HttpHeaderBlock ) { … }
void SpdySession::OnHeaders(spdy::SpdyStreamId stream_id,
bool has_priority,
int weight,
spdy::SpdyStreamId parent_stream_id,
bool exclusive,
bool fin,
quiche::HttpHeaderBlock headers,
base::TimeTicks recv_first_byte_time) { … }
void SpdySession::OnAltSvc(
spdy::SpdyStreamId stream_id,
std::string_view origin,
const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector& altsvc_vector) { … }
bool SpdySession::OnUnknownFrame(spdy::SpdyStreamId stream_id,
uint8_t frame_type) { … }
void SpdySession::OnSendCompressedFrame(spdy::SpdyStreamId stream_id,
spdy::SpdyFrameType type,
size_t payload_len,
size_t frame_len) { … }
void SpdySession::OnReceiveCompressedFrame(spdy::SpdyStreamId stream_id,
spdy::SpdyFrameType type,
size_t frame_len) { … }
void SpdySession::OnWriteBufferConsumed(
size_t frame_payload_size,
size_t consume_size,
SpdyBuffer::ConsumeSource consume_source) { … }
void SpdySession::IncreaseSendWindowSize(int delta_window_size) { … }
void SpdySession::DecreaseSendWindowSize(int32_t delta_window_size) { … }
void SpdySession::OnReadBufferConsumed(
size_t consume_size,
SpdyBuffer::ConsumeSource consume_source) { … }
void SpdySession::IncreaseRecvWindowSize(int32_t delta_window_size) { … }
void SpdySession::DecreaseRecvWindowSize(int32_t delta_window_size) { … }
void SpdySession::QueueSendStalledStream(const SpdyStream& stream) { … }
void SpdySession::ResumeSendStalledStreams() { … }
spdy::SpdyStreamId SpdySession::PopStreamToPossiblyResume() { … }
void SpdySession::CheckConnectionStatus() { … }
void SpdySession::OnDefaultNetworkActive() { … }
void SpdySession::MaybeDisableBrokenConnectionDetection() { … }
}