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