Add an extra endpoint to the QuicTransport simple server called
/receive-bidirectional. This creates a server-initiated bidirectional stream
every time an incoming stream is received from the client.

This will be used to test receiving bidirectional streams in Chrome.

PiperOrigin-RevId: 332362367
Change-Id: I5b88c266b51b079126691bd6ae52e46795d7297a
diff --git a/quic/tools/quic_transport_simple_server_session.cc b/quic/tools/quic_transport_simple_server_session.cc
index 49c86e5..d07da11 100644
--- a/quic/tools/quic_transport_simple_server_session.cc
+++ b/quic/tools/quic_transport_simple_server_session.cc
@@ -176,6 +176,12 @@
           break;
       }
       break;
+
+    case OUTGOING_BIDIRECTIONAL:
+      stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
+      ++pending_outgoing_bidirectional_streams_;
+      MaybeCreateOutgoingBidirectionalStream();
+      break;
   }
 }
 
@@ -183,6 +189,8 @@
     bool unidirectional) {
   if (mode_ == ECHO && unidirectional) {
     MaybeEchoStreamsBack();
+  } else if (mode_ == OUTGOING_BIDIRECTIONAL && !unidirectional) {
+    MaybeCreateOutgoingBidirectionalStream();
   }
 }
 
@@ -208,6 +216,10 @@
     mode_ = ECHO;
     return true;
   }
+  if (url.path() == "/receive-bidirectional") {
+    mode_ = OUTGOING_BIDIRECTIONAL;
+    return true;
+  }
 
   QUIC_DLOG(WARNING) << "Unknown path requested: " << url.path();
   return false;
@@ -246,4 +258,21 @@
   }
 }
 
+void QuicTransportSimpleServerSession::
+    MaybeCreateOutgoingBidirectionalStream() {
+  while (pending_outgoing_bidirectional_streams_ > 0 &&
+         CanOpenNextOutgoingBidirectionalStream()) {
+    auto stream_owned = std::make_unique<QuicTransportStream>(
+        GetNextOutgoingBidirectionalStreamId(), this, this);
+    QuicTransportStream* stream = stream_owned.get();
+    ActivateStream(std::move(stream_owned));
+    QUIC_DVLOG(1) << "Opened outgoing bidirectional stream " << stream->id();
+    stream->set_visitor(std::make_unique<BidirectionalEchoVisitor>(stream));
+    if (!stream->Write("hello")) {
+      QUIC_DVLOG(1) << "Write failed.";
+    }
+    --pending_outgoing_bidirectional_streams_;
+  }
+}
+
 }  // namespace quic
diff --git a/quic/tools/quic_transport_simple_server_session.h b/quic/tools/quic_transport_simple_server_session.h
index 7a5fb09..7cfd197 100644
--- a/quic/tools/quic_transport_simple_server_session.h
+++ b/quic/tools/quic_transport_simple_server_session.h
@@ -34,6 +34,13 @@
     // a server-initiated unidirectional stream that is sent as soon as a FIN is
     // received on the incoming stream.
     ECHO,
+    // In OUTGOING_BIDIRECTIONAL mode, a server-originated bidirectional stream
+    // is created on receipt of a unidirectional stream. The contents of the
+    // unidirectional stream are disregarded. The bidirectional stream initially
+    // sends "hello", then any received data is echoed back.
+    // TODO(ricea): Maybe this should be replaced by a more general mechanism
+    // where commands on the unidirectional stream trigger different behaviour?
+    OUTGOING_BIDIRECTIONAL,
   };
 
   QuicTransportSimpleServerSession(
@@ -60,8 +67,10 @@
 
  private:
   void MaybeEchoStreamsBack();
+  void MaybeCreateOutgoingBidirectionalStream();
 
   const bool owns_connection_;
+  size_t pending_outgoing_bidirectional_streams_ = 0u;
   Mode mode_;
   std::vector<url::Origin> accepted_origins_;
   QuicCircularDeque<std::string> streams_to_echo_back_;