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