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 // A base class for the toy client, which connects to a specified port and sends 6 // QUIC request to that endpoint. 7 8 #ifndef QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_ 9 #define QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_ 10 11 #include <string> 12 13 #include "absl/strings/string_view.h" 14 #include "quiche/quic/core/crypto/crypto_handshake.h" 15 #include "quiche/quic/core/http/quic_client_push_promise_index.h" 16 #include "quiche/quic/core/http/quic_spdy_client_session.h" 17 #include "quiche/quic/core/http/quic_spdy_client_stream.h" 18 #include "quiche/quic/core/quic_config.h" 19 #include "quiche/quic/platform/api/quic_socket_address.h" 20 #include "quiche/quic/tools/quic_client_base.h" 21 #include "quiche/spdy/core/http2_header_block.h" 22 23 namespace quic { 24 25 class ProofVerifier; 26 class QuicServerId; 27 class SessionCache; 28 29 class QuicSpdyClientBase : public QuicClientBase, 30 public QuicClientPushPromiseIndex::Delegate, 31 public QuicSpdyStream::Visitor { 32 public: 33 // A ResponseListener is notified when a complete response is received. 34 class ResponseListener { 35 public: ResponseListener()36 ResponseListener() {} ~ResponseListener()37 virtual ~ResponseListener() {} 38 virtual void OnCompleteResponse( 39 QuicStreamId id, const spdy::Http2HeaderBlock& response_headers, 40 absl::string_view response_body) = 0; 41 }; 42 43 // A piece of data that can be sent multiple times. For example, it can be a 44 // HTTP request that is resent after a connect=>version negotiation=>reconnect 45 // sequence. 46 class QuicDataToResend { 47 public: 48 // |headers| may be null, since it's possible to send data without headers. 49 QuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers, 50 absl::string_view body, bool fin); 51 QuicDataToResend(const QuicDataToResend&) = delete; 52 QuicDataToResend& operator=(const QuicDataToResend&) = delete; 53 54 virtual ~QuicDataToResend(); 55 56 // Must be overridden by specific classes with the actual method for 57 // re-sending data. 58 virtual void Resend() = 0; 59 60 protected: 61 std::unique_ptr<spdy::Http2HeaderBlock> headers_; 62 absl::string_view body_; 63 bool fin_; 64 }; 65 66 QuicSpdyClientBase(const QuicServerId& server_id, 67 const ParsedQuicVersionVector& supported_versions, 68 const QuicConfig& config, 69 QuicConnectionHelperInterface* helper, 70 QuicAlarmFactory* alarm_factory, 71 std::unique_ptr<NetworkHelper> network_helper, 72 std::unique_ptr<ProofVerifier> proof_verifier, 73 std::unique_ptr<SessionCache> session_cache); 74 QuicSpdyClientBase(const QuicSpdyClientBase&) = delete; 75 QuicSpdyClientBase& operator=(const QuicSpdyClientBase&) = delete; 76 77 ~QuicSpdyClientBase() override; 78 79 // QuicSpdyStream::Visitor 80 void OnClose(QuicSpdyStream* stream) override; 81 82 // A spdy session has to call CryptoConnect on top of the regular 83 // initialization. 84 void InitializeSession() override; 85 86 // Sends an HTTP request and does not wait for response before returning. 87 void SendRequest(const spdy::Http2HeaderBlock& headers, 88 absl::string_view body, bool fin); 89 90 // Sends an HTTP request and waits for response before returning. 91 void SendRequestAndWaitForResponse(const spdy::Http2HeaderBlock& headers, 92 absl::string_view body, bool fin); 93 94 // Sends a request simple GET for each URL in |url_list|, and then waits for 95 // each to complete. 96 void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list); 97 98 // Returns a newly created QuicSpdyClientStream. 99 virtual QuicSpdyClientStream* CreateClientStream(); 100 101 // Returns a the session used for this client downcasted to a 102 // QuicSpdyClientSession. 103 QuicSpdyClientSession* client_session(); 104 const QuicSpdyClientSession* client_session() const; 105 push_promise_index()106 QuicClientPushPromiseIndex* push_promise_index() { 107 return &push_promise_index_; 108 } 109 110 bool CheckVary(const spdy::Http2HeaderBlock& client_request, 111 const spdy::Http2HeaderBlock& promise_request, 112 const spdy::Http2HeaderBlock& promise_response) override; 113 void OnRendezvousResult(QuicSpdyStream*) override; 114 115 // If the crypto handshake has not yet been confirmed, adds the data to the 116 // queue of data to resend if the client receives a stateless reject. 117 // Otherwise, deletes the data. 118 void MaybeAddQuicDataToResend( 119 std::unique_ptr<QuicDataToResend> data_to_resend); 120 set_store_response(bool val)121 void set_store_response(bool val) { store_response_ = val; } 122 123 int latest_response_code() const; 124 const std::string& latest_response_headers() const; 125 const std::string& preliminary_response_headers() const; 126 const spdy::Http2HeaderBlock& latest_response_header_block() const; 127 const std::string& latest_response_body() const; 128 const std::string& latest_response_trailers() const; 129 set_response_listener(std::unique_ptr<ResponseListener> listener)130 void set_response_listener(std::unique_ptr<ResponseListener> listener) { 131 response_listener_ = std::move(listener); 132 } 133 set_drop_response_body(bool drop_response_body)134 void set_drop_response_body(bool drop_response_body) { 135 drop_response_body_ = drop_response_body; 136 } drop_response_body()137 bool drop_response_body() const { return drop_response_body_; } 138 set_enable_web_transport(bool enable_web_transport)139 void set_enable_web_transport(bool enable_web_transport) { 140 enable_web_transport_ = enable_web_transport; 141 } enable_web_transport()142 bool enable_web_transport() const { return enable_web_transport_; } 143 set_use_datagram_contexts(bool use_datagram_contexts)144 void set_use_datagram_contexts(bool use_datagram_contexts) { 145 use_datagram_contexts_ = use_datagram_contexts; 146 } use_datagram_contexts()147 bool use_datagram_contexts() const { return use_datagram_contexts_; } 148 149 // QuicClientBase methods. 150 bool goaway_received() const override; 151 bool EarlyDataAccepted() override; 152 bool ReceivedInchoateReject() override; 153 set_max_inbound_header_list_size(size_t size)154 void set_max_inbound_header_list_size(size_t size) { 155 max_inbound_header_list_size_ = size; 156 } 157 158 protected: 159 int GetNumSentClientHellosFromSession() override; 160 int GetNumReceivedServerConfigUpdatesFromSession() override; 161 162 // Takes ownership of |connection|. 163 std::unique_ptr<QuicSession> CreateQuicClientSession( 164 const quic::ParsedQuicVersionVector& supported_versions, 165 QuicConnection* connection) override; 166 167 void ClearDataToResend() override; 168 169 void ResendSavedData() override; 170 171 void AddPromiseDataToResend(const spdy::Http2HeaderBlock& headers, 172 absl::string_view body, bool fin); 173 bool HasActiveRequests() override; 174 175 private: 176 // Specific QuicClient class for storing data to resend. 177 class ClientQuicDataToResend : public QuicDataToResend { 178 public: ClientQuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers,absl::string_view body,bool fin,QuicSpdyClientBase * client)179 ClientQuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers, 180 absl::string_view body, bool fin, 181 QuicSpdyClientBase* client) 182 : QuicDataToResend(std::move(headers), body, fin), client_(client) { 183 QUICHE_DCHECK(headers_); 184 QUICHE_DCHECK(client); 185 } 186 187 ClientQuicDataToResend(const ClientQuicDataToResend&) = delete; 188 ClientQuicDataToResend& operator=(const ClientQuicDataToResend&) = delete; ~ClientQuicDataToResend()189 ~ClientQuicDataToResend() override {} 190 191 void Resend() override; 192 193 private: 194 QuicSpdyClientBase* client_; 195 }; 196 197 void SendRequestInternal(spdy::Http2HeaderBlock sanitized_headers, 198 absl::string_view body, bool fin); 199 200 // Index of pending promised streams. Must outlive |session_|. 201 QuicClientPushPromiseIndex push_promise_index_; 202 203 // If true, store the latest response code, headers, and body. 204 bool store_response_; 205 // HTTP response code from most recent response. 206 int latest_response_code_; 207 // HTTP/2 headers from most recent response. 208 std::string latest_response_headers_; 209 // preliminary 100 Continue HTTP/2 headers from most recent response, if any. 210 std::string preliminary_response_headers_; 211 // HTTP/2 headers from most recent response. 212 spdy::Http2HeaderBlock latest_response_header_block_; 213 // Body of most recent response. 214 std::string latest_response_body_; 215 // HTTP/2 trailers from most recent response. 216 std::string latest_response_trailers_; 217 218 // Listens for full responses. 219 std::unique_ptr<ResponseListener> response_listener_; 220 221 // Keeps track of any data that must be resent upon a subsequent successful 222 // connection, in case the client receives a stateless reject. 223 std::vector<std::unique_ptr<QuicDataToResend>> data_to_resend_on_connect_; 224 225 std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_; 226 227 bool drop_response_body_ = false; 228 bool enable_web_transport_ = false; 229 bool use_datagram_contexts_ = false; 230 // If not zero, used to set client's max inbound header size before session 231 // initialize. 232 size_t max_inbound_header_list_size_ = 0; 233 }; 234 235 } // namespace quic 236 237 #endif // QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_ 238