Handle GOAWAY gracefully in MasqueH2Connection

PiperOrigin-RevId: 923377735
diff --git a/quiche/quic/masque/masque_connection_pool.cc b/quiche/quic/masque/masque_connection_pool.cc
index d3803c8..abc4cd5 100644
--- a/quiche/quic/masque/masque_connection_pool.cc
+++ b/quiche/quic/masque/masque_connection_pool.cc
@@ -358,7 +358,8 @@
       ConnectionState * connection,
       GetOrCreateConnectionState(std::string(authority->second), mtls));
   auto pending_request = std::make_unique<PendingRequest>();
-  if (connection->connection() != nullptr) {
+  if (connection->connection() != nullptr &&
+      !connection->connection()->aborted()) {
     QUICHE_LOG(INFO) << ENDPOINT << "Reusing existing connection "
                      << connection->connection()->info() << " to "
                      << authority->second;
diff --git a/quiche/quic/masque/masque_h2_connection.cc b/quiche/quic/masque/masque_h2_connection.cc
index c856a56..8413215 100644
--- a/quiche/quic/masque/masque_h2_connection.cc
+++ b/quiche/quic/masque/masque_h2_connection.cc
@@ -100,6 +100,13 @@
 
 void MasqueH2Connection::Abort(absl::Status error) {
   QUICHE_CHECK(!error.ok());
+  if (has_closed_gracefully_) {
+    QUICHE_LOG(INFO)
+        << ENDPOINT
+        << "Connection already closed gracefully, ignoring new error: "
+        << error.message();
+    return;
+  }
   if (aborted()) {
     QUICHE_LOG(ERROR) << ENDPOINT
                       << "Connection already aborted, ignoring new error: "
@@ -549,6 +556,28 @@
                    << last_accepted_stream_id
                    << " error_code: " << Http2ErrorCodeToString(error_code)
                    << " opaque_data length: " << opaque_data.size();
+  for (auto it = h2_streams_.begin(); it != h2_streams_.end();) {
+    if (it->first > last_accepted_stream_id) {
+      if (!it->second->callback_fired) {
+        visitor_->OnStreamFailure(
+            this, it->first,
+            absl::InternalError(
+                absl::StrCat("Stream ", it->first,
+                             " cancelled due to GOAWAY with error code ",
+                             Http2ErrorCodeToString(error_code))));
+      }
+      h2_streams_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+  if (h2_streams_.empty() && !has_closed_gracefully_) {
+    QUICHE_LOG(INFO) << ENDPOINT
+                     << "Received GOAWAY and all streams closed, closing "
+                        "connection gracefully";
+    has_closed_gracefully_ = true;
+    visitor_->OnConnectionFinished(this, absl::OkStatus());
+  }
   return true;
 }
 
diff --git a/quiche/quic/masque/masque_h2_connection.h b/quiche/quic/masque/masque_h2_connection.h
index ee9fe95..1a93e0b 100644
--- a/quiche/quic/masque/masque_h2_connection.h
+++ b/quiche/quic/masque/masque_h2_connection.h
@@ -65,7 +65,7 @@
 
   ~MasqueH2Connection();
 
-  bool aborted() const { return !error_.ok(); }
+  bool aborted() const { return !error_.ok() || has_closed_gracefully_; }
   // Call when there is more data to be read from SSL.
   void OnTransportReadable();
   // Call when there is more data to be written to SSL.
@@ -155,6 +155,7 @@
   SSL* ssl_;
   std::unique_ptr<http2::adapter::OgHttp2Adapter> h2_adapter_;
   const bool is_server_;
+  bool has_closed_gracefully_ = false;
   const std::string info_;
   bool tls_connected_ = false;
   absl::Status error_ = absl::OkStatus();