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/test_tools/quic_test_backend.cc b/quic/test_tools/quic_test_backend.cc
index 9623d75..b88301a 100644
--- a/quic/test_tools/quic_test_backend.cc
+++ b/quic/test_tools/quic_test_backend.cc
@@ -18,95 +18,6 @@
 namespace quic {
 namespace test {
 
-namespace {
-
-class EchoWebTransportServer : public WebTransportVisitor {
- public:
-  EchoWebTransportServer(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) << "EchoWebTransportServer 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)
-          << "EchoWebTransportServer 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
-
 QuicSimpleServerBackend::WebTransportResponse
 QuicTestBackend::ProcessWebTransportRequest(
     const spdy::Http2HeaderBlock& request_headers,
@@ -126,7 +37,8 @@
   if (path == "/echo") {
     WebTransportResponse response;
     response.response_headers[":status"] = "200";
-    response.visitor = std::make_unique<EchoWebTransportServer>(session);
+    response.visitor =
+        std::make_unique<EchoWebTransportSessionVisitor>(session);
     return response;
   }
 
diff --git a/quic/tools/quic_memory_cache_backend.cc b/quic/tools/quic_memory_cache_backend.cc
index e76a6cf..967e60f 100644
--- a/quic/tools/quic_memory_cache_backend.cc
+++ b/quic/tools/quic_memory_cache_backend.cc
@@ -15,6 +15,7 @@
 #include "quic/platform/api/quic_file_utils.h"
 #include "quic/platform/api/quic_logging.h"
 #include "quic/platform/api/quic_map_util.h"
+#include "quic/tools/web_transport_test_visitors.h"
 #include "common/platform/api/quiche_text_utils.h"
 
 using spdy::Http2HeaderBlock;
@@ -313,6 +314,10 @@
       QuicBackendResponse::GENERATE_BYTES);
 }
 
+void QuicMemoryCacheBackend::EnableWebTransport() {
+  enable_webtransport_ = true;
+}
+
 bool QuicMemoryCacheBackend::IsBackendInitialized() const {
   return cache_initialized_;
 }
@@ -361,6 +366,35 @@
   return resources;
 }
 
+QuicMemoryCacheBackend::WebTransportResponse
+QuicMemoryCacheBackend::ProcessWebTransportRequest(
+    const spdy::Http2HeaderBlock& request_headers,
+    WebTransportSession* session) {
+  if (!SupportsWebTransport()) {
+    return QuicSimpleServerBackend::ProcessWebTransportRequest(request_headers,
+                                                               session);
+  }
+
+  auto path_it = request_headers.find(":path");
+  if (path_it == request_headers.end()) {
+    WebTransportResponse response;
+    response.response_headers[":status"] = "400";
+    return response;
+  }
+  absl::string_view path = path_it->second;
+  if (path == "/echo") {
+    WebTransportResponse response;
+    response.response_headers[":status"] = "200";
+    response.visitor =
+        std::make_unique<EchoWebTransportSessionVisitor>(session);
+    return response;
+  }
+
+  WebTransportResponse response;
+  response.response_headers[":status"] = "404";
+  return response;
+}
+
 QuicMemoryCacheBackend::~QuicMemoryCacheBackend() {
   {
     QuicWriterMutexLock lock(&response_mutex_);
diff --git a/quic/tools/quic_memory_cache_backend.h b/quic/tools/quic_memory_cache_backend.h
index 8ba6d60..1caea5d 100644
--- a/quic/tools/quic_memory_cache_backend.h
+++ b/quic/tools/quic_memory_cache_backend.h
@@ -139,6 +139,8 @@
   // generated response of that many bytes.
   void GenerateDynamicResponses();
 
+  void EnableWebTransport();
+
   // Find all the server push resources associated with |request_url|.
   std::list<QuicBackendResponse::ServerPushInfo> GetServerPushResources(
       std::string request_url);
@@ -153,6 +155,10 @@
       QuicSimpleServerBackend::RequestHandler* quic_server_stream) override;
   void CloseBackendResponseStream(
       QuicSimpleServerBackend::RequestHandler* quic_server_stream) override;
+  WebTransportResponse ProcessWebTransportRequest(
+      const spdy::Http2HeaderBlock& request_headers,
+      WebTransportSession* session) override;
+  bool SupportsWebTransport() override { return enable_webtransport_; }
 
  private:
   void AddResponseImpl(absl::string_view host,
@@ -197,6 +203,8 @@
   // server threads accessing those responses.
   mutable QuicMutex response_mutex_;
   bool cache_initialized_;
+
+  bool enable_webtransport_ = false;
 };
 
 }  // namespace quic
diff --git a/quic/tools/quic_toy_server.cc b/quic/tools/quic_toy_server.cc
index 93f699b..e7b4e1e 100644
--- a/quic/tools/quic_toy_server.cc
+++ b/quic/tools/quic_toy_server.cc
@@ -46,6 +46,11 @@
     "QUIC versions to enable, e.g. \"h3-25,h3-27\". If not set, then all "
     "available versions are enabled.");
 
+DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
+                              enable_webtransport,
+                              false,
+                              "If true, WebTransport support is enabled.");
+
 namespace quic {
 
 std::unique_ptr<quic::QuicSimpleServerBackend>
@@ -58,6 +63,9 @@
     memory_cache_backend->InitializeBackend(
         GetQuicFlag(FLAGS_quic_response_cache_dir));
   }
+  if (GetQuicFlag(FLAGS_enable_webtransport)) {
+    memory_cache_backend->EnableWebTransport();
+  }
   return memory_cache_backend;
 }
 
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_