xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/quic_test_client.h (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 #ifndef QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
6 #define QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
7 
8 #include <cstdint>
9 #include <memory>
10 #include <string>
11 
12 #include "absl/strings/string_view.h"
13 #include "quiche/quic/core/io/quic_event_loop.h"
14 #include "quiche/quic/core/proto/cached_network_parameters_proto.h"
15 #include "quiche/quic/core/quic_framer.h"
16 #include "quiche/quic/core/quic_packet_creator.h"
17 #include "quiche/quic/core/quic_packets.h"
18 #include "quiche/quic/platform/api/quic_test.h"
19 #include "quiche/quic/tools/quic_default_client.h"
20 #include "quiche/common/quiche_callbacks.h"
21 #include "quiche/common/quiche_linked_hash_map.h"
22 #include "quiche/spdy/core/http2_header_block.h"
23 
24 namespace quic {
25 
26 class ProofVerifier;
27 class QuicPacketWriterWrapper;
28 
29 namespace test {
30 
31 class MockableQuicClientDefaultNetworkHelper
32     : public QuicClientDefaultNetworkHelper {
33  public:
34   using QuicClientDefaultNetworkHelper::QuicClientDefaultNetworkHelper;
35   ~MockableQuicClientDefaultNetworkHelper() override = default;
36 
37   void ProcessPacket(const QuicSocketAddress& self_address,
38                      const QuicSocketAddress& peer_address,
39                      const QuicReceivedPacket& packet) override;
40 
41   SocketFd CreateUDPSocket(QuicSocketAddress server_address,
42                            bool* overflow_supported) override;
43 
44   QuicPacketWriter* CreateQuicPacketWriter() override;
45 
46   void set_socket_fd_configurator(
47       quiche::MultiUseCallback<void(SocketFd)> socket_fd_configurator);
48 
49   const QuicReceivedPacket* last_incoming_packet();
50 
51   void set_track_last_incoming_packet(bool track);
52 
53   void UseWriter(QuicPacketWriterWrapper* writer);
54 
55   void set_peer_address(const QuicSocketAddress& address);
56 
57  private:
58   QuicPacketWriterWrapper* test_writer_ = nullptr;
59   // The last incoming packet, iff |track_last_incoming_packet_| is true.
60   std::unique_ptr<QuicReceivedPacket> last_incoming_packet_;
61   // If true, copy each packet from ProcessPacket into |last_incoming_packet_|
62   bool track_last_incoming_packet_ = false;
63   // If set, |socket_fd_configurator_| will be called after a socket fd is
64   // created.
65   quiche::MultiUseCallback<void(SocketFd)> socket_fd_configurator_;
66 };
67 
68 // A quic client which allows mocking out reads and writes.
69 class MockableQuicClient : public QuicDefaultClient {
70  public:
71   MockableQuicClient(QuicSocketAddress server_address,
72                      const QuicServerId& server_id,
73                      const ParsedQuicVersionVector& supported_versions,
74                      QuicEventLoop* event_loop);
75 
76   MockableQuicClient(QuicSocketAddress server_address,
77                      const QuicServerId& server_id, const QuicConfig& config,
78                      const ParsedQuicVersionVector& supported_versions,
79                      QuicEventLoop* event_loop);
80 
81   MockableQuicClient(QuicSocketAddress server_address,
82                      const QuicServerId& server_id, const QuicConfig& config,
83                      const ParsedQuicVersionVector& supported_versions,
84                      QuicEventLoop* event_loop,
85                      std::unique_ptr<ProofVerifier> proof_verifier);
86 
87   MockableQuicClient(QuicSocketAddress server_address,
88                      const QuicServerId& server_id, const QuicConfig& config,
89                      const ParsedQuicVersionVector& supported_versions,
90                      QuicEventLoop* event_loop,
91                      std::unique_ptr<ProofVerifier> proof_verifier,
92                      std::unique_ptr<SessionCache> session_cache);
93   MockableQuicClient(const MockableQuicClient&) = delete;
94   MockableQuicClient& operator=(const MockableQuicClient&) = delete;
95 
96   ~MockableQuicClient() override;
97 
98   QuicConnectionId GetClientConnectionId() override;
99   void UseClientConnectionId(QuicConnectionId client_connection_id);
100   void UseClientConnectionIdLength(int client_connection_id_length);
101 
102   void UseWriter(QuicPacketWriterWrapper* writer);
103   void set_peer_address(const QuicSocketAddress& address);
104   // The last incoming packet, iff |track_last_incoming_packet| is true.
105   const QuicReceivedPacket* last_incoming_packet();
106   // If true, copy each packet from ProcessPacket into |last_incoming_packet|
107   void set_track_last_incoming_packet(bool track);
108 
109   // Casts the network helper to a MockableQuicClientDefaultNetworkHelper.
110   MockableQuicClientDefaultNetworkHelper* mockable_network_helper();
111   const MockableQuicClientDefaultNetworkHelper* mockable_network_helper() const;
112 
113  private:
114   // Client connection ID to use, if client_connection_id_overridden_.
115   // TODO(wub): Move client_connection_id_(length_) overrides to QuicClientBase.
116   QuicConnectionId override_client_connection_id_;
117   bool client_connection_id_overridden_;
118   int override_client_connection_id_length_ = -1;
119   CachedNetworkParameters cached_network_paramaters_;
120 };
121 
122 // A toy QUIC client used for testing.
123 class QuicTestClient : public QuicSpdyStream::Visitor {
124  public:
125   QuicTestClient(QuicSocketAddress server_address,
126                  const std::string& server_hostname,
127                  const ParsedQuicVersionVector& supported_versions);
128   QuicTestClient(QuicSocketAddress server_address,
129                  const std::string& server_hostname, const QuicConfig& config,
130                  const ParsedQuicVersionVector& supported_versions);
131   QuicTestClient(QuicSocketAddress server_address,
132                  const std::string& server_hostname, const QuicConfig& config,
133                  const ParsedQuicVersionVector& supported_versions,
134                  std::unique_ptr<ProofVerifier> proof_verifier);
135   QuicTestClient(QuicSocketAddress server_address,
136                  const std::string& server_hostname, const QuicConfig& config,
137                  const ParsedQuicVersionVector& supported_versions,
138                  std::unique_ptr<ProofVerifier> proof_verifier,
139                  std::unique_ptr<SessionCache> session_cache);
140   QuicTestClient(QuicSocketAddress server_address,
141                  const std::string& server_hostname, const QuicConfig& config,
142                  const ParsedQuicVersionVector& supported_versions,
143                  std::unique_ptr<ProofVerifier> proof_verifier,
144                  std::unique_ptr<SessionCache> session_cache,
145                  std::unique_ptr<QuicEventLoop> event_loop);
146 
147   ~QuicTestClient() override;
148 
149   // Sets the |user_agent_id| of the |client_|.
150   void SetUserAgentID(const std::string& user_agent_id);
151 
152   // Wraps data in a quic packet and sends it.
153   int64_t SendData(const std::string& data, bool last_data);
154   // As above, but |delegate| will be notified when |data| is ACKed.
155   int64_t SendData(
156       const std::string& data, bool last_data,
157       quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
158           ack_listener);
159 
160   // Clears any outstanding state and sends a simple GET of 'uri' to the
161   // server.  Returns 0 if the request failed and no bytes were written.
162   int64_t SendRequest(const std::string& uri);
163   // Send a request R and a RST_FRAME which resets R, in the same packet.
164   int64_t SendRequestAndRstTogether(const std::string& uri);
165   // Sends requests for all the urls and waits for the responses.  To process
166   // the individual responses as they are returned, the caller should use the
167   // set the response_listener on the client().
168   void SendRequestsAndWaitForResponses(
169       const std::vector<std::string>& url_list);
170   // Sends a request containing |headers| and |body| and returns the number of
171   // bytes sent (the size of the serialized request headers and body).
172   int64_t SendMessage(const spdy::Http2HeaderBlock& headers,
173                       absl::string_view body);
174   // Sends a request containing |headers| and |body| with the fin bit set to
175   // |fin| and returns the number of bytes sent (the size of the serialized
176   // request headers and body).
177   int64_t SendMessage(const spdy::Http2HeaderBlock& headers,
178                       absl::string_view body, bool fin);
179   // Sends a request containing |headers| and |body| with the fin bit set to
180   // |fin| and returns the number of bytes sent (the size of the serialized
181   // request headers and body). If |flush| is true, will wait for the message to
182   // be flushed before returning.
183   int64_t SendMessage(const spdy::Http2HeaderBlock& headers,
184                       absl::string_view body, bool fin, bool flush);
185   // Sends a request containing |headers| and |body|, waits for the response,
186   // and returns the response body.
187   std::string SendCustomSynchronousRequest(
188       const spdy::Http2HeaderBlock& headers, const std::string& body);
189   // Sends a GET request for |uri|, waits for the response, and returns the
190   // response body.
191   std::string SendSynchronousRequest(const std::string& uri);
192   void SendConnectivityProbing();
193   void Connect();
194   void ResetConnection();
195   void Disconnect();
196   QuicSocketAddress local_address() const;
197   void ClearPerRequestState();
198   bool WaitUntil(int timeout_ms,
199                  std::optional<quiche::UnretainedCallback<bool()>> trigger);
200   int64_t Send(absl::string_view data);
201   bool connected() const;
202   bool buffer_body() const;
203   void set_buffer_body(bool buffer_body);
204 
205   // Getters for stream state that only get updated once a complete response is
206   // received.
207   const spdy::Http2HeaderBlock& response_trailers() const;
208   bool response_complete() const;
209   int64_t response_body_size() const;
210   const std::string& response_body() const;
211   // Getters for stream state that return state of the oldest active stream that
212   // have received a partial response.
213   bool response_headers_complete() const;
214   const spdy::Http2HeaderBlock* response_headers() const;
215   int64_t response_size() const;
216   size_t bytes_read() const;
217   size_t bytes_written() const;
218 
219   // Returns response body received so far by the stream that has been most
220   // recently opened among currently open streams.  To query response body
221   // received by a stream that is already closed, use `response_body()` instead.
222   absl::string_view partial_response_body() const;
223 
224   // Returns once at least one complete response or a connection close has been
225   // received from the server. If responses are received for multiple (say 2)
226   // streams, next WaitForResponse will return immediately.
WaitForResponse()227   void WaitForResponse() { WaitForResponseForMs(-1); }
228 
229   // Returns once some data is received on any open streams or at least one
230   // complete response is received from the server.
WaitForInitialResponse()231   void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); }
232 
233   // Returns once at least one complete response or a connection close has been
234   // received from the server, or once the timeout expires.
235   // Passing in a timeout value of -1 disables the timeout. If multiple
236   // responses are received while the client is waiting, subsequent calls to
237   // this function will return immediately.
WaitForResponseForMs(int timeout_ms)238   void WaitForResponseForMs(int timeout_ms) {
239     WaitUntil(timeout_ms, [this]() {
240       return !HaveActiveStream() || !closed_stream_states_.empty();
241     });
242     if (response_complete()) {
243       QUIC_VLOG(1) << "Client received response:"
244                    << response_headers()->DebugString() << response_body();
245     }
246   }
247 
248   // Returns once a goaway a connection close has been
249   // received from the server, or once the timeout expires.
250   // Passing in a timeout value of -1 disables the timeout.
WaitForGoAway(int timeout_ms)251   void WaitForGoAway(int timeout_ms) {
252     WaitUntil(timeout_ms, [this]() { return client()->goaway_received(); });
253   }
254 
255   // Returns once some data is received on any open streams or at least one
256   // complete response is received from the server, or once the timeout
257   // expires. -1 means no timeout.
WaitForInitialResponseForMs(int timeout_ms)258   void WaitForInitialResponseForMs(int timeout_ms) {
259     WaitUntil(timeout_ms,
260               [this]() { return !HaveActiveStream() || response_size() != 0; });
261   }
262 
263   // Migrate local address to <|new_host|, a random port>.
264   // Return whether the migration succeeded.
265   bool MigrateSocket(const QuicIpAddress& new_host);
266   // Migrate local address to <|new_host|, |port|>.
267   // Return whether the migration succeeded.
268   bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port);
269   QuicIpAddress bind_to_address() const;
270   void set_bind_to_address(QuicIpAddress address);
271   const QuicSocketAddress& address() const;
272 
273   // From QuicSpdyStream::Visitor
274   void OnClose(QuicSpdyStream* stream) override;
275 
276   // Configures client_ to take ownership of and use the writer.
277   // Must be called before initial connect.
278   void UseWriter(QuicPacketWriterWrapper* writer);
279   // Configures client_ to use a specific server connection ID instead of a
280   // random one.
281   void UseConnectionId(QuicConnectionId server_connection_id);
282   // Configures client_ to use a specific server connection ID length instead
283   // of the default of kQuicDefaultConnectionIdLength.
284   void UseConnectionIdLength(uint8_t server_connection_id_length);
285   // Configures client_ to use a specific client connection ID instead of an
286   // empty one.
287   void UseClientConnectionId(QuicConnectionId client_connection_id);
288   // Configures client_ to use a specific client connection ID length instead
289   // of the default of zero.
290   void UseClientConnectionIdLength(uint8_t client_connection_id_length);
291 
292   // Returns nullptr if the maximum number of streams have already been created.
293   QuicSpdyClientStream* GetOrCreateStream();
294 
295   // Calls GetOrCreateStream(), sends the request on the stream, and
296   // stores the request in case it needs to be resent.  If |headers| is
297   // null, only the body will be sent on the stream.
298   int64_t GetOrCreateStreamAndSendRequest(
299       const spdy::Http2HeaderBlock* headers, absl::string_view body, bool fin,
300       quiche::QuicheReferenceCountedPointer<QuicAckListenerInterface>
301           ack_listener);
302 
stream_error()303   QuicRstStreamErrorCode stream_error() { return stream_error_; }
304   QuicErrorCode connection_error() const;
305 
client()306   MockableQuicClient* client() { return client_.get(); }
client()307   const MockableQuicClient* client() const { return client_.get(); }
308 
309   // cert_common_name returns the common name value of the server's certificate,
310   // or the empty std::string if no certificate was presented.
311   const std::string& cert_common_name() const;
312 
313   // cert_sct returns the signed timestamp of the server's certificate,
314   // or the empty std::string if no signed timestamp was presented.
315   const std::string& cert_sct() const;
316 
317   // Get the server config map.  Server config must exist.
318   const QuicTagValueMap& GetServerConfig() const;
319 
set_auto_reconnect(bool reconnect)320   void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
321 
set_priority(spdy::SpdyPriority priority)322   void set_priority(spdy::SpdyPriority priority) { priority_ = priority; }
323 
324   void WaitForWriteToFlush();
325 
event_loop()326   QuicEventLoop* event_loop() { return event_loop_.get(); }
327 
num_requests()328   size_t num_requests() const { return num_requests_; }
329 
num_responses()330   size_t num_responses() const { return num_responses_; }
331 
set_server_address(const QuicSocketAddress & server_address)332   void set_server_address(const QuicSocketAddress& server_address) {
333     client_->set_server_address(server_address);
334   }
335 
set_peer_address(const QuicSocketAddress & address)336   void set_peer_address(const QuicSocketAddress& address) {
337     client_->set_peer_address(address);
338   }
339 
340   // Explicitly set the SNI value for this client, overriding the default
341   // behavior which extracts the SNI value from the request URL.
OverrideSni(const std::string & sni)342   void OverrideSni(const std::string& sni) {
343     override_sni_set_ = true;
344     override_sni_ = sni;
345   }
346 
347   void Initialize();
348 
set_client(std::unique_ptr<MockableQuicClient> client)349   void set_client(std::unique_ptr<MockableQuicClient> client) {
350     client_ = std::move(client);
351   }
352 
353   // Given |uri|, populates the fields in |headers| for a simple GET
354   // request. If |uri| is a relative URL, the QuicServerId will be
355   // use to specify the authority.
356   bool PopulateHeaderBlockFromUrl(const std::string& uri,
357                                   spdy::Http2HeaderBlock* headers);
358 
359   // Waits for a period of time that is long enough to receive all delayed acks
360   // sent by peer.
361   void WaitForDelayedAcks();
362 
latest_created_stream()363   QuicSpdyClientStream* latest_created_stream() {
364     return latest_created_stream_;
365   }
366 
367  protected:
368   QuicTestClient();
369   QuicTestClient(const QuicTestClient&) = delete;
370   QuicTestClient(const QuicTestClient&&) = delete;
371   QuicTestClient& operator=(const QuicTestClient&) = delete;
372   QuicTestClient& operator=(const QuicTestClient&&) = delete;
373 
374  private:
375   // PerStreamState of a stream is updated when it is closed.
376   struct PerStreamState {
377     PerStreamState(const PerStreamState& other);
378     PerStreamState(QuicRstStreamErrorCode stream_error, bool response_complete,
379                    bool response_headers_complete,
380                    const spdy::Http2HeaderBlock& response_headers,
381                    const std::string& response,
382                    const spdy::Http2HeaderBlock& response_trailers,
383                    uint64_t bytes_read, uint64_t bytes_written,
384                    int64_t response_body_size);
385     ~PerStreamState();
386 
387     QuicRstStreamErrorCode stream_error;
388     bool response_complete;
389     bool response_headers_complete;
390     spdy::Http2HeaderBlock response_headers;
391     std::string response;
392     spdy::Http2HeaderBlock response_trailers;
393     uint64_t bytes_read;
394     uint64_t bytes_written;
395     int64_t response_body_size;
396   };
397 
398   bool HaveActiveStream();
399 
400   // Read oldest received response and remove it from closed_stream_states_.
401   void ReadNextResponse();
402 
403   // Clear open_streams_, closed_stream_states_ and reset
404   // latest_created_stream_.
405   void ClearPerConnectionState();
406 
407   // Update latest_created_stream_, add |stream| to open_streams_ and starts
408   // tracking its state.
409   void SetLatestCreatedStream(QuicSpdyClientStream* stream);
410 
411   std::unique_ptr<QuicEventLoop> event_loop_;
412   std::unique_ptr<MockableQuicClient> client_;  // The actual client
413   QuicSpdyClientStream* latest_created_stream_;
414   std::map<QuicStreamId, QuicSpdyClientStream*> open_streams_;
415   // Received responses of closed streams.
416   quiche::QuicheLinkedHashMap<QuicStreamId, PerStreamState>
417       closed_stream_states_;
418 
419   QuicRstStreamErrorCode stream_error_;
420 
421   bool response_complete_;
422   bool response_headers_complete_;
423   mutable spdy::Http2HeaderBlock response_headers_;
424 
425   // Parsed response trailers (if present), copied from the stream in OnClose.
426   spdy::Http2HeaderBlock response_trailers_;
427 
428   spdy::SpdyPriority priority_;
429   std::string response_;
430   // bytes_read_ and bytes_written_ are updated only when stream_ is released;
431   // prefer bytes_read() and bytes_written() member functions.
432   uint64_t bytes_read_;
433   uint64_t bytes_written_;
434   // The number of HTTP body bytes received.
435   int64_t response_body_size_;
436   // True if we tried to connect already since the last call to Disconnect().
437   bool connect_attempted_;
438   // The client will auto-connect exactly once before sending data.  If
439   // something causes a connection reset, it will not automatically reconnect
440   // unless auto_reconnect_ is true.
441   bool auto_reconnect_;
442   // Should we buffer the response body? Defaults to true.
443   bool buffer_body_;
444   // Number of requests/responses this client has sent/received.
445   size_t num_requests_;
446   size_t num_responses_;
447 
448   // If set, this value is used for the connection SNI, overriding the usual
449   // logic which extracts the SNI from the request URL.
450   bool override_sni_set_ = false;
451   std::string override_sni_;
452 };
453 
454 }  // namespace test
455 
456 }  // namespace quic
457 
458 #endif  // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_
459