Reject TE headers with values other than "trailers" in oghttp2.

This CL improves oghttp2 spec compliance:
https://httpwg.org/specs/rfc7540.html#n-connection-specific-header-fields

In particular, the TE header field may only have the "trailers" value;
otherwise the headers will be rejected as invalid.

Http2RequestsTest.InvalidTeHeader with oghttp2:
http://sponge2/6330792e-5128-4114-ab14-b99eeb73e17b

PiperOrigin-RevId: 424381258
diff --git a/http2/adapter/header_validator.cc b/http2/adapter/header_validator.cc
index d018991..dd605f4 100644
--- a/http2/adapter/header_validator.cc
+++ b/http2/adapter/header_validator.cc
@@ -155,6 +155,8 @@
     if (!success) {
       return HEADER_FIELD_INVALID;
     }
+  } else if (key == "te" && value != "trailers") {
+    return HEADER_FIELD_INVALID;
   }
   return HEADER_OK;
 }
diff --git a/http2/adapter/header_validator_test.cc b/http2/adapter/header_validator_test.cc
index c76a770..52148df 100644
--- a/http2/adapter/header_validator_test.cc
+++ b/http2/adapter/header_validator_test.cc
@@ -460,6 +460,18 @@
   EXPECT_THAT(v.content_length(), Optional(42));
 }
 
+TEST(HeaderValidatorTest, TeHeader) {
+  HeaderValidator v;
+
+  v.StartHeaderBlock();
+  EXPECT_EQ(HeaderValidator::HEADER_OK,
+            v.ValidateSingleHeader("te", "trailers"));
+
+  v.StartHeaderBlock();
+  EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
+            v.ValidateSingleHeader("te", "trailers, deflate"));
+}
+
 }  // namespace test
 }  // namespace adapter
 }  // namespace http2
diff --git a/http2/adapter/nghttp2_adapter_test.cc b/http2/adapter/nghttp2_adapter_test.cc
index dbab8c6..a2fd68f 100644
--- a/http2/adapter/nghttp2_adapter_test.cc
+++ b/http2/adapter/nghttp2_adapter_test.cc
@@ -5038,6 +5038,72 @@
                                             spdy::SpdyFrameType::RST_STREAM}));
 }
 
+TEST(NgHttp2AdapterTest, ServerHandlesTeHeader) {
+  DataSavingVisitor visitor;
+  auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+  testing::InSequence s;
+
+  const std::string stream_frames = TestFrameSequence()
+                                        .ClientPreface()
+                                        .Headers(1,
+                                                 {{":scheme", "https"},
+                                                  {":authority", "example.com"},
+                                                  {":path", "/"},
+                                                  {":method", "GET"},
+                                                  {"te", "trailers"}},
+                                                 /*fin=*/true)
+                                        .Headers(3,
+                                                 {{":scheme", "https"},
+                                                  {":authority", "example.com"},
+                                                  {":path", "/"},
+                                                  {":method", "GET"},
+                                                  {"te", "trailers, deflate"}},
+                                                 /*fin=*/true)
+                                        .Serialize();
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+
+  // Stream 1: TE: trailers should be allowed.
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnEndStream(1));
+
+  // Stream 3: TE: <non-trailers> should be rejected.
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(4);
+  EXPECT_CALL(
+      visitor,
+      OnErrorDebug("Invalid HTTP header field was received: frame type: 1, "
+                   "stream: 3, name: [te], value: [trailers, deflate]"));
+  EXPECT_CALL(
+      visitor,
+      OnInvalidFrame(3, Http2VisitorInterface::InvalidFrameError::kHttpHeader));
+
+  const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+  EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
+
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 3, _, 0x0));
+  EXPECT_CALL(visitor,
+              OnFrameSent(RST_STREAM, 3, _, 0x0,
+                          static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::PROTOCOL_ERROR));
+
+  EXPECT_TRUE(adapter->want_write());
+  int result = adapter->Send();
+  EXPECT_EQ(0, result);
+  EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+                                            spdy::SpdyFrameType::RST_STREAM}));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace adapter
diff --git a/http2/adapter/oghttp2_adapter_test.cc b/http2/adapter/oghttp2_adapter_test.cc
index 672f6fb..7917bf2 100644
--- a/http2/adapter/oghttp2_adapter_test.cc
+++ b/http2/adapter/oghttp2_adapter_test.cc
@@ -5103,7 +5103,7 @@
            spdy::SpdyFrameType::RST_STREAM, spdy::SpdyFrameType::RST_STREAM}));
 }
 
-TEST(NgHttp2AdapterTest, ServerHandlesAsteriskPathForOptions) {
+TEST(OgHttp2AdapterServerTest, ServerHandlesAsteriskPathForOptions) {
   DataSavingVisitor visitor;
   OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
   auto adapter = OgHttp2Adapter::Create(visitor, options);
@@ -5146,7 +5146,7 @@
                                             spdy::SpdyFrameType::SETTINGS}));
 }
 
-TEST(NgHttp2AdapterTest, ServerHandlesInvalidPath) {
+TEST(OgHttp2AdapterServerTest, ServerHandlesInvalidPath) {
   DataSavingVisitor visitor;
   OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
   auto adapter = OgHttp2Adapter::Create(visitor, options);
@@ -5235,6 +5235,72 @@
                                             spdy::SpdyFrameType::RST_STREAM}));
 }
 
+TEST(OgHttp2AdapterServerTest, ServerHandlesTeHeader) {
+  DataSavingVisitor visitor;
+  OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+  auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+  testing::InSequence s;
+
+  const std::string stream_frames = TestFrameSequence()
+                                        .ClientPreface()
+                                        .Headers(1,
+                                                 {{":scheme", "https"},
+                                                  {":authority", "example.com"},
+                                                  {":path", "/"},
+                                                  {":method", "GET"},
+                                                  {"te", "trailers"}},
+                                                 /*fin=*/true)
+                                        .Headers(3,
+                                                 {{":scheme", "https"},
+                                                  {":authority", "example.com"},
+                                                  {":path", "/"},
+                                                  {":method", "GET"},
+                                                  {"te", "trailers, deflate"}},
+                                                 /*fin=*/true)
+                                        .Serialize();
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+
+  // Stream 1: TE: trailers should be allowed.
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnEndStream(1));
+
+  // Stream 3: TE: <non-trailers> should be rejected.
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(4);
+  EXPECT_CALL(
+      visitor,
+      OnInvalidFrame(3, Http2VisitorInterface::InvalidFrameError::kHttpHeader));
+
+  const int64_t stream_result = adapter->ProcessBytes(stream_frames);
+  EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
+
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 3, _, 0x0));
+  EXPECT_CALL(visitor,
+              OnFrameSent(RST_STREAM, 3, _, 0x0,
+                          static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::HTTP2_NO_ERROR));
+
+  EXPECT_TRUE(adapter->want_write());
+  int result = adapter->Send();
+  EXPECT_EQ(0, result);
+  EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS,
+                                            spdy::SpdyFrameType::SETTINGS,
+                                            spdy::SpdyFrameType::RST_STREAM}));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace adapter