chromium/net/spdy/spdy_session.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#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 =;

// Default initial value for HTTP/2 SETTINGS.
const uint32_t kDefaultInitialHeaderTableSize =;
const uint32_t kDefaultInitialEnablePush =;
const uint32_t kDefaultInitialInitialWindowSize =;
const uint32_t kDefaultInitialMaxFrameSize =;

// These values are persisted to logs. Entries should not be renumbered, and
// numeric values should never be reused.
enum class SpdyAcceptChEntries {};

// A SpdyBufferProducer implementation that creates an HTTP/2 frame by adding
// stream ID to greased frame parameters.
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) {}

// Helper function to return the total size of an array of objects
// with .size() member functions.
template <typename T, size_t N>
size_t GetTotalSize(const T (&arr)[N]) {}

// The maximum number of concurrent streams we will ever create.  Even if
// the server permits more, we will never exceed this limit.
const size_t kMaxConcurrentStreamLimit =;

}  // namespace

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) {}

// static
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) {}

// {,Try}CreateStream() can be called with |in_io_loop_| set if a stream is
// being created in response to another being closed due to received data.

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 /*stream_id*/,
                                spdy::SpdyStreamId /*promised_stream_id*/,
                                quiche::HttpHeaderBlock /*headers*/) {}

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() {}

}  // namespace net