• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Provides a simple interface for QUIC tests to create a variety of packets.
6 
7 #ifndef NET_QUIC_QUIC_TEST_PACKET_MAKER_H_
8 #define NET_QUIC_QUIC_TEST_PACKET_MAKER_H_
9 
10 #include <stddef.h>
11 #include <sys/types.h>
12 
13 #include <map>
14 #include <memory>
15 #include <optional>
16 #include <string>
17 #include <string_view>
18 #include <vector>
19 
20 #include "base/memory/raw_ptr.h"
21 #include "net/base/request_priority.h"
22 #include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
23 #include "net/third_party/quiche/src/quiche/quic/core/http/http_encoder.h"
24 #include "net/third_party/quiche/src/quiche/quic/core/qpack/qpack_encoder.h"
25 #include "net/third_party/quiche/src/quiche/quic/core/quic_clock.h"
26 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
27 #include "net/third_party/quiche/src/quiche/quic/core/quic_stream_frame_data_producer.h"
28 #include "net/third_party/quiche/src/quiche/quic/core/quic_types.h"
29 #include "net/third_party/quiche/src/quiche/quic/core/quic_utils.h"
30 #include "net/third_party/quiche/src/quiche/quic/test_tools/mock_random.h"
31 #include "net/third_party/quiche/src/quiche/quic/test_tools/qpack/qpack_test_utils.h"
32 #include "net/third_party/quiche/src/quiche/quic/test_tools/simple_data_producer.h"
33 
34 namespace net::test {
35 
36 class QuicTestPacketBuilder;
37 
38 class QuicTestPacketMaker {
39  public:
40   // A container for the state of a connection, tracking stream offsets,
41   // frames already sent, and so on.
42   struct ConnectionState {
43     ConnectionState();
44     ~ConnectionState();
45 
46     // Save the given stream data to last for the duration of this packet build.
47     std::string_view SaveStreamData(std::string_view data);
48 
49     void Reset();
50 
51     // Current offset of each QUIC stream on this connection.
52     std::map<quic::QuicStreamId, quic::QuicStreamOffset> stream_offsets;
53 
54     // Save a copy of stream frame data that QuicStreamFrame objects can refer
55     // to.
56     std::vector<std::unique_ptr<std::string>> saved_stream_data;
57 
58     // If `save_packet_frames_` is true, save generated packets in
59     // `saved_frames_`, allowing retransmission packets to be built.
60     bool save_packet_frames = false;
61     std::map<quic::QuicPacketNumber, quic::QuicFrames> saved_frames;
62   };
63 
64   // |client_priority_uses_incremental| affects the output of any method that
65   // includes HTTP3 priority data. The protocol default is to omit the
66   // incremental flag in the priority data but HTTP streams may enable it
67   // if the client supports incremental streams.
68   QuicTestPacketMaker(quic::ParsedQuicVersion version,
69                       quic::QuicConnectionId connection_id,
70                       const quic::QuicClock* clock,
71                       const std::string& host,
72                       quic::Perspective perspective,
73                       bool client_priority_uses_incremental = false,
74                       bool use_priority_header = false);
75   ~QuicTestPacketMaker();
76 
77   QuicTestPacketMaker(const QuicTestPacketMaker&) = delete;
78   QuicTestPacketMaker& operator=(const QuicTestPacketMaker&) = delete;
79 
80   void set_hostname(const std::string& host);
81 
set_use_priority_header(const bool use_priority_header)82   void set_use_priority_header(const bool use_priority_header) {
83     use_priority_header_ = use_priority_header;
84   }
85 
set_connection_id(const quic::QuicConnectionId & connection_id)86   void set_connection_id(const quic::QuicConnectionId& connection_id) {
87     connection_id_ = connection_id;
88   }
89 
90   // Begin building a packet. Call methods on the returned builder to
91   // define the frames in the packet, and finish with its `Build` method.
92   QuicTestPacketBuilder& Packet(uint64_t packet_number);
93 
94   // Clone all frames from |packet_number|.
95   quic::QuicFrames CloneSavedFrames(uint64_t packet_number);
96 
97   std::unique_ptr<quic::QuicReceivedPacket> MakeDummyCHLOPacket(
98       uint64_t packet_number);
99 
100   std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndDatagramPacket(
101       uint64_t packet_number,
102       uint64_t largest_received,
103       uint64_t smallest_received,
104       std::string_view data);
105 
106   std::unique_ptr<quic::QuicReceivedPacket> MakeAckAndRetransmissionPacket(
107       uint64_t packet_number,
108       uint64_t first_received,
109       uint64_t largest_received,
110       uint64_t smallest_received,
111       const std::vector<uint64_t>& original_packet_numbers);
112 
113   std::unique_ptr<quic::QuicReceivedPacket>
114   MakeRequestHeadersAndMultipleDataFramesPacket(
115       uint64_t packet_number,
116       quic::QuicStreamId stream_id,
117       bool fin,
118       spdy::SpdyPriority spdy_priority,
119       quiche::HttpHeaderBlock headers,
120       size_t* spdy_headers_frame_length,
121       const std::vector<std::string>& data_writes);
122 
123   // If |spdy_headers_frame_length| is non-null, it will be set to the size of
124   // the SPDY headers frame created for this packet.
125   std::unique_ptr<quic::QuicReceivedPacket> MakeRequestHeadersPacket(
126       uint64_t packet_number,
127       quic::QuicStreamId stream_id,
128       bool fin,
129       spdy::SpdyPriority spdy_priority,
130       quiche::HttpHeaderBlock headers,
131       size_t* spdy_headers_frame_length,
132       bool should_include_priority_frame = true);
133 
134   std::unique_ptr<quic::QuicReceivedPacket>
135   MakeRetransmissionAndRequestHeadersPacket(
136       const std::vector<uint64_t>& original_packet_numbers,
137       uint64_t packet_number,
138       quic::QuicStreamId stream_id,
139       bool fin,
140       spdy::SpdyPriority spdy_priority,
141       quiche::HttpHeaderBlock headers,
142       size_t* spdy_headers_frame_length);
143 
144   std::unique_ptr<quic::QuicReceivedPacket> MakeRequestHeadersAndRstPacket(
145       uint64_t packet_number,
146       quic::QuicStreamId stream_id,
147       bool fin,
148       spdy::SpdyPriority spdy_priority,
149       quiche::HttpHeaderBlock headers,
150       size_t* spdy_headers_frame_length,
151       quic::QuicRstStreamErrorCode error_code);
152 
153   // If |spdy_headers_frame_length| is non-null, it will be set to the size of
154   // the SPDY headers frame created for this packet.
155   std::unique_ptr<quic::QuicReceivedPacket> MakeResponseHeadersPacket(
156       uint64_t packet_number,
157       quic::QuicStreamId stream_id,
158       bool fin,
159       quiche::HttpHeaderBlock headers,
160       size_t* spdy_headers_frame_length);
161 
162   // Creates a packet containing the initial SETTINGS frame, and saves the
163   // headers stream offset into |offset|.
164   std::unique_ptr<quic::QuicReceivedPacket> MakeInitialSettingsPacket(
165       uint64_t packet_number);
166 
167   std::unique_ptr<quic::QuicReceivedPacket> MakePriorityPacket(
168       uint64_t packet_number,
169       quic::QuicStreamId id,
170       spdy::SpdyPriority spdy_priority);
171 
172   std::unique_ptr<quic::QuicReceivedPacket> MakeRetransmissionPacket(
173       uint64_t original_packet_number,
174       uint64_t new_packet_number);
175 
176   std::unique_ptr<quic::QuicReceivedPacket> MakeCombinedRetransmissionPacket(
177       const std::vector<uint64_t>& original_packet_numbers,
178       uint64_t new_packet_number);
179 
180   std::unique_ptr<quic::QuicEncryptedPacket> MakeStatelessResetPacket();
181 
182   // Removes all stream frames associated with |stream_id|.
183   void RemoveSavedStreamFrames(quic::QuicStreamId stream_id);
184 
185   void SetEncryptionLevel(quic::EncryptionLevel level);
186 
187   quiche::HttpHeaderBlock GetRequestHeaders(const std::string& method,
188                                             const std::string& scheme,
189                                             const std::string& path) const;
190 
191   quiche::HttpHeaderBlock ConnectRequestHeaders(
192       const std::string& host_port) const;
193 
194   quiche::HttpHeaderBlock GetResponseHeaders(const std::string& status) const;
195 
196   quiche::HttpHeaderBlock GetResponseHeaders(const std::string& status,
197                                              const std::string& alt_svc) const;
198 
199   // Reset some of the state in the packet maker.
200   // TODO(https://issues.chromium.org/u/1/issues/335279177): reset all state.
201   void Reset();
202 
version()203   quic::ParsedQuicVersion version() { return version_; }
perspective()204   quic::Perspective perspective() { return perspective_; }
clock()205   const quic::QuicClock* clock() { return clock_.get(); }
encryption_level()206   quic::EncryptionLevel encryption_level() { return encryption_level_; }
long_header_type()207   quic::QuicLongHeaderType long_header_type() { return long_header_type_; }
connection_id()208   quic::QuicConnectionId connection_id() { return connection_id_; }
209 
set_save_packet_frames(bool save_packet_frames)210   void set_save_packet_frames(bool save_packet_frames) {
211     connection_state_.save_packet_frames = save_packet_frames;
212   }
set_max_plaintext_size(size_t max_plaintext_size)213   void set_max_plaintext_size(size_t max_plaintext_size) {
214     max_plaintext_size_ = max_plaintext_size;
215   }
216 
217   std::string QpackEncodeHeaders(quic::QuicStreamId stream_id,
218                                  quiche::HttpHeaderBlock headers,
219                                  size_t* encoded_data_length);
220 
set_ecn_codepoint(quic::QuicEcnCodepoint ecn)221   void set_ecn_codepoint(quic::QuicEcnCodepoint ecn) { ecn_codepoint_ = ecn; }
222 
223  protected:
224   friend class QuicTestPacketBuilder;
225   std::unique_ptr<quic::QuicReceivedPacket> FinishPacket(
226       quic::QuicPacketHeader header,
227       quic::QuicFrames frames,
228       std::unique_ptr<quic::QuicStreamFrameDataProducer> data_producer);
229 
230  private:
231   void AddPriorityHeader(spdy::SpdyPriority spdy_priority,
232                          quiche::HttpHeaderBlock* headers);
233 
234   quic::QuicStreamId GetFirstBidirectionalStreamId() const;
235 
236   std::string GenerateHttp3PriorityData(spdy::SpdyPriority spdy_priority,
237                                         quic::QuicStreamId stream_id);
238 
239   // Parameters used throughout the lifetime of the class.
240   quic::QuicConnectionId connection_id_;
241   quic::ParsedQuicVersion version_;
242   raw_ptr<const quic::QuicClock> clock_;  // Not owned.
243   std::string host_;
244   quic::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate_;
245   quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate_;
246   quic::QpackEncoder qpack_encoder_;
247   quic::test::MockRandom random_generator_;
248   quic::Perspective perspective_;
249   quic::EncryptionLevel encryption_level_ = quic::ENCRYPTION_FORWARD_SECURE;
250   quic::QuicLongHeaderType long_header_type_ = quic::INVALID_PACKET_TYPE;
251   size_t max_plaintext_size_ = quic::kDefaultMaxPacketSize;
252 
253   // The value of incremental flag in generated priority headers.
254   bool client_priority_uses_incremental_;
255 
256   // Add the priority header to outbound requests
257   bool use_priority_header_;
258 
259   ConnectionState connection_state_;
260 
261   // The current packet builder, if one is in progress.
262   std::unique_ptr<QuicTestPacketBuilder> builder_;
263 
264   // Explicit Congestion Notification (ECN) codepoint to use when making
265   // packets.
266   quic::QuicEcnCodepoint ecn_codepoint_ = quic::ECN_NOT_ECT;
267 };
268 
269 // A packet builder provides methods for building a new packet, usable via
270 // `QuicTestPacketMaker::Packet`. Finish building the packet with the `Build`
271 // method.
272 //
273 // This implements a "builder" pattern, and method calls can be chained:
274 //
275 //   auto packet = maker.Packet(num)
276 //     .AddFooFrame(..)
277 //     .AddBarFrame(..)
278 //     .Build();
279 //
280 //  Methods may also be called individually:
281 //
282 //  auto& builder = maker.Packet(num);
283 //  builder.AddFooFrame(..);
284 //  builder.AddBarFrame(..);
285 //  auto packet = builder.Build();
286 class QuicTestPacketBuilder {
287  public:
288   QuicTestPacketBuilder(uint64_t packet_number,
289                         QuicTestPacketMaker* maker,
290                         QuicTestPacketMaker::ConnectionState* connection_state);
291   ~QuicTestPacketBuilder();
292 
293   QuicTestPacketBuilder& AddPaddingFrame(size_t padding_size = 0);
294   QuicTestPacketBuilder& AddPingFrame();
295   QuicTestPacketBuilder& AddRetireConnectionIdFrame(uint64_t sequence_number);
296   QuicTestPacketBuilder& AddNewConnectionIdFrame(
297       const quic::QuicConnectionId& cid,
298       uint64_t sequence_number,
299       uint64_t retire_prior_to);
300   QuicTestPacketBuilder& AddMaxStreamsFrame(
301       quic::QuicControlFrameId control_frame_id,
302       quic::QuicStreamCount stream_count,
303       bool unidirectional);
304   QuicTestPacketBuilder& AddStreamsBlockedFrame(
305       quic::QuicControlFrameId control_frame_id,
306       quic::QuicStreamCount stream_count,
307       bool unidirectional);
308   // Add a stream frame, using an offset calculated from any previous stream
309   // frames with this stream_id. The given data is copied and may be deallocated
310   // after this call.
311   QuicTestPacketBuilder& AddStreamFrame(quic::QuicStreamId stream_id,
312                                         bool fin,
313                                         std::string_view data);
314   QuicTestPacketBuilder& AddAckFrame(
315       uint64_t first_received,
316       uint64_t largest_received,
317       uint64_t smallest_received,
318       std::optional<quic::QuicEcnCounts> ecn = std::nullopt);
319   // Add a DATAGRAM frame. The given data is copied and may be deallocated after
320   // this call.
321   QuicTestPacketBuilder& AddMessageFrame(std::string_view data);
322   QuicTestPacketBuilder& AddRstStreamFrame(
323       quic::QuicStreamId stream_id,
324       quic::QuicRstStreamErrorCode error_code);
325   QuicTestPacketBuilder& AddConnectionCloseFrame(
326       quic::QuicErrorCode quic_error,
327       const std::string& quic_error_details,
328       uint64_t frame_type = 0);
329   QuicTestPacketBuilder& AddGoAwayFrame(quic::QuicErrorCode error_code,
330                                         std::string reason_phrase);
331   QuicTestPacketBuilder& AddPathResponseFrame();
332   QuicTestPacketBuilder& AddPathChallengeFrame();
333   QuicTestPacketBuilder& AddStopSendingFrame(
334       quic::QuicStreamId stream_id,
335       quic::QuicRstStreamErrorCode error_code);
336   QuicTestPacketBuilder& AddCryptoFrame(quic::EncryptionLevel level,
337                                         quic::QuicStreamOffset offset,
338                                         const quic::QuicData& data);
339 
340   // Add a frame to the packet.
341   QuicTestPacketBuilder& AddFrame(quic::QuicFrame frame);
342 
343   // Add a frame to the packet, coalescing adjacent stream frames for the same
344   // stream ID into a single frame.
345   QuicTestPacketBuilder& AddFrameWithCoalescing(const quic::QuicFrame& frame);
346 
347   // Retransmit the frames in a previously-transmitted packet, optionally
348   // filtering frames with the given callback.
349   QuicTestPacketBuilder& AddPacketRetransmission(
350       uint64_t packet_number,
351       base::RepeatingCallback<bool(const quic::QuicFrame&)> filter =
352           base::RepeatingCallback<bool(const quic::QuicFrame&)>());
353 
354   // Complete the building process and return the resulting packet.
355   std::unique_ptr<quic::QuicReceivedPacket> Build();
356 
357   // Add an H/3 SETTINGS frame on the control stream if one has not already been
358   // sent.
359   QuicTestPacketBuilder& MaybeAddHttp3SettingsFrames();
360 
361  private:
362   std::string GenerateHttp3SettingsData() const;
363   std::string GenerateHttp3GreaseData() const;
364 
365   void InitializeHeader(uint64_t packet_number);
366 
367   quic::QuicConnectionId DestinationConnectionId() const;
368   quic::QuicConnectionId SourceConnectionId() const;
369 
370   bool ShouldIncludeVersion() const;
371 
372   // State necessary for building the current packet.
373   quic::QuicPacketHeader header_;
374   quic::QuicFrames frames_;
375   std::unique_ptr<quic::test::SimpleDataProducer> data_producer_;
376 
377   // The `QuicTestPacketMaker` for which we are building this packet.Reset some
378   // of the state in the packet maker.
379   // TODO(https://issues.chromium.org/u/1/issues/335279177): reset all state.
380   raw_ptr<QuicTestPacketMaker> maker_;
381 
382   // The connection state. This is owned by `maker_` but borrowed for
383   // the lifetime of this builder.
384   raw_ptr<QuicTestPacketMaker::ConnectionState> connection_state_;
385 };
386 
387 }  // namespace net::test
388 
389 #endif  // NET_QUIC_QUIC_TEST_PACKET_MAKER_H_
390