| // Copyright (c) 2012 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/quic_test_utils.h" |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <memory> |
| |
| #include "third_party/boringssl/src/include/openssl/chacha.h" |
| #include "third_party/boringssl/src/include/openssl/sha.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" |
| #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" |
| #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/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_utils.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" |
| #include "net/third_party/quiche/src/quic/platform/api/quic_endian.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/platform/api/quic_ptr_util.h" |
| #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" |
| #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" |
| #include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h" |
| |
| using testing::_; |
| using testing::Invoke; |
| |
| namespace quic { |
| namespace test { |
| |
| QuicConnectionId TestConnectionId() { |
| // Chosen by fair dice roll. |
| // Guaranteed to be random. |
| return TestConnectionId(42); |
| } |
| |
| QuicConnectionId TestConnectionId(uint64_t connection_number) { |
| const uint64_t connection_id64_net = |
| QuicEndian::HostToNet64(connection_number); |
| return QuicConnectionId(reinterpret_cast<const char*>(&connection_id64_net), |
| sizeof(connection_id64_net)); |
| } |
| |
| QuicConnectionId TestConnectionIdNineBytesLong(uint64_t connection_number) { |
| const uint64_t connection_number_net = |
| QuicEndian::HostToNet64(connection_number); |
| char connection_id_bytes[9] = {}; |
| static_assert( |
| sizeof(connection_id_bytes) == 1 + sizeof(connection_number_net), |
| "bad lengths"); |
| memcpy(connection_id_bytes + 1, &connection_number_net, |
| sizeof(connection_number_net)); |
| return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes)); |
| } |
| |
| uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) { |
| DCHECK_EQ(connection_id.length(), kQuicDefaultConnectionIdLength); |
| uint64_t connection_id64_net = 0; |
| memcpy(&connection_id64_net, connection_id.data(), |
| std::min<size_t>(static_cast<size_t>(connection_id.length()), |
| sizeof(connection_id64_net))); |
| return QuicEndian::NetToHost64(connection_id64_net); |
| } |
| |
| QuicAckFrame InitAckFrame(const std::vector<QuicAckBlock>& ack_blocks) { |
| DCHECK_GT(ack_blocks.size(), 0u); |
| |
| QuicAckFrame ack; |
| QuicPacketNumber end_of_previous_block(1); |
| for (const QuicAckBlock& block : ack_blocks) { |
| DCHECK_GE(block.start, end_of_previous_block); |
| DCHECK_GT(block.limit, block.start); |
| ack.packets.AddRange(block.start, block.limit); |
| end_of_previous_block = block.limit; |
| } |
| |
| ack.largest_acked = ack.packets.Max(); |
| |
| return ack; |
| } |
| |
| QuicAckFrame InitAckFrame(uint64_t largest_acked) { |
| return InitAckFrame(QuicPacketNumber(largest_acked)); |
| } |
| |
| QuicAckFrame InitAckFrame(QuicPacketNumber largest_acked) { |
| return InitAckFrame({{QuicPacketNumber(1), largest_acked + 1}}); |
| } |
| |
| QuicAckFrame MakeAckFrameWithAckBlocks(size_t num_ack_blocks, |
| uint64_t least_unacked) { |
| QuicAckFrame ack; |
| ack.largest_acked = QuicPacketNumber(2 * num_ack_blocks + least_unacked); |
| // Add enough received packets to get num_ack_blocks ack blocks. |
| for (QuicPacketNumber i = QuicPacketNumber(2); |
| i < QuicPacketNumber(2 * num_ack_blocks + 1); i += 2) { |
| ack.packets.Add(i + least_unacked); |
| } |
| return ack; |
| } |
| |
| std::unique_ptr<QuicPacket> BuildUnsizedDataPacket( |
| QuicFramer* framer, |
| const QuicPacketHeader& header, |
| const QuicFrames& frames) { |
| const size_t max_plaintext_size = |
| framer->GetMaxPlaintextSize(kMaxOutgoingPacketSize); |
| size_t packet_size = GetPacketHeaderSize(framer->transport_version(), header); |
| for (size_t i = 0; i < frames.size(); ++i) { |
| DCHECK_LE(packet_size, max_plaintext_size); |
| bool first_frame = i == 0; |
| bool last_frame = i == frames.size() - 1; |
| const size_t frame_size = framer->GetSerializedFrameLength( |
| frames[i], max_plaintext_size - packet_size, first_frame, last_frame, |
| header.packet_number_length); |
| DCHECK(frame_size); |
| packet_size += frame_size; |
| } |
| return BuildUnsizedDataPacket(framer, header, frames, packet_size); |
| } |
| |
| std::unique_ptr<QuicPacket> BuildUnsizedDataPacket( |
| QuicFramer* framer, |
| const QuicPacketHeader& header, |
| const QuicFrames& frames, |
| size_t packet_size) { |
| char* buffer = new char[packet_size]; |
| size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size, |
| ENCRYPTION_INITIAL); |
| DCHECK_NE(0u, length); |
| // Re-construct the data packet with data ownership. |
| return QuicMakeUnique<QuicPacket>( |
| buffer, length, /* owns_buffer */ true, |
| GetIncludedDestinationConnectionIdLength(header), |
| GetIncludedSourceConnectionIdLength(header), header.version_flag, |
| header.nonce != nullptr, header.packet_number_length, |
| header.retry_token_length_length, header.retry_token.length(), |
| header.length_length); |
| } |
| |
| std::string Sha1Hash(QuicStringPiece data) { |
| char buffer[SHA_DIGEST_LENGTH]; |
| SHA1(reinterpret_cast<const uint8_t*>(data.data()), data.size(), |
| reinterpret_cast<uint8_t*>(buffer)); |
| return std::string(buffer, QUIC_ARRAYSIZE(buffer)); |
| } |
| |
| bool ClearControlFrame(const QuicFrame& frame) { |
| DeleteFrame(&const_cast<QuicFrame&>(frame)); |
| return true; |
| } |
| |
| uint64_t SimpleRandom::RandUint64() { |
| uint64_t result; |
| RandBytes(&result, sizeof(result)); |
| return result; |
| } |
| |
| void SimpleRandom::RandBytes(void* data, size_t len) { |
| uint8_t* data_bytes = reinterpret_cast<uint8_t*>(data); |
| while (len > 0) { |
| const size_t buffer_left = sizeof(buffer_) - buffer_offset_; |
| const size_t to_copy = std::min(buffer_left, len); |
| memcpy(data_bytes, buffer_ + buffer_offset_, to_copy); |
| data_bytes += to_copy; |
| buffer_offset_ += to_copy; |
| len -= to_copy; |
| |
| if (buffer_offset_ == sizeof(buffer_)) { |
| FillBuffer(); |
| } |
| } |
| } |
| |
| void SimpleRandom::FillBuffer() { |
| uint8_t nonce[12]; |
| memcpy(nonce, buffer_, sizeof(nonce)); |
| CRYPTO_chacha_20(buffer_, buffer_, sizeof(buffer_), key_, nonce, 0); |
| buffer_offset_ = 0; |
| } |
| |
| void SimpleRandom::set_seed(uint64_t seed) { |
| static_assert(sizeof(key_) == SHA256_DIGEST_LENGTH, "Key has to be 256 bits"); |
| SHA256(reinterpret_cast<const uint8_t*>(&seed), sizeof(seed), key_); |
| |
| memset(buffer_, 0, sizeof(buffer_)); |
| FillBuffer(); |
| } |
| |
| MockFramerVisitor::MockFramerVisitor() { |
| // By default, we want to accept packets. |
| ON_CALL(*this, OnProtocolVersionMismatch(_)) |
| .WillByDefault(testing::Return(false)); |
| |
| // By default, we want to accept packets. |
| ON_CALL(*this, OnUnauthenticatedHeader(_)) |
| .WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnUnauthenticatedPublicHeader(_)) |
| .WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnPacketHeader(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnStreamFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnCryptoFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnStopWaitingFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnPaddingFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnPingFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnRstStreamFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnConnectionCloseFrame(_)) |
| .WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnStopSendingFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnPathChallengeFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnPathResponseFrame(_)).WillByDefault(testing::Return(true)); |
| |
| ON_CALL(*this, OnGoAwayFrame(_)).WillByDefault(testing::Return(true)); |
| ON_CALL(*this, OnMaxStreamsFrame(_)).WillByDefault(testing::Return(true)); |
| ON_CALL(*this, OnStreamsBlockedFrame(_)).WillByDefault(testing::Return(true)); |
| } |
| |
| MockFramerVisitor::~MockFramerVisitor() {} |
| |
| bool NoOpFramerVisitor::OnProtocolVersionMismatch( |
| ParsedQuicVersion /*version*/) { |
| return false; |
| } |
| |
| bool NoOpFramerVisitor::OnUnauthenticatedPublicHeader( |
| const QuicPacketHeader& /*header*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnUnauthenticatedHeader( |
| const QuicPacketHeader& /*header*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnPacketHeader(const QuicPacketHeader& /*header*/) { |
| return true; |
| } |
| |
| void NoOpFramerVisitor::OnCoalescedPacket( |
| const QuicEncryptedPacket& /*packet*/) {} |
| |
| bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/, |
| QuicTime::Delta /*ack_delay_time*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnAckRange(QuicPacketNumber /*start*/, |
| QuicPacketNumber /*end*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/, |
| QuicTime /*timestamp*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnStopWaitingFrame( |
| const QuicStopWaitingFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnPingFrame(const QuicPingFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnConnectionCloseFrame( |
| const QuicConnectionCloseFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnNewConnectionIdFrame( |
| const QuicNewConnectionIdFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnRetireConnectionIdFrame( |
| const QuicRetireConnectionIdFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnStopSendingFrame( |
| const QuicStopSendingFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnPathChallengeFrame( |
| const QuicPathChallengeFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnPathResponseFrame( |
| const QuicPathResponseFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnMaxStreamsFrame( |
| const QuicMaxStreamsFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnStreamsBlockedFrame( |
| const QuicStreamsBlockedFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnWindowUpdateFrame( |
| const QuicWindowUpdateFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::OnMessageFrame(const QuicMessageFrame& /*frame*/) { |
| return true; |
| } |
| |
| bool NoOpFramerVisitor::IsValidStatelessResetToken( |
| QuicUint128 /*token*/) const { |
| return false; |
| } |
| |
| MockQuicConnectionVisitor::MockQuicConnectionVisitor() {} |
| |
| MockQuicConnectionVisitor::~MockQuicConnectionVisitor() {} |
| |
| MockQuicConnectionHelper::MockQuicConnectionHelper() {} |
| |
| MockQuicConnectionHelper::~MockQuicConnectionHelper() {} |
| |
| const QuicClock* MockQuicConnectionHelper::GetClock() const { |
| return &clock_; |
| } |
| |
| QuicRandom* MockQuicConnectionHelper::GetRandomGenerator() { |
| return &random_generator_; |
| } |
| |
| QuicAlarm* MockAlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) { |
| return new MockAlarmFactory::TestAlarm( |
| QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate)); |
| } |
| |
| QuicArenaScopedPtr<QuicAlarm> MockAlarmFactory::CreateAlarm( |
| QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, |
| QuicConnectionArena* arena) { |
| if (arena != nullptr) { |
| return arena->New<TestAlarm>(std::move(delegate)); |
| } else { |
| return QuicArenaScopedPtr<TestAlarm>(new TestAlarm(std::move(delegate))); |
| } |
| } |
| |
| QuicBufferAllocator* MockQuicConnectionHelper::GetStreamSendBufferAllocator() { |
| return &buffer_allocator_; |
| } |
| |
| void MockQuicConnectionHelper::AdvanceTime(QuicTime::Delta delta) { |
| clock_.AdvanceTime(delta); |
| } |
| |
| MockQuicConnection::MockQuicConnection(MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective) |
| : MockQuicConnection(TestConnectionId(), |
| QuicSocketAddress(TestPeerIPAddress(), kTestPort), |
| helper, |
| alarm_factory, |
| perspective, |
| ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {} |
| |
| MockQuicConnection::MockQuicConnection(QuicSocketAddress address, |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective) |
| : MockQuicConnection(TestConnectionId(), |
| address, |
| helper, |
| alarm_factory, |
| perspective, |
| ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {} |
| |
| MockQuicConnection::MockQuicConnection(QuicConnectionId connection_id, |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective) |
| : MockQuicConnection(connection_id, |
| QuicSocketAddress(TestPeerIPAddress(), kTestPort), |
| helper, |
| alarm_factory, |
| perspective, |
| ParsedVersionOfIndex(CurrentSupportedVersions(), 0)) {} |
| |
| MockQuicConnection::MockQuicConnection( |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective, |
| const ParsedQuicVersionVector& supported_versions) |
| : MockQuicConnection(TestConnectionId(), |
| QuicSocketAddress(TestPeerIPAddress(), kTestPort), |
| helper, |
| alarm_factory, |
| perspective, |
| supported_versions) {} |
| |
| MockQuicConnection::MockQuicConnection( |
| QuicConnectionId connection_id, |
| QuicSocketAddress address, |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective, |
| const ParsedQuicVersionVector& supported_versions) |
| : QuicConnection(connection_id, |
| address, |
| helper, |
| alarm_factory, |
| new testing::NiceMock<MockPacketWriter>(), |
| /* owns_writer= */ true, |
| perspective, |
| supported_versions) { |
| ON_CALL(*this, OnError(_)) |
| .WillByDefault( |
| Invoke(this, &PacketSavingConnection::QuicConnection_OnError)); |
| ON_CALL(*this, SendCryptoData(_, _, _)) |
| .WillByDefault( |
| Invoke(this, &MockQuicConnection::QuicConnection_SendCryptoData)); |
| |
| SetSelfAddress(QuicSocketAddress(QuicIpAddress::Any4(), 5)); |
| } |
| |
| MockQuicConnection::~MockQuicConnection() {} |
| |
| void MockQuicConnection::AdvanceTime(QuicTime::Delta delta) { |
| static_cast<MockQuicConnectionHelper*>(helper())->AdvanceTime(delta); |
| } |
| |
| bool MockQuicConnection::OnProtocolVersionMismatch( |
| ParsedQuicVersion /*version*/) { |
| return false; |
| } |
| |
| PacketSavingConnection::PacketSavingConnection(MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective) |
| : MockQuicConnection(helper, alarm_factory, perspective) {} |
| |
| PacketSavingConnection::PacketSavingConnection( |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| Perspective perspective, |
| const ParsedQuicVersionVector& supported_versions) |
| : MockQuicConnection(helper, |
| alarm_factory, |
| perspective, |
| supported_versions) {} |
| |
| PacketSavingConnection::~PacketSavingConnection() {} |
| |
| void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { |
| encrypted_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>( |
| CopyBuffer(*packet), packet->encrypted_length, true)); |
| clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); |
| // Transfer ownership of the packet to the SentPacketManager and the |
| // ack notifier to the AckNotifierManager. |
| QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( |
| packet, QuicPacketNumber(), clock_.ApproximateNow(), NOT_RETRANSMISSION, |
| HAS_RETRANSMITTABLE_DATA); |
| } |
| |
| MockQuicSession::MockQuicSession(QuicConnection* connection) |
| : MockQuicSession(connection, true) {} |
| |
| MockQuicSession::MockQuicSession(QuicConnection* connection, |
| bool create_mock_crypto_stream) |
| : QuicSession(connection, |
| nullptr, |
| DefaultQuicConfig(), |
| connection->supported_versions()) { |
| if (create_mock_crypto_stream) { |
| crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); |
| } |
| ON_CALL(*this, WritevData(_, _, _, _, _)) |
| .WillByDefault(testing::Return(QuicConsumedData(0, false))); |
| } |
| |
| MockQuicSession::~MockQuicSession() { |
| delete connection(); |
| } |
| |
| QuicCryptoStream* MockQuicSession::GetMutableCryptoStream() { |
| return crypto_stream_.get(); |
| } |
| |
| const QuicCryptoStream* MockQuicSession::GetCryptoStream() const { |
| return crypto_stream_.get(); |
| } |
| |
| void MockQuicSession::SetCryptoStream(QuicCryptoStream* crypto_stream) { |
| crypto_stream_.reset(crypto_stream); |
| } |
| |
| // static |
| QuicConsumedData MockQuicSession::ConsumeData(QuicStream* stream, |
| QuicStreamId /*id*/, |
| size_t write_length, |
| QuicStreamOffset offset, |
| StreamSendingState state) { |
| if (write_length > 0) { |
| auto buf = QuicMakeUnique<char[]>(write_length); |
| QuicDataWriter writer(write_length, buf.get(), HOST_BYTE_ORDER); |
| stream->WriteStreamData(offset, write_length, &writer); |
| } else { |
| DCHECK(state != NO_FIN); |
| } |
| return QuicConsumedData(write_length, state != NO_FIN); |
| } |
| |
| MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session) |
| : QuicCryptoStream(session), params_(new QuicCryptoNegotiatedParameters) {} |
| |
| MockQuicCryptoStream::~MockQuicCryptoStream() {} |
| |
| bool MockQuicCryptoStream::encryption_established() const { |
| return false; |
| } |
| |
| bool MockQuicCryptoStream::handshake_confirmed() const { |
| return false; |
| } |
| |
| const QuicCryptoNegotiatedParameters& |
| MockQuicCryptoStream::crypto_negotiated_params() const { |
| return *params_; |
| } |
| |
| CryptoMessageParser* MockQuicCryptoStream::crypto_message_parser() { |
| return &crypto_framer_; |
| } |
| |
| MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection) |
| : MockQuicSpdySession(connection, true) {} |
| |
| MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection, |
| bool create_mock_crypto_stream) |
| : QuicSpdySession(connection, |
| nullptr, |
| DefaultQuicConfig(), |
| connection->supported_versions()) { |
| if (create_mock_crypto_stream) { |
| crypto_stream_ = QuicMakeUnique<MockQuicCryptoStream>(this); |
| } |
| |
| ON_CALL(*this, WritevData(_, _, _, _, _)) |
| .WillByDefault(testing::Return(QuicConsumedData(0, false))); |
| } |
| |
| MockQuicSpdySession::~MockQuicSpdySession() { |
| delete connection(); |
| } |
| |
| QuicCryptoStream* MockQuicSpdySession::GetMutableCryptoStream() { |
| return crypto_stream_.get(); |
| } |
| |
| const QuicCryptoStream* MockQuicSpdySession::GetCryptoStream() const { |
| return crypto_stream_.get(); |
| } |
| |
| void MockQuicSpdySession::SetCryptoStream(QuicCryptoStream* crypto_stream) { |
| crypto_stream_.reset(crypto_stream); |
| } |
| |
| TestQuicSpdyServerSession::TestQuicSpdyServerSession( |
| QuicConnection* connection, |
| const QuicConfig& config, |
| const ParsedQuicVersionVector& supported_versions, |
| const QuicCryptoServerConfig* crypto_config, |
| QuicCompressedCertsCache* compressed_certs_cache) |
| : QuicServerSessionBase(config, |
| supported_versions, |
| connection, |
| &visitor_, |
| &helper_, |
| crypto_config, |
| compressed_certs_cache) { |
| Initialize(); |
| ON_CALL(helper_, GenerateConnectionIdForReject(_, _)) |
| .WillByDefault(testing::Return( |
| QuicUtils::CreateRandomConnectionId(connection->random_generator()))); |
| ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _)) |
| .WillByDefault(testing::Return(true)); |
| } |
| |
| TestQuicSpdyServerSession::~TestQuicSpdyServerSession() { |
| delete connection(); |
| } |
| |
| QuicCryptoServerStreamBase* |
| TestQuicSpdyServerSession::CreateQuicCryptoServerStream( |
| const QuicCryptoServerConfig* crypto_config, |
| QuicCompressedCertsCache* compressed_certs_cache) { |
| return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, this, |
| &helper_); |
| } |
| |
| void TestQuicSpdyServerSession::OnCryptoHandshakeEvent( |
| CryptoHandshakeEvent event) { |
| QuicSession::OnCryptoHandshakeEvent(event); |
| } |
| |
| QuicCryptoServerStream* TestQuicSpdyServerSession::GetMutableCryptoStream() { |
| return static_cast<QuicCryptoServerStream*>( |
| QuicServerSessionBase::GetMutableCryptoStream()); |
| } |
| |
| const QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream() |
| const { |
| return static_cast<const QuicCryptoServerStream*>( |
| QuicServerSessionBase::GetCryptoStream()); |
| } |
| |
| TestQuicSpdyClientSession::TestQuicSpdyClientSession( |
| QuicConnection* connection, |
| const QuicConfig& config, |
| const ParsedQuicVersionVector& supported_versions, |
| const QuicServerId& server_id, |
| QuicCryptoClientConfig* crypto_config) |
| : QuicSpdyClientSessionBase(connection, |
| &push_promise_index_, |
| config, |
| supported_versions) { |
| crypto_stream_ = QuicMakeUnique<QuicCryptoClientStream>( |
| server_id, this, crypto_test_utils::ProofVerifyContextForTesting(), |
| crypto_config, this); |
| Initialize(); |
| } |
| |
| TestQuicSpdyClientSession::~TestQuicSpdyClientSession() {} |
| |
| bool TestQuicSpdyClientSession::IsAuthorized(const std::string& /*authority*/) { |
| return true; |
| } |
| |
| void TestQuicSpdyClientSession::OnCryptoHandshakeEvent( |
| CryptoHandshakeEvent event) { |
| QuicSession::OnCryptoHandshakeEvent(event); |
| } |
| |
| QuicCryptoClientStream* TestQuicSpdyClientSession::GetMutableCryptoStream() { |
| return crypto_stream_.get(); |
| } |
| |
| const QuicCryptoClientStream* TestQuicSpdyClientSession::GetCryptoStream() |
| const { |
| return crypto_stream_.get(); |
| } |
| |
| TestPushPromiseDelegate::TestPushPromiseDelegate(bool match) |
| : match_(match), rendezvous_fired_(false), rendezvous_stream_(nullptr) {} |
| |
| bool TestPushPromiseDelegate::CheckVary( |
| const spdy::SpdyHeaderBlock& /*client_request*/, |
| const spdy::SpdyHeaderBlock& /*promise_request*/, |
| const spdy::SpdyHeaderBlock& /*promise_response*/) { |
| QUIC_DVLOG(1) << "match " << match_; |
| return match_; |
| } |
| |
| void TestPushPromiseDelegate::OnRendezvousResult(QuicSpdyStream* stream) { |
| rendezvous_fired_ = true; |
| rendezvous_stream_ = stream; |
| } |
| |
| MockPacketWriter::MockPacketWriter() { |
| ON_CALL(*this, GetMaxPacketSize(_)) |
| .WillByDefault(testing::Return(kMaxOutgoingPacketSize)); |
| ON_CALL(*this, IsBatchMode()).WillByDefault(testing::Return(false)); |
| ON_CALL(*this, GetNextWriteLocation(_, _)) |
| .WillByDefault(testing::Return(nullptr)); |
| ON_CALL(*this, Flush()) |
| .WillByDefault(testing::Return(WriteResult(WRITE_STATUS_OK, 0))); |
| } |
| |
| MockPacketWriter::~MockPacketWriter() {} |
| |
| MockSendAlgorithm::MockSendAlgorithm() {} |
| |
| MockSendAlgorithm::~MockSendAlgorithm() {} |
| |
| MockLossAlgorithm::MockLossAlgorithm() {} |
| |
| MockLossAlgorithm::~MockLossAlgorithm() {} |
| |
| MockAckListener::MockAckListener() {} |
| |
| MockAckListener::~MockAckListener() {} |
| |
| MockNetworkChangeVisitor::MockNetworkChangeVisitor() {} |
| |
| MockNetworkChangeVisitor::~MockNetworkChangeVisitor() {} |
| |
| namespace { |
| |
| std::string HexDumpWithMarks(const char* data, |
| int length, |
| const bool* marks, |
| int mark_length) { |
| static const char kHexChars[] = "0123456789abcdef"; |
| static const int kColumns = 4; |
| |
| const int kSizeLimit = 1024; |
| if (length > kSizeLimit || mark_length > kSizeLimit) { |
| QUIC_LOG(ERROR) << "Only dumping first " << kSizeLimit << " bytes."; |
| length = std::min(length, kSizeLimit); |
| mark_length = std::min(mark_length, kSizeLimit); |
| } |
| |
| std::string hex; |
| for (const char* row = data; length > 0; |
| row += kColumns, length -= kColumns) { |
| for (const char* p = row; p < row + 4; ++p) { |
| if (p < row + length) { |
| const bool mark = |
| (marks && (p - data) < mark_length && marks[p - data]); |
| hex += mark ? '*' : ' '; |
| hex += kHexChars[(*p & 0xf0) >> 4]; |
| hex += kHexChars[*p & 0x0f]; |
| hex += mark ? '*' : ' '; |
| } else { |
| hex += " "; |
| } |
| } |
| hex = hex + " "; |
| |
| for (const char* p = row; p < row + 4 && p < row + length; ++p) { |
| hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.'; |
| } |
| |
| hex = hex + '\n'; |
| } |
| return hex; |
| } |
| |
| } // namespace |
| |
| QuicIpAddress TestPeerIPAddress() { |
| return QuicIpAddress::Loopback4(); |
| } |
| |
| ParsedQuicVersion QuicVersionMax() { |
| return AllSupportedVersions().front(); |
| } |
| |
| ParsedQuicVersion QuicVersionMin() { |
| return AllSupportedVersions().back(); |
| } |
| |
| QuicTransportVersion QuicTransportVersionMax() { |
| return AllSupportedTransportVersions().front(); |
| } |
| |
| QuicTransportVersion QuicTransportVersionMin() { |
| return AllSupportedTransportVersions().back(); |
| } |
| |
| QuicEncryptedPacket* ConstructEncryptedPacket( |
| QuicConnectionId destination_connection_id, |
| QuicConnectionId source_connection_id, |
| bool version_flag, |
| bool reset_flag, |
| uint64_t packet_number, |
| const std::string& data) { |
| return ConstructEncryptedPacket( |
| destination_connection_id, source_connection_id, version_flag, reset_flag, |
| packet_number, data, CONNECTION_ID_PRESENT, CONNECTION_ID_ABSENT, |
| PACKET_4BYTE_PACKET_NUMBER); |
| } |
| |
| QuicEncryptedPacket* ConstructEncryptedPacket( |
| QuicConnectionId destination_connection_id, |
| QuicConnectionId source_connection_id, |
| bool version_flag, |
| bool reset_flag, |
| uint64_t packet_number, |
| const std::string& data, |
| QuicConnectionIdIncluded destination_connection_id_included, |
| QuicConnectionIdIncluded source_connection_id_included, |
| QuicPacketNumberLength packet_number_length) { |
| return ConstructEncryptedPacket( |
| destination_connection_id, source_connection_id, version_flag, reset_flag, |
| packet_number, data, destination_connection_id_included, |
| source_connection_id_included, packet_number_length, nullptr); |
| } |
| |
| QuicEncryptedPacket* ConstructEncryptedPacket( |
| QuicConnectionId destination_connection_id, |
| QuicConnectionId source_connection_id, |
| bool version_flag, |
| bool reset_flag, |
| uint64_t packet_number, |
| const std::string& data, |
| QuicConnectionIdIncluded destination_connection_id_included, |
| QuicConnectionIdIncluded source_connection_id_included, |
| QuicPacketNumberLength packet_number_length, |
| ParsedQuicVersionVector* versions) { |
| return ConstructEncryptedPacket( |
| destination_connection_id, source_connection_id, version_flag, reset_flag, |
| packet_number, data, destination_connection_id_included, |
| source_connection_id_included, packet_number_length, versions, |
| Perspective::IS_CLIENT); |
| } |
| QuicEncryptedPacket* ConstructEncryptedPacket( |
| QuicConnectionId destination_connection_id, |
| QuicConnectionId source_connection_id, |
| bool version_flag, |
| bool reset_flag, |
| uint64_t packet_number, |
| const std::string& data, |
| QuicConnectionIdIncluded destination_connection_id_included, |
| QuicConnectionIdIncluded source_connection_id_included, |
| QuicPacketNumberLength packet_number_length, |
| ParsedQuicVersionVector* versions, |
| Perspective perspective) { |
| QuicPacketHeader header; |
| header.destination_connection_id = destination_connection_id; |
| header.destination_connection_id_included = |
| destination_connection_id_included; |
| header.source_connection_id = source_connection_id; |
| header.source_connection_id_included = source_connection_id_included; |
| header.version_flag = version_flag; |
| header.reset_flag = reset_flag; |
| header.packet_number_length = packet_number_length; |
| header.packet_number = QuicPacketNumber(packet_number); |
| ParsedQuicVersionVector supported_versions = CurrentSupportedVersions(); |
| if (!versions) { |
| versions = &supported_versions; |
| } |
| if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) && |
| version_flag) { |
| header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; |
| header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; |
| } |
| |
| QuicFrames frames; |
| QuicFramer framer(*versions, QuicTime::Zero(), perspective, |
| kQuicDefaultConnectionIdLength); |
| ParsedQuicVersion version = (*versions)[0]; |
| EncryptionLevel level = |
| header.version_flag ? ENCRYPTION_INITIAL : ENCRYPTION_FORWARD_SECURE; |
| if (version.handshake_protocol == PROTOCOL_TLS1_3 && |
| level == ENCRYPTION_INITIAL) { |
| CrypterPair crypters; |
| CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, |
| version.transport_version, |
| destination_connection_id, &crypters); |
| framer.SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); |
| if (version.KnowsWhichDecrypterToUse()) { |
| framer.InstallDecrypter(ENCRYPTION_INITIAL, |
| std::move(crypters.decrypter)); |
| } else { |
| framer.SetDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); |
| } |
| } |
| if (!QuicVersionUsesCryptoFrames(version.transport_version)) { |
| QuicFrame frame( |
| QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version), |
| false, 0, QuicStringPiece(data))); |
| frames.push_back(frame); |
| } else { |
| QuicFrame frame(new QuicCryptoFrame(level, 0, data)); |
| frames.push_back(frame); |
| } |
| // We need a minimum number of bytes of encrypted payload. This will |
| // guarantee that we have at least that much. (It ignores the overhead of the |
| // stream/crypto framing, so it overpads slightly.) |
| size_t min_plaintext_size = |
| QuicPacketCreator::MinPlaintextPacketSize(version); |
| if (data.length() < min_plaintext_size) { |
| size_t padding_length = min_plaintext_size - data.length(); |
| frames.push_back(QuicFrame(QuicPaddingFrame(padding_length))); |
| } |
| |
| std::unique_ptr<QuicPacket> packet( |
| BuildUnsizedDataPacket(&framer, header, frames)); |
| EXPECT_TRUE(packet != nullptr); |
| char* buffer = new char[kMaxOutgoingPacketSize]; |
| size_t encrypted_length = |
| framer.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(packet_number), |
| *packet, buffer, kMaxOutgoingPacketSize); |
| EXPECT_NE(0u, encrypted_length); |
| DeleteFrames(&frames); |
| return new QuicEncryptedPacket(buffer, encrypted_length, true); |
| } |
| |
| QuicReceivedPacket* ConstructReceivedPacket( |
| const QuicEncryptedPacket& encrypted_packet, |
| QuicTime receipt_time) { |
| char* buffer = new char[encrypted_packet.length()]; |
| memcpy(buffer, encrypted_packet.data(), encrypted_packet.length()); |
| return new QuicReceivedPacket(buffer, encrypted_packet.length(), receipt_time, |
| true); |
| } |
| |
| QuicEncryptedPacket* ConstructMisFramedEncryptedPacket( |
| QuicConnectionId destination_connection_id, |
| QuicConnectionId source_connection_id, |
| bool version_flag, |
| bool reset_flag, |
| uint64_t packet_number, |
| const std::string& data, |
| QuicConnectionIdIncluded destination_connection_id_included, |
| QuicConnectionIdIncluded source_connection_id_included, |
| QuicPacketNumberLength packet_number_length, |
| ParsedQuicVersionVector* versions, |
| Perspective perspective) { |
| QuicPacketHeader header; |
| header.destination_connection_id = destination_connection_id; |
| header.destination_connection_id_included = |
| destination_connection_id_included; |
| header.source_connection_id = source_connection_id; |
| header.source_connection_id_included = source_connection_id_included; |
| header.version_flag = version_flag; |
| header.reset_flag = reset_flag; |
| header.packet_number_length = packet_number_length; |
| header.packet_number = QuicPacketNumber(packet_number); |
| if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) && |
| version_flag) { |
| header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; |
| header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; |
| } |
| QuicFrame frame(QuicStreamFrame(1, false, 0, QuicStringPiece(data))); |
| QuicFrames frames; |
| frames.push_back(frame); |
| ParsedQuicVersion version = |
| (versions != nullptr ? *versions : AllSupportedVersions())[0]; |
| QuicFramer framer(versions != nullptr ? *versions : AllSupportedVersions(), |
| QuicTime::Zero(), perspective, |
| kQuicDefaultConnectionIdLength); |
| if (version.handshake_protocol == PROTOCOL_TLS1_3 && version_flag) { |
| CrypterPair crypters; |
| CryptoUtils::CreateTlsInitialCrypters(Perspective::IS_CLIENT, |
| version.transport_version, |
| destination_connection_id, &crypters); |
| framer.SetEncrypter(ENCRYPTION_INITIAL, std::move(crypters.encrypter)); |
| framer.InstallDecrypter(ENCRYPTION_INITIAL, std::move(crypters.decrypter)); |
| } |
| // We need a minimum of 7 bytes of encrypted payload. This will guarantee that |
| // we have at least that much. (It ignores the overhead of the stream/crypto |
| // framing, so it overpads slightly.) |
| if (data.length() < 7) { |
| size_t padding_length = 7 - data.length(); |
| frames.push_back(QuicFrame(QuicPaddingFrame(padding_length))); |
| } |
| |
| std::unique_ptr<QuicPacket> packet( |
| BuildUnsizedDataPacket(&framer, header, frames)); |
| EXPECT_TRUE(packet != nullptr); |
| |
| // Now set the frame type to 0x1F, which is an invalid frame type. |
| reinterpret_cast<unsigned char*>( |
| packet->mutable_data())[GetStartOfEncryptedData( |
| framer.transport_version(), |
| GetIncludedDestinationConnectionIdLength(header), |
| GetIncludedSourceConnectionIdLength(header), version_flag, |
| false /* no diversification nonce */, packet_number_length, |
| header.retry_token_length_length, 0, header.length_length)] = 0x1F; |
| |
| char* buffer = new char[kMaxOutgoingPacketSize]; |
| size_t encrypted_length = |
| framer.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(packet_number), |
| *packet, buffer, kMaxOutgoingPacketSize); |
| EXPECT_NE(0u, encrypted_length); |
| return new QuicEncryptedPacket(buffer, encrypted_length, true); |
| } |
| |
| void CompareCharArraysWithHexError(const std::string& description, |
| const char* actual, |
| const int actual_len, |
| const char* expected, |
| const int expected_len) { |
| EXPECT_EQ(actual_len, expected_len); |
| const int min_len = std::min(actual_len, expected_len); |
| const int max_len = std::max(actual_len, expected_len); |
| std::unique_ptr<bool[]> marks(new bool[max_len]); |
| bool identical = (actual_len == expected_len); |
| for (int i = 0; i < min_len; ++i) { |
| if (actual[i] != expected[i]) { |
| marks[i] = true; |
| identical = false; |
| } else { |
| marks[i] = false; |
| } |
| } |
| for (int i = min_len; i < max_len; ++i) { |
| marks[i] = true; |
| } |
| if (identical) |
| return; |
| ADD_FAILURE() << "Description:\n" |
| << description << "\n\nExpected:\n" |
| << HexDumpWithMarks(expected, expected_len, marks.get(), |
| max_len) |
| << "\nActual:\n" |
| << HexDumpWithMarks(actual, actual_len, marks.get(), max_len); |
| } |
| |
| QuicConfig DefaultQuicConfig() { |
| QuicConfig config; |
| config.SetInitialStreamFlowControlWindowToSend( |
| kInitialStreamFlowControlWindowForTest); |
| config.SetInitialSessionFlowControlWindowToSend( |
| kInitialSessionFlowControlWindowForTest); |
| QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( |
| &config, kDefaultMaxStreamsPerConnection); |
| // Default enable NSTP. |
| // This is unnecessary for versions > 44 |
| if (!config.HasClientSentConnectionOption(quic::kNSTP, |
| quic::Perspective::IS_CLIENT)) { |
| quic::QuicTagVector connection_options; |
| connection_options.push_back(quic::kNSTP); |
| config.SetConnectionOptionsToSend(connection_options); |
| } |
| return config; |
| } |
| |
| QuicTransportVersionVector SupportedTransportVersions( |
| QuicTransportVersion version) { |
| QuicTransportVersionVector versions; |
| versions.push_back(version); |
| return versions; |
| } |
| |
| ParsedQuicVersionVector SupportedVersions(ParsedQuicVersion version) { |
| ParsedQuicVersionVector versions; |
| versions.push_back(version); |
| return versions; |
| } |
| |
| MockQuicConnectionDebugVisitor::MockQuicConnectionDebugVisitor() {} |
| |
| MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {} |
| |
| MockReceivedPacketManager::MockReceivedPacketManager(QuicConnectionStats* stats) |
| : QuicReceivedPacketManager(stats) {} |
| |
| MockReceivedPacketManager::~MockReceivedPacketManager() {} |
| |
| MockPacketCreatorDelegate::MockPacketCreatorDelegate() {} |
| MockPacketCreatorDelegate::~MockPacketCreatorDelegate() {} |
| |
| MockSessionNotifier::MockSessionNotifier() {} |
| MockSessionNotifier::~MockSessionNotifier() {} |
| |
| void CreateClientSessionForTest( |
| QuicServerId server_id, |
| QuicTime::Delta connection_start_time, |
| const ParsedQuicVersionVector& supported_versions, |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| QuicCryptoClientConfig* crypto_client_config, |
| PacketSavingConnection** client_connection, |
| TestQuicSpdyClientSession** client_session) { |
| CHECK(crypto_client_config); |
| CHECK(client_connection); |
| CHECK(client_session); |
| CHECK(!connection_start_time.IsZero()) |
| << "Connections must start at non-zero times, otherwise the " |
| << "strike-register will be unhappy."; |
| |
| QuicConfig config = DefaultQuicConfig(); |
| *client_connection = new PacketSavingConnection( |
| helper, alarm_factory, Perspective::IS_CLIENT, supported_versions); |
| *client_session = new TestQuicSpdyClientSession(*client_connection, config, |
| supported_versions, server_id, |
| crypto_client_config); |
| (*client_connection)->AdvanceTime(connection_start_time); |
| } |
| |
| void CreateServerSessionForTest( |
| QuicServerId /*server_id*/, |
| QuicTime::Delta connection_start_time, |
| ParsedQuicVersionVector supported_versions, |
| MockQuicConnectionHelper* helper, |
| MockAlarmFactory* alarm_factory, |
| QuicCryptoServerConfig* server_crypto_config, |
| QuicCompressedCertsCache* compressed_certs_cache, |
| PacketSavingConnection** server_connection, |
| TestQuicSpdyServerSession** server_session) { |
| CHECK(server_crypto_config); |
| CHECK(server_connection); |
| CHECK(server_session); |
| CHECK(!connection_start_time.IsZero()) |
| << "Connections must start at non-zero times, otherwise the " |
| << "strike-register will be unhappy."; |
| |
| *server_connection = |
| new PacketSavingConnection(helper, alarm_factory, Perspective::IS_SERVER, |
| ParsedVersionOfIndex(supported_versions, 0)); |
| *server_session = new TestQuicSpdyServerSession( |
| *server_connection, DefaultQuicConfig(), supported_versions, |
| server_crypto_config, compressed_certs_cache); |
| |
| // We advance the clock initially because the default time is zero and the |
| // strike register worries that we've just overflowed a uint32_t time. |
| (*server_connection)->AdvanceTime(connection_start_time); |
| } |
| |
| QuicStreamId GetNthClientInitiatedBidirectionalStreamId( |
| QuicTransportVersion version, |
| int n) { |
| int num = n; |
| if (!VersionLacksHeadersStream(version)) { |
| num++; // + 1 because spdy_session contains headers stream. |
| } |
| return QuicUtils::GetFirstBidirectionalStreamId(version, |
| Perspective::IS_CLIENT) + |
| QuicUtils::StreamIdDelta(version) * num; |
| } |
| |
| QuicStreamId GetNthServerInitiatedBidirectionalStreamId( |
| QuicTransportVersion version, |
| int n) { |
| return QuicUtils::GetFirstBidirectionalStreamId(version, |
| Perspective::IS_SERVER) + |
| QuicUtils::StreamIdDelta(version) * n; |
| } |
| |
| QuicStreamId GetNthServerInitiatedUnidirectionalStreamId( |
| QuicTransportVersion version, |
| int n) { |
| return QuicUtils::GetFirstUnidirectionalStreamId(version, |
| Perspective::IS_SERVER) + |
| QuicUtils::StreamIdDelta(version) * n; |
| } |
| |
| QuicStreamId GetNthClientInitiatedUnidirectionalStreamId( |
| QuicTransportVersion version, |
| int n) { |
| return QuicUtils::GetFirstUnidirectionalStreamId(version, |
| Perspective::IS_CLIENT) + |
| QuicUtils::StreamIdDelta(version) * n; |
| } |
| |
| StreamType DetermineStreamType(QuicStreamId id, |
| QuicTransportVersion version, |
| Perspective perspective, |
| bool is_incoming, |
| StreamType default_type) { |
| return VersionHasIetfQuicFrames(version) |
| ? QuicUtils::GetStreamType(id, perspective, is_incoming) |
| : default_type; |
| } |
| |
| QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator, |
| QuicStringPiece message_data, |
| QuicMemSliceStorage* storage) { |
| if (message_data.length() == 0) { |
| *storage = |
| QuicMemSliceStorage(nullptr, 0, allocator, kMaxOutgoingPacketSize); |
| return storage->ToSpan(); |
| } |
| struct iovec iov = {const_cast<char*>(message_data.data()), |
| message_data.length()}; |
| *storage = QuicMemSliceStorage(&iov, 1, allocator, kMaxOutgoingPacketSize); |
| return storage->ToSpan(); |
| } |
| |
| } // namespace test |
| } // namespace quic |