Do not QUIC_BUG 0-RTT stream data retransmission before 1-RTT keys arrive. PiperOrigin-RevId: 329566741 Change-Id: I0a881a90377ddfc3de4063b295e09a8278e38a32
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index ff6d357..33bfee0 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -1670,6 +1670,65 @@ EXPECT_TRUE(client_->client()->EarlyDataAccepted()); } +// Regression test for b/166836136. +TEST_P(EndToEndTest, LargePostZeroRTTRejectRequestDuringHandshake) { + if (!version_.UsesTls()) { + // This test is TLS specific. + ASSERT_TRUE(Initialize()); + return; + } + // Send a request and then disconnect. This prepares the client to attempt + // a 0-RTT handshake for the next request. + NiceMock<MockQuicConnectionDebugVisitor> visitor; + connection_debug_visitor_ = &visitor; + ASSERT_TRUE(Initialize()); + + SendSynchronousFooRequestAndCheckResponse(); + QuicSpdyClientSession* client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + EXPECT_FALSE(client_session->ReceivedInchoateReject()); + EXPECT_FALSE(client_->client()->EarlyDataAccepted()); + EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); + + client_->Disconnect(); + + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_TRUE(client_session->EarlyDataAccepted()); + EXPECT_TRUE(client_->client()->EarlyDataAccepted()); + + client_->Disconnect(); + + // Restart the server so that the 0-RTT handshake will take 1 RTT. + StopServer(); + server_writer_ = new PacketDroppingTestWriter(); + StartServer(); + + ON_CALL(visitor, OnZeroRttRejected()).WillByDefault(Invoke([this]() { + EXPECT_FALSE(GetClientSession()->IsEncryptionEstablished()); + // Trigger an OnCanWrite() to make sure no unencrypted data will be written. + GetClientSession()->OnCanWrite(); + })); + + // The 0-RTT handshake should fail. + client_->Connect(); + ASSERT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + client_->WaitForWriteToFlush(); + client_->WaitForResponse(); + ASSERT_TRUE(client_->client()->connected()); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + EXPECT_FALSE(client_->client()->EarlyDataAccepted()); +} + TEST_P(EndToEndTest, RejectWithPacketLoss) { // In this test, we intentionally drop the first packet from the // server, which corresponds with the initial REJ response from
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 9e0a493..d89639f 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -2471,10 +2471,10 @@ } void QuicConnection::MarkZeroRttPacketsForRetransmission() { + sent_packet_manager_.MarkZeroRttPacketsForRetransmission(); if (debug_visitor_ != nullptr && version().UsesTls()) { debug_visitor_->OnZeroRttRejected(); } - sent_packet_manager_.MarkZeroRttPacketsForRetransmission(); } void QuicConnection::NeuterUnencryptedPackets() {
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index 8989269..aa7c491 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -719,8 +719,15 @@ !QuicUtils::IsCryptoStreamId(transport_version(), id)) { // Do not let streams write without encryption. The calling stream will end // up write blocked until OnCanWrite is next called. - QUIC_BUG << ENDPOINT << "Try to send data of stream " << id - << " before encryption is established."; + if (was_zero_rtt_rejected_ && !OneRttKeysAvailable()) { + DCHECK(version().UsesTls() && perspective() == Perspective::IS_CLIENT); + QUIC_BUG_IF(type == NOT_RETRANSMISSION) + << ENDPOINT << "Try to send new data on stream " << id + << "before 1-RTT keys are available while 0-RTT is rejected."; + } else { + QUIC_BUG << ENDPOINT << "Try to send data of stream " << id + << " before encryption is established."; + } return QuicConsumedData(0, false); }
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index aac4a2c..614e958 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -1464,6 +1464,8 @@ OnTransportParametersReceived, (const TransportParameters&), (override)); + + MOCK_METHOD(void, OnZeroRttRejected, (), (override)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager {