Add quic::test::GetFirstFlightOfPackets()
This CL adds GetFirstFlightOfPackets, a mechanism to extract
the first flight of packets from a QUIC connection. This will be
used to test code that parses the CHLO. This CL also adds various
test classes and methods that are used by GetFirstFlightOfPackets.
gfe-relnote: n/a, test-only
PiperOrigin-RevId: 307703986
Change-Id: Iedd17f41f1120d2be2188694710dcd698d61efc8
diff --git a/quic/test_tools/first_flight.cc b/quic/test_tools/first_flight.cc
new file mode 100644
index 0000000..e4d2816
--- /dev/null
+++ b/quic/test_tools/first_flight.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/test_tools/first_flight.h"
+
+#include <memory>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+
+namespace quic {
+namespace test {
+
+// Utility class that creates a custom HTTP/3 session and QUIC connection in
+// order to extract the first flight of packets it sends. This is meant to only
+// be used by GetFirstFlightOfPackets() below.
+class FirstFlightExtractor : public DelegatedPacketWriter::Delegate {
+ public:
+ FirstFlightExtractor(const ParsedQuicVersion& version,
+ const QuicConfig& config,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id)
+ : version_(version),
+ server_connection_id_(server_connection_id),
+ client_connection_id_(client_connection_id),
+ writer_(this),
+ config_(config),
+ crypto_config_(crypto_test_utils::ProofVerifierForTesting()) {
+ EXPECT_NE(version_, UnsupportedQuicVersion());
+ }
+
+ void GenerateFirstFlight() {
+ crypto_config_.set_alpn(AlpnForVersion(version_));
+ connection_ =
+ new QuicConnection(server_connection_id_,
+ QuicSocketAddress(TestPeerIPAddress(), kTestPort),
+ &connection_helper_, &alarm_factory_, &writer_,
+ /*owns_writer=*/false, Perspective::IS_CLIENT,
+ ParsedQuicVersionVector{version_});
+ connection_->set_client_connection_id(client_connection_id_);
+ session_ = std::make_unique<QuicSpdyClientSession>(
+ config_, ParsedQuicVersionVector{version_},
+ connection_, // session_ takes ownership of connection_ here.
+ TestServerId(), &crypto_config_, &push_promise_index_);
+ session_->Initialize();
+ session_->CryptoConnect();
+ }
+
+ void OnDelegatedPacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& /*self_client_address*/,
+ const QuicSocketAddress& /*peer_client_address*/,
+ PerPacketOptions* /*options*/) override {
+ packets_.emplace_back(
+ QuicReceivedPacket(buffer, buf_len,
+ connection_helper_.GetClock()->ApproximateNow(),
+ /*owns_buffer=*/false)
+ .Clone());
+ }
+
+ std::vector<std::unique_ptr<QuicReceivedPacket>>&& ConsumePackets() {
+ return std::move(packets_);
+ }
+
+ private:
+ ParsedQuicVersion version_;
+ QuicConnectionId server_connection_id_;
+ QuicConnectionId client_connection_id_;
+ MockQuicConnectionHelper connection_helper_;
+ MockAlarmFactory alarm_factory_;
+ DelegatedPacketWriter writer_;
+ QuicConfig config_;
+ QuicCryptoClientConfig crypto_config_;
+ QuicClientPushPromiseIndex push_promise_index_;
+ QuicConnection* connection_; // Owned by session_.
+ std::unique_ptr<QuicSpdyClientSession> session_;
+ std::vector<std::unique_ptr<QuicReceivedPacket>> packets_;
+};
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id) {
+ FirstFlightExtractor first_flight_extractor(
+ version, config, server_connection_id, client_connection_id);
+ first_flight_extractor.GenerateFirstFlight();
+ return first_flight_extractor.ConsumePackets();
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config,
+ const QuicConnectionId& server_connection_id) {
+ return GetFirstFlightOfPackets(version, config, server_connection_id,
+ EmptyQuicConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config) {
+ return GetFirstFlightOfPackets(version, config, TestConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id) {
+ return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+ server_connection_id, client_connection_id);
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id) {
+ return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+ server_connection_id, EmptyQuicConnectionId());
+}
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version) {
+ return GetFirstFlightOfPackets(version, DefaultQuicConfig(),
+ TestConnectionId());
+}
+
+} // namespace test
+} // namespace quic
diff --git a/quic/test_tools/first_flight.h b/quic/test_tools/first_flight.h
new file mode 100644
index 0000000..b2a4ebd
--- /dev/null
+++ b/quic/test_tools/first_flight.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_
+#define QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_
+
+#include <memory>
+#include <vector>
+
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+
+namespace quic {
+namespace test {
+
+// Implementation of QuicPacketWriter that sends all packets to a delegate.
+class QUIC_NO_EXPORT DelegatedPacketWriter : public QuicPacketWriter {
+ public:
+ class QUIC_NO_EXPORT Delegate {
+ public:
+ virtual ~Delegate() {}
+ // Note that |buffer| may be released after this call completes so overrides
+ // that want to use the data after the call is complete MUST copy it.
+ virtual void OnDelegatedPacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_client_address,
+ const QuicSocketAddress& peer_client_address,
+ PerPacketOptions* options) = 0;
+ };
+
+ // |delegate| MUST be valid for the duration of the DelegatedPacketWriter's
+ // lifetime.
+ explicit DelegatedPacketWriter(Delegate* delegate) : delegate_(delegate) {
+ CHECK_NE(delegate_, nullptr);
+ }
+
+ // Overrides for QuicPacketWriter.
+ bool IsWriteBlocked() const override { return false; }
+ void SetWritable() override {}
+ QuicByteCount GetMaxPacketSize(
+ const QuicSocketAddress& /*peer_address*/) const override {
+ return kMaxOutgoingPacketSize;
+ }
+ bool SupportsReleaseTime() const override { return false; }
+ bool IsBatchMode() const override { return false; }
+ char* GetNextWriteLocation(
+ const QuicIpAddress& /*self_address*/,
+ const QuicSocketAddress& /*peer_address*/) override {
+ return nullptr;
+ }
+ WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const QuicIpAddress& self_client_address,
+ const QuicSocketAddress& peer_client_address,
+ PerPacketOptions* options) override {
+ delegate_->OnDelegatedPacket(buffer, buf_len, self_client_address,
+ peer_client_address, options);
+ return WriteResult(WRITE_STATUS_OK, buf_len);
+ }
+
+ private:
+ Delegate* delegate_; // Unowned.
+};
+
+// Returns an array of packets that represent the first flight of a real
+// HTTP/3 connection. In most cases, this array will only contain one packet
+// that carries the CHLO.
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id);
+
+// Below are various convenience overloads that use default values for the
+// omitted parameters:
+// |config| = DefaultQuicConfig(),
+// |server_connection_id| = TestConnectionId(),
+// |client_connection_id| = EmptyQuicConnectionId().
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config,
+ const QuicConnectionId& server_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id,
+ const QuicConnectionId& client_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConnectionId& server_connection_id);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version,
+ const QuicConfig& config);
+
+std::vector<std::unique_ptr<QuicReceivedPacket>> GetFirstFlightOfPackets(
+ const ParsedQuicVersion& version);
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_FIRST_FLIGHT_H_
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc
index 47fd05f..bb45ae3 100644
--- a/quic/test_tools/quic_test_utils.cc
+++ b/quic/test_tools/quic_test_utils.cc
@@ -17,13 +17,16 @@
#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
+#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h"
#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
@@ -74,6 +77,14 @@
return quiche::QuicheEndian::NetToHost64(connection_id64_net);
}
+std::string TestHostname() {
+ return "test.example.org";
+}
+
+QuicServerId TestServerId() {
+ return QuicServerId(TestHostname(), kTestPort);
+}
+
QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) {
DCHECK_GT(ack_blocks.size(), 0u);
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index b8e0eae..d70cbef 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -19,9 +19,11 @@
#include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
#include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
#include "net/third_party/quiche/src/quic/core/quic_framer.h"
#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
#include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
+#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
@@ -56,6 +58,12 @@
kInitialSessionFlowControlWindowForTest = 1536 * 1024, // 1.5 MB
};
+// A hostname useful for testing, returns "test.example.org".
+std::string TestHostname();
+
+// A server ID useful for testing, returns test.example.org:12345.
+QuicServerId TestServerId();
+
// Returns the test peer IP address.
QuicIpAddress TestPeerIPAddress();