blob: a4ee0d5cb804f7332a99c28d80630b50653426f4 [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
QUICHE teama6ef0a62019-03-07 20:34:33 -050012#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.pb.h"
13#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"
19#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
dschinazi580d30b2019-04-26 15:05:20 -070020#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021#include "net/third_party/quiche/src/quic/tools/quic_client.h"
22
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);
QUICHE teama6ef0a62019-03-07 20:34:33 -050059
60 void UseWriter(QuicPacketWriterWrapper* writer);
61 void set_peer_address(const QuicSocketAddress& address);
62 // The last incoming packet, iff |track_last_incoming_packet| is true.
63 const QuicReceivedPacket* last_incoming_packet();
64 // If true, copy each packet from ProcessPacket into |last_incoming_packet|
65 void set_track_last_incoming_packet(bool track);
66
67 // Casts the network helper to a MockableQuicClientEpollNetworkHelper.
68 MockableQuicClientEpollNetworkHelper* mockable_network_helper();
69 const MockableQuicClientEpollNetworkHelper* mockable_network_helper() const;
70
71 private:
dschinazi8ff74822019-05-28 16:37:20 -070072 // Server connection ID to use, if server_connection_id_overridden_
73 QuicConnectionId override_server_connection_id_;
74 bool server_connection_id_overridden_;
QUICHE teama6ef0a62019-03-07 20:34:33 -050075 CachedNetworkParameters cached_network_paramaters_;
76};
77
78// A toy QUIC client used for testing.
79class QuicTestClient : public QuicSpdyStream::Visitor,
80 public QuicClientPushPromiseIndex::Delegate {
81 public:
82 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070083 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050084 const ParsedQuicVersionVector& supported_versions);
85 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070086 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050087 const QuicConfig& config,
88 const ParsedQuicVersionVector& supported_versions);
89 QuicTestClient(QuicSocketAddress server_address,
vasilvvc48c8712019-03-11 13:38:16 -070090 const std::string& server_hostname,
QUICHE teama6ef0a62019-03-07 20:34:33 -050091 const QuicConfig& config,
92 const ParsedQuicVersionVector& supported_versions,
93 std::unique_ptr<ProofVerifier> proof_verifier);
94
95 ~QuicTestClient() override;
96
97 // Sets the |user_agent_id| of the |client_|.
vasilvvc48c8712019-03-11 13:38:16 -070098 void SetUserAgentID(const std::string& user_agent_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -050099
100 // Wraps data in a quic packet and sends it.
vasilvvc48c8712019-03-11 13:38:16 -0700101 ssize_t SendData(const std::string& data, bool last_data);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500102 // As above, but |delegate| will be notified when |data| is ACKed.
103 ssize_t SendData(
vasilvvc48c8712019-03-11 13:38:16 -0700104 const std::string& data,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500105 bool last_data,
106 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
107
108 // Clears any outstanding state and sends a simple GET of 'uri' to the
109 // server. Returns 0 if the request failed and no bytes were written.
vasilvvc48c8712019-03-11 13:38:16 -0700110 ssize_t SendRequest(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111 // Send a request R and a RST_FRAME which resets R, in the same packet.
vasilvvc48c8712019-03-11 13:38:16 -0700112 ssize_t SendRequestAndRstTogether(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113 // Sends requests for all the urls and waits for the responses. To process
114 // the individual responses as they are returned, the caller should use the
115 // set the response_listener on the client().
vasilvvc48c8712019-03-11 13:38:16 -0700116 void SendRequestsAndWaitForResponses(
117 const std::vector<std::string>& url_list);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500118 // Sends a request containing |headers| and |body| and returns the number of
119 // bytes sent (the size of the serialized request headers and body).
120 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
121 QuicStringPiece body);
122 // Sends a request containing |headers| and |body| with the fin bit set to
123 // |fin| and returns the number of bytes sent (the size of the serialized
124 // request headers and body).
125 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
126 QuicStringPiece body,
127 bool fin);
128 // Sends a request containing |headers| and |body| with the fin bit set to
129 // |fin| and returns the number of bytes sent (the size of the serialized
130 // request headers and body). If |flush| is true, will wait for the message to
131 // be flushed before returning.
132 ssize_t SendMessage(const spdy::SpdyHeaderBlock& headers,
133 QuicStringPiece body,
134 bool fin,
135 bool flush);
136 // Sends a request containing |headers| and |body|, waits for the response,
137 // and returns the response body.
vasilvvc48c8712019-03-11 13:38:16 -0700138 std::string SendCustomSynchronousRequest(const spdy::SpdyHeaderBlock& headers,
139 const std::string& body);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500140 // Sends a GET request for |uri|, waits for the response, and returns the
141 // response body.
vasilvvc48c8712019-03-11 13:38:16 -0700142 std::string SendSynchronousRequest(const std::string& uri);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143 void SendConnectivityProbing();
144 void Connect();
145 void ResetConnection();
146 void Disconnect();
147 QuicSocketAddress local_address() const;
148 void ClearPerRequestState();
149 bool WaitUntil(int timeout_ms, std::function<bool()> trigger);
150 ssize_t Send(const void* buffer, size_t size);
151 bool connected() const;
152 bool buffer_body() const;
153 void set_buffer_body(bool buffer_body);
154
155 // Getters for stream state. Please note, these getters are divided into two
156 // groups. 1) returns state which only get updated once a complete response
157 // is received. 2) returns state of the oldest active stream which have
158 // received partial response (if any).
159 // Group 1.
160 const spdy::SpdyHeaderBlock& response_trailers() const;
161 bool response_complete() const;
162 int64_t response_body_size() const;
vasilvvc48c8712019-03-11 13:38:16 -0700163 const std::string& response_body() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500164 // Group 2.
165 bool response_headers_complete() const;
166 const spdy::SpdyHeaderBlock* response_headers() const;
167 const spdy::SpdyHeaderBlock* preliminary_headers() const;
168 int64_t response_size() const;
169 size_t bytes_read() const;
170 size_t bytes_written() const;
171
172 // Returns once at least one complete response or a connection close has been
173 // received from the server. If responses are received for multiple (say 2)
174 // streams, next WaitForResponse will return immediately.
175 void WaitForResponse() { WaitForResponseForMs(-1); }
176
177 // Returns once some data is received on any open streams or at least one
178 // complete response is received from the server.
179 void WaitForInitialResponse() { WaitForInitialResponseForMs(-1); }
180
181 // Returns once at least one complete response or a connection close has been
182 // received from the server, or once the timeout expires. -1 means no timeout.
183 // If responses are received for multiple (say 2) streams, next
184 // WaitForResponseForMs will return immediately.
185 void WaitForResponseForMs(int timeout_ms) {
186 WaitUntil(timeout_ms, [this]() { return !closed_stream_states_.empty(); });
187 if (response_complete()) {
dschinazi4620e9a2019-04-26 16:07:11 -0700188 QUIC_VLOG(1) << "Client received response:"
189 << response_headers()->DebugString() << response_body();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500190 }
191 }
192
193 // Returns once some data is received on any open streams or at least one
194 // complete response is received from the server, or once the timeout
195 // expires. -1 means no timeout.
196 void WaitForInitialResponseForMs(int timeout_ms) {
197 WaitUntil(timeout_ms, [this]() { return response_size() != 0; });
198 }
199
200 // Migrate local address to <|new_host|, a random port>.
201 // Return whether the migration succeeded.
202 bool MigrateSocket(const QuicIpAddress& new_host);
203 // Migrate local address to <|new_host|, |port|>.
204 // Return whether the migration succeeded.
205 bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port);
206 QuicIpAddress bind_to_address() const;
207 void set_bind_to_address(QuicIpAddress address);
208 const QuicSocketAddress& address() const;
209
210 // From QuicSpdyStream::Visitor
211 void OnClose(QuicSpdyStream* stream) override;
212
213 // From QuicClientPushPromiseIndex::Delegate
214 bool CheckVary(const spdy::SpdyHeaderBlock& client_request,
215 const spdy::SpdyHeaderBlock& promise_request,
216 const spdy::SpdyHeaderBlock& promise_response) override;
217 void OnRendezvousResult(QuicSpdyStream*) override;
218
219 // Configures client_ to take ownership of and use the writer.
220 // Must be called before initial connect.
221 void UseWriter(QuicPacketWriterWrapper* writer);
dschinazi8ff74822019-05-28 16:37:20 -0700222 // Configures client_ to use a specific server connection ID instead of a
223 // random one.
224 void UseConnectionId(QuicConnectionId server_connection_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500225
226 // Returns nullptr if the maximum number of streams have already been created.
227 QuicSpdyClientStream* GetOrCreateStream();
228
229 // Calls GetOrCreateStream(), sends the request on the stream, and
230 // stores the request in case it needs to be resent. If |headers| is
231 // null, only the body will be sent on the stream.
232 ssize_t GetOrCreateStreamAndSendRequest(
233 const spdy::SpdyHeaderBlock* headers,
234 QuicStringPiece body,
235 bool fin,
236 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
237
238 QuicRstStreamErrorCode stream_error() { return stream_error_; }
239 QuicErrorCode connection_error();
240
241 MockableQuicClient* client();
242
243 // cert_common_name returns the common name value of the server's certificate,
vasilvvc48c8712019-03-11 13:38:16 -0700244 // or the empty std::string if no certificate was presented.
245 const std::string& cert_common_name() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246
247 // cert_sct returns the signed timestamp of the server's certificate,
vasilvvc48c8712019-03-11 13:38:16 -0700248 // or the empty std::string if no signed timestamp was presented.
249 const std::string& cert_sct() const;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500250
251 // Get the server config map.
252 QuicTagValueMap GetServerConfig() const;
253
254 void set_auto_reconnect(bool reconnect) { auto_reconnect_ = reconnect; }
255
256 void set_priority(spdy::SpdyPriority priority) { priority_ = priority; }
257
258 void WaitForWriteToFlush();
259
260 QuicEpollServer* epoll_server() { return &epoll_server_; }
261
262 size_t num_requests() const { return num_requests_; }
263
264 size_t num_responses() const { return num_responses_; }
265
266 void set_server_address(const QuicSocketAddress& server_address) {
267 client_->set_server_address(server_address);
268 }
269
270 void set_peer_address(const QuicSocketAddress& address) {
271 client_->set_peer_address(address);
272 }
273
274 // Explicitly set the SNI value for this client, overriding the default
275 // behavior which extracts the SNI value from the request URL.
vasilvvc48c8712019-03-11 13:38:16 -0700276 void OverrideSni(const std::string& sni) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500277 override_sni_set_ = true;
278 override_sni_ = sni;
279 }
280
281 void Initialize();
282
283 void set_client(MockableQuicClient* client) { client_.reset(client); }
284
285 // Given |uri|, populates the fields in |headers| for a simple GET
286 // request. If |uri| is a relative URL, the QuicServerId will be
287 // use to specify the authority.
vasilvvc48c8712019-03-11 13:38:16 -0700288 bool PopulateHeaderBlockFromUrl(const std::string& uri,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500289 spdy::SpdyHeaderBlock* headers);
290
291 // Waits for a period of time that is long enough to receive all delayed acks
292 // sent by peer.
293 void WaitForDelayedAcks();
294
295 QuicSpdyClientStream* latest_created_stream() {
296 return latest_created_stream_;
297 }
298
299 protected:
300 QuicTestClient();
301 QuicTestClient(const QuicTestClient&) = delete;
302 QuicTestClient& operator=(const QuicTestClient&) = delete;
303
304 private:
305 class TestClientDataToResend : public QuicClient::QuicDataToResend {
306 public:
307 TestClientDataToResend(
308 std::unique_ptr<spdy::SpdyHeaderBlock> headers,
309 QuicStringPiece body,
310 bool fin,
311 QuicTestClient* test_client,
312 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener);
313
314 ~TestClientDataToResend() override;
315
316 void Resend() override;
317
318 protected:
319 QuicTestClient* test_client_;
320 QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_;
321 };
322
323 // PerStreamState of a stream is updated when it is closed.
324 struct PerStreamState {
325 PerStreamState(const PerStreamState& other);
326 PerStreamState(QuicRstStreamErrorCode stream_error,
327 bool response_complete,
328 bool response_headers_complete,
329 const spdy::SpdyHeaderBlock& response_headers,
330 const spdy::SpdyHeaderBlock& preliminary_headers,
vasilvvc48c8712019-03-11 13:38:16 -0700331 const std::string& response,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500332 const spdy::SpdyHeaderBlock& response_trailers,
333 uint64_t bytes_read,
334 uint64_t bytes_written,
335 int64_t response_body_size);
336 ~PerStreamState();
337
338 QuicRstStreamErrorCode stream_error;
339 bool response_complete;
340 bool response_headers_complete;
341 spdy::SpdyHeaderBlock response_headers;
342 spdy::SpdyHeaderBlock preliminary_headers;
vasilvvc48c8712019-03-11 13:38:16 -0700343 std::string response;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344 spdy::SpdyHeaderBlock response_trailers;
345 uint64_t bytes_read;
346 uint64_t bytes_written;
347 int64_t response_body_size;
348 };
349
350 bool HaveActiveStream();
351
352 // Read oldest received response and remove it from closed_stream_states_.
353 void ReadNextResponse();
354
355 // Clear open_streams_, closed_stream_states_ and reset
356 // latest_created_stream_.
357 void ClearPerConnectionState();
358
359 // Update latest_created_stream_, add |stream| to open_streams_ and starts
360 // tracking its state.
361 void SetLatestCreatedStream(QuicSpdyClientStream* stream);
362
363 QuicEpollServer epoll_server_;
364 std::unique_ptr<MockableQuicClient> client_; // The actual client
365 QuicSpdyClientStream* latest_created_stream_;
366 std::map<QuicStreamId, QuicSpdyClientStream*> open_streams_;
367 // Received responses of closed streams.
368 QuicLinkedHashMap<QuicStreamId, PerStreamState> closed_stream_states_;
369
370 QuicRstStreamErrorCode stream_error_;
371
372 bool response_complete_;
373 bool response_headers_complete_;
374 mutable spdy::SpdyHeaderBlock preliminary_headers_;
375 mutable spdy::SpdyHeaderBlock response_headers_;
376
377 // Parsed response trailers (if present), copied from the stream in OnClose.
378 spdy::SpdyHeaderBlock response_trailers_;
379
380 spdy::SpdyPriority priority_;
vasilvvc48c8712019-03-11 13:38:16 -0700381 std::string response_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500382 // bytes_read_ and bytes_written_ are updated only when stream_ is released;
383 // prefer bytes_read() and bytes_written() member functions.
384 uint64_t bytes_read_;
385 uint64_t bytes_written_;
386 // The number of HTTP body bytes received.
387 int64_t response_body_size_;
388 // True if we tried to connect already since the last call to Disconnect().
389 bool connect_attempted_;
390 // The client will auto-connect exactly once before sending data. If
391 // something causes a connection reset, it will not automatically reconnect
392 // unless auto_reconnect_ is true.
393 bool auto_reconnect_;
394 // Should we buffer the response body? Defaults to true.
395 bool buffer_body_;
396 // For async push promise rendezvous, validation may fail in which
397 // case the request should be retried.
398 std::unique_ptr<TestClientDataToResend> push_promise_data_to_resend_;
399 // Number of requests/responses this client has sent/received.
400 size_t num_requests_;
401 size_t num_responses_;
402
403 // If set, this value is used for the connection SNI, overriding the usual
404 // logic which extracts the SNI from the request URL.
405 bool override_sni_set_ = false;
vasilvvc48c8712019-03-11 13:38:16 -0700406 std::string override_sni_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500407};
408
409} // namespace test
410
411} // namespace quic
412
413#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_TEST_CLIENT_H_