Move WebTransportEchoServer from test_tools to tools.

So that it can be used from QUIC test servers.

Add `enable_webtransport` flag in QuicToyServer. If true, QuicMemoryCacheBackend
is set up to handle WebTransport requests.

PiperOrigin-RevId: 370638467
Change-Id: I0f3555fa7da6cb1e4ca211134f5123eed8ae56e3
diff --git a/quic/tools/web_transport_test_visitors.h b/quic/tools/web_transport_test_visitors.h
index 9bf6e6b..c9efcb7 100644
--- a/quic/tools/web_transport_test_visitors.h
+++ b/quic/tools/web_transport_test_visitors.h
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include "quic/core/quic_circular_deque.h"
+#include "quic/core/quic_simple_buffer_allocator.h"
 #include "quic/core/web_transport_interface.h"
 #include "quic/platform/api/quic_logging.h"
 
@@ -132,6 +134,95 @@
   std::string data_;
 };
 
+// A session visitor which sets unidirectional or bidirectional stream visitors
+// to echo.
+class EchoWebTransportSessionVisitor : public WebTransportVisitor {
+ public:
+  EchoWebTransportSessionVisitor(WebTransportSession* session)
+      : session_(session) {}
+
+  void OnSessionReady() override {
+    if (session_->CanOpenNextOutgoingBidirectionalStream()) {
+      OnCanCreateNewOutgoingBidirectionalStream();
+    }
+  }
+
+  void OnIncomingBidirectionalStreamAvailable() override {
+    while (true) {
+      WebTransportStream* stream =
+          session_->AcceptIncomingBidirectionalStream();
+      if (stream == nullptr) {
+        return;
+      }
+      QUIC_DVLOG(1)
+          << "EchoWebTransportSessionVisitor received a bidirectional stream "
+          << stream->GetStreamId();
+      stream->SetVisitor(
+          std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
+      stream->visitor()->OnCanRead();
+    }
+  }
+
+  void OnIncomingUnidirectionalStreamAvailable() override {
+    while (true) {
+      WebTransportStream* stream =
+          session_->AcceptIncomingUnidirectionalStream();
+      if (stream == nullptr) {
+        return;
+      }
+      QUIC_DVLOG(1)
+          << "EchoWebTransportSessionVisitor received a unidirectional stream";
+      stream->SetVisitor(
+          std::make_unique<WebTransportUnidirectionalEchoReadVisitor>(
+              stream, [this](const std::string& data) {
+                streams_to_echo_back_.push_back(data);
+                TrySendingUnidirectionalStreams();
+              }));
+      stream->visitor()->OnCanRead();
+    }
+  }
+
+  void OnDatagramReceived(absl::string_view datagram) override {
+    auto buffer = MakeUniqueBuffer(&allocator_, datagram.size());
+    memcpy(buffer.get(), datagram.data(), datagram.size());
+    QuicMemSlice slice(std::move(buffer), datagram.size());
+    session_->SendOrQueueDatagram(std::move(slice));
+  }
+
+  void OnCanCreateNewOutgoingBidirectionalStream() override {
+    if (!echo_stream_opened_) {
+      WebTransportStream* stream = session_->OpenOutgoingBidirectionalStream();
+      stream->SetVisitor(
+          std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
+      echo_stream_opened_ = true;
+    }
+  }
+  void OnCanCreateNewOutgoingUnidirectionalStream() override {
+    TrySendingUnidirectionalStreams();
+  }
+
+  void TrySendingUnidirectionalStreams() {
+    while (!streams_to_echo_back_.empty() &&
+           session_->CanOpenNextOutgoingUnidirectionalStream()) {
+      QUIC_DVLOG(1)
+          << "EchoWebTransportServer echoed a unidirectional stream back";
+      WebTransportStream* stream = session_->OpenOutgoingUnidirectionalStream();
+      stream->SetVisitor(
+          std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(
+              stream, streams_to_echo_back_.front()));
+      streams_to_echo_back_.pop_front();
+      stream->visitor()->OnCanWrite();
+    }
+  }
+
+ private:
+  WebTransportSession* session_;
+  SimpleBufferAllocator allocator_;
+  bool echo_stream_opened_ = false;
+
+  QuicCircularDeque<std::string> streams_to_echo_back_;
+};
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_