Explicitly adds "host" to the set of accepted request headers, and allows "host" in place of ":authority".

PiperOrigin-RevId: 437861314
diff --git a/http2/adapter/header_validator.cc b/http2/adapter/header_validator.cc
index 1220634..d269501 100644
--- a/http2/adapter/header_validator.cc
+++ b/http2/adapter/header_validator.cc
@@ -50,13 +50,6 @@
   return true;
 }
 
-// Returns whether `authority` contains only characters from the `host` ABNF
-// from RFC 3986 section 3.2.2.
-bool IsValidAuthority(absl::string_view authority) {
-  static const CharMap valid_chars = BuildValidCharMap(kValidAuthorityChars);
-  return AllCharsInMap(authority, valid_chars);
-}
-
 bool IsValidHeaderName(absl::string_view name) {
   static const CharMap valid_chars =
       BuildValidCharMap(kHttp2HeaderNameAllowedChars);
@@ -127,6 +120,7 @@
   status_.clear();
   method_.clear();
   path_.clear();
+  authority_ = absl::nullopt;
   content_length_.reset();
 }
 
@@ -166,7 +160,7 @@
       status_ = std::string(value);
     } else if (key == ":method") {
       method_ = std::string(value);
-    } else if (key == ":authority" && !IsValidAuthority(value)) {
+    } else if (key == ":authority" && !ValidateAndSetAuthority(value)) {
       return HEADER_FIELD_INVALID;
     } else if (key == ":path") {
       if (value.empty()) {
@@ -176,6 +170,17 @@
       path_ = std::string(value);
     }
     pseudo_headers_.push_back(std::string(key));
+  } else if (key == "host") {
+    if (!status_.empty()) {
+      // Response headers can contain "Host".
+    } else {
+      if (!authority_.has_value()) {
+        pseudo_headers_.push_back(std::string(":authority"));
+      }
+      if (!ValidateAndSetAuthority(value)) {
+        return HEADER_FIELD_INVALID;
+      }
+    }
   } else if (key == "content-length") {
     const bool success = HandleContentLength(value);
     if (!success) {
@@ -234,5 +239,19 @@
   return true;
 }
 
+// Returns whether `authority` contains only characters from the `host` ABNF
+// from RFC 3986 section 3.2.2.
+bool HeaderValidator::ValidateAndSetAuthority(absl::string_view authority) {
+  static const CharMap valid_chars = BuildValidCharMap(kValidAuthorityChars);
+  if (!AllCharsInMap(authority, valid_chars)) {
+    return false;
+  }
+  if (authority_.has_value() && authority != authority_.value()) {
+    return false;
+  }
+  authority_ = std::string(authority);
+  return true;
+}
+
 }  // namespace adapter
 }  // namespace http2
diff --git a/http2/adapter/header_validator.h b/http2/adapter/header_validator.h
index 30f16d5..8b8744e 100644
--- a/http2/adapter/header_validator.h
+++ b/http2/adapter/header_validator.h
@@ -50,8 +50,10 @@
 
  private:
   bool HandleContentLength(absl::string_view value);
+  bool ValidateAndSetAuthority(absl::string_view authority);
 
   std::vector<std::string> pseudo_headers_;
+  absl::optional<std::string> authority_ = absl::nullopt;
   std::string status_;
   std::string method_;
   std::string path_;
diff --git a/http2/adapter/header_validator_test.cc b/http2/adapter/header_validator_test.cc
index 85ff3bb..a6d0326 100644
--- a/http2/adapter/header_validator_test.cc
+++ b/http2/adapter/header_validator_test.cc
@@ -134,37 +134,76 @@
 }
 
 TEST(HeaderValidatorTest, AuthorityHasInvalidChar) {
+  for (absl::string_view key : {":authority", "host"}) {
+    // These characters should be allowed. (Not exhaustive.)
+    for (const absl::string_view c : {"1", "-", "!", ":", "+", "=", ","}) {
+      HeaderValidator v;
+      v.StartHeaderBlock();
+      HeaderValidator::HeaderStatus status =
+          v.ValidateSingleHeader(key, absl::StrCat("ho", c, "st.example.com"));
+      EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+    }
+    // These should not.
+    for (const absl::string_view c : {"\r", "\n", "|", "\\", "`"}) {
+      HeaderValidator v;
+      v.StartHeaderBlock();
+      HeaderValidator::HeaderStatus status =
+          v.ValidateSingleHeader(key, absl::StrCat("ho", c, "st.example.com"));
+      EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
+    }
+
+    {
+      // IPv4 example
+      HeaderValidator v;
+      v.StartHeaderBlock();
+      HeaderValidator::HeaderStatus status =
+          v.ValidateSingleHeader(key, "123.45.67.89");
+      EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+    }
+
+    {
+      // IPv6 examples
+      HeaderValidator v;
+      v.StartHeaderBlock();
+      HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(
+          key, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+      EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+      HeaderValidator v2;
+      v2.StartHeaderBlock();
+      status = v2.ValidateSingleHeader(key, "[::1]:80");
+      EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+    }
+
+    {
+      // Empty field
+      HeaderValidator v;
+      v.StartHeaderBlock();
+      HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(key, "");
+      EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+    }
+  }
+}
+
+TEST(HeaderValidatorTest, RequestHostAndAuthority) {
   HeaderValidator v;
   v.StartHeaderBlock();
-
-  // These characters should be allowed. (Not exhaustive.)
-  for (const absl::string_view c : {"1", "-", "!", ":", "+", "=", ","}) {
-    HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(
-        ":authority", absl::StrCat("ho", c, "st.example.com"));
-    EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+  for (Header to_add : kSampleRequestPseudoheaders) {
+    EXPECT_EQ(HeaderValidator::HEADER_OK,
+              v.ValidateSingleHeader(to_add.first, to_add.second));
   }
-  // These should not.
-  for (const absl::string_view c : {"\r", "\n", "|", "\\", "`"}) {
-    HeaderValidator::HeaderStatus status = v.ValidateSingleHeader(
-        ":authority", absl::StrCat("ho", c, "st.example.com"));
-    EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID, status);
+  // If both "host" and ":authority" have the same value, validation succeeds.
+  EXPECT_EQ(HeaderValidator::HEADER_OK,
+            v.ValidateSingleHeader("host", "www.foo.com"));
+  EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::REQUEST));
+
+  v.StartHeaderBlock();
+  for (Header to_add : kSampleRequestPseudoheaders) {
+    EXPECT_EQ(HeaderValidator::HEADER_OK,
+              v.ValidateSingleHeader(to_add.first, to_add.second));
   }
-
-  // IPv4 example
-  HeaderValidator::HeaderStatus status =
-      v.ValidateSingleHeader(":authority", "123.45.67.89");
-  EXPECT_EQ(HeaderValidator::HEADER_OK, status);
-
-  // IPv6 examples
-  status = v.ValidateSingleHeader(":authority",
-                                  "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
-  EXPECT_EQ(HeaderValidator::HEADER_OK, status);
-  status = v.ValidateSingleHeader(":authority", "[::1]:80");
-  EXPECT_EQ(HeaderValidator::HEADER_OK, status);
-
-  // Empty field
-  status = v.ValidateSingleHeader(":authority", "");
-  EXPECT_EQ(HeaderValidator::HEADER_OK, status);
+  // If "host" and ":authority" have different values, validation fails.
+  EXPECT_EQ(HeaderValidator::HEADER_FIELD_INVALID,
+            v.ValidateSingleHeader("host", "www.bar.com"));
 }
 
 TEST(HeaderValidatorTest, RequestPseudoHeaders) {
@@ -354,6 +393,17 @@
   }
 }
 
+TEST(HeaderValidatorTest, ResponseWithHost) {
+  HeaderValidator v;
+
+  v.StartHeaderBlock();
+  EXPECT_EQ(HeaderValidator::HEADER_OK,
+            v.ValidateSingleHeader(":status", "200"));
+  EXPECT_EQ(HeaderValidator::HEADER_OK,
+            v.ValidateSingleHeader("host", "myserver.com"));
+  EXPECT_TRUE(v.FinishHeaderBlock(HeaderType::RESPONSE));
+}
+
 TEST(HeaderValidatorTest, Response204) {
   HeaderValidator v;
 
diff --git a/http2/adapter/nghttp2_adapter_test.cc b/http2/adapter/nghttp2_adapter_test.cc
index d238fd2..7a2bb11 100644
--- a/http2/adapter/nghttp2_adapter_test.cc
+++ b/http2/adapter/nghttp2_adapter_test.cc
@@ -3228,6 +3228,72 @@
   EXPECT_THAT(visitor.data(), EqualsFrames({SpdyFrameType::SETTINGS}));
 }
 
+TEST(NgHttp2AdapterTest, ServerHandlesHostHeader) {
+  DataSavingVisitor visitor;
+  auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor);
+
+  const std::string frames = TestFrameSequence()
+                                 .ClientPreface()
+                                 .Headers(1,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "example.com"}},
+                                          /*fin=*/true)
+                                 .Headers(3,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "example.com"}},
+                                          /*fin=*/true)
+                                 .Headers(5,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "foo.com"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "bar.com"}},
+                                          /*fin=*/true)
+                                 .Serialize();
+
+  testing::InSequence s;
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, _, _)).Times(4);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnEndStream(1));
+
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(3));
+  EXPECT_CALL(visitor, OnEndStream(3));
+
+  EXPECT_CALL(visitor, OnFrameHeader(5, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(5));
+  EXPECT_CALL(visitor, OnHeaderForStream(5, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(5));
+  EXPECT_CALL(visitor, OnEndStream(5));
+
+  const int64_t result = adapter->ProcessBytes(frames);
+  EXPECT_EQ(frames.size(), static_cast<size_t>(result));
+
+  EXPECT_TRUE(adapter->want_write());
+
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+
+  int send_result = adapter->Send();
+  EXPECT_EQ(0, send_result);
+  visitor.Clear();
+}
+
 // Tests the case where the response body is in the progress of being sent while
 // trailers are queued.
 TEST(NgHttp2AdapterTest, ServerSubmitsTrailersWhileDataDeferred) {
diff --git a/http2/adapter/oghttp2_adapter_test.cc b/http2/adapter/oghttp2_adapter_test.cc
index 9e3b1cc..eed1071 100644
--- a/http2/adapter/oghttp2_adapter_test.cc
+++ b/http2/adapter/oghttp2_adapter_test.cc
@@ -4178,6 +4178,81 @@
               EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::SETTINGS}));
 }
 
+TEST(OgHttp2AdapterTest, ServerHandlesHostHeader) {
+  DataSavingVisitor visitor;
+  OgHttp2Adapter::Options options{.perspective = Perspective::kServer};
+  auto adapter = OgHttp2Adapter::Create(visitor, options);
+
+  const std::string frames = TestFrameSequence()
+                                 .ClientPreface()
+                                 .Headers(1,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "example.com"}},
+                                          /*fin=*/true)
+                                 .Headers(3,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "example.com"}},
+                                          /*fin=*/true)
+                                 .Headers(5,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "foo.com"},
+                                           {":path", "/this/is/request/one"},
+                                           {"host", "bar.com"}},
+                                          /*fin=*/true)
+                                 .Serialize();
+
+  testing::InSequence s;
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, _, _)).Times(4);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnEndStream(1));
+
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(3));
+  EXPECT_CALL(visitor, OnEndStream(3));
+
+  EXPECT_CALL(visitor, OnFrameHeader(5, _, HEADERS, 5));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(5));
+  EXPECT_CALL(visitor, OnHeaderForStream(5, _, _)).Times(4);
+  EXPECT_CALL(
+      visitor,
+      OnInvalidFrame(5, Http2VisitorInterface::InvalidFrameError::kHttpHeader));
+
+  const int64_t result = adapter->ProcessBytes(frames);
+  EXPECT_EQ(frames.size(), static_cast<size_t>(result));
+
+  EXPECT_TRUE(adapter->want_write());
+
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 5, 4, 0x0));
+  EXPECT_CALL(visitor,
+              OnFrameSent(RST_STREAM, 5, 4, 0x0,
+                          static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(5, Http2ErrorCode::HTTP2_NO_ERROR));
+
+  int send_result = adapter->Send();
+  EXPECT_EQ(0, send_result);
+  visitor.Clear();
+}
+
 // Tests the case where the response body is in the progress of being sent while
 // trailers are queued.
 TEST(OgHttp2AdapterTest, ServerSubmitsTrailersWhileDataDeferred) {