Internal change

PiperOrigin-RevId: 390263074
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index e559110..071ee65 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -5297,14 +5297,17 @@
         << "EffectivePeerMigration started without address change.";
     return;
   }
-  if (packet_creator_.HasPendingFrames()) {
-    QUIC_BUG(bug_731_2)
-        << "Starts effective peer migration with pending frame types: "
-        << packet_creator_.GetPendingFramesInfo() << ". Address change type is "
-        << AddressChangeTypeToString(type)
-        << ". Current frame type: " << framer_.current_received_frame_type()
-        << ". Previous frame type: "
-        << framer_.previously_received_frame_type();
+  // There could be pending NEW_TOKEN_FRAME triggered by non-probing
+  // PATH_RESPONSE_FRAME in the same packet.
+  if (GetQuicReloadableFlag(
+          quic_flush_pending_frame_before_updating_default_path) &&
+      packet_creator_.HasPendingFrames()) {
+    QUICHE_RELOADABLE_FLAG_COUNT(
+        quic_flush_pending_frame_before_updating_default_path);
+    packet_creator_.FlushCurrentPacket();
+    if (!connected_) {
+      return;
+    }
   }
 
   // Action items:
@@ -5361,17 +5364,7 @@
           std::move(alternative_path_.rtt_stats).value());
     }
   }
-
   // Update to the new peer address.
-  if (packet_creator_.HasPendingFrames()) {
-    QUIC_BUG(bug_731_1)
-        << "Starts effective peer migration with pending frame types: "
-        << packet_creator_.GetPendingFramesInfo() << ". Address change type is "
-        << AddressChangeTypeToString(type)
-        << ". Current frame type: " << framer_.current_received_frame_type()
-        << ". Previous frame type: "
-        << framer_.previously_received_frame_type();
-  }
   UpdatePeerAddress(last_received_packet_info_.source_address);
   // Update the default path.
   if (IsAlternativePath(last_received_packet_info_.destination_address,
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 8466ab0..e991fbf 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2079,6 +2079,65 @@
   }
 }
 
+// Regression test for b/196208556.
+TEST_P(QuicConnectionTest,
+       ReversePathValidationResponseReceivedFromUnexpectedPeerAddress) {
+  set_perspective(Perspective::IS_SERVER);
+  if (!GetQuicReloadableFlag(
+          quic_flush_pending_frame_before_updating_default_path) ||
+      !connection_.connection_migration_use_new_cid()) {
+    return;
+  }
+  QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+  connection_.CreateConnectionIdManager();
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  QuicConnectionPeer::SetPeerAddress(&connection_, kPeerAddress);
+  QuicConnectionPeer::SetEffectivePeerAddress(&connection_, kPeerAddress);
+  QuicConnectionPeer::SetAddressValidated(&connection_);
+  EXPECT_EQ(kPeerAddress, connection_.peer_address());
+  EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+
+  // Sends new server CID to client.
+  QuicConnectionId new_cid;
+  EXPECT_CALL(visitor_, OnServerConnectionIdIssued(_))
+      .WillOnce(Invoke([&](const QuicConnectionId& cid) { new_cid = cid; }));
+  EXPECT_CALL(visitor_, SendNewConnectionId(_));
+  connection_.OnHandshakeComplete();
+  EXPECT_CALL(visitor_, GetHandshakeState())
+      .WillRepeatedly(Return(HANDSHAKE_CONFIRMED));
+
+  // Process a non-probing packet to migrate to path 2 and kick off reverse path
+  // validation.
+  EXPECT_CALL(visitor_, OnConnectionMigration(IPV6_TO_IPV4_CHANGE)).Times(1);
+  const QuicSocketAddress kPeerAddress2 =
+      QuicSocketAddress(QuicIpAddress::Loopback4(), /*port=*/23456);
+  peer_creator_.SetServerConnectionId(new_cid);
+  ProcessFramesPacketWithAddresses({QuicFrame(QuicPingFrame())}, kSelfAddress,
+                                   kPeerAddress2, ENCRYPTION_FORWARD_SECURE);
+  EXPECT_FALSE(writer_->path_challenge_frames().empty());
+  QuicPathFrameBuffer reverse_path_challenge_payload =
+      writer_->path_challenge_frames().front().data_buffer;
+
+  // Receiveds a packet from path 3 with PATH_RESPONSE frame intended to
+  // validate path 2 and a non-probing frame.
+  {
+    QuicConnection::ScopedPacketFlusher flusher(&connection_);
+    const QuicSocketAddress kPeerAddress3 =
+        QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/56789);
+    auto ack_frame = InitAckFrame(1);
+    EXPECT_CALL(visitor_, OnConnectionMigration(IPV4_TO_IPV6_CHANGE)).Times(1);
+    EXPECT_CALL(visitor_, MaybeSendAddressToken()).WillOnce(Invoke([this]() {
+      connection_.SendControlFrame(
+          QuicFrame(new QuicNewTokenFrame(1, "new_token")));
+    }));
+    ProcessFramesPacketWithAddresses({QuicFrame(new QuicPathResponseFrame(
+                                          0, reverse_path_challenge_payload)),
+                                      QuicFrame(&ack_frame)},
+                                     kSelfAddress, kPeerAddress3,
+                                     ENCRYPTION_FORWARD_SECURE);
+  }
+}
+
 TEST_P(QuicConnectionTest, ReversePathValidationFailureAtServer) {
   set_perspective(Perspective::IS_SERVER);
   if (!connection_.connection_migration_use_new_cid()) {
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 258f70c..0f4fd18 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -75,6 +75,8 @@
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_server_on_wire_ping, true)
 // If true, fix a bug in TlsServerHandshaker where the ticket decrypt callback is cleared without being cancelled first.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_fix_ticket_decrypt, true)
+// If true, flush any pending frame before default path is about to be updated.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_flush_pending_frame_before_updating_default_path, true)
 // If true, ignore peer_max_ack_delay during handshake.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_ignore_peer_max_ack_delay_during_handshake, true)
 // If true, include stream information in idle timeout connection close detail.