Add QUIC_BUG_IF to QuicUtils::GetCryptoStreamId In QUIC versions that use CRYPTO frames (instead of stream 1 frames) for the crypto handshake, the concept of a "crypto stream ID" makes no sense, so QuicUtils::GetCryptoStreamId should hit a QUIC_BUG_IF to prevent its misuse. gfe-relnote: Add QUIC_BUG_IF protected behind QuicVersionUsesCryptoFrames PiperOrigin-RevId: 248463613 Change-Id: If6768658e9ffc058778b53a91f95839826602fbf
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc index 2398693..ec3a899 100644 --- a/quic/core/chlo_extractor.cc +++ b/quic/core/chlo_extractor.cc
@@ -151,8 +151,8 @@ return false; } QuicStringPiece data(frame.data_buffer, frame.data_length); - if (frame.stream_id == - QuicUtils::GetCryptoStreamId(framer_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_id) && frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) { return OnHandshakeData(data); }
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc index e5e084c..258e141 100644 --- a/quic/core/chlo_extractor_test.cc +++ b/quic/core/chlo_extractor_test.cc
@@ -141,11 +141,15 @@ } TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { + ParsedQuicVersion version = AllSupportedVersions()[0]; + if (QuicVersionUsesCryptoFrames(version.transport_version)) { + return; + } CryptoHandshakeMessage client_hello; client_hello.set_tag(kCHLO); std::string client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(AllSupportedVersions()[0], client_hello_str, + MakePacket(version, client_hello_str, /*munge_offset*/ false, /*munge_stream_id*/ true); EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_, @@ -165,7 +169,11 @@ } TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { - MakePacket(AllSupportedVersions()[0], "foo", /*munge_offset*/ false, + ParsedQuicVersion version = AllSupportedVersions()[0]; + if (QuicVersionUsesCryptoFrames(version.transport_version)) { + return; + } + MakePacket(version, "foo", /*munge_offset*/ false, /*munge_stream_id*/ true); EXPECT_FALSE(ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_,
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc index 33b9393..1fe3465 100644 --- a/quic/core/congestion_control/uber_loss_algorithm_test.cc +++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -31,12 +31,17 @@ void SendPacket(uint64_t packet_number, EncryptionLevel encryption_level) { QuicStreamFrame frame; - frame.stream_id = - encryption_level == ENCRYPTION_INITIAL - ? QuicUtils::GetCryptoStreamId( - CurrentSupportedVersions()[0].transport_version) - : QuicUtils::GetHeadersStreamId( - CurrentSupportedVersions()[0].transport_version); + QuicTransportVersion version = + CurrentSupportedVersions()[0].transport_version; + frame.stream_id = QuicUtils::GetHeadersStreamId(version); + if (encryption_level == ENCRYPTION_INITIAL) { + if (QuicVersionUsesCryptoFrames(version)) { + frame.stream_id = QuicUtils::GetFirstBidirectionalStreamId( + version, Perspective::IS_CLIENT); + } else { + frame.stream_id = QuicUtils::GetCryptoStreamId(version); + } + } SerializedPacket packet(QuicPacketNumber(packet_number), PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, false, false);
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc index 599f939..77d105c 100644 --- a/quic/core/http/quic_spdy_client_session_test.cc +++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -207,10 +207,8 @@ EXPECT_TRUE(session_->IsEncryptionEstablished()); QuicSpdyClientStream* stream = session_->CreateOutgoingBidirectionalStream(); ASSERT_TRUE(stream != nullptr); - if (!QuicVersionUsesCryptoFrames(GetParam().transport_version)) { - EXPECT_NE(QuicUtils::GetCryptoStreamId(connection_->transport_version()), - stream->id()); - } + EXPECT_FALSE(QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream->id())); // Process an "inchoate" REJ from the server which will cause // an inchoate CHLO to be sent and will leave the encryption level @@ -300,11 +298,8 @@ // frame; pretend we got one. // Note that this is to be the second stream created, hence - // the stream count is 4 (the two streams created as a part of - // the test plus the crypto and header stream, internally created). - // TODO(nharper): Change 4 to 3 & update comment accordingly when the crypto - // stuff is no longer in a regular stream. - // TODO(fkastenholz): do above if nharper doesn't :-) + // the stream count is 3 (the two streams created as a part of + // the test plus the header stream, internally created). QuicMaxStreamsFrame frame( 0, QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) @@ -316,11 +311,9 @@ stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_NE(nullptr, stream); if (GetParam().transport_version == QUIC_VERSION_99) { - // Ensure that we have/have had four open streams, crypto, header, and the - // two test streams. Primary purpose of this is to fail when crypto - // no longer uses a normal stream. Some above constants will then need - // to be changed. - EXPECT_EQ(4u, + // Ensure that we have/have had three open streams: two test streams and the + // header stream. + EXPECT_EQ(3u, QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) ->outgoing_stream_count()); } @@ -384,11 +377,8 @@ EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); if (GetParam().transport_version == QUIC_VERSION_99) { // Note that this is to be the second stream created, hence - // the stream count is 4 (the two streams created as a part of - // the test plus the crypto and header stream, internally created). - // TODO(nharper): Change 4 to 3 & update comment accordingly when the crypto - // stuff is no longer in a regular stream. - // TODO(fkastenholz): do above if nharper doesn't :-) + // the stream count is 3 (the two streams created as a part of + // the test plus the header stream, internally created). QuicMaxStreamsFrame frame( 0, QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) @@ -401,11 +391,9 @@ stream = session_->CreateOutgoingBidirectionalStream(); EXPECT_NE(nullptr, stream); if (GetParam().transport_version == QUIC_VERSION_99) { - // Ensure that we have/have had four open streams, crypto, header, and the - // two test streams. Primary purpose of this is to fail when crypto - // no longer uses a normal stream. Some above constants will then need - // to be changed. - EXPECT_EQ(4u, + // Ensure that we have/have had three open streams: two test streams and the + // header stream. + EXPECT_EQ(3u, QuicSessionPeer::v99_bidirectional_stream_id_manager(&*session_) ->outgoing_stream_count()); } @@ -448,7 +436,7 @@ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); session_->OnStreamHeaderList( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), /*fin=*/false, 0, trailers); } @@ -464,7 +452,7 @@ EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); session_->OnPromiseHeaderList( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), promised_stream_id_, 0, trailers); }
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc index c7ce057..e0e417a 100644 --- a/quic/core/http/quic_spdy_session_test.cc +++ b/quic/core/http/quic_spdy_session_test.cc
@@ -94,7 +94,7 @@ MOCK_METHOD0(OnCanWrite, void()); - bool HasPendingCryptoRetransmission() override { return false; } + bool HasPendingCryptoRetransmission() const override { return false; } MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); @@ -241,9 +241,8 @@ QuicConsumedData SendStreamData(QuicStream* stream) { struct iovec iov; - if ((QuicVersionUsesCryptoFrames(connection()->transport_version()) || - stream->id() != - QuicUtils::GetCryptoStreamId(connection()->transport_version())) && + if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(), + stream->id()) && connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) { this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -396,6 +395,12 @@ if (perspective == Perspective::IS_SERVER) { id |= 0x1; } + if (bidirectional && perspective == Perspective::IS_CLIENT && + QuicVersionUsesCryptoFrames(transport_version())) { + // Once stream ID 0 is used as a normal client initiated bidirectional + // stream, this shouldn't be needed any more. + id += 4; + } return id; } @@ -1072,7 +1077,7 @@ TEST_P(QuicSpdySessionTestServer, OnStreamFrameFinStaticStreamId) { // Send two bytes of payload. QuicStreamFrame data1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), true, 0, + QuicUtils::GetHeadersStreamId(connection_->transport_version()), true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, CloseConnection( @@ -1085,7 +1090,7 @@ // Send two bytes of payload. QuicRstStreamFrame rst1( kInvalidControlFrameId, - QuicUtils::GetCryptoStreamId(connection_->transport_version()), + QuicUtils::GetHeadersStreamId(connection_->transport_version()), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(*connection_, CloseConnection( @@ -1559,7 +1564,7 @@ EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 28 would exceed stream count limit 7", _)); + "Stream id 28 would exceed stream count limit 6", _)); } // Create one more data streams to exceed limit of open stream. QuicStreamFrame data1(kFinalStreamId, false, 0, QuicStringPiece("HT"));
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index bcea7e5..d04efc5 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -146,9 +146,8 @@ http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), ack_listener_(nullptr) { - DCHECK_NE(QuicUtils::GetCryptoStreamId( - spdy_session->connection()->transport_version()), - id); + DCHECK(!QuicUtils::IsCryptoStreamId( + spdy_session->connection()->transport_version(), id)); // Don't receive any callbacks from the sequencer until headers // are complete. sequencer()->SetBlockedUntilFlush(); @@ -172,9 +171,8 @@ http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), ack_listener_(nullptr) { - DCHECK_NE(QuicUtils::GetCryptoStreamId( - spdy_session->connection()->transport_version()), - id()); + DCHECK(!QuicUtils::IsCryptoStreamId( + spdy_session->connection()->transport_version(), id())); // Don't receive any callbacks from the sequencer until headers // are complete. sequencer()->SetBlockedUntilFlush();
diff --git a/quic/core/legacy_quic_stream_id_manager.cc b/quic/core/legacy_quic_stream_id_manager.cc index 6fb662a..447f16d 100644 --- a/quic/core/legacy_quic_stream_id_manager.cc +++ b/quic/core/legacy_quic_stream_id_manager.cc
@@ -19,14 +19,18 @@ : session_(session), max_open_outgoing_streams_(max_open_outgoing_streams), max_open_incoming_streams_(max_open_incoming_streams), - next_outgoing_stream_id_( - QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()) + - (session->perspective() == Perspective::IS_SERVER ? 1 : 2)), + next_outgoing_stream_id_(QuicUtils::GetFirstBidirectionalStreamId( + session->connection()->transport_version(), + session->perspective())), largest_peer_created_stream_id_( session->perspective() == Perspective::IS_SERVER - ? QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()) + ? (QuicVersionUsesCryptoFrames( + session->connection()->transport_version()) + ? QuicUtils::GetFirstBidirectionalStreamId( + session->connection()->transport_version(), + Perspective::IS_CLIENT) + : QuicUtils::GetCryptoStreamId( + session->connection()->transport_version())) : QuicUtils::GetInvalidStreamId( session->connection()->transport_version())) {}
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index af388a9..c1d1d76 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -1027,7 +1027,7 @@ if (debug_visitor_ != nullptr) { debug_visitor_->OnStreamFrame(frame); } - if (frame.stream_id != QuicUtils::GetCryptoStreamId(transport_version()) && + if (!QuicUtils::IsCryptoStreamId(transport_version(), frame.stream_id) && last_decrypted_packet_level_ == ENCRYPTION_INITIAL) { if (MaybeConsiderAsMemoryCorruption(frame)) { CloseConnection(QUIC_MAYBE_CORRUPTED_MEMORY, @@ -3744,7 +3744,7 @@ bool QuicConnection::MaybeConsiderAsMemoryCorruption( const QuicStreamFrame& frame) { - if (frame.stream_id == QuicUtils::GetCryptoStreamId(transport_version()) || + if (QuicUtils::IsCryptoStreamId(transport_version(), frame.stream_id) || last_decrypted_packet_level_ != ENCRYPTION_INITIAL) { return false; }
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index d80b55f..4ecb780 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -660,7 +660,7 @@ QuicStreamOffset offset, StreamSendingState state) { ScopedPacketFlusher flusher(this, NO_ACK); - if (id != QuicUtils::GetCryptoStreamId(transport_version()) && + if (!QuicUtils::IsCryptoStreamId(transport_version(), id) && this->encryption_level() == ENCRYPTION_INITIAL) { this->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -709,6 +709,11 @@ QuicConsumedData SendCryptoStreamData() { QuicStreamOffset offset = 0; QuicStringPiece data("chlo"); + return SendCryptoDataWithString(data, offset); + } + + QuicConsumedData SendCryptoDataWithString(QuicStringPiece data, + QuicStreamOffset offset) { if (!QuicVersionUsesCryptoFrames(transport_version())) { return SendStreamDataWithString( QuicUtils::GetCryptoStreamId(transport_version()), data, offset, @@ -815,6 +820,8 @@ next_effective_peer_addr_ = QuicMakeUnique<QuicSocketAddress>(addr); } + SimpleDataProducer* producer() { return &producer_; } + using QuicConnection::active_effective_peer_migration_type; using QuicConnection::IsCurrentPacketConnectivityProbing; using QuicConnection::SelectMutualVersion; @@ -917,14 +924,9 @@ creator_(QuicConnectionPeer::GetPacketCreator(&connection_)), generator_(QuicConnectionPeer::GetPacketGenerator(&connection_)), manager_(QuicConnectionPeer::GetSentPacketManager(&connection_)), - frame1_(QuicUtils::GetCryptoStreamId(version().transport_version), - false, - 0, - QuicStringPiece(data1)), - frame2_(QuicUtils::GetCryptoStreamId(version().transport_version), - false, - 3, - QuicStringPiece(data2)), + frame1_(0, false, 0, QuicStringPiece(data1)), + frame2_(0, false, 3, QuicStringPiece(data2)), + crypto_frame_(ENCRYPTION_INITIAL, 0, QuicStringPiece(data1)), packet_number_length_(PACKET_4BYTE_PACKET_NUMBER), connection_id_included_(CONNECTION_ID_PRESENT), notifier_(&connection_) { @@ -944,6 +946,15 @@ QuicConnectionPeer::SetNoStopWaitingFrames(&connection_, GetParam().no_stop_waiting); } + QuicStreamId stream_id; + if (QuicVersionUsesCryptoFrames(version().transport_version)) { + stream_id = QuicUtils::GetFirstBidirectionalStreamId( + version().transport_version, Perspective::IS_CLIENT); + } else { + stream_id = QuicUtils::GetCryptoStreamId(version().transport_version); + } + frame1_.stream_id = stream_id; + frame2_.stream_id = stream_id; connection_.set_visitor(&visitor_); if (connection_.session_decides_what_to_write()) { connection_.SetSessionNotifier(¬ifier_); @@ -1180,6 +1191,29 @@ level); } + size_t ProcessCryptoPacketAtLevel(uint64_t number, EncryptionLevel level) { + QuicPacketHeader header = ConstructPacketHeader(1000, ENCRYPTION_INITIAL); + QuicFrames frames; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } + std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames); + char buffer[kMaxOutgoingPacketSize]; + peer_creator_.set_encryption_level(ENCRYPTION_INITIAL); + size_t encrypted_length = + peer_framer_.EncryptPayload(ENCRYPTION_INITIAL, QuicPacketNumber(1000), + *packet, buffer, kMaxOutgoingPacketSize); + connection_.ProcessUdpPacket( + kSelfAddress, kPeerAddress, + QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false)); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } + return encrypted_length; + } + size_t ProcessDataPacketAtLevel(uint64_t number, bool has_stop_waiting, EncryptionLevel level) { @@ -1302,9 +1336,8 @@ return packet; } - std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number, - bool has_stop_waiting, - EncryptionLevel level) { + QuicPacketHeader ConstructPacketHeader(uint64_t number, + EncryptionLevel level) { QuicPacketHeader header; if (peer_framer_.transport_version() > QUIC_VERSION_43 && level < ENCRYPTION_FORWARD_SECURE) { @@ -1344,7 +1377,13 @@ } header.packet_number_length = packet_number_length_; header.packet_number = QuicPacketNumber(number); + return header; + } + std::unique_ptr<QuicPacket> ConstructDataPacket(uint64_t number, + bool has_stop_waiting, + EncryptionLevel level) { + QuicPacketHeader header = ConstructPacketHeader(number, level); QuicFrames frames; frames.push_back(QuicFrame(frame1_)); if (has_stop_waiting) { @@ -1514,6 +1553,7 @@ QuicStreamFrame frame1_; QuicStreamFrame frame2_; + QuicCryptoFrame crypto_frame_; QuicAckFrame ack_; QuicStopWaitingFrame stop_waiting_; QuicPacketNumberLength packet_number_length_; @@ -1533,19 +1573,27 @@ EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address, - kPeerAddress); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); EXPECT_TRUE(connection_.connected()); } @@ -1558,20 +1606,24 @@ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Cause change in self_address. QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address(host, 123); EXPECT_CALL(visitor_, AllowSelfAddressChange()).WillOnce(Return(false)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_ERROR_MIGRATING_ADDRESS, _, _)); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address, kPeerAddress); EXPECT_FALSE(connection_.connected()); } @@ -1584,26 +1636,29 @@ EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); EXPECT_TRUE(connection_.connected()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(3); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(3); + } QuicIpAddress host; host.FromString("1.1.1.1"); QuicSocketAddress self_address1(host, 443); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address1, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); // Cause self_address change to mapped Ipv4 address. QuicIpAddress host2; host2.FromString( QuicStrCat("::ffff:", connection_.self_address().host().ToString())); QuicSocketAddress self_address2(host2, connection_.self_address().port()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address2, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address2, kPeerAddress); EXPECT_TRUE(connection_.connected()); // self_address change back to Ipv4 address. - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), self_address1, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, self_address1, kPeerAddress); EXPECT_TRUE(connection_.connected()); } @@ -1619,16 +1674,21 @@ QuicConnectionPeer::SetEffectivePeerAddress(&connection_, QuicSocketAddress()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); @@ -1636,8 +1696,7 @@ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4); // This is an old packet, do not migrate. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -1656,12 +1715,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1670,8 +1734,7 @@ const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -1692,12 +1755,17 @@ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/43210); connection_.ReturnEffectivePeerAddressForNextPacket(kEffectivePeerAddress); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kEffectivePeerAddress, connection_.effective_peer_address()); @@ -1707,8 +1775,7 @@ QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/54321); connection_.ReturnEffectivePeerAddressForNextPacket(kNewEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewEffectivePeerAddress, connection_.effective_peer_address()); @@ -1737,8 +1804,7 @@ connection_.ReturnEffectivePeerAddressForNextPacket( kNewerEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kFinalPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewerEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(PORT_CHANGE, connection_.active_effective_peer_migration_type()); @@ -1752,8 +1818,7 @@ kNewestEffectivePeerAddress); EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1); EXPECT_CALL(*send_algorithm_, OnConnectionMigration()).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kFinalPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kFinalPeerAddress); EXPECT_EQ(kFinalPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewestEffectivePeerAddress, connection_.effective_peer_address()); EXPECT_EQ(IPV6_TO_IPV4_CHANGE, @@ -1774,12 +1839,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1881,12 +1951,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1916,8 +1991,7 @@ // Process another packet with the old peer address on server side will not // start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); } @@ -1936,13 +2010,18 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -1988,12 +2067,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2018,8 +2102,7 @@ // side will start peer migration. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -2037,12 +2120,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2079,12 +2167,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2124,12 +2217,17 @@ QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2138,8 +2236,7 @@ const QuicSocketAddress kNewPeerAddress = QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kNewPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -2177,7 +2274,11 @@ QuicFrames frames; QuicPaddingFrame padding; - frames.push_back(QuicFrame(frame1_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } frames.push_back(QuicFrame(padding)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxOutgoingPacketSize]; @@ -2187,7 +2288,11 @@ EXPECT_EQ(kMaxOutgoingPacketSize, encrypted_length); framer_.set_version(version()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -2218,7 +2323,11 @@ QuicFrames frames; QuicPaddingFrame padding; - frames.push_back(QuicFrame(frame1_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frames.push_back(QuicFrame(&crypto_frame_)); + } else { + frames.push_back(QuicFrame(frame1_)); + } frames.push_back(QuicFrame(padding)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); char buffer[kMaxOutgoingPacketSize]; @@ -2228,7 +2337,11 @@ EXPECT_EQ(kMaxOutgoingPacketSize, encrypted_length); framer_.set_version(version()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false)); @@ -2587,7 +2700,8 @@ } // Send a packet containing stream frame. SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.version().transport_version), + QuicUtils::GetFirstBidirectionalStreamId( + connection_.version().transport_version, Perspective::IS_CLIENT), "bar", 0, NO_FIN, nullptr); // Session will not be informed until receiving another 20 packets. @@ -2917,9 +3031,13 @@ EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacket(1); QuicPacketNumber last_packet; - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.version().transport_version), - "foo", 0, NO_FIN, &last_packet); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + connection_.SendCryptoDataWithString("foo", 0); + } else { + SendStreamDataToPeer( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, + NO_FIN, &last_packet); + } // Verify ack is bundled with outging packet. EXPECT_FALSE(writer_->ack_frames().empty()); @@ -2960,6 +3078,7 @@ } TEST_P(QuicConnectionTest, FramePackingSendv) { + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Send data in 1 packet by writing multiple blocks in a single iovector // using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -2970,25 +3089,25 @@ iov[0].iov_len = 4; iov[1].iov_base = data + 4; iov[1].iov_len = 2; - connection_.SaveAndSendStreamData( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), iov, 2, 6, - 0, NO_FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); // Parse the last packet and ensure multiple iovector blocks have // been packed into a single stream frame from one stream. - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(1u, writer_->padding_frames().size()); + EXPECT_EQ(0u, writer_->padding_frames().size()); QuicStreamFrame* frame = writer_->stream_frames()[0].get(); - EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), - frame->stream_id); + EXPECT_EQ(stream_id, frame->stream_id); EXPECT_EQ("ABCDEF", QuicStringPiece(frame->data_buffer, frame->data_length)); } TEST_P(QuicConnectionTest, FramePackingSendvQueued) { + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Try to send two stream frames in 1 packet by using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); @@ -2999,9 +3118,9 @@ iov[0].iov_len = 4; iov[1].iov_base = data + 4; iov[1].iov_len = 2; - connection_.SaveAndSendStreamData( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), iov, 2, 6, - 0, NO_FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN); EXPECT_EQ(1u, connection_.NumQueuedPackets()); EXPECT_TRUE(connection_.HasQueuedData()); @@ -3012,20 +3131,19 @@ EXPECT_EQ(0u, connection_.NumQueuedPackets()); // Parse the last packet and ensure it's one stream frame from one stream. - EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_EQ(1u, writer_->frame_count()); EXPECT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(1u, writer_->padding_frames().size()); - EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), - writer_->stream_frames()[0]->stream_id); + EXPECT_EQ(0u, writer_->padding_frames().size()); + EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id); } TEST_P(QuicConnectionTest, SendingZeroBytes) { connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); // Send a zero byte write with a fin using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.SaveAndSendStreamData( - QuicUtils::GetHeadersStreamId(connection_.transport_version()), nullptr, - 0, 0, 0, FIN); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + connection_.transport_version(), Perspective::IS_CLIENT); + connection_.SaveAndSendStreamData(stream_id, nullptr, 0, 0, 0, FIN); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -3040,8 +3158,7 @@ EXPECT_EQ(1u + extra_padding_frames, writer_->frame_count()); EXPECT_EQ(extra_padding_frames, writer_->padding_frames().size()); ASSERT_EQ(1u, writer_->stream_frames().size()); - EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_.transport_version()), - writer_->stream_frames()[0]->stream_id); + EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id); EXPECT_TRUE(writer_->stream_frames()[0]->fin); } @@ -3563,7 +3680,7 @@ const bool has_stop_waiting = false; const EncryptionLevel level = ENCRYPTION_INITIAL; std::unique_ptr<QuicPacket> packet(ConstructDataPacket( - received_packet_num, has_stop_waiting, ENCRYPTION_INITIAL)); + received_packet_num, has_stop_waiting, ENCRYPTION_FORWARD_SECURE)); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload(level, QuicPacketNumber(received_packet_num), @@ -3953,9 +4070,11 @@ // the end of the packet. We can test this to check which encrypter was used. connection_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<TaggingEncrypter>(0x01)); - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN, nullptr); + QuicByteCount packet_size; + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(SaveArg<3>(&packet_size)); + connection_.SendCryptoDataWithString("foo", 0); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, @@ -3992,9 +4111,7 @@ // Attempt to send a handshake message and have the socket block. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true)); BlockOnNextWrite(); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); // The packet should be serialized, but not queued. EXPECT_EQ(1u, connection_.NumQueuedPackets()); @@ -4046,9 +4163,7 @@ QuicMakeUnique<TaggingEncrypter>(0x01)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN, nullptr); + connection_.SendCryptoDataWithString("foo", 0); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); @@ -6235,9 +6350,7 @@ } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); // Check that ack is bundled with outgoing crypto data. if (GetParam().no_stop_waiting) { EXPECT_EQ(3u, writer_->frame_count()); @@ -6254,14 +6367,10 @@ ProcessPacket(1); BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN); + connection_.SendCryptoDataWithString("foo", 0); EXPECT_TRUE(writer_->IsWriteBlocked()); EXPECT_FALSE(connection_.HasQueuedData()); - connection_.SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "bar", 3, - NO_FIN); + connection_.SendCryptoDataWithString("bar", 3); EXPECT_TRUE(writer_->IsWriteBlocked()); EXPECT_TRUE(connection_.HasQueuedData()); } @@ -8209,13 +8318,18 @@ return; } set_perspective(Perspective::IS_SERVER); - QuicStreamFrame stream_frame( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, 0u, - QuicStringPiece()); + QuicFrame frame; + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + frame = QuicFrame(&crypto_frame_); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + } else { + frame = QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_.transport_version()), false, + 0u, QuicStringPiece())); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessFramePacketWithAddresses(QuicFrame(stream_frame), kSelfAddress, - kPeerAddress); + ProcessFramePacketWithAddresses(frame, kSelfAddress, kPeerAddress); // Let connection process a Google QUIC packet. peer_framer_.set_version_for_tests( @@ -8334,10 +8448,13 @@ return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); use_tagging_decrypter(); // Receives packet 1000 in initial data. - ProcessDataPacketAtLevel(1000, false, ENCRYPTION_INITIAL); + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); @@ -8382,10 +8499,13 @@ return; } EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); use_tagging_decrypter(); // Receives packet 1000 in initial data. - ProcessDataPacketAtLevel(1000, false, ENCRYPTION_INITIAL); + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02));
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc index 2263546..f394b3d 100644 --- a/quic/core/quic_crypto_stream.cc +++ b/quic/core/quic_crypto_stream.cc
@@ -24,8 +24,12 @@ " ") QuicCryptoStream::QuicCryptoStream(QuicSession* session) - : QuicStream(QuicUtils::GetCryptoStreamId( - session->connection()->transport_version()), + : QuicStream(QuicVersionUsesCryptoFrames( + session->connection()->transport_version()) + ? QuicUtils::GetInvalidStreamId( + session->connection()->transport_version()) + : QuicUtils::GetCryptoStreamId( + session->connection()->transport_version()), session, /*is_static=*/true, QuicVersionUsesCryptoFrames( @@ -159,6 +163,9 @@ size_t bytes_consumed = session()->connection()->SendCryptoData(level, data.length(), offset); session()->connection()->SetDefaultEncryptionLevel(current_level); + // Since CRYPTO frames aren't flow controlled, SendCryptoData should have sent + // all data we asked it to send. + DCHECK_EQ(bytes_consumed, data.length()); send_buffer->OnStreamDataConsumed(bytes_consumed); } @@ -213,7 +220,7 @@ QuicStream::OnStreamDataConsumed(bytes_consumed); } -bool QuicCryptoStream::HasPendingCryptoRetransmission() { +bool QuicCryptoStream::HasPendingCryptoRetransmission() const { if (!QuicVersionUsesCryptoFrames( session()->connection()->transport_version())) { return false;
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h index 0c6d08a..1b641b1 100644 --- a/quic/core/quic_crypto_stream.h +++ b/quic/core/quic_crypto_stream.h
@@ -92,7 +92,7 @@ // Returns whether there are any bytes pending retransmission in CRYPTO // frames. - virtual bool HasPendingCryptoRetransmission(); + virtual bool HasPendingCryptoRetransmission() const; // Writes any pending CRYPTO frame retransmissions. void WritePendingCryptoRetransmission();
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index 831aac5..9af5f84 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -186,7 +186,8 @@ } offset += frame.crypto_frame->data_length; } - if (offset < reject.length()) { + if (offset < reject.length() && + !QuicVersionUsesCryptoFrames(framer_.transport_version())) { DCHECK(!creator_.HasRoomForStreamFrame( QuicUtils::GetCryptoStreamId(framer_.transport_version()), offset, frame.stream_frame.data_length));
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index 347df84..bf87ace 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -10012,7 +10012,7 @@ static QuicStreamId kTestQuicStreamId = 1; static bool ExpectedStreamFrame(const QuicStreamFrame& frame) { return (frame.stream_id == kTestQuicStreamId || - frame.stream_id == QuicUtils::GetCryptoStreamId(QUIC_VERSION_99)) && + QuicUtils::IsCryptoStreamId(QUIC_VERSION_99, frame.stream_id)) && !frame.fin && frame.offset == 0 && std::string(frame.data_buffer, frame.data_length) == kTestString; // FIN is hard-coded false in ConstructEncryptedPacket.
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index 0ffcc37..c013ce8 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -887,8 +887,8 @@ QUIC_DVLOG(1) << ENDPOINT << "Adding frame with transmission type " << transmission_type << ": " << frame; if (frame.type == STREAM_FRAME && - frame.stream_frame.stream_id != - QuicUtils::GetCryptoStreamId(framer_->transport_version()) && + !QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_frame.stream_id) && (packet_.encryption_level == ENCRYPTION_INITIAL || packet_.encryption_level == ENCRYPTION_HANDSHAKE)) { const std::string error_details = QuicStrCat( @@ -1011,8 +1011,8 @@ bool QuicPacketCreator::StreamFrameIsClientHello( const QuicStreamFrame& frame) const { if (framer_->perspective() == Perspective::IS_SERVER || - frame.stream_id != - QuicUtils::GetCryptoStreamId(framer_->transport_version())) { + !QuicUtils::IsCryptoStreamId(framer_->transport_version(), + frame.stream_id)) { return false; } // The ClientHello is always sent with INITIAL encryption.
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc index f87715b..655d587 100644 --- a/quic/core/quic_packet_creator_test.cc +++ b/quic/core/quic_packet_creator_test.cc
@@ -1285,8 +1285,14 @@ const size_t max_plaintext_size = client_framer_.GetMaxPlaintextSize(creator_.max_packet_length()); EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId( + client_framer_.transport_version(), Perspective::IS_CLIENT); + if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) { + stream_id = + QuicUtils::GetCryptoStreamId(client_framer_.transport_version()); + } + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(), @@ -1307,20 +1313,17 @@ EXPECT_TRUE( creator_.AddSavedFrame(QuicFrame(&ack_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); QuicFrame frame; MakeIOVector("test", &iov_); EXPECT_CALL(debug, OnFrameAddedToPacket(_)); - ASSERT_TRUE(creator_.ConsumeData( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, - 1u, iov_.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION, &frame)); + ASSERT_TRUE(creator_.ConsumeData(stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, + false, false, NOT_RETRANSMISSION, &frame)); size_t consumed = frame.stream_frame.data_length; EXPECT_EQ(4u, consumed); EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id)); QuicPaddingFrame padding_frame; EXPECT_CALL(debug, OnFrameAddedToPacket(_)); @@ -1346,8 +1349,7 @@ DeleteSerializedPacket(); EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream( - QuicUtils::GetCryptoStreamId(client_framer_.transport_version()))); + EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id)); EXPECT_EQ(max_plaintext_size - GetPacketHeaderSize( client_framer_.transport_version(),
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index ee15df0..d811f9d 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -138,7 +138,7 @@ QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to write stream data."; bool has_handshake = - (id == QuicUtils::GetCryptoStreamId(packet_creator_.transport_version())); + QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id); if (deprecate_ack_bundling_mode_) { MaybeBundleAckOpportunistically(); } @@ -228,8 +228,7 @@ QuicStreamOffset offset, bool fin, size_t total_bytes_consumed) { - DCHECK_NE(id, - QuicUtils::GetCryptoStreamId(packet_creator_.transport_version())); + DCHECK(!QuicUtils::IsCryptoStreamId(packet_creator_.transport_version(), id)); while (total_bytes_consumed < write_length && delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA,
diff --git a/quic/core/quic_packet_generator_test.cc b/quic/core/quic_packet_generator_test.cc index 705142a..676d6e7 100644 --- a/quic/core/quic_packet_generator_test.cc +++ b/quic/core/quic_packet_generator_test.cc
@@ -587,16 +587,29 @@ EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - MakeIOVector("foo bar", &iov_); - QuicConsumedData consumed = generator_.ConsumeData( - QuicUtils::GetCryptoStreamId(framer_.transport_version()), &iov_, 1u, - iov_.iov_len, 0, NO_FIN); - EXPECT_EQ(7u, consumed.bytes_consumed); + std::string data = "foo bar"; + MakeIOVector(data, &iov_); + size_t consumed_bytes = 0; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + consumed_bytes = generator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0); + } else { + consumed_bytes = + generator_ + .ConsumeData( + QuicUtils::GetCryptoStreamId(framer_.transport_version()), + &iov_, 1u, iov_.iov_len, 0, NO_FIN) + .bytes_consumed; + } + EXPECT_EQ(7u, consumed_bytes); EXPECT_FALSE(generator_.HasQueuedFrames()); EXPECT_FALSE(generator_.HasRetransmittableFrames()); PacketContents contents; - contents.num_stream_frames = 1; + if (QuicVersionUsesCryptoFrames(framer_.transport_version())) { + contents.num_crypto_frames = 1; + } else { + contents.num_stream_frames = 1; + } contents.num_padding_frames = 1; CheckPacketContains(contents, 0);
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index d56689f..96f98ad 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -102,6 +102,10 @@ connection_->SetDataProducer(this); connection_->SetFromConfig(config_); + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } + DCHECK_EQ(QuicUtils::GetCryptoStreamId(connection_->transport_version()), GetMutableCryptoStream()->id()); if (!eliminate_static_stream_map_) { @@ -250,8 +254,8 @@ // make exceptions for them with respect to processing things like // STOP_SENDING. if (QuicContainsKey(static_stream_map_, stream_id) || - stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream_id)) { QUIC_DVLOG(1) << ENDPOINT << "Received STOP_SENDING for a static stream, id: " << stream_id << " Closing connection"; @@ -658,6 +662,11 @@ } bool QuicSession::HasPendingHandshake() const { + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + // Writing CRYPTO frames is not subject to flow control, so there can't be + // pending data to write, only pending retransmissions. + return GetCryptoStream()->HasPendingCryptoRetransmission(); + } return QuicContainsKey( streams_with_pending_retransmission_, QuicUtils::GetCryptoStreamId(connection_->transport_version())) || @@ -687,7 +696,7 @@ // it might end up resulting in unencrypted stream data being sent. // While this is impossible to avoid given sufficient corruption, this // seems like a reasonable mitigation. - if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) && stream != GetMutableCryptoStream()) { QUIC_BUG << "Stream id mismatch"; connection_->CloseConnection( @@ -697,7 +706,7 @@ return QuicConsumedData(0, false); } if (!IsEncryptionEstablished() && - id != QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + !QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { // Do not let streams write without encryption. The calling stream will end // up write blocked until OnCanWrite is next called. return QuicConsumedData(0, false); @@ -1265,8 +1274,8 @@ QuicSession::StreamHandler QuicSession::GetOrCreateStreamImpl( QuicStreamId stream_id) { if (eliminate_static_stream_map_ && - stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + QuicUtils::IsCryptoStreamId(connection_->transport_version(), + stream_id)) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_2, 13, 17); return StreamHandler(GetMutableCryptoStream()); } @@ -1407,7 +1416,7 @@ if (QuicContainsKey(static_stream_map_, id) || QuicContainsKey(dynamic_stream_map_, id) || QuicContainsKey(pending_stream_map_, id) || - id == QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { // Stream is active return true; } @@ -1562,7 +1571,7 @@ } if (eliminate_static_stream_map_ && - id == QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + QuicUtils::IsCryptoStreamId(connection_->transport_version(), id)) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_eliminate_static_stream_map_2, 15, 17); return const_cast<QuicCryptoStream*>(GetCryptoStream()); } @@ -1803,7 +1812,8 @@ if (connection_->session_decides_what_to_write()) { QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); crypto_stream->NeuterUnencryptedStreamData(); - if (!crypto_stream->HasPendingRetransmission()) { + if (!crypto_stream->HasPendingRetransmission() && + !QuicVersionUsesCryptoFrames(connection_->transport_version())) { streams_with_pending_retransmission_.erase( QuicUtils::GetCryptoStreamId(connection_->transport_version())); }
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index 95bb6d4..deb6643 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -94,7 +94,7 @@ } MOCK_METHOD0(OnCanWrite, void()); - bool HasPendingCryptoRetransmission() override { return false; } + bool HasPendingCryptoRetransmission() const override { return false; } MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); @@ -109,7 +109,13 @@ class TestStream : public QuicStream { public: TestStream(QuicStreamId id, QuicSession* session, StreamType type) - : QuicStream(id, session, /*is_static=*/false, type) {} + : TestStream(id, session, /*is_static=*/false, type) {} + + TestStream(QuicStreamId id, + QuicSession* session, + bool is_static, + StreamType type) + : QuicStream(id, session, is_static, type) {} TestStream(PendingStream pending, StreamType type) : QuicStream(std::move(pending), type, /*is_static=*/false) {} @@ -260,8 +266,8 @@ QuicConsumedData SendStreamData(QuicStream* stream) { struct iovec iov; - if (stream->id() != - QuicUtils::GetCryptoStreamId(connection()->transport_version()) && + if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(), + stream->id()) && this->connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) { this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); } @@ -417,6 +423,10 @@ if (perspective == Perspective::IS_SERVER) { id |= 0x1; } + if (QuicVersionUsesCryptoFrames(connection_->transport_version()) && + bidirectional && perspective == Perspective::IS_CLIENT) { + id += 4; + } return id; } @@ -780,7 +790,7 @@ EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 800 would exceed stream count limit 51", + "Stream id 800 would exceed stream count limit 50", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET )) @@ -1255,10 +1265,19 @@ } TEST_P(QuicSessionTestServer, OnStreamFrameFinStaticStreamId) { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + std::unique_ptr<TestStream> fake_headers_stream = QuicMakeUnique<TestStream>( + headers_stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_2)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_headers_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, headers_stream_id, + fake_headers_stream.get()); + } // Send two bytes of payload. - QuicStreamFrame data1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), true, 0, - QuicStringPiece("HT")); + QuicStreamFrame data1(headers_stream_id, true, 0, QuicStringPiece("HT")); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Attempt to close a static stream", @@ -1267,11 +1286,20 @@ } TEST_P(QuicSessionTestServer, OnRstStreamStaticStreamId) { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + std::unique_ptr<TestStream> fake_headers_stream = QuicMakeUnique<TestStream>( + headers_stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_2)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_headers_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, headers_stream_id, + fake_headers_stream.get()); + } // Send two bytes of payload. - QuicRstStreamFrame rst1( - kInvalidControlFrameId, - QuicUtils::GetCryptoStreamId(connection_->transport_version()), - QUIC_ERROR_PROCESSING_STREAM, 0); + QuicRstStreamFrame rst1(kInvalidControlFrameId, headers_stream_id, + QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(*connection_, CloseConnection( QUIC_INVALID_STREAM_ID, "Attempt to reset a static stream", @@ -1620,7 +1648,7 @@ EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 24 would exceed stream count limit 6", _)); + "Stream id 24 would exceed stream count limit 5", _)); } else { EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); EXPECT_CALL(*connection_, @@ -1916,9 +1944,12 @@ TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); TestStream* stream4 = session_.CreateOutgoingBidirectionalStream(); - QuicStreamFrame frame1( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, 0, - 1300); + QuicStreamFrame frame1; + if (!QuicVersionUsesCryptoFrames(connection_->transport_version())) { + frame1 = QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, + 0, 1300); + } QuicStreamFrame frame2(stream2->id(), false, 0, 9); QuicStreamFrame frame3(stream4->id(), false, 0, 9); @@ -2354,7 +2385,7 @@ EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, - "Stream id 404 would exceed stream count limit 101", _)); + "Stream id 404 would exceed stream count limit 100", _)); session_.OnStreamFrame(bidirectional_stream_frame); QuicStreamId unidirectional_stream_id = StreamCountToId( @@ -2395,9 +2426,19 @@ // Applicable only to V99 return; } + QuicStreamId stream_id = 0; + std::unique_ptr<TestStream> fake_static_stream = QuicMakeUnique<TestStream>( + stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); + if (GetQuicReloadableFlag(quic_eliminate_static_stream_map_2)) { + QuicSessionPeer::RegisterStaticStreamNew(&session_, + std::move(fake_static_stream)); + } else { + QuicSessionPeer::RegisterStaticStream(&session_, stream_id, + fake_static_stream.get()); + } // Check that a stream id in the static stream map is ignored. // Note that the notion of a static stream is Google-specific. - QuicStopSendingFrame frame(1, 0, 123); + QuicStopSendingFrame frame(1, stream_id, 123); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", _));
diff --git a/quic/core/quic_stream_id_manager.cc b/quic/core/quic_stream_id_manager.cc index 94a8487..7fac723 100644 --- a/quic/core/quic_stream_id_manager.cc +++ b/quic/core/quic_stream_id_manager.cc
@@ -283,24 +283,6 @@ return false; } - // This is a stream id for a stream that is started by this node - if (perspective() == Perspective::IS_CLIENT && - stream_id == QuicUtils::GetCryptoStreamId(transport_version())) { - // TODO(fkastenholz): When crypto is moved into the CRYPTO_STREAM - // and streamID 0 is no longer special, this needs to be removed. - // Stream-id-0 seems not be allocated via get-next-stream-id, - // which would increment outgoing_stream_count_, so increment - // the count here to account for it. - // Do not need to update next_outgoing_stream_id_ because it is - // initiated to 4 (that is, it skips the crypto stream ID). - if (outgoing_stream_count_ >= - QuicUtils::GetMaxStreamCount(unidirectional_, perspective())) { - // Already at the implementation limit, return false... - return false; - } - outgoing_stream_count_++; - } - // Increase the outgoing_max_streams_ limit to reflect the semantic that // outgoing_max_streams_ was inialized to a "maximum request/response" count // and only becomes a maximum stream count when we receive the first
diff --git a/quic/core/quic_stream_id_manager_test.cc b/quic/core/quic_stream_id_manager_test.cc index 164e911..79c4845 100644 --- a/quic/core/quic_stream_id_manager_test.cc +++ b/quic/core/quic_stream_id_manager_test.cc
@@ -202,10 +202,14 @@ // If bidi, Crypto stream default created at start up, it is one // more stream to account for since initialization is "number of // request/responses" & crypto is added in to that, not streams. - EXPECT_EQ(kDefaultMaxStreamsPerConnection + (GetParam() ? 1u : 0u), + size_t extra_stream_count = 0; + if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, stream_id_manager_->outgoing_max_streams()); // Test is predicated on having 1 static stream going if bidi, 0 if not...) - EXPECT_EQ((GetParam() ? 1u : 0u), + EXPECT_EQ(extra_stream_count, stream_id_manager_->outgoing_static_stream_count()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, @@ -243,7 +247,11 @@ // If bidi, Crypto stream default created at start up, it is one // more stream to account for since initialization is "number of // request/responses" & crypto is added in to that, not streams. - EXPECT_EQ(implementation_max - 1u + (GetParam() ? 1u : 0u), + size_t extra_stream_count = 0; + if (GetParam() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(implementation_max - 1u + extra_stream_count, stream_id_manager_->outgoing_max_streams()); stream_id_manager_->AdjustMaxOpenOutgoingStreams(implementation_max); @@ -496,7 +504,11 @@ // If bidi, Crypto stream default created at start up, it is one // more stream to account for since initialization is "number of // request/responses" & crypto is added in to that, not streams. - EXPECT_EQ(number_of_streams + (IsBidi() ? 1u : 0u), + size_t extra_stream_count = 0; + if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(number_of_streams + extra_stream_count, stream_id_manager_->outgoing_max_streams()); while (number_of_streams) { EXPECT_TRUE(stream_id_manager_->CanOpenNextOutgoingStream()); @@ -515,7 +527,7 @@ // If bidi, Crypto stream default created at start up, it is one // more stream to account for since initialization is "number of // request/responses" & crypto is added in to that, not streams. - EXPECT_EQ(kDefaultMaxStreamsPerConnection + (IsBidi() ? 1u : 0u), + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, session_->save_frame().max_streams_frame.stream_count); // If we try to get the next id (above the limit), it should cause a quic-bug. EXPECT_QUIC_BUG( @@ -783,7 +795,11 @@ // more stream to account for since initialization is "number of // request/responses" & crypto is added in to that, not streams. // Since this is the server, the stream is incoming. - EXPECT_EQ(kDefaultMaxStreamsPerConnection + (IsBidi() ? 1u : 0u), + size_t extra_stream_count = 0; + if (IsBidi() && !QuicVersionUsesCryptoFrames(transport_version())) { + extra_stream_count = 1; + } + EXPECT_EQ(kDefaultMaxStreamsPerConnection + extra_stream_count, stream_id_manager_->incoming_actual_max_streams()); EXPECT_EQ(kDefaultMaxStreamsPerConnection, stream_id_manager_->outgoing_max_streams()); @@ -814,9 +830,17 @@ stream_id_manager_->incoming_actual_max_streams() + 20, Perspective::IS_CLIENT); // This node is a server, incoming stream // ids must be client-originated. - std::string error_details = - IsBidi() ? "Stream id 480 would exceed stream count limit 101" - : "Stream id 478 would exceed stream count limit 100"; + std::string error_details; + if (IsBidi()) { + if (QuicVersionUsesCryptoFrames(transport_version())) { + error_details = "Stream id 476 would exceed stream count limit 100"; + } else { + error_details = "Stream id 480 would exceed stream count limit 101"; + } + } else { + error_details = "Stream id 478 would exceed stream count limit 100"; + } + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _)); EXPECT_FALSE(
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc index 85ce4f2..dc40122 100644 --- a/quic/core/quic_utils.cc +++ b/quic/core/quic_utils.cc
@@ -383,9 +383,18 @@ // static QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) { - // TODO(nharper): Change this to return GetInvalidStreamId for version 47 or - // greater. Currently, too many things break with that change. - return version == QUIC_VERSION_99 ? 0 : 1; + QUIC_BUG_IF(QuicVersionUsesCryptoFrames(version)) + << "CRYPTO data aren't in stream frames; they have no stream ID."; + return QuicVersionUsesCryptoFrames(version) ? GetInvalidStreamId(version) : 1; +} + +// static +bool QuicUtils::IsCryptoStreamId(QuicTransportVersion version, + QuicStreamId stream_id) { + if (QuicVersionUsesCryptoFrames(version)) { + return false; + } + return stream_id == GetCryptoStreamId(version); } // static @@ -453,6 +462,7 @@ QuicTransportVersion version, Perspective perspective) { if (perspective == Perspective::IS_CLIENT) { + // TODO(nharper): Return 0 instead of 4 when CRYPTO frames are used. return version == QUIC_VERSION_99 ? 4 : 3; } return version == QUIC_VERSION_99 ? 1 : 2;
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h index befeee7..bac025e 100644 --- a/quic/core/quic_utils.h +++ b/quic/core/quic_utils.h
@@ -116,6 +116,11 @@ // Returns crypto stream ID of |version|. static QuicStreamId GetCryptoStreamId(QuicTransportVersion version); + // Returns whether |id| is the stream ID for the crypto stream. If |version| + // is a version where crypto data doesn't go over stream frames, this function + // will always return false. + static bool IsCryptoStreamId(QuicTransportVersion version, QuicStreamId id); + // Returns headers stream ID of |version|. static QuicStreamId GetHeadersStreamId(QuicTransportVersion version);
diff --git a/quic/test_tools/quic_server_session_base_peer.h b/quic/test_tools/quic_server_session_base_peer.h index 30c9b22..d2a21a6 100644 --- a/quic/test_tools/quic_server_session_base_peer.h +++ b/quic/test_tools/quic_server_session_base_peer.h
@@ -21,9 +21,11 @@ static void SetCryptoStream(QuicServerSessionBase* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); - s->RegisterStaticStream( - QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), - crypto_stream); + if (!QuicVersionUsesCryptoFrames(s->connection()->transport_version())) { + s->RegisterStaticStream( + QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), + crypto_stream); + } } static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) { return s->bandwidth_resumption_enabled_;
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc index 0683fd7..ed7043d 100644 --- a/quic/test_tools/quic_session_peer.cc +++ b/quic/test_tools/quic_session_peer.cc
@@ -166,6 +166,20 @@ } // static +void QuicSessionPeer::RegisterStaticStream(QuicSession* session, + QuicStreamId id, + QuicStream* stream) { + return session->RegisterStaticStream(id, stream); +} + +// static +void QuicSessionPeer::RegisterStaticStreamNew( + QuicSession* session, + std::unique_ptr<QuicStream> stream) { + return session->RegisterStaticStreamNew(std::move(stream)); +} + +// static bool QuicSessionPeer::IsStreamClosed(QuicSession* session, QuicStreamId id) { DCHECK_NE(0u, id); return session->IsClosedStream(id);
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h index 994a36c..3828981 100644 --- a/quic/test_tools/quic_session_peer.h +++ b/quic/test_tools/quic_session_peer.h
@@ -64,6 +64,11 @@ QuicSession* session); static void ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream); + static void RegisterStaticStream(QuicSession* session, + QuicStreamId stream_id, + QuicStream* stream); + static void RegisterStaticStreamNew(QuicSession* session, + std::unique_ptr<QuicStream> stream); // Discern the state of a stream. Exactly one of these should be true at a // time for any stream id > 0 (other than the special streams 1 and 3).
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc index 9ae4d22..e72e0e1 100644 --- a/quic/test_tools/simple_session_notifier.cc +++ b/quic/test_tools/simple_session_notifier.cc
@@ -72,7 +72,7 @@ QuicByteCount data_length, bool fin) { StreamState& state = stream_map_.find(id)->second; - if (id == QuicUtils::GetCryptoStreamId(connection_->transport_version()) && + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), id) && data_length > 0) { crypto_bytes_transferred_[connection_->encryption_level()].Add( offset, offset + data_length); @@ -127,8 +127,11 @@ } void SimpleSessionNotifier::NeuterUnencryptedData() { + // TODO(nharper): Handle CRYPTO frame case. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + return; + } for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_INITIAL]) { - // TODO(nharper): Handle CRYPTO frame case. QuicStreamFrame stream_frame( QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, interval.min(), interval.max() - interval.min()); @@ -146,7 +149,6 @@ return; } // Write new data. - // TODO(nharper): Write CRYPTO frames. for (const auto& pair : stream_map_) { const auto& state = pair.second; if (!StreamHasBufferedData(pair.first)) { @@ -320,8 +322,8 @@ EncryptionLevel retransmission_encryption_level = connection_->encryption_level(); EncryptionLevel current_encryption_level = connection_->encryption_level(); - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) { if (retransmission.Intersects(crypto_bytes_transferred_[i])) { retransmission_encryption_level = static_cast<EncryptionLevel>(i); @@ -339,8 +341,8 @@ const bool can_bundle_fin = retransmit_fin && (retransmission_offset + retransmission_length == state.bytes_sent); - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { // Set appropriate encryption level for crypto stream. connection_->SetDefaultEncryptionLevel(retransmission_encryption_level); } @@ -356,8 +358,8 @@ if (can_bundle_fin) { retransmit_fin = !consumed.fin_consumed; } - if (frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(connection_->transport_version())) { + if (QuicUtils::IsCryptoStreamId(connection_->transport_version(), + frame.stream_frame.stream_id)) { // Restore encryption level. connection_->SetDefaultEncryptionLevel(current_encryption_level); } @@ -497,7 +499,36 @@ } bool SimpleSessionNotifier::RetransmitLostCryptoData() { - // TODO(nharper): Handle CRYPTO frame case. + if (QuicVersionUsesCryptoFrames(connection_->transport_version())) { + for (EncryptionLevel level : + {ENCRYPTION_INITIAL, ENCRYPTION_HANDSHAKE, ENCRYPTION_ZERO_RTT, + ENCRYPTION_FORWARD_SECURE}) { + auto& state = crypto_state_[level]; + while (!state.pending_retransmissions.Empty()) { + connection_->SetTransmissionType(HANDSHAKE_RETRANSMISSION); + EncryptionLevel current_encryption_level = + connection_->encryption_level(); + connection_->SetDefaultEncryptionLevel(level); + QuicIntervalSet<QuicStreamOffset> retransmission( + state.pending_retransmissions.begin()->min(), + state.pending_retransmissions.begin()->max()); + retransmission.Intersection(crypto_bytes_transferred_[level]); + QuicStreamOffset retransmission_offset = retransmission.begin()->min(); + QuicByteCount retransmission_length = + retransmission.begin()->max() - retransmission.begin()->min(); + size_t bytes_consumed = connection_->SendCryptoData( + level, retransmission_length, retransmission_offset); + // Restore encryption level. + connection_->SetDefaultEncryptionLevel(current_encryption_level); + state.pending_retransmissions.Difference( + retransmission_offset, retransmission_offset + bytes_consumed); + if (bytes_consumed < retransmission_length) { + return false; + } + } + } + return true; + } if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId( connection_->transport_version()))) { return true;
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc index 53712fd..e5298eb 100644 --- a/quic/test_tools/simple_session_notifier_test.cc +++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -4,10 +4,12 @@ #include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h" using testing::_; using testing::InSequence; @@ -126,6 +128,9 @@ } TEST_F(SimpleSessionNotifierTest, NeuterUnencryptedData) { + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } InSequence s; // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); @@ -159,6 +164,9 @@ } TEST_F(SimpleSessionNotifierTest, OnCanWrite) { + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } InSequence s; // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); @@ -221,6 +229,71 @@ EXPECT_FALSE(notifier_.WillingToWrite()); } +TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) { + if (!QuicVersionUsesCryptoFrames(connection_.transport_version())) { + return; + } + SimpleDataProducer producer; + connection_.SetDataProducer(&producer); + InSequence s; + // Send crypto data [0, 1024) in ENCRYPTION_INITIAL. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 1024, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + producer.SaveCryptoData(ENCRYPTION_INITIAL, 0, std::string(1024, 'a')); + producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, std::string(524, 'a')); + notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0); + // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<NullEncrypter>( + Perspective::IS_CLIENT)); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + producer.SaveCryptoData(ENCRYPTION_ZERO_RTT, 0, std::string(1024, 'a')); + notifier_.WriteCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0); + // Send stream 3 [0, 1024) and connection is blocked. + EXPECT_CALL(connection_, SendStreamData(3, 1024, 0, FIN)) + .WillOnce(Return(QuicConsumedData(512, false))); + notifier_.WriteOrBufferData(3, 1024, FIN); + // Send stream 5 [0, 1024). + EXPECT_CALL(connection_, SendStreamData(5, _, _, _)).Times(0); + notifier_.WriteOrBufferData(5, 1024, NO_FIN); + // Reset stream 5 with error. + EXPECT_CALL(connection_, SendControlFrame(_)).Times(0); + notifier_.WriteOrBufferRstStream(5, QUIC_ERROR_PROCESSING_STREAM, 1024); + + // Lost crypto data [500, 1500) and stream 3 [0, 512). + QuicCryptoFrame crypto_frame1(ENCRYPTION_INITIAL, 500, 524); + QuicCryptoFrame crypto_frame2(ENCRYPTION_ZERO_RTT, 0, 476); + QuicStreamFrame stream3_frame(3, false, 0, 512); + notifier_.OnFrameLost(QuicFrame(&crypto_frame1)); + notifier_.OnFrameLost(QuicFrame(&crypto_frame2)); + notifier_.OnFrameLost(QuicFrame(stream3_frame)); + + // Connection becomes writable. + // Lost crypto data gets retransmitted as [500, 1024) and [1024, 1500), as + // they are in different encryption levels. + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_INITIAL, 524, 500)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 476, 0)) + .WillOnce(Invoke(&connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + // Lost stream 3 data gets retransmitted. + EXPECT_CALL(connection_, SendStreamData(3, 512, 0, NO_FIN)) + .WillOnce(Return(QuicConsumedData(512, false))); + // Buffered control frames get sent. + EXPECT_CALL(connection_, SendControlFrame(_)) + .WillOnce(Invoke(this, &SimpleSessionNotifierTest::ControlFrameConsumed)); + // Buffered stream 3 data [512, 1024) gets sent. + EXPECT_CALL(connection_, SendStreamData(3, 512, 512, FIN)) + .WillOnce(Return(QuicConsumedData(512, true))); + notifier_.OnCanWrite(); + EXPECT_FALSE(notifier_.WillingToWrite()); +} + TEST_F(SimpleSessionNotifierTest, RetransmitFrames) { InSequence s; // Send stream 3 data [0, 10) and fin.
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc index 7429732..aa9104a 100644 --- a/quic/tools/quic_simple_server_session_test.cc +++ b/quic/tools/quic_simple_server_session_test.cc
@@ -54,9 +54,11 @@ static void SetCryptoStream(QuicSimpleServerSession* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); - s->RegisterStaticStream( - QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), - crypto_stream); + if (!QuicVersionUsesCryptoFrames(s->connection()->transport_version())) { + s->RegisterStaticStream( + QuicUtils::GetCryptoStreamId(s->connection()->transport_version()), + crypto_stream); + } } static QuicSpdyStream* CreateIncomingStream(QuicSimpleServerSession* s,