xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/tools/quic_spdy_client_base.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2015 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/tools/quic_spdy_client_base.h"
6 
7 #include <utility>
8 
9 
10 #include "absl/strings/numbers.h"
11 #include "absl/strings/str_cat.h"
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/crypto/quic_random.h"
14 #include "quiche/quic/core/http/spdy_utils.h"
15 #include "quiche/quic/core/quic_server_id.h"
16 #include "quiche/quic/platform/api/quic_flags.h"
17 #include "quiche/quic/platform/api/quic_logging.h"
18 #include "quiche/common/quiche_text_utils.h"
19 
20 using spdy::Http2HeaderBlock;
21 
22 namespace quic {
23 
QuicSpdyClientBase(const QuicServerId & server_id,const ParsedQuicVersionVector & supported_versions,const QuicConfig & config,QuicConnectionHelperInterface * helper,QuicAlarmFactory * alarm_factory,std::unique_ptr<NetworkHelper> network_helper,std::unique_ptr<ProofVerifier> proof_verifier,std::unique_ptr<SessionCache> session_cache)24 QuicSpdyClientBase::QuicSpdyClientBase(
25     const QuicServerId& server_id,
26     const ParsedQuicVersionVector& supported_versions, const QuicConfig& config,
27     QuicConnectionHelperInterface* helper, QuicAlarmFactory* alarm_factory,
28     std::unique_ptr<NetworkHelper> network_helper,
29     std::unique_ptr<ProofVerifier> proof_verifier,
30     std::unique_ptr<SessionCache> session_cache)
31     : QuicClientBase(server_id, supported_versions, config, helper,
32                      alarm_factory, std::move(network_helper),
33                      std::move(proof_verifier), std::move(session_cache)),
34       store_response_(false),
35       latest_response_code_(-1) {}
36 
~QuicSpdyClientBase()37 QuicSpdyClientBase::~QuicSpdyClientBase() {
38   ResetSession();
39 }
40 
client_session()41 QuicSpdyClientSession* QuicSpdyClientBase::client_session() {
42   return static_cast<QuicSpdyClientSession*>(QuicClientBase::session());
43 }
44 
client_session() const45 const QuicSpdyClientSession* QuicSpdyClientBase::client_session() const {
46   return static_cast<const QuicSpdyClientSession*>(QuicClientBase::session());
47 }
48 
InitializeSession()49 void QuicSpdyClientBase::InitializeSession() {
50   if (max_inbound_header_list_size_ > 0) {
51     client_session()->set_max_inbound_header_list_size(
52         max_inbound_header_list_size_);
53   }
54   client_session()->Initialize();
55   client_session()->CryptoConnect();
56 }
57 
OnClose(QuicSpdyStream * stream)58 void QuicSpdyClientBase::OnClose(QuicSpdyStream* stream) {
59   QUICHE_DCHECK(stream != nullptr);
60   QuicSpdyClientStream* client_stream =
61       static_cast<QuicSpdyClientStream*>(stream);
62 
63   const Http2HeaderBlock& response_headers = client_stream->response_headers();
64   if (response_listener_ != nullptr) {
65     response_listener_->OnCompleteResponse(stream->id(), response_headers,
66                                            client_stream->data());
67   }
68 
69   // Store response headers and body.
70   if (store_response_) {
71     auto status = response_headers.find(":status");
72     if (status == response_headers.end()) {
73       QUIC_LOG(ERROR) << "Missing :status response header";
74     } else if (!absl::SimpleAtoi(status->second, &latest_response_code_)) {
75       QUIC_LOG(ERROR) << "Invalid :status response header: " << status->second;
76     }
77     latest_response_headers_ = response_headers.DebugString();
78     for (const Http2HeaderBlock& headers :
79          client_stream->preliminary_headers()) {
80       absl::StrAppend(&preliminary_response_headers_, headers.DebugString());
81     }
82     latest_response_header_block_ = response_headers.Clone();
83     latest_response_body_ = std::string(client_stream->data());
84     latest_response_trailers_ =
85         client_stream->received_trailers().DebugString();
86     latest_ttfb_ = client_stream->time_to_response_headers_received();
87     latest_ttlb_ = client_stream->time_to_response_complete();
88   }
89 }
90 
CreateQuicClientSession(const quic::ParsedQuicVersionVector & supported_versions,QuicConnection * connection)91 std::unique_ptr<QuicSession> QuicSpdyClientBase::CreateQuicClientSession(
92     const quic::ParsedQuicVersionVector& supported_versions,
93     QuicConnection* connection) {
94   return std::make_unique<QuicSpdyClientSession>(
95       *config(), supported_versions, connection, server_id(), crypto_config());
96 }
97 
SendRequest(const Http2HeaderBlock & headers,absl::string_view body,bool fin)98 void QuicSpdyClientBase::SendRequest(const Http2HeaderBlock& headers,
99                                      absl::string_view body, bool fin) {
100   if (GetQuicFlag(quic_client_convert_http_header_name_to_lowercase)) {
101     QUIC_CODE_COUNT(quic_client_convert_http_header_name_to_lowercase);
102     Http2HeaderBlock sanitized_headers;
103     for (const auto& p : headers) {
104       sanitized_headers[quiche::QuicheTextUtils::ToLower(p.first)] = p.second;
105     }
106 
107     SendRequestInternal(std::move(sanitized_headers), body, fin);
108   } else {
109     SendRequestInternal(headers.Clone(), body, fin);
110   }
111 }
112 
SendRequestInternal(Http2HeaderBlock sanitized_headers,absl::string_view body,bool fin)113 void QuicSpdyClientBase::SendRequestInternal(Http2HeaderBlock sanitized_headers,
114                                              absl::string_view body, bool fin) {
115   QuicSpdyClientStream* stream = CreateClientStream();
116   if (stream == nullptr) {
117     QUIC_BUG(quic_bug_10949_1) << "stream creation failed!";
118     return;
119   }
120   stream->SendRequest(std::move(sanitized_headers), body, fin);
121 }
122 
SendRequestAndWaitForResponse(const Http2HeaderBlock & headers,absl::string_view body,bool fin)123 void QuicSpdyClientBase::SendRequestAndWaitForResponse(
124     const Http2HeaderBlock& headers, absl::string_view body, bool fin) {
125   SendRequest(headers, body, fin);
126   while (WaitForEvents()) {
127   }
128 }
129 
SendRequestsAndWaitForResponse(const std::vector<std::string> & url_list)130 void QuicSpdyClientBase::SendRequestsAndWaitForResponse(
131     const std::vector<std::string>& url_list) {
132   for (size_t i = 0; i < url_list.size(); ++i) {
133     Http2HeaderBlock headers;
134     if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
135       QUIC_BUG(quic_bug_10949_2) << "Unable to create request";
136       continue;
137     }
138     SendRequest(headers, "", true);
139   }
140   while (WaitForEvents()) {
141   }
142 }
143 
CreateClientStream()144 QuicSpdyClientStream* QuicSpdyClientBase::CreateClientStream() {
145   if (!connected()) {
146     return nullptr;
147   }
148   if (VersionHasIetfQuicFrames(client_session()->transport_version())) {
149     // Process MAX_STREAMS from peer or wait for liveness testing succeeds.
150     while (!client_session()->CanOpenNextOutgoingBidirectionalStream()) {
151       network_helper()->RunEventLoop();
152     }
153   }
154   auto* stream = static_cast<QuicSpdyClientStream*>(
155       client_session()->CreateOutgoingBidirectionalStream());
156   if (stream) {
157     stream->set_visitor(this);
158   }
159   return stream;
160 }
161 
goaway_received() const162 bool QuicSpdyClientBase::goaway_received() const {
163   return client_session() && client_session()->goaway_received();
164 }
165 
last_received_http3_goaway_id()166 std::optional<uint64_t> QuicSpdyClientBase::last_received_http3_goaway_id() {
167   return client_session() ? client_session()->last_received_http3_goaway_id()
168                           : std::nullopt;
169 }
170 
EarlyDataAccepted()171 bool QuicSpdyClientBase::EarlyDataAccepted() {
172   return client_session()->EarlyDataAccepted();
173 }
174 
ReceivedInchoateReject()175 bool QuicSpdyClientBase::ReceivedInchoateReject() {
176   return client_session()->ReceivedInchoateReject();
177 }
178 
GetNumSentClientHellosFromSession()179 int QuicSpdyClientBase::GetNumSentClientHellosFromSession() {
180   return client_session()->GetNumSentClientHellos();
181 }
182 
GetNumReceivedServerConfigUpdatesFromSession()183 int QuicSpdyClientBase::GetNumReceivedServerConfigUpdatesFromSession() {
184   return client_session()->GetNumReceivedServerConfigUpdates();
185 }
186 
latest_response_code() const187 int QuicSpdyClientBase::latest_response_code() const {
188   QUIC_BUG_IF(quic_bug_10949_3, !store_response_) << "Response not stored!";
189   return latest_response_code_;
190 }
191 
latest_response_headers() const192 const std::string& QuicSpdyClientBase::latest_response_headers() const {
193   QUIC_BUG_IF(quic_bug_10949_4, !store_response_) << "Response not stored!";
194   return latest_response_headers_;
195 }
196 
preliminary_response_headers() const197 const std::string& QuicSpdyClientBase::preliminary_response_headers() const {
198   QUIC_BUG_IF(quic_bug_10949_5, !store_response_) << "Response not stored!";
199   return preliminary_response_headers_;
200 }
201 
latest_response_header_block() const202 const Http2HeaderBlock& QuicSpdyClientBase::latest_response_header_block()
203     const {
204   QUIC_BUG_IF(quic_bug_10949_6, !store_response_) << "Response not stored!";
205   return latest_response_header_block_;
206 }
207 
latest_response_body() const208 const std::string& QuicSpdyClientBase::latest_response_body() const {
209   QUIC_BUG_IF(quic_bug_10949_7, !store_response_) << "Response not stored!";
210   return latest_response_body_;
211 }
212 
latest_response_trailers() const213 const std::string& QuicSpdyClientBase::latest_response_trailers() const {
214   QUIC_BUG_IF(quic_bug_10949_8, !store_response_) << "Response not stored!";
215   return latest_response_trailers_;
216 }
217 
HasActiveRequests()218 bool QuicSpdyClientBase::HasActiveRequests() {
219   return client_session()->HasActiveRequestStreams();
220 }
221 
222 }  // namespace quic
223