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