xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_client_session.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 "quiche/quic/core/http/quic_spdy_client_session.h"
6 
7 #include <string>
8 #include <utility>
9 
10 #include "absl/memory/memory.h"
11 #include "quiche/quic/core/crypto/crypto_protocol.h"
12 #include "quiche/quic/core/http/quic_server_initiated_spdy_stream.h"
13 #include "quiche/quic/core/http/quic_spdy_client_stream.h"
14 #include "quiche/quic/core/http/spdy_utils.h"
15 #include "quiche/quic/core/quic_server_id.h"
16 #include "quiche/quic/core/quic_utils.h"
17 #include "quiche/quic/platform/api/quic_bug_tracker.h"
18 #include "quiche/quic/platform/api/quic_flag_utils.h"
19 #include "quiche/quic/platform/api/quic_flags.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 
22 namespace quic {
23 
QuicSpdyClientSession(const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QuicConnection * connection,const QuicServerId & server_id,QuicCryptoClientConfig * crypto_config)24 QuicSpdyClientSession::QuicSpdyClientSession(
25     const QuicConfig& config, const ParsedQuicVersionVector& supported_versions,
26     QuicConnection* connection, const QuicServerId& server_id,
27     QuicCryptoClientConfig* crypto_config)
28     : QuicSpdyClientSession(config, supported_versions, connection, nullptr,
29                             server_id, crypto_config) {}
30 
QuicSpdyClientSession(const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QuicConnection * connection,QuicSession::Visitor * visitor,const QuicServerId & server_id,QuicCryptoClientConfig * crypto_config)31 QuicSpdyClientSession::QuicSpdyClientSession(
32     const QuicConfig& config, const ParsedQuicVersionVector& supported_versions,
33     QuicConnection* connection, QuicSession::Visitor* visitor,
34     const QuicServerId& server_id, QuicCryptoClientConfig* crypto_config)
35     : QuicSpdyClientSessionBase(connection, visitor, config,
36                                 supported_versions),
37       server_id_(server_id),
38       crypto_config_(crypto_config),
39       respect_goaway_(true) {}
40 
41 QuicSpdyClientSession::~QuicSpdyClientSession() = default;
42 
Initialize()43 void QuicSpdyClientSession::Initialize() {
44   crypto_stream_ = CreateQuicCryptoStream();
45   QuicSpdyClientSessionBase::Initialize();
46 }
47 
OnProofValid(const QuicCryptoClientConfig::CachedState &)48 void QuicSpdyClientSession::OnProofValid(
49     const QuicCryptoClientConfig::CachedState& /*cached*/) {}
50 
OnProofVerifyDetailsAvailable(const ProofVerifyDetails &)51 void QuicSpdyClientSession::OnProofVerifyDetailsAvailable(
52     const ProofVerifyDetails& /*verify_details*/) {}
53 
ShouldCreateOutgoingBidirectionalStream()54 bool QuicSpdyClientSession::ShouldCreateOutgoingBidirectionalStream() {
55   if (!crypto_stream_->encryption_established()) {
56     QUIC_DLOG(INFO) << "Encryption not active so no outgoing stream created.";
57     QUIC_CODE_COUNT(
58         quic_client_fails_to_create_stream_encryption_not_established);
59     return false;
60   }
61   if (goaway_received() && respect_goaway_) {
62     QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
63                     << "Already received goaway.";
64     QUIC_CODE_COUNT(quic_client_fails_to_create_stream_goaway_received);
65     return false;
66   }
67   return CanOpenNextOutgoingBidirectionalStream();
68 }
69 
ShouldCreateOutgoingUnidirectionalStream()70 bool QuicSpdyClientSession::ShouldCreateOutgoingUnidirectionalStream() {
71   QUIC_BUG(quic_bug_10396_1)
72       << "Try to create outgoing unidirectional client data streams";
73   return false;
74 }
75 
76 QuicSpdyClientStream*
CreateOutgoingBidirectionalStream()77 QuicSpdyClientSession::CreateOutgoingBidirectionalStream() {
78   if (!ShouldCreateOutgoingBidirectionalStream()) {
79     return nullptr;
80   }
81   std::unique_ptr<QuicSpdyClientStream> stream = CreateClientStream();
82   QuicSpdyClientStream* stream_ptr = stream.get();
83   ActivateStream(std::move(stream));
84   return stream_ptr;
85 }
86 
87 QuicSpdyClientStream*
CreateOutgoingUnidirectionalStream()88 QuicSpdyClientSession::CreateOutgoingUnidirectionalStream() {
89   QUIC_BUG(quic_bug_10396_2)
90       << "Try to create outgoing unidirectional client data streams";
91   return nullptr;
92 }
93 
94 std::unique_ptr<QuicSpdyClientStream>
CreateClientStream()95 QuicSpdyClientSession::CreateClientStream() {
96   return std::make_unique<QuicSpdyClientStream>(
97       GetNextOutgoingBidirectionalStreamId(), this, BIDIRECTIONAL);
98 }
99 
GetMutableCryptoStream()100 QuicCryptoClientStreamBase* QuicSpdyClientSession::GetMutableCryptoStream() {
101   return crypto_stream_.get();
102 }
103 
GetCryptoStream() const104 const QuicCryptoClientStreamBase* QuicSpdyClientSession::GetCryptoStream()
105     const {
106   return crypto_stream_.get();
107 }
108 
CryptoConnect()109 void QuicSpdyClientSession::CryptoConnect() {
110   QUICHE_DCHECK(flow_controller());
111   crypto_stream_->CryptoConnect();
112 }
113 
GetNumSentClientHellos() const114 int QuicSpdyClientSession::GetNumSentClientHellos() const {
115   return crypto_stream_->num_sent_client_hellos();
116 }
117 
ResumptionAttempted() const118 bool QuicSpdyClientSession::ResumptionAttempted() const {
119   return crypto_stream_->ResumptionAttempted();
120 }
121 
IsResumption() const122 bool QuicSpdyClientSession::IsResumption() const {
123   return crypto_stream_->IsResumption();
124 }
125 
EarlyDataAccepted() const126 bool QuicSpdyClientSession::EarlyDataAccepted() const {
127   return crypto_stream_->EarlyDataAccepted();
128 }
129 
ReceivedInchoateReject() const130 bool QuicSpdyClientSession::ReceivedInchoateReject() const {
131   return crypto_stream_->ReceivedInchoateReject();
132 }
133 
GetNumReceivedServerConfigUpdates() const134 int QuicSpdyClientSession::GetNumReceivedServerConfigUpdates() const {
135   return crypto_stream_->num_scup_messages_received();
136 }
137 
ShouldCreateIncomingStream(QuicStreamId id)138 bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) {
139   if (!connection()->connected()) {
140     QUIC_BUG(quic_bug_10396_3)
141         << "ShouldCreateIncomingStream called when disconnected";
142     return false;
143   }
144   if (goaway_received() && respect_goaway_) {
145     QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. "
146                     << "Already received goaway.";
147     return false;
148   }
149 
150   if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
151     QUIC_BUG(quic_bug_10396_4)
152         << "ShouldCreateIncomingStream called with client initiated "
153            "stream ID.";
154     return false;
155   }
156 
157   if (QuicUtils::IsClientInitiatedStreamId(transport_version(), id)) {
158     QUIC_LOG(WARNING) << "Received invalid push stream id " << id;
159     connection()->CloseConnection(
160         QUIC_INVALID_STREAM_ID,
161         "Server created non write unidirectional stream",
162         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
163     return false;
164   }
165 
166   if (VersionHasIetfQuicFrames(transport_version()) &&
167       QuicUtils::IsBidirectionalStreamId(id, version()) &&
168       !WillNegotiateWebTransport()) {
169     connection()->CloseConnection(
170         QUIC_HTTP_SERVER_INITIATED_BIDIRECTIONAL_STREAM,
171         "Server created bidirectional stream.",
172         ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
173     return false;
174   }
175 
176   return true;
177 }
178 
CreateIncomingStream(PendingStream * pending)179 QuicSpdyStream* QuicSpdyClientSession::CreateIncomingStream(
180     PendingStream* pending) {
181   QuicSpdyStream* stream = new QuicSpdyClientStream(pending, this);
182   ActivateStream(absl::WrapUnique(stream));
183   return stream;
184 }
185 
CreateIncomingStream(QuicStreamId id)186 QuicSpdyStream* QuicSpdyClientSession::CreateIncomingStream(QuicStreamId id) {
187   if (!ShouldCreateIncomingStream(id)) {
188     return nullptr;
189   }
190   QuicSpdyStream* stream;
191   if (version().UsesHttp3() &&
192       QuicUtils::IsBidirectionalStreamId(id, version())) {
193     QUIC_BUG_IF(QuicServerInitiatedSpdyStream but no WebTransport support,
194                 !WillNegotiateWebTransport())
195         << "QuicServerInitiatedSpdyStream created but no WebTransport support";
196     stream = new QuicServerInitiatedSpdyStream(id, this, BIDIRECTIONAL);
197   } else {
198     stream = new QuicSpdyClientStream(id, this, READ_UNIDIRECTIONAL);
199   }
200   ActivateStream(absl::WrapUnique(stream));
201   return stream;
202 }
203 
204 std::unique_ptr<QuicCryptoClientStreamBase>
CreateQuicCryptoStream()205 QuicSpdyClientSession::CreateQuicCryptoStream() {
206   return std::make_unique<QuicCryptoClientStream>(
207       server_id_, this,
208       crypto_config_->proof_verifier()->CreateDefaultContext(), crypto_config_,
209       this, /*has_application_state = */ version().UsesHttp3());
210 }
211 
212 }  // namespace quic
213