Allow CONNECT requests without :path in QuicSimpleServerStream

This CL also fixes a bug where QuicMemoryCacheBackend could dereference missing headers. This is all test/tool code that is not used in production.

PiperOrigin-RevId: 360278864
Change-Id: Iec74365d5090245ec9b53718e301f820f9e1cf39
diff --git a/quic/tools/quic_memory_cache_backend.cc b/quic/tools/quic_memory_cache_backend.cc
index c67e5b3..c030732 100644
--- a/quic/tools/quic_memory_cache_backend.cc
+++ b/quic/tools/quic_memory_cache_backend.cc
@@ -316,8 +316,13 @@
     quic_response = GetResponse(authority->second, path->second);
   }
 
-  std::string request_url =
-      std::string(authority->second) + std::string(path->second);
+  std::string request_url;
+  if (authority != request_headers.end()) {
+    request_url = std::string(authority->second);
+  }
+  if (path != request_headers.end()) {
+    request_url += std::string(path->second);
+  }
   std::list<ServerPushInfo> resources = GetServerPushResources(request_url);
   QUIC_DVLOG(1)
       << "Fetching QUIC response from backend in-memory cache for url "
diff --git a/quic/tools/quic_simple_server_stream.cc b/quic/tools/quic_simple_server_stream.cc
index 800608b..4377b56 100644
--- a/quic/tools/quic_simple_server_stream.cc
+++ b/quic/tools/quic_simple_server_stream.cc
@@ -153,13 +153,24 @@
     return;
   }
 
-  if (!QuicContainsKey(request_headers_, ":authority") ||
-      !QuicContainsKey(request_headers_, ":path")) {
-    QUIC_DVLOG(1) << "Request headers do not contain :authority or :path.";
+  if (!QuicContainsKey(request_headers_, ":authority")) {
+    QUIC_DVLOG(1) << "Request headers do not contain :authority.";
     SendErrorResponse();
     return;
   }
 
+  if (!QuicContainsKey(request_headers_, ":path")) {
+    // CONNECT and other CONNECT-like methods (such as CONNECT-UDP) do not all
+    // require :path to be present.
+    auto it = request_headers_.find(":method");
+    if (it == request_headers_.end() ||
+        !absl::StartsWith(it->second, "CONNECT")) {
+      QUIC_DVLOG(1) << "Request headers do not contain :path.";
+      SendErrorResponse();
+      return;
+    }
+  }
+
   if (quic_simple_server_backend_ == nullptr) {
     QUIC_DVLOG(1) << "Backend is missing.";
     SendErrorResponse();
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc
index 5806ad7..541316a 100644
--- a/quic/tools/quic_simple_server_stream_test.cc
+++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -77,6 +77,9 @@
   const std::string& body() const { return body_; }
   int content_length() const { return content_length_; }
   bool send_response_was_called() const { return send_response_was_called_; }
+  bool send_error_response_was_called() const {
+    return send_error_response_was_called_;
+  }
 
   absl::string_view GetHeader(absl::string_view key) const {
     auto it = request_headers_.find(key);
@@ -90,8 +93,14 @@
     QuicSimpleServerStream::SendResponse();
   }
 
+  void SendErrorResponse() override {
+    send_error_response_was_called_ = true;
+    QuicSimpleServerStream::SendErrorResponse();
+  }
+
  private:
   bool send_response_was_called_ = false;
+  bool send_error_response_was_called_ = false;
 };
 
 namespace {
@@ -778,6 +787,7 @@
   EXPECT_EQ("CONNECT-SILLY", StreamHeadersValue(":method"));
   EXPECT_EQ(body_, StreamBody());
   EXPECT_TRUE(stream_->send_response_was_called());
+  EXPECT_FALSE(stream_->send_error_response_was_called());
 }
 
 }  // namespace