binary_http: allow for empty body and headers to be omitted without a parsing error when decoding.

PiperOrigin-RevId: 737820021
diff --git a/quiche/binary_http/binary_http_message.cc b/quiche/binary_http/binary_http_message.cc
index b29fb8a..cf95e34 100644
--- a/quiche/binary_http/binary_http_message.cc
+++ b/quiche/binary_http/binary_http_message.cc
@@ -114,6 +114,12 @@
     return control_data.status();
   }
   BinaryHttpRequest request(std::move(*control_data));
+  if (reader.IsDoneReading()) {
+    // Per RFC 9292, Section 3.8, "Decoders MUST treat missing truncated fields
+    // as equivalent to having been sent with the length field set to zero."
+    // If we've run out of payload, stop parsing and return the request.
+    return request;
+  }
   if (const absl::Status status = DecodeFieldsAndBody(reader, request);
       !status.ok()) {
     return status;
diff --git a/quiche/binary_http/binary_http_message_test.cc b/quiche/binary_http/binary_http_message_test.cc
index eb81e80..5841b2a 100644
--- a/quiche/binary_http/binary_http_message_test.cc
+++ b/quiche/binary_http/binary_http_message_test.cc
@@ -123,6 +123,68 @@
   TestPrintTo(request);
 }
 
+TEST(BinaryHttpRequest, EncodeGetNoBodyOrHeaders) {
+  /*
+    (HTTP/2)
+    :method GET
+    :authority example.com
+    :path /
+    :scheme https
+  */
+  BinaryHttpRequest request({"GET", "https", "example.com", "/"});
+
+  /*
+      00000000: 00034745 54056874 7470730b 6578616d  ..GET.https.exam
+      00000010: 706c652e 636f6d01 2f000              ple.com./..
+  */
+  const uint32_t expected_words[] = {0x00034745, 0x54056874, 0x7470730b,
+                                     0x6578616d, 0x706c652e, 0x636f6d01,
+                                     0x2f000000};
+  std::string expected;
+  for (const auto& word : expected_words) {
+    expected += WordToBytes(word);
+  }
+  // Remove padding.
+  expected.resize(expected.size() - 1);
+
+  const auto result = request.Serialize();
+  ASSERT_TRUE(result.ok());
+  ASSERT_EQ(*result, expected);
+  EXPECT_THAT(request.DebugString(),
+              StrEq("BinaryHttpRequest{BinaryHttpMessage{Headers{}Body{}}}"));
+  TestPrintTo(request);
+}
+
+TEST(BinaryHttpRequest, DecodeGetNoBodyOrHeaders) {
+  const uint32_t words[] = {0x00034745, 0x54056874, 0x7470730b, 0x6578616d,
+                            0x706c652e, 0x636f6d01, 0x2f000000};
+  std::string data;
+  for (const auto& word : words) {
+    data += WordToBytes(word);
+  }
+
+  for (int i = 0; i < 3; ++i) {
+    // In the first pass, we remove a byte of padding, or alternatively an empty
+    // set of trailers. In the second pass, we further omit the empty body. In
+    // the third pass, we further omit the empty headers.
+    data.resize(data.size() - 1);
+    const auto request_so = BinaryHttpRequest::Create(data);
+    ASSERT_TRUE(request_so.ok());
+    const BinaryHttpRequest request = *request_so;
+    ASSERT_THAT(request.control_data(),
+                FieldsAre("GET", "https", "example.com", "/"));
+    std::vector<BinaryHttpMessage::Field> expected_fields = {};
+    for (const auto& field : expected_fields) {
+      TestPrintTo(field);
+    }
+    ASSERT_THAT(request.GetHeaderFields(), ContainerEq(expected_fields));
+    ASSERT_EQ(request.body(), "");
+    EXPECT_THAT(request.DebugString(),
+                StrEq("BinaryHttpRequest{BinaryHttpMessage{Headers{}Body{}}}"));
+    TestPrintTo(request);
+  }
+}
+
 TEST(BinaryHttpRequest, EncodeGetWithAuthority) {
   /*
     GET https://www.example.com/hello.txt HTTP/1.1