Balsa: enable trailers in requests.

PiperOrigin-RevId: 457704589
diff --git a/quiche/balsa/balsa_frame.h b/quiche/balsa/balsa_frame.h
index 230bf66..70d3aaf 100644
--- a/quiche/balsa/balsa_frame.h
+++ b/quiche/balsa/balsa_frame.h
@@ -19,6 +19,7 @@
 #include "quiche/balsa/noop_balsa_visitor.h"
 #include "quiche/common/platform/api/quiche_bug_tracker.h"
 #include "quiche/common/platform/api/quiche_export.h"
+#include "quiche/common/platform/api/quiche_flag_utils.h"
 
 namespace quiche {
 
@@ -104,15 +105,13 @@
     }
   }
 
-  // The method set_balsa_trailer clears the trailer provided and attaches it
-  // to the framer.  This is a required step before the framer will process any
-  // input message data.
-  // To detach the trailer object from the framer, use
+  // The method set_balsa_trailer() clears `trailer` and attaches it to the
+  // framer.  This is a required step before the framer will process any input
+  // message data.  To detach the trailer object from the framer, use
   // set_balsa_trailer(nullptr).
   void set_balsa_trailer(BalsaHeaders* trailer) {
     if (trailer != nullptr && is_request()) {
-      QUICHE_BUG(bug_1317_1) << "Trailer in request is not allowed.";
-      return;
+      QUICHE_CODE_COUNT(balsa_trailer_in_request);
     }
 
     if (trailer_ != trailer) {
diff --git a/quiche/balsa/balsa_frame_test.cc b/quiche/balsa/balsa_frame_test.cc
index 1ce4c7b..b6dc2ae 100644
--- a/quiche/balsa/balsa_frame_test.cc
+++ b/quiche/balsa/balsa_frame_test.cc
@@ -577,6 +577,7 @@
     balsa_frame_.set_http_validation_policy(
         HttpValidationPolicy::CreateDefault());
     balsa_frame_.set_balsa_headers(&headers_);
+    balsa_frame_.set_balsa_trailer(&trailer_);
     balsa_frame_.set_balsa_visitor(&visitor_mock_);
     balsa_frame_.set_is_request(true);
   }
@@ -1197,6 +1198,10 @@
             balsa_frame_.ProcessInput(trailer.data(), trailer.size()));
   EXPECT_TRUE(balsa_frame_.MessageFullyRead());
   EXPECT_EQ(BalsaFrameEnums::BALSA_NO_ERROR, balsa_frame_.ErrorCode());
+  const absl::string_view crass = trailer_.GetHeader("crass");
+  EXPECT_EQ("monkeys", crass);
+  const absl::string_view funky = trailer_.GetHeader("funky");
+  EXPECT_EQ("monkeys", funky);
 }
 
 TEST_F(HTTPBalsaFrameTest, NothingBadHappensWhenNoVisitorIsAssignedInResponse) {
@@ -1215,7 +1220,6 @@
       "funky: monkeys\r\n"
       "\r\n";
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
   balsa_frame_.set_balsa_visitor(nullptr);
 
   ASSERT_EQ(headers.size(),
@@ -1297,7 +1301,6 @@
       "\n";
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
 
   ASSERT_EQ(headers.size(),
             balsa_frame_.ProcessInput(headers.data(), headers.size()));
@@ -2128,7 +2131,6 @@
   fake_headers_in_trailer.AddKeyValue("a_trailer_key", "and a trailer value");
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
 
   {
     InSequence s1;
@@ -2201,7 +2203,6 @@
   fake_headers_in_trailer.AddKeyValue("a_trailer_key", "and a trailer value");
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
 
   {
     InSequence s1;
@@ -3123,7 +3124,6 @@
       "\r\n";
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
   EXPECT_CALL(visitor_mock_,
               HandleWarning(BalsaFrameEnums::TRAILER_MISSING_COLON));
   ASSERT_EQ(headers.size(),
@@ -3215,7 +3215,6 @@
   EXPECT_CALL(visitor_mock_, OnBodyChunkInput("123"));
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
 
   ASSERT_EQ(headers.size(),
             balsa_frame_.ProcessInput(headers.data(), headers.size()));
@@ -3282,7 +3281,6 @@
       "\n";
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
   balsa_frame_.set_balsa_visitor(nullptr);
 
   ASSERT_EQ(headers.size(),
@@ -3513,7 +3511,6 @@
   std::string trailer = absl::StrCat("k: v\n", gibberish_headers, "\n");
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
   balsa_frame_.set_balsa_visitor(nullptr);
 
   ASSERT_EQ(headers.size(),
@@ -3541,12 +3538,6 @@
   EXPECT_EQ("bar : eeep : baz", field_value);
 }
 
-// Test that trailer is not allowed for request.
-TEST_F(HTTPBalsaFrameTest, TrailerIsNotAllowedInRequest) {
-  EXPECT_QUICHE_BUG(balsa_frame_.set_balsa_trailer(&trailer_),
-                    "Trailer in request is not allowed");
-}
-
 // Note we reuse the header length limit because trailer is just multiple
 // headers.
 TEST_F(HTTPBalsaFrameTest, TrailerTooLong) {
@@ -3566,7 +3557,6 @@
       "\r\n";
 
   balsa_frame_.set_is_request(false);
-  balsa_frame_.set_balsa_trailer(&trailer_);
   ASSERT_LT(headers.size(), trailer.size());
   balsa_frame_.set_max_header_length(headers.size());
 
@@ -3584,8 +3574,8 @@
   EXPECT_EQ(BalsaFrameEnums::TRAILER_TOO_LONG, balsa_frame_.ErrorCode());
 }
 
-// If the trailer_ object in the framer is not set, ProcessTrailers won't be
-// called.
+// If the `trailer_` object in the framer is set to `nullptr`,
+// ProcessTrailers() will not be called.
 TEST_F(HTTPBalsaFrameTest,
        NoProcessTrailersCallWhenFramerHasNullTrailerObject) {
   std::string headers =
@@ -3602,6 +3592,7 @@
       "\r\n";
 
   balsa_frame_.set_is_request(false);
+  balsa_frame_.set_balsa_trailer(nullptr);
 
   EXPECT_CALL(visitor_mock_, ProcessTrailers(_)).Times(0);
   ASSERT_EQ(headers.size(),