blob: f74974f4231a663ea9633a966af364919ad63384 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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
dschinazi56fb53e2019-06-21 15:30:04 -070012#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/core/quic_framer.h"
14#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
15#include "net/third_party/quiche/src/quic/core/quic_packets.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
17#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
dschinazi580d30b2019-04-26 15:05:20 -070019#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050020#include "net/third_party/quiche/src/quic/tools/quic_client.h"
QUICHE team6dcf6ab2019-12-11 10:10:51 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022
23namespace quic {
24
25class ProofVerifier;
26class QuicPacketWriterWrapper;
27
28namespace test {
29
30class MockableQuicClientEpollNetworkHelper;
31
32// A quic client which allows mocking out reads and writes.
33class MockableQuicClient : public QuicClient {
34 public:
35 MockableQuicClient(QuicSocketAddress server_address,
36 const QuicServerId& server_id,
37 const ParsedQuicVersionVector& supported_versions,
38 QuicEpollServer* epoll_server);
39
40 MockableQuicClient(QuicSocketAddress server_address,
41 const QuicServerId& server_id,
42 const QuicConfig& config,
43 const ParsedQuicVersionVector& supported_versions,
44 QuicEpollServer* epoll_server);
45
46 MockableQuicClient(QuicSocketAddress server_address,
47 const QuicServerId& server_id,
48 const QuicConfig& config,
49 const ParsedQuicVersionVector& supported_versions,
50 QuicEpollServer* epoll_server,
51 std::unique_ptr<ProofVerifier> proof_verifier);
52 MockableQuicClient(const MockableQuicClient&) = delete;
53 MockableQuicClient& operator=(const MockableQuicClient&) = delete;
54
55 ~MockableQuicClient() override;
56
57 QuicConnectionId GenerateNewConnectionId() override;
dschinazi8ff74822019-05-28 16:37:20 -070058 void UseConnectionId(QuicConnectionId server_connection_id);
dschinazic8579862019-07-24 18:20:20 -070059 void UseConnectionIdLength(int server_connection_id_length);
dschinazi346b7ce2019-06-05 01:38:18 -070060 QuicConnectionId GetClientConnectionId() override;
61 void UseClientConnectionId(QuicConnectionId client_connection_id);
dschinazic8579862019-07-24 18:20:20 -070062 void UseClientConnectionIdLength(int client_connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -050063
64 void UseWriter(QuicPacketWriterWrapper* writer);
65 void set_peer_address(const QuicSocketAddress& address);
66 // The last incoming packet, iff |track_last_incoming_packet| is true.
67 const QuicReceivedPacket* last_incoming_packet();
68 // If true, copy each packet from ProcessPacket into |last_incoming_packet|
69 void set_track_last_incoming_packet(bool track);
70
71 // Casts the network helper to a MockableQuicClientEpollNetworkHelper.
72 MockableQuicClientEpollNetworkHelper* mockable_network_helper();
73 const MockableQuicClientEpollNetworkHelper* mockable_network_helper() const;
74
75 private:
dschinazi8ff74822019-05-28 16:37:20 -070076 // Server connection ID to use, if server_connection_id_overridden_
77 QuicConnectionId override_server_connection_id_;
78 bool server_connection_id_overridden_;
dschinazic8579862019-07-24 18:20:20 -070079 int override_server_connection_id_length_ = -1;
dschinazi346b7ce2019-06-05 01:38:18 -070080 // Client connection ID to use, if client_connection_id_overridden_
81 QuicConnectionId override_client_connection_id_;
82 bool client_connection_id_overridden_;
dschinazic8579862019-07-24 18:20:20 -070083 int override_client_connection_id_length_ = -1;
QUICHE teama6ef0a62019-03-07 20:34:33 -050084 CachedNetworkParameters cached_network_paramaters_;
85};
86
87// A toy QUIC client used for testing.
88class QuicTestClient : public QuicSpdyStream::Visitor,
89 public QuicClientPushPromiseIndex::Delegate {
90 public:
91 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070092 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050093 const ParsedQuicVersionVector& supported_versions);
94 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070095 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050096 const QuicConfig& config,
97 const ParsedQuicVersionVector& supported_versions);
98 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070099 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100 const QuicConfig& config,
101 const ParsedQuicVersionVector& supported_versions,
102 std::unique_ptr<ProofVerifier> proof_verifier);
103
104 ~QuicTestClient() override;
105
106 // Sets the |user_agent_id| of the |client_|.
vasilvvc48c8712019-03-11 13:38:16 -0700107 void SetUserAgentID(const std::string& user_agent_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500108
109 // Wraps data in a quic packet and sends it.
vasilvvc48c8712019-03-11 13:38:16 -0700110 ssize_t SendData(const std::string& data, bool last_data);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 // As above, but |delegate| will be notified when |data| is ACKed.
112 ssize_t SendData(
vasilvvc48c8712019-03-11 13:38:16 -0700113 const std::string& data,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500114 bool last_data,
115 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
116
117 // Clears any outstanding state and sends a simple GET of 'uri' to the
118 // server. Returns 0 if the request failed and no bytes were written.
vasilvvc48c8712019-03-11 13:38:16 -0700119 ssize_t SendRequest(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 // Send a request R and a RST_FRAME which resets R, in the same packet.
vasilvvc48c8712019-03-11 13:38:16 -0700121 ssize_t SendRequestAndRstTogether(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500122 // Sends requests for all the urls and waits for the responses. To process
123 // the individual responses as they are returned, the caller should use the
124 // set the response_listener on the client().
vasilvvc48c8712019-03-11 13:38:16 -0700125 void SendRequestsAndWaitForResponses(
126 const std::vector<std::string>& url_list);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500127 // Sends a request containing |headers| and |body| and returns the number of
128 // bytes sent (the size of the serialized request headers and body).
129 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800130 quiche::QuicheStringPiece body);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500131 // Sends a request containing |headers| and |body| with the fin bit set to
132 // |fin| and returns the number of bytes sent (the size of the serialized
133 // request headers and body).
134 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800135 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500136 bool fin);
137 // Sends a request containing |headers| and |body| with the fin bit set to
138 // |fin| and returns the number of bytes sent (the size of the serialized
139 // request headers and body). If |flush| is true, will wait for the message to
140 // be flushed before returning.
141 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800142 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 bool fin,
144 bool flush);
145 // Sends a request containing |headers| and |body|, waits for the response,
146 // and returns the response body.
vasilvvc48c8712019-03-11 13:38:16 -0700147 std::string SendCustomSynchronousRequest(const spdy::SpdyHeaderBlock& headers,
148 const std::string& body);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500149 // Sends a GET request for |uri|, waits for the response, and returns the
150 // response body.
vasilvvc48c8712019-03-11 13:38:16 -0700151 std::string SendSynchronousRequest(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500152 void SendConnectivityProbing();
153 void Connect();
154 void ResetConnection();
155 void Disconnect();
156 QuicSocketAddress local_address() const;
157 void ClearPerRequestState();
158 bool WaitUntil(int timeout_ms, std::function<bool()> trigger);
dschinazib3b51de2019-12-19 16:52:04 -0800159 ssize_t Send(quiche::QuicheStringPiece data);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500160 bool connected() const;
161 bool buffer_body() const;
162 void set_buffer_body(bool buffer_body);
163
164 // Getters for stream state. Please note, these getters are divided into two
165 // groups. 1) returns state which only get updated once a complete response
166 // is received. 2) returns state of the oldest active stream which have
167 // received partial response (if any).
168 // Group 1.
169 const spdy::SpdyHeaderBlock& response_trailers() const;
170 bool response_complete() const;
171 int64_t response_body_size() const;
vasilvvc48c8712019-03-11 13:38:16 -0700172 const std::string& response_body() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 // Group 2.
174 bool response_headers_complete() const;
175 const spdy::SpdyHeaderBlock* response_headers() const;
176 const spdy::SpdyHeaderBlock* preliminary_headers() const;
177 int64_t response_size() const;
178 size_t bytes_read() const;
179 size_t bytes_written() const;
180
181 // Returns once at least one complete response or a connection close has been
182 // received from the server. If responses are received for multiple (say 2)
183 // streams, next WaitForResponse will return immediately.
184 void WaitForResponse() { WaitForResponseForMs(-1); }
185
186 // Returns once some data is received on any open streams or at least one
187 // complete response is received from the server.
188 void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); }
189
190 // Returns once at least one complete response or a connection close has been
191 // received from the server, or once the timeout expires. -1 means no timeout.
192 // If responses are received for multiple (say 2) streams, next
193 // WaitForResponseForMs will return immediately.
194 void WaitForResponseForMs(int timeout_ms) {
195 WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); });
196 if (response_complete()) {
dschinazi4620e9a2019-04-26 16:07:11 -0700197 QUIC_VLOG(1) << "Client received response:"
198 << response_headers()->DebugString() << response_body();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500199 }
200 }
201
202 // Returns once some data is received on any open streams or at least one
203 // complete response is received from the server, or once the timeout
204 // expires. -1 means no timeout.
205 void WaitForInitialResponseForMs(int timeout_ms) {
206 WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
207 }
208
209 // Migrate local address to <|new_host|, a random port>.
210 // Return whether the migration succeeded.
211 bool MigrateSocket(const QuicIpAddress& new_host);
212 // Migrate local address to <|new_host|, |port|>.
213 // Return whether the migration succeeded.
214 bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port);
215 QuicIpAddress bind_to_address() const;
216 void set_bind_to_address(QuicIpAddress address);
217 const QuicSocketAddress& address() const;
218
219 // From QuicSpdyStream::Visitor
220 void OnClose(QuicSpdyStream* stream) override;
221
222 // From QuicClientPushPromiseIndex::Delegate
223 bool CheckVary(const spdy::SpdyHeaderBlock& client_request,
224 const spdy::SpdyHeaderBlock& promise_request,
225 const spdy::SpdyHeaderBlock& promise_response) override;
226 void OnRendezvousResult(QuicSpdyStream*) override;
227
228 // Configures client_ to take ownership of and use the writer.
229 // Must be called before initial connect.
230 void UseWriter(QuicPacketWriterWrapper* writer);
dschinazi8ff74822019-05-28 16:37:20 -0700231 // Configures client_ to use a specific server connection ID instead of a
232 // random one.
233 void UseConnectionId(QuicConnectionId server_connection_id);
dschinazic8579862019-07-24 18:20:20 -0700234 // Configures client_ to use a specific server connection ID length instead
235 // of the default of kQuicDefaultConnectionIdLength.
236 void UseConnectionIdLength(int server_connection_id_length);
dschinazi346b7ce2019-06-05 01:38:18 -0700237 // Configures client_ to use a specific client connection ID instead of an
238 // empty one.
239 void UseClientConnectionId(QuicConnectionId client_connection_id);
dschinazic8579862019-07-24 18:20:20 -0700240 // Configures client_ to use a specific client connection ID length instead
241 // of the default of zero.
242 void UseClientConnectionIdLength(int client_connection_id_length);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500243
244 // Returns nullptr if the maximum number of streams have already been created.
245 QuicSpdyClientStream* GetOrCreateStream();
246
247 // Calls GetOrCreateStream(), sends the request on the stream, and
248 // stores the request in case it needs to be resent. If |headers| is
249 // null, only the body will be sent on the stream.
250 ssize_t GetOrCreateStreamAndSendRequest(
251 const spdy::SpdyHeaderBlock* headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800252 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500253 bool fin,
254 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
255
256 QuicRstStreamErrorCode stream_error() { return stream_error_; }
257 QuicErrorCode connection_error();
258
259 MockableQuicClient* client();
260
261 // cert_common_name returns the common name value of the server's certificate,
vasilvvc48c8712019-03-11 13:38:16 -0700262 // or the empty std::string if no certificate was presented.
263 const std::string& cert_common_name() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500264
265 // cert_sct returns the signed timestamp of the server's certificate,
vasilvvc48c8712019-03-11 13:38:16 -0700266 // or the empty std::string if no signed timestamp was presented.
267 const std::string& cert_sct() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268
269 // Get the server config map.
270 QuicTagValueMap GetServerConfig() const;
271
272 void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
273
274 void set_priority(spdy::SpdyPriority priority) { priority_ = priority; }
275
276 void WaitForWriteToFlush();
277
278 QuicEpollServer* epoll_server() { return &epoll_server_; }
279
280 size_t num_requests() const { return num_requests_; }
281
282 size_t num_responses() const { return num_responses_; }
283
284 void set_server_address(const QuicSocketAddress& server_address) {
285 client_->set_server_address(server_address);
286 }
287
288 void set_peer_address(const QuicSocketAddress& address) {
289 client_->set_peer_address(address);
290 }
291
292 // Explicitly set the SNI value for this client, overriding the default
293 // behavior which extracts the SNI value from the request URL.
vasilvvc48c8712019-03-11 13:38:16 -0700294 void OverrideSni(const std::string& sni) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295 override_sni_set_ = true;
296 override_sni_ = sni;
297 }
298
299 void Initialize();
300
301 void set_client(MockableQuicClient* client) { client_.reset(client); }
302
303 // Given |uri|, populates the fields in |headers| for a simple GET
304 // request. If |uri| is a relative URL, the QuicServerId will be
305 // use to specify the authority.
vasilvvc48c8712019-03-11 13:38:16 -0700306 bool PopulateHeaderBlockFromUrl(const std::string& uri,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500307 spdy::SpdyHeaderBlock* headers);
308
309 // Waits for a period of time that is long enough to receive all delayed acks
310 // sent by peer.
311 void WaitForDelayedAcks();
312
313 QuicSpdyClientStream* latest_created_stream() {
314 return latest_created_stream_;
315 }
316
317 protected:
318 QuicTestClient();
319 QuicTestClient(const QuicTestClient&) = delete;
320 QuicTestClient& operator=(const QuicTestClient&) = delete;
321
322 private:
323 class TestClientDataToResend : public QuicClient::QuicDataToResend {
324 public:
325 TestClientDataToResend(
326 std::unique_ptr<spdy::SpdyHeaderBlock> headers,
QUICHE team6dcf6ab2019-12-11 10:10:51 -0800327 quiche::QuicheStringPiece body,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500328 bool fin,
329 QuicTestClient* test_client,
330 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
331
332 ~TestClientDataToResend() override;
333
334 void Resend() override;
335
336 protected:
337 QuicTestClient* test_client_;
338 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
339 };
340
341 // PerStreamState of a stream is updated when it is closed.
342 struct PerStreamState {
343 PerStreamState(const PerStreamState& other);
344 PerStreamState(QuicRstStreamErrorCode stream_error,
345 bool response_complete,
346 bool response_headers_complete,
347 const spdy::SpdyHeaderBlock& response_headers,
348 const spdy::SpdyHeaderBlock& preliminary_headers,
vasilvvc48c8712019-03-11 13:38:16 -0700349 const std::string& response,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 const spdy::SpdyHeaderBlock& response_trailers,
351 uint64_t bytes_read,
352 uint64_t bytes_written,
353 int64_t response_body_size);
354 ~PerStreamState();
355
356 QuicRstStreamErrorCode stream_error;
357 bool response_complete;
358 bool response_headers_complete;
359 spdy::SpdyHeaderBlock response_headers;
360 spdy::SpdyHeaderBlock preliminary_headers;
vasilvvc48c8712019-03-11 13:38:16 -0700361 std::string response;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362 spdy::SpdyHeaderBlock response_trailers;
363 uint64_t bytes_read;
364 uint64_t bytes_written;
365 int64_t response_body_size;
366 };
367
368 bool HaveActiveStream();
369
370 // Read oldest received response and remove it from closed_stream_states_.
371 void ReadNextResponse();
372
373 // Clear open_streams_, closed_stream_states_ and reset
374 // latest_created_stream_.
375 void ClearPerConnectionState();
376
377 // Update latest_created_stream_, add |stream| to open_streams_ and starts
378 // tracking its state.
379 void SetLatestCreatedStream(QuicSpdyClientStream* stream);
380
381 QuicEpollServer epoll_server_;
382 std::unique_ptr<MockableQuicClient> client_; // The actual client
383 QuicSpdyClientStream* latest_created_stream_;
384 std::map<QuicStreamId, QuicSpdyClientStream*> open_streams_;
385 // Received responses of closed streams.
386 QuicLinkedHashMap<QuicStreamId, PerStreamState> closed_stream_states_;
387
388 QuicRstStreamErrorCode stream_error_;
389
390 bool response_complete_;
391 bool response_headers_complete_;
392 mutable spdy::SpdyHeaderBlock preliminary_headers_;
393 mutable spdy::SpdyHeaderBlock response_headers_;
394
395 // Parsed response trailers (if present), copied from the stream in OnClose.
396 spdy::SpdyHeaderBlock response_trailers_;
397
398 spdy::SpdyPriority priority_;
vasilvvc48c8712019-03-11 13:38:16 -0700399 std::string response_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500400 // bytes_read_ and bytes_written_ are updated only when stream_ is released;
401 // prefer bytes_read() and bytes_written() member functions.
402 uint64_t bytes_read_;
403 uint64_t bytes_written_;
404 // The number of HTTP body bytes received.
405 int64_t response_body_size_;
406 // True if we tried to connect already since the last call to Disconnect().
407 bool connect_attempted_;
408 // The client will auto-connect exactly once before sending data. If
409 // something causes a connection reset, it will not automatically reconnect
410 // unless auto_reconnect_ is true.
411 bool auto_reconnect_;
412 // Should we buffer the response body? Defaults to true.
413 bool buffer_body_;
414 // For async push promise rendezvous, validation may fail in which
415 // case the request should be retried.
416 std::unique_ptr<TestClientDataToResend> push_promise_data_to_resend_;
417 // Number of requests/responses this client has sent/received.
418 size_t num_requests_;
419 size_t num_responses_;
420
421 // If set, this value is used for the connection SNI, overriding the usual
422 // logic which extracts the SNI from the request URL.
423 bool override_sni_set_ = false;
vasilvvc48c8712019-03-11 13:38:16 -0700424 std::string override_sni_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500425};
426
427} // namespace test
428
429} // namespace quic
430
431#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_