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