Do not add extra padding when reserializing INITIAL packets.

Protected by FLAGS_quic_reloadable_flag_quic_close_connection_if_fail_to_serialzie_coalesced_packet2.

PiperOrigin-RevId: 436302707
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 0ceafd9..72e47a3 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -5909,11 +5909,11 @@
   const size_t length = packet_creator_.SerializeCoalescedPacket(
       coalesced_packet_, buffer, coalesced_packet_.max_packet_length());
   if (length == 0) {
-    if (GetQuicReloadableFlag(
-            quic_close_connection_if_fail_to_serialzie_coalesced_packet) &&
+    if (packet_creator_
+            .close_connection_if_fail_to_serialzie_coalesced_packet() &&
         connected_) {
-      QUIC_RELOADABLE_FLAG_COUNT(
-          quic_close_connection_if_fail_to_serialzie_coalesced_packet);
+      QUIC_RELOADABLE_FLAG_COUNT_N(
+          quic_close_connection_if_fail_to_serialzie_coalesced_packet2, 2, 2);
       CloseConnection(QUIC_FAILED_TO_SERIALIZE_PACKET,
                       "Failed to serialize coalesced packet.",
                       ConnectionCloseBehavior::SILENT_CLOSE);
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 337e6b7..93a2364 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -198,10 +198,16 @@
     SetEncrypter(ENCRYPTION_FORWARD_SECURE,
                  std::make_unique<NullEncrypter>(perspective));
     SetDataProducer(&producer_);
+    ON_CALL(*this, OnSerializedPacket(_))
+        .WillByDefault([this](SerializedPacket packet) {
+          QuicConnection::OnSerializedPacket(std::move(packet));
+        });
   }
   TestConnection(const TestConnection&) = delete;
   TestConnection& operator=(const TestConnection&) = delete;
 
+  MOCK_METHOD(void, OnSerializedPacket, (SerializedPacket packet), (override));
+
   void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
     QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
   }
@@ -10281,7 +10287,7 @@
   EXPECT_CALL(visitor_, OnHandshakePacketSent());
 
   if (GetQuicReloadableFlag(
-          quic_close_connection_if_fail_to_serialzie_coalesced_packet)) {
+          quic_close_connection_if_fail_to_serialzie_coalesced_packet2)) {
     EXPECT_CALL(visitor_,
                 OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
         .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
@@ -10332,7 +10338,7 @@
   EXPECT_QUIC_BUG(test_body(), "SerializeCoalescedPacket failed.");
 
   if (GetQuicReloadableFlag(
-          quic_close_connection_if_fail_to_serialzie_coalesced_packet)) {
+          quic_close_connection_if_fail_to_serialzie_coalesced_packet2)) {
     EXPECT_FALSE(connection_.connected());
     EXPECT_THAT(saved_connection_close_frame_.quic_error_code,
                 IsError(QUIC_FAILED_TO_SERIALIZE_PACKET));
@@ -15412,6 +15418,114 @@
   EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT);
 }
 
+// Regression test for b/112480134.
+TEST_P(QuicConnectionTest, NoExtraPaddingInReserializedInitial) {
+  // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
+  if (!IsDefaultTestConfiguration() ||
+      !connection_.version().CanSendCoalescedPackets()) {
+    return;
+  }
+
+  set_perspective(Perspective::IS_SERVER);
+  MockQuicConnectionDebugVisitor debug_visitor;
+  connection_.set_debug_visitor(&debug_visitor);
+
+  uint64_t debug_visitor_sent_count = 0;
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _))
+      .WillRepeatedly([&]() { debug_visitor_sent_count++; });
+
+  EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+  use_tagging_decrypter();
+
+  // Received INITIAL 1.
+  ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+
+  peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
+                            std::make_unique<TaggingEncrypter>(0x02));
+
+  connection_.SetEncrypter(ENCRYPTION_INITIAL,
+                           std::make_unique<TaggingEncrypter>(0x01));
+  connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+                           std::make_unique<TaggingEncrypter>(0x03));
+  SetDecrypter(ENCRYPTION_HANDSHAKE,
+               std::make_unique<StrictTaggingDecrypter>(0x03));
+  SetDecrypter(ENCRYPTION_ZERO_RTT,
+               std::make_unique<StrictTaggingDecrypter>(0x02));
+  connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                           std::make_unique<TaggingEncrypter>(0x04));
+
+  // Received ENCRYPTION_ZERO_RTT 2.
+  ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT);
+
+  {
+    QuicConnection::ScopedPacketFlusher flusher(&connection_);
+    // Send INITIAL 1.
+    connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+    connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL);
+    // Send HANDSHAKE 2.
+    EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
+    connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
+    connection_.SendCryptoDataWithString(std::string(200, 'a'), 0,
+                                         ENCRYPTION_HANDSHAKE);
+    // Send 1-RTT 3.
+    connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+    connection_.SendStreamDataWithString(0, std::string(400, 'b'), 0, NO_FIN);
+  }
+
+  // Arrange the stream data to be sent in response to ENCRYPTION_INITIAL 3.
+  const std::string data4(1000, '4');  // Data to send in stream id 4
+  const std::string data8(3000, '8');  // Data to send in stream id 8
+  EXPECT_CALL(visitor_, OnCanWrite()).WillOnce([&]() {
+    connection_.producer()->SaveStreamData(4, data4);
+    connection_.producer()->SaveStreamData(8, data8);
+
+    notifier_.WriteOrBufferData(4, data4.size(), FIN_AND_PADDING);
+
+    // This should trigger FlushCoalescedPacket.
+    notifier_.WriteOrBufferData(8, data8.size(), FIN);
+  });
+
+  QuicByteCount pending_padding_after_serialize_2nd_1rtt_packet = 0;
+  QuicPacketCount num_1rtt_packets_serialized = 0;
+  EXPECT_CALL(connection_, OnSerializedPacket(_))
+      .WillRepeatedly([&](SerializedPacket packet) {
+        if (packet.encryption_level == ENCRYPTION_FORWARD_SECURE) {
+          num_1rtt_packets_serialized++;
+          if (num_1rtt_packets_serialized == 2) {
+            pending_padding_after_serialize_2nd_1rtt_packet =
+                connection_.packet_creator().pending_padding_bytes();
+          }
+        }
+        connection_.QuicConnection::OnSerializedPacket(std::move(packet));
+      });
+
+  // Server receives INITIAL 3, this will serialzie FS 7 (stream 4, stream 8),
+  // which will trigger a flush of a coalesced packet consists of INITIAL 4,
+  // HS 5 and FS 6 (stream 4).
+  if (GetQuicReloadableFlag(
+          quic_close_connection_if_fail_to_serialzie_coalesced_packet2)) {
+    // Expect no QUIC_BUG.
+    ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL);
+    EXPECT_EQ(
+        debug_visitor_sent_count,
+        connection_.sent_packet_manager().GetLargestSentPacket().ToUint64());
+  } else {
+    // Expect QUIC_BUG due to extra padding.
+    EXPECT_QUIC_BUG(
+        { ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL); },
+        "Reserialize initial packet in coalescer has unexpected size");
+    EXPECT_EQ(
+        debug_visitor_sent_count + 1,
+        connection_.sent_packet_manager().GetLargestSentPacket().ToUint64());
+  }
+
+  // The error only happens if after serializing the second 1RTT packet(pkt #7),
+  // the pending padding bytes is non zero.
+  EXPECT_GT(pending_padding_after_serialize_2nd_1rtt_packet, 0u);
+  EXPECT_TRUE(connection_.connected());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 5bb98cc..f0f472d 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -24,7 +24,7 @@
 // If true, 1) QUIC connections will use a lower minimum for trusted initial rtt, 2) When TRTT is received, QUIC server sessions will mark the initial rtt from CachedNetworkParameters as trusted.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_lower_min_for_trusted_irtt, false)
 // If true, QUIC connection will be closed if it fails to serialize a coalesced packet.
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_close_connection_if_fail_to_serialzie_coalesced_packet, true)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_close_connection_if_fail_to_serialzie_coalesced_packet2, true)
 // If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false)
 // If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so.
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc
index 5fa63b7..05ec64a 100644
--- a/quic/core/quic_packet_creator.cc
+++ b/quic/core/quic_packet_creator.cc
@@ -479,7 +479,8 @@
   }
 
   QUICHE_DCHECK_EQ(nullptr, packet_.encrypted_buffer) << ENDPOINT;
-  if (!SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize)) {
+  if (!SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize,
+                       /*allow_padding=*/true)) {
     return;
   }
   OnSerializedPacket();
@@ -525,6 +526,14 @@
       << ENDPOINT
       << "Attempt to serialize empty ENCRYPTION_INITIAL packet in coalesced "
          "packet";
+
+  if (close_connection_if_fail_to_serialzie_coalesced_packet_ &&
+      HasPendingFrames()) {
+    QUIC_BUG(quic_packet_creator_unexpected_queued_frames)
+        << "Unexpected queued frames: " << GetPendingFramesInfo();
+    return 0;
+  }
+
   ScopedPacketContextSwitcher switcher(
       packet.packet_number -
           1,  // -1 because serialize packet increase packet number.
@@ -555,7 +564,16 @@
       return 0;
     }
   }
-  if (!SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len)) {
+
+  if (close_connection_if_fail_to_serialzie_coalesced_packet_) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(
+        quic_close_connection_if_fail_to_serialzie_coalesced_packet2, 1, 2);
+  }
+
+  if (!SerializePacket(
+          QuicOwnedPacketBuffer(buffer, nullptr), buffer_len,
+          /*allow_padding=*/
+          !close_connection_if_fail_to_serialzie_coalesced_packet_)) {
     return 0;
   }
   const size_t encrypted_length = packet_.encrypted_length;
@@ -788,7 +806,8 @@
 }
 
 bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer,
-                                        size_t encrypted_buffer_len) {
+                                        size_t encrypted_buffer_len,
+                                        bool allow_padding) {
   if (packet_.encrypted_buffer != nullptr) {
     const std::string error_details =
         "Packet's encrypted buffer is not empty before serialization";
@@ -817,11 +836,14 @@
                   << EncryptionLevelToString(packet_.encryption_level);
   }
 
-  MaybeAddPadding();
+  if (allow_padding) {
+    MaybeAddPadding();
+  }
 
   QUIC_DVLOG(2) << ENDPOINT << "Serializing packet " << header
                 << QuicFramesToString(queued_frames_) << " at encryption_level "
-                << packet_.encryption_level;
+                << packet_.encryption_level
+                << ", allow_padding:" << allow_padding;
 
   if (!framer_->HasEncrypterOfEncryptionLevel(packet_.encryption_level)) {
     // TODO(fayang): Use QUIC_MISSING_WRITE_KEYS for serialization failures due
@@ -1919,6 +1941,13 @@
   // Header protection requires a minimum plaintext packet size.
   MaybeAddExtraPaddingForHeaderProtection();
 
+  QUIC_DVLOG(3) << "MaybeAddPadding for " << packet_.packet_number
+                << ": transmission_type:" << packet_.transmission_type
+                << ", fate:" << packet_.fate
+                << ", needs_full_padding_:" << needs_full_padding_
+                << ", pending_padding_bytes_:" << pending_padding_bytes_
+                << ", BytesFree:" << BytesFree();
+
   if (!needs_full_padding_ && pending_padding_bytes_ == 0) {
     // Do not need padding.
     return;
@@ -1951,6 +1980,8 @@
 
 void QuicPacketCreator::AddPendingPadding(QuicByteCount size) {
   pending_padding_bytes_ += size;
+  QUIC_DVLOG(3) << "After AddPendingPadding(" << size
+                << "), pending_padding_bytes_:" << pending_padding_bytes_;
 }
 
 bool QuicPacketCreator::StreamFrameIsClientHello(
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h
index b32be86..183bf2b 100644
--- a/quic/core/quic_packet_creator.h
+++ b/quic/core/quic_packet_creator.h
@@ -30,6 +30,7 @@
 #include "quic/core/quic_packets.h"
 #include "quic/core/quic_types.h"
 #include "quic/platform/api/quic_export.h"
+#include "quic/platform/api/quic_flags.h"
 #include "common/platform/api/quiche_mem_slice.h"
 #include "common/quiche_circular_deque.h"
 
@@ -505,6 +506,10 @@
 
   const QuicSocketAddress& peer_address() const { return packet_.peer_address; }
 
+  bool close_connection_if_fail_to_serialzie_coalesced_packet() const {
+    return close_connection_if_fail_to_serialzie_coalesced_packet_;
+  }
+
  private:
   friend class test::QuicPacketCreatorPeer;
 
@@ -553,9 +558,12 @@
   // retransmitted to packet_.retransmittable_frames. All frames must fit into
   // a single packet. Returns true on success, otherwise, returns false.
   // Fails if |encrypted_buffer| is not large enough for the encrypted packet.
+  //
+  // Padding may be added if |allow_padding|. Currently, the only case where it
+  // is disallowed is reserializing a coalesced initial packet.
   ABSL_MUST_USE_RESULT bool SerializePacket(
-      QuicOwnedPacketBuffer encrypted_buffer,
-      size_t encrypted_buffer_len);
+      QuicOwnedPacketBuffer encrypted_buffer, size_t encrypted_buffer_len,
+      bool allow_padding);
 
   // Called after a new SerialiedPacket is created to call the delegate's
   // OnSerializedPacket and reset state.
@@ -713,6 +721,10 @@
 
   // Whether to attempt protecting initial packets with chaos.
   bool chaos_protection_enabled_;
+
+  const bool close_connection_if_fail_to_serialzie_coalesced_packet_ =
+      GetQuicReloadableFlag(
+          quic_close_connection_if_fail_to_serialzie_coalesced_packet2);
 };
 
 }  // namespace quic
diff --git a/quic/test_tools/quic_packet_creator_peer.cc b/quic/test_tools/quic_packet_creator_peer.cc
index d638959..8baef92 100644
--- a/quic/test_tools/quic_packet_creator_peer.cc
+++ b/quic/test_tools/quic_packet_creator_peer.cc
@@ -111,8 +111,9 @@
     bool success = creator->AddFrame(frame, NOT_RETRANSMISSION);
     QUICHE_DCHECK(success);
   }
-  const bool success = creator->SerializePacket(
-      QuicOwnedPacketBuffer(buffer, nullptr), buffer_len);
+  const bool success =
+      creator->SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr),
+                               buffer_len, /*allow_padding=*/true);
   QUICHE_DCHECK(success);
   SerializedPacket packet = std::move(creator->packet_);
   // The caller takes ownership of the QuicEncryptedPacket.
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc
index 4eca1f7..d2be965 100644
--- a/quic/test_tools/simple_session_notifier.cc
+++ b/quic/test_tools/simple_session_notifier.cc
@@ -57,8 +57,7 @@
   const size_t length = stream_state.bytes_total - stream_state.bytes_sent;
   connection_->SetTransmissionType(NOT_RETRANSMISSION);
   QuicConsumedData consumed =
-      connection_->SendStreamData(id, length, stream_state.bytes_sent,
-                                  stream_state.fin_buffered ? FIN : NO_FIN);
+      connection_->SendStreamData(id, length, stream_state.bytes_sent, state);
   QUIC_DVLOG(1) << "consumed: " << consumed;
   OnStreamDataConsumed(id, stream_state.bytes_sent, consumed.bytes_consumed,
                        consumed.fin_consumed);