Commit message: http: header map security fixes for duplicate headers (#197)

Previously header matching did not match on all headers for
non-inline headers. This patch changes the default behavior to
always logically match on all headers. Multiple individual
headers will be logically concatenated with ',' similar to what
is done with inline headers. This makes the behavior effectively
consistent. This behavior can be temporary reverted by setting
the runtime value "envoy.reloadable_features.header_match_on_all_headers"
to "false".

Targeted fixes have been additionally performed on the following
extensions which make them consider all duplicate headers by default as
a comma concatenated list:
1) Any extension using CEL matching on headers.
2) The header to metadata filter.
3) The JWT filter.
4) The Lua filter.
Like primary header matching used in routing, RBAC, etc. this behavior
can be disabled by setting the runtime value
"envoy.reloadable_features.header_match_on_all_headers" to false.

Finally, the setCopy() header map API previously only set the first
header in the case of duplicate non-inline headers. setCopy() now
behaves similiarly to the other set*() APIs and replaces all found
headers with a single value. This may have had security implications
in the extauth filter which uses this API. This behavior can be disabled
by setting the runtime value
"envoy.reloadable_features.http_set_copy_replace_all_headers" to false.

Fixes https://github.com/envoyproxy/envoy-setec/issues/188

Signed-off-by: Matt Klein <mklein@lyft.com>
CVE: CVE-2020-25017
CWE: NVD-CWE-Other
Vulnerability description: Envoy through 1.15.0 only considers the first value when multiple header values are present for some HTTP headers. Envoy’s setCopy() header map API does not replace all existing occurences of a non-inline header.

Project: envoy

TEST_P(RBACIntegrationTest, RouteOverride) {
  config_helper_.addConfigModifier(
      [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
             cfg) {
        envoy::extensions::filters::http::rbac::v3::RBACPerRoute per_route_config;
        TestUtility::loadFromJson("{}", per_route_config);

        auto* config = cfg.mutable_route_config()
                           ->mutable_virtual_hosts()
                           ->Mutable(0)
                           ->mutable_typed_per_filter_config();

        (*config)[Extensions::HttpFilters::HttpFilterNames::get().Rbac].PackFrom(per_route_config);
      });
  config_helper_.addFilter(RBAC_CONFIG);

  initialize();

  codec_client_ = makeHttpConnection(lookupPort("http"));
  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "POST"},
          {":path", "/"},
          {":scheme", "http"},
          {":authority", "host"},
          {"x-forwarded-for", "10.0.0.1"},
      },
      1024);

  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true);

  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
}

Project: envoy

    std::list<HeaderEntryImpl>::const_iterator end() const { return headers_.end(); }

Project: envoy

absl::optional<CelValue> ConnectionWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();
  if (value == MTLS) {
    return CelValue::CreateBool(info_.downstreamSslConnection() != nullptr &&
                                info_.downstreamSslConnection()->peerCertificatePresented());
  } else if (value == RequestedServerName) {
    return CelValue::CreateString(&info_.requestedServerName());
  }

  auto ssl_info = info_.downstreamSslConnection();
  if (ssl_info != nullptr) {
    return extractSslInfo(*ssl_info, value);
  }

  return {};
}

Project: envoy

int DynamicMetadataMapIterator::luaPairsIterator(lua_State* state) {
  if (current_ == parent_.streamInfo().dynamicMetadata().filter_metadata().end()) {
    parent_.iterator_.reset();
    return 0;
  }

  lua_pushstring(state, current_->first.c_str());
  Filters::Common::Lua::MetadataMapHelper::createTable(state, current_->second.fields());

  current_++;
  return 2;
}

Project: envoy

  void lower() {
    std::transform(string_.begin(), string_.end(), string_.begin(), absl::ascii_tolower);
  }

Project: envoy

absl::string_view getStrView(const VariantHeader& buffer) {
  return absl::get<absl::string_view>(buffer);
}

Project: envoy

template <> HeaderMapImpl::StaticLookupTable<RequestHeaderMap>::StaticLookupTable() {
#define REGISTER_DEFAULT_REQUEST_HEADER(name)                                                      \
  CustomInlineHeaderRegistry::registerInlineHeader<RequestHeaderMap::header_map_type>(             \
      Headers::get().name);
  INLINE_REQ_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER)
  INLINE_REQ_RESP_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER)

  finalizeTable();

  // Special case where we map a legacy host header to :authority.
  const auto handle =
      CustomInlineHeaderRegistry::getInlineHeader<RequestHeaderMap::header_map_type>(
          Headers::get().Host);
  add(Headers::get().HostLegacy.get().c_str(), [handle](HeaderMapImpl& h) -> StaticLookupResponse {
    return {&h.inlineHeaders()[handle.value().it_->second], &handle.value().it_->first};
  });
}

Project: envoy

TEST(Context, RequestFallbackAttributes) {
  NiceMock<StreamInfo::MockStreamInfo> info;
  Http::TestRequestHeaderMapImpl header_map{
      {":method", "POST"},
      {":scheme", "http"},
      {":path", "/meow?yes=1"},
  };
  Protobuf::Arena arena;
  RequestWrapper request(arena, &header_map, info);

  EXPECT_CALL(info, bytesReceived()).WillRepeatedly(Return(10));

  {
    auto value = request[CelValue::CreateStringView(Size)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(10, value.value().Int64OrDie());
  }

  {
    auto value = request[CelValue::CreateStringView(UrlPath)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("/meow", value.value().StringOrDie().value());
  }
}

Project: envoy

  bool operator==(const LowerCaseString& rhs) const { return string_ == rhs.string_; }

Project: envoy

absl::optional<CelValue> FilterStateWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();
  if (filter_state_.hasDataWithName(value)) {
    const StreamInfo::FilterState::Object* object = filter_state_.getDataReadOnlyGeneric(value);
    absl::optional<std::string> serialized = object->serializeAsString();
    if (serialized.has_value()) {
      std::string* out = ProtobufWkt::Arena::Create<std::string>(arena_, serialized.value());
      return CelValue::CreateBytes(out);
    }
  }
  return {};
}

Project: envoy

  static const MessageType& downcastAndValidate(const Protobuf::Message& config) {
    return MessageUtil::downcastAndValidate<MessageType>(
        config, ProtobufMessage::getStrictValidationVisitor());
  }

Project: envoy

  size_t removePrefix(const LowerCaseString& key) override {
    return HeaderMapImpl::removePrefix(key);
  }

Project: envoy

ExpressionPtr createExpression(Builder& builder, const google::api::expr::v1alpha1::Expr& expr) {
  google::api::expr::v1alpha1::SourceInfo source_info;
  auto cel_expression_status = builder.CreateExpression(&expr, &source_info);
  if (!cel_expression_status.ok()) {
    throw CelException(
        absl::StrCat("failed to create an expression: ", cel_expression_status.status().message()));
  }
  return std::move(cel_expression_status.value());
}

Project: envoy

TEST(MatchHeadersTest, HeaderRangeInverseMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "0"},
                                            {"match-header", "somestring"},
                                            {"match-header", "10.9"},
                                            {"match-header", "-1somestring"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "-1"}};

  const std::string yaml = R"EOF(
name: match-header
range_match:
  start: -10
  end: 0
invert_match: true
  )EOF";

  std::vector<HeaderUtility::HeaderDataPtr> header_data;
  header_data.push_back(
      std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(yaml)));
  EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data));
}

Project: envoy

  void addViaMove(HeaderString&& key, HeaderString&& value) override {
    HeaderMapImpl::addViaMove(std::move(key), std::move(value));
  }

Project: envoy

uint32_t HeaderString::size() const {
  if (type() == Type::Reference) {
    return getStrView(buffer_).size();
  }
  ASSERT(type() == Type::Inline);
  return getInVec(buffer_).size();
}

Project: envoy

    bool empty() const { return result_.empty(); }

Project: envoy

TEST_P(RBACIntegrationTest, LogConnectionAllow) {
  config_helper_.addFilter(RBAC_CONFIG_WITH_LOG_ACTION);
  initialize();

  codec_client_ = makeHttpConnection(lookupPort("http"));

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "POST"},
          {":path", "/"},
          {":scheme", "http"},
          {":authority", "host"},
          {"x-forwarded-for", "10.0.0.1"},
      },
      1024);
  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true);

  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
}

Project: envoy

bool HeaderUtility::headerValueIsValid(const absl::string_view header_value) {
  return nghttp2_check_header_value(reinterpret_cast<const uint8_t*>(header_value.data()),
                                    header_value.size()) != 0;
}

Project: envoy

TEST(HeaderMapImplTest, Remove) {
  TestRequestHeaderMapImpl headers;

  // Add random header and then remove by name.
  LowerCaseString static_key("hello");
  std::string ref_value("value");
  headers.addReference(static_key, ref_value);
  EXPECT_EQ("value", headers.get(static_key)->value().getStringView());
  EXPECT_TRUE(headers.get(static_key)->value().isReference());
  EXPECT_EQ(1UL, headers.size());
  EXPECT_FALSE(headers.empty());
  EXPECT_EQ(1UL, headers.remove(static_key));
  EXPECT_EQ(nullptr, headers.get(static_key));
  EXPECT_EQ(0UL, headers.size());
  EXPECT_TRUE(headers.empty());

  // Add and remove by inline.
  EXPECT_EQ(0UL, headers.removeContentLength());
  headers.setContentLength(5);
  EXPECT_EQ("5", headers.getContentLengthValue());
  EXPECT_EQ(1UL, headers.size());
  EXPECT_FALSE(headers.empty());
  EXPECT_EQ(1UL, headers.removeContentLength());
  EXPECT_EQ(nullptr, headers.ContentLength());
  EXPECT_EQ(0UL, headers.size());
  EXPECT_TRUE(headers.empty());

  // Add inline and remove by name.
  headers.setContentLength(5);
  EXPECT_EQ("5", headers.getContentLengthValue());
  EXPECT_EQ(1UL, headers.size());
  EXPECT_FALSE(headers.empty());
  EXPECT_EQ(1UL, headers.remove(Headers::get().ContentLength));
  EXPECT_EQ(nullptr, headers.ContentLength());
  EXPECT_EQ(0UL, headers.size());
  EXPECT_TRUE(headers.empty());

  // Try to remove nonexistent headers.
  EXPECT_EQ(0UL, headers.remove(static_key));
  EXPECT_EQ(0UL, headers.remove(Headers::get().ContentLength));
}

Project: envoy

int DynamicMetadataMapWrapper::luaGet(lua_State* state) {
  const char* filter_name = luaL_checkstring(state, 2);
  const auto& metadata = streamInfo().dynamicMetadata().filter_metadata();
  const auto filter_it = metadata.find(filter_name);
  if (filter_it == metadata.end()) {
    return 0;
  }

  Filters::Common::Lua::MetadataMapHelper::createTable(state, filter_it->second.fields());
  return 1;
}

Project: envoy

  bool operator==(const HeaderMap& rhs) const override { return HeaderMapImpl::operator==(rhs); }

Project: envoy

TEST_F(HeaderToMetadataTest, IgnoreHeaderValueUseConstant) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-something
    on_header_present:
      key: something
      value: else
      type: STRING
    remove: true
)EOF";
  initializeFilter(response_config_yaml);
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-something", "thing"}};
  std::map<std::string, std::string> expected = {{"something", "else"}};
  Http::TestResponseHeaderMapImpl empty_headers;

  EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_,
              setDynamicMetadata(HttpFilterNames::get().HeaderToMetadata, MapEq(expected)));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false));
  EXPECT_EQ(empty_headers, incoming_headers);
}

Project: envoy

TEST(PercentEncoding, ShouldCloseConnection) {
  EXPECT_TRUE(HeaderUtility::shouldCloseConnection(Protocol::Http10,
                                                   TestRequestHeaderMapImpl{{"foo", "bar"}}));
  EXPECT_FALSE(HeaderUtility::shouldCloseConnection(
      Protocol::Http10, TestRequestHeaderMapImpl{{"connection", "keep-alive"}}));
  EXPECT_FALSE(HeaderUtility::shouldCloseConnection(
      Protocol::Http10, TestRequestHeaderMapImpl{{"connection", "foo, keep-alive"}}));

  EXPECT_FALSE(HeaderUtility::shouldCloseConnection(Protocol::Http11,
                                                    TestRequestHeaderMapImpl{{"foo", "bar"}}));
  EXPECT_TRUE(HeaderUtility::shouldCloseConnection(
      Protocol::Http11, TestRequestHeaderMapImpl{{"connection", "close"}}));
  EXPECT_TRUE(HeaderUtility::shouldCloseConnection(
      Protocol::Http11, TestRequestHeaderMapImpl{{"connection", "te,close"}}));
  EXPECT_TRUE(HeaderUtility::shouldCloseConnection(
      Protocol::Http11, TestRequestHeaderMapImpl{{"proxy-connection", "close"}}));
  EXPECT_TRUE(HeaderUtility::shouldCloseConnection(
      Protocol::Http11, TestRequestHeaderMapImpl{{"proxy-connection", "foo,close"}}));
}

Project: envoy

  void dumpState(std::ostream& os, int indent_level = 0) const override {
    HeaderMapImpl::dumpState(os, indent_level);
  }

Project: envoy

TEST(HeaderMapImplTest, InlineAppend) {
  {
    TestRequestHeaderMapImpl headers;
    // Create via header and append.
    headers.setVia("");
    headers.appendVia("1.0 fred", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred");
    headers.appendVia("1.1 nowhere.com", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred,1.1 nowhere.com");
  }
  {
    // Append to via header without explicitly creating first.
    TestRequestHeaderMapImpl headers;
    headers.appendVia("1.0 fred", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred");
    headers.appendVia("1.1 nowhere.com", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred,1.1 nowhere.com");
  }
  {
    // Custom delimiter.
    TestRequestHeaderMapImpl headers;
    headers.setVia("");
    headers.appendVia("1.0 fred", ", ");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred");
    headers.appendVia("1.1 nowhere.com", ", ");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred, 1.1 nowhere.com");
  }
  {
    // Append and then later set.
    TestRequestHeaderMapImpl headers;
    headers.appendVia("1.0 fred", ",");
    headers.appendVia("1.1 nowhere.com", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred,1.1 nowhere.com");
    headers.setVia("2.0 override");
    EXPECT_EQ(headers.getViaValue(), "2.0 override");
  }
  {
    // Set and then append. This mimics how GrpcTimeout is set.
    TestRequestHeaderMapImpl headers;
    headers.setGrpcTimeout(42);
    EXPECT_EQ(headers.getGrpcTimeoutValue(), "42");
    headers.appendGrpcTimeout("s", "");
    EXPECT_EQ(headers.getGrpcTimeoutValue(), "42s");
  }
}

Project: envoy

  void setReferenceInline(Handle handle, absl::string_view value) override {
    header_map_->setReferenceInline(handle, value);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

TEST(MatchHeadersTest, HeaderRegexMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "123"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "1234"},
                                              {"match-header", "123.456"}};
  const std::string yaml = R"EOF(
name: match-header
regex_match: \d{3}
  )EOF";

  std::vector<HeaderUtility::HeaderDataPtr> header_data;
  header_data.push_back(
      std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(yaml)));
  EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data));
}

Project: envoy

TEST_F(ExtractorTest, TestMultipleTokens) {
  auto headers = TestRequestHeaderMapImpl{
      {":path", "/path?token_param=token3&access_token=token4"},
      {"token-header", "token2"},
      {"authorization", "Bearer token1"},
      {"prefix-header", "AAAtoken5"},
  };
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 5);

  EXPECT_EQ(tokens[0]->token(), "token1"); // from authorization
  EXPECT_EQ(tokens[1]->token(), "token5"); // from prefix-header
  EXPECT_EQ(tokens[2]->token(), "token2"); // from token-header
  EXPECT_EQ(tokens[3]->token(), "token4"); // from access_token param
  EXPECT_EQ(tokens[4]->token(), "token3"); // from token_param param
}

Project: envoy

    std::list<HeaderEntryImpl>::const_iterator begin() const { return headers_.begin(); }

Project: envoy

    void finalizeTable() {
      CustomInlineHeaderRegistry::finalize<Interface::header_map_type>();
      auto& headers = CustomInlineHeaderRegistry::headers<Interface::header_map_type>();
      size_ = headers.size();
      for (const auto& header : headers) {
        this->add(header.first.get().c_str(), [&header](HeaderMapImpl& h) -> StaticLookupResponse {
          return {&h.inlineHeaders()[header.second], &header.first};
        });
      }
    }

Project: envoy

TEST_P(RBACIntegrationTest, HeaderMatchCondition) {
  config_helper_.addFilter(fmt::format(RBAC_CONFIG_HEADER_MATCH_CONDITION, "yyy"));
  initialize();

  codec_client_ = makeHttpConnection(lookupPort("http"));

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "POST"},
          {":path", "/path"},
          {":scheme", "http"},
          {":authority", "host"},
          {"xxx", "yyy"},
      },
      1024);
  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true);

  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
}

Project: envoy

  static std::string getIpv4Loopback() {
#ifdef __APPLE__
    return "127.0.0.1";
#else
    return "127.0.0.9";
#endif
  }

Project: envoy

  bool operator==(absl::string_view rhs) const { return getStringView() == rhs; }

Project: envoy

TEST_F(HeaderToMetadataTest, CookieRegexSubstitution) {
  const std::string config = R"EOF(
request_rules:
  - cookie: foo
    on_header_present:
      metadata_namespace: envoy.lb
      key: cluster
      regex_value_rewrite:
        pattern:
          google_re2: {}
          regex: "^(cluster[\\d\\w-]+)$"
        substitution: "\\1 matched"
)EOF";
  initializeFilter(config);

  // match.
  {
    Http::TestRequestHeaderMapImpl headers{{"cookie", "foo=cluster-prod-001"}};
    std::map<std::string, std::string> expected = {{"cluster", "cluster-prod-001 matched"}};

    EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
    EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected)));
    EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
  }

  // No match.
  {
    Http::TestRequestHeaderMapImpl headers{{"cookie", "foo=cluster"}};
    std::map<std::string, std::string> expected = {{"cluster", "cluster"}};

    EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
    EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected)));
    EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
  }
}

Project: envoy

TEST_F(ExtractorTest, TestPrefixHeaderFlexibleMatch1) {
  auto headers =
      TestRequestHeaderMapImpl{{"prefix-header", "preamble CCCDDD=jwt_token,extra=more"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);

  // Match issuer 7 with map key as: prefix-header + 'CCCDDD'
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer7"));
  EXPECT_EQ(tokens[0]->token(), "jwt_token");
}

Project: envoy

  bool empty() const override { return HeaderMapImpl::empty(); }

Project: envoy

DynamicMetadataMapIterator::DynamicMetadataMapIterator(DynamicMetadataMapWrapper& parent)
    : parent_{parent}, current_{parent_.streamInfo().dynamicMetadata().filter_metadata().begin()} {}

Project: envoy

void HeaderString::setReference(absl::string_view ref_value) {
  buffer_ = ref_value;
  ASSERT(valid());
}

Project: envoy

int DynamicMetadataMapWrapper::luaPairs(lua_State* state) {
  if (iterator_.get() != nullptr) {
    luaL_error(state, "cannot create a second iterator before completing the first");
  }

  iterator_.reset(DynamicMetadataMapIterator::create(state, *this), true);
  lua_pushcclosure(state, DynamicMetadataMapIterator::static_luaPairsIterator, 1);
  return 1;
}

Project: envoy

bool HeaderUtility::authorityIsValid(const absl::string_view header_value) {
  return nghttp2_check_authority(reinterpret_cast<const uint8_t*>(header_value.data()),
                                 header_value.size()) != 0;
}

Project: envoy

TEST(HeaderMapImplTest, InlineHeaderByteSize) {
  {
    TestRequestHeaderMapImpl headers;
    std::string foo = "foo";
    headers.setHost(foo);
    EXPECT_EQ(headers.byteSize(), 13);
  }
  {
    // Overwrite an inline headers with set.
    TestRequestHeaderMapImpl headers;
    std::string foo = "foo";
    headers.setHost(foo);
    std::string big_foo = "big_foo";
    headers.setHost(big_foo);
    EXPECT_EQ(headers.byteSize(), 17);
  }
  {
    // Overwrite an inline headers with setReference and clear.
    TestRequestHeaderMapImpl headers;
    std::string foo = "foo";
    headers.setHost(foo);
    EXPECT_EQ(headers.byteSize(), 13);
    std::string big_foo = "big_foo";
    headers.setReferenceHost(big_foo);
    EXPECT_EQ(headers.byteSize(), 17);
    EXPECT_EQ(1UL, headers.removeHost());
    EXPECT_EQ(headers.byteSize(), 0);
  }
  {
    // Overwrite an inline headers with set integer value.
    TestResponseHeaderMapImpl headers;
    uint64_t status = 200;
    headers.setStatus(status);
    EXPECT_EQ(headers.byteSize(), 10);
    uint64_t newStatus = 500;
    headers.setStatus(newStatus);
    EXPECT_EQ(headers.byteSize(), 10);
    EXPECT_EQ(1UL, headers.removeStatus());
    EXPECT_EQ(headers.byteSize(), 0);
  }
  {
    // Set an inline header, remove, and rewrite.
    TestResponseHeaderMapImpl headers;
    uint64_t status = 200;
    headers.setStatus(status);
    EXPECT_EQ(headers.byteSize(), 10);
    EXPECT_EQ(1UL, headers.removeStatus());
    EXPECT_EQ(headers.byteSize(), 0);
    uint64_t newStatus = 500;
    headers.setStatus(newStatus);
    EXPECT_EQ(headers.byteSize(), 10);
  }
}

Project: envoy

TEST_F(HeaderToMetadataTest, IgnoreCookieValueUseConstant) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - cookie: meh
    on_header_present:
      key: meh
      value: some_value
      type: STRING
    remove: false
)EOF";
  initializeFilter(response_config_yaml);
  Http::TestResponseHeaderMapImpl incoming_headers{{"cookie", "meh=foo"}};
  std::map<std::string, std::string> expected = {{"meh", "some_value"}};

  EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_,
              setDynamicMetadata(HttpFilterNames::get().HeaderToMetadata, MapEq(expected)));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false));
}

Project: envoy

  JwtLocationBase(const std::string& token, const absl::node_hash_set<std::string>& issuers)
      : token_(token), specified_issuers_(issuers) {}

Project: envoy

ExtractorConstPtr Extractor::create(const JwtProviderList& providers) {
  return std::make_unique<ExtractorImpl>(providers);
}

Project: envoy

    const std::string& backingString() const { return result_backing_string_; }

Project: envoy

HeaderMap::NonConstGetResult HeaderMapImpl::getExisting(const LowerCaseString& key) {
  // Attempt a trie lookup first to see if the user is requesting an O(1) header. This may be
  // relatively common in certain header matching / routing patterns.
  // TODO(mattklein123): Add inline handle support directly to the header matcher code to support
  // this use case more directly.
  HeaderMap::NonConstGetResult ret;
  auto lookup = staticLookup(key.get());
  if (lookup.has_value()) {
    if (*lookup.value().entry_ != nullptr) {
      ret.push_back(*lookup.value().entry_);
    }
    return ret;
  }

  // If the requested header is not an O(1) header we do a full scan. Doing the trie lookup is
  // wasteful in the miss case, but is present for code consistency with other functions that do
  // similar things.
  // TODO(mattklein123): The full scan here and in remove() are the biggest issues with this
  // implementation for certain use cases. We can either replace this with a totally different
  // implementation or potentially create a lazy map if the size of the map is above a threshold.
  for (HeaderEntryImpl& header : headers_) {
    if (header.key() == key.get().c_str()) {
      ret.push_back(&header);
    }
  }

  return ret;
}

Project: envoy

  typename CustomInlineHeaderRegistry::Handle<type> handle() { return handle_; }

Project: envoy

  static std::vector<HeaderUtility::HeaderDataPtr> buildHeaderDataVector(
      const Protobuf::RepeatedPtrField<envoy::config::route::v3::HeaderMatcher>& header_matchers) {
    std::vector<HeaderUtility::HeaderDataPtr> ret;
    for (const auto& header_matcher : header_matchers) {
      ret.emplace_back(std::make_unique<HeaderUtility::HeaderData>(header_matcher));
    }
    return ret;
  }

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, IteratorAcrossYield) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      iterator = pairs(object)
      coroutine.yield()
      iterator()
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers{{"foo", "bar"}, {"hello", "world"}};
  Filters::Common::Lua::LuaDeathRef<HeaderMapWrapper> wrapper(
      HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; }), true);
  yield_callback_ = [] {};
  start("callMe");
  wrapper.reset();
  EXPECT_THROW_WITH_MESSAGE(coroutine_->resume(0, [] {}), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:5: object used outside of proper scope");
}

Project: envoy

  bool operator!=(absl::string_view rhs) const { return getStringView() != rhs; }

Project: envoy

  void setReferenceKey(const LowerCaseString& key, absl::string_view value) override {
    header_map_->setReferenceKey(key, value);
  }

Project: envoy

  int size() const override { return value_ == nullptr ? 0 : value_->size(); }

Project: envoy

  template <class It> static void initFromInitList(HeaderMap& new_header_map, It begin, It end) {
    for (auto it = begin; it != end; ++it) {
      static_assert(std::is_same<decltype(it->first), LowerCaseString>::value,
                    "iterator must be pair and the first value of them must be LowerCaseString");
      HeaderString key_string;
      key_string.setCopy(it->first.get().c_str(), it->first.get().size());
      HeaderString value_string;
      value_string.setCopy(it->second.c_str(), it->second.size());
      new_header_map.addViaMove(std::move(key_string), std::move(value_string));
    }
  }

Project: envoy

  size_t removeIf(const HeaderMap::HeaderMatchPredicate& predicate) override {
    size_t headers_removed = header_map_->removeIf(predicate);
    header_map_->verifyByteSizeInternalForTest();
    return headers_removed;
  }

Project: envoy

  decodeResources(std::initializer_list<MessageType> resources,
                  const std::string& name_field = "name") {
    Config::DecodedResourcesWrapper decoded_resources;
    for (const auto& resource : resources) {
      auto owned_resource = std::make_unique<MessageType>(resource);
      decoded_resources.owned_resources_.emplace_back(new Config::DecodedResourceImpl(
          std::move(owned_resource), MessageUtil::getStringField(resource, name_field), {}, ""));
      decoded_resources.refvec_.emplace_back(*decoded_resources.owned_resources_.back());
    }
    return decoded_resources;
  }

Project: envoy

  explicit LowerCaseString(const std::string& new_string) : string_(new_string) {
    ASSERT(valid());
    lower();
  }

Project: envoy

void HeaderString::setCopy(const char* data, uint32_t size) {
  ASSERT(validHeaderString(absl::string_view(data, size)));

  if (!absl::holds_alternative<InlineHeaderVector>(buffer_)) {
    // Switching from Type::Reference to Type::Inline
    buffer_ = InlineHeaderVector();
  }

  getInVec(buffer_).reserve(size);
  getInVec(buffer_).assign(data, data + size);
  ASSERT(valid());
}

Project: envoy

TEST_F(HeaderToMetadataTest, NumberTypeTest) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-authenticated
    on_header_present:
      key: auth
      type: NUMBER
)EOF";
  initializeFilter(response_config_yaml);
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-authenticated", "1"}};
  std::map<std::string, int> expected = {{"auth", 1}};
  Http::TestResponseHeaderMapImpl empty_headers;

  EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_,
              setDynamicMetadata(HttpFilterNames::get().HeaderToMetadata, MapEqNum(expected)));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false));
}

Project: envoy

TEST(HeaderIsValidTest, IsConnectResponse) {
  RequestHeaderMapPtr connect_request{new TestRequestHeaderMapImpl{{":method", "CONNECT"}}};
  RequestHeaderMapPtr get_request{new TestRequestHeaderMapImpl{{":method", "GET"}}};
  TestResponseHeaderMapImpl success_response{{":status", "200"}};
  TestResponseHeaderMapImpl failure_response{{":status", "500"}};

  EXPECT_TRUE(HeaderUtility::isConnectResponse(connect_request.get(), success_response));
  EXPECT_FALSE(HeaderUtility::isConnectResponse(connect_request.get(), failure_response));
  EXPECT_FALSE(HeaderUtility::isConnectResponse(nullptr, success_response));
  EXPECT_FALSE(HeaderUtility::isConnectResponse(get_request.get(), success_response));
}

Project: envoy

TEST(Context, InvalidRequest) {
  Http::TestRequestHeaderMapImpl header_map{{"referer", "dogs.com"}};
  Protobuf::Arena arena;
  HeadersWrapper<Http::RequestHeaderMap> headers(arena, &header_map);
  auto header = headers[CelValue::CreateStringView("dogs.com\n")];
  EXPECT_FALSE(header.has_value());
}

Project: envoy

absl::optional<CelValue> PeerWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();
  if (value == Address) {
    if (local_) {
      return CelValue::CreateStringView(info_.downstreamLocalAddress()->asStringView());
    } else {
      return CelValue::CreateStringView(info_.downstreamRemoteAddress()->asStringView());
    }
  } else if (value == Port) {
    if (local_) {
      if (info_.downstreamLocalAddress()->ip() != nullptr) {
        return CelValue::CreateInt64(info_.downstreamLocalAddress()->ip()->port());
      }
    } else {
      if (info_.downstreamRemoteAddress()->ip() != nullptr) {
        return CelValue::CreateInt64(info_.downstreamRemoteAddress()->ip()->port());
      }
    }
  }

  return {};
}

Project: envoy

TEST(HeaderIsValidTest, InvalidHeaderValuesAreRejected) {
  // ASCII values 1-31 are control characters (with the exception of ASCII
  // values 9, 10, and 13 which are a horizontal tab, line feed, and carriage
  // return, respectively), and are not valid in an HTTP header, per
  // RFC 7230, section 3.2
  for (int i = 0; i < 32; i++) {
    if (i == 9) {
      continue;
    }

    EXPECT_FALSE(HeaderUtility::headerValueIsValid(std::string(1, i)));
  }
}

Project: envoy

  static std::unique_ptr<ResponseHeaderMapImpl> create() {
    return std::unique_ptr<ResponseHeaderMapImpl>(new (inlineHeadersSize())
                                                      ResponseHeaderMapImpl());
  }

Project: envoy

  void clear() override {
    header_map_->clear();
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

  bool has(const std::string& key) const { return get(LowerCaseString(key)) != nullptr; }

Project: envoy

TEST(GetAllOfHeaderAsStringTest, All) {
  const LowerCaseString test_header("test");
  {
    TestRequestHeaderMapImpl headers;
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_FALSE(ret.result().has_value());
    EXPECT_TRUE(ret.backingString().empty());
  }
  {
    TestRequestHeaderMapImpl headers{{"test", "foo"}};
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_EQ("foo", ret.result().value());
    EXPECT_TRUE(ret.backingString().empty());
  }
  {
    TestRequestHeaderMapImpl headers{{"test", "foo"}, {"test", "bar"}};
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_EQ("foo,bar", ret.result().value());
    EXPECT_EQ("foo,bar", ret.backingString());
  }
  {
    TestRequestHeaderMapImpl headers{{"test", ""}, {"test", "bar"}};
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_EQ(",bar", ret.result().value());
    EXPECT_EQ(",bar", ret.backingString());
  }
  {
    TestRequestHeaderMapImpl headers{{"test", ""}, {"test", ""}};
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_EQ(",", ret.result().value());
    EXPECT_EQ(",", ret.backingString());
  }
  {
    TestRequestHeaderMapImpl headers{
        {"test", "a"}, {"test", "b"}, {"test", "c"}, {"test", ""}, {"test", ""}};
    const auto ret = HeaderUtility::getAllOfHeaderAsString(headers, test_header);
    EXPECT_EQ("a,b,c,,", ret.result().value());
    EXPECT_EQ("a,b,c,,", ret.backingString());
    // Make sure copying the return value works correctly.
    const auto ret2 = ret; // NOLINT(performance-unnecessary-copy-initialization)
    EXPECT_EQ(ret2.result(), ret.result());
    EXPECT_EQ(ret2.backingString(), ret.backingString());
    EXPECT_EQ(ret2.result().value().data(), ret2.backingString().data());
    EXPECT_NE(ret2.result().value().data(), ret.backingString().data());
  }
}

Project: envoy

void HeaderMapImpl::verifyByteSizeInternalForTest() const {
  // Computes the total byte size by summing the byte size of the keys and values.
  uint64_t byte_size = 0;
  for (const HeaderEntryImpl& header : headers_) {
    byte_size += header.key().size();
    byte_size += header.value().size();
  }
  ASSERT(cached_byte_size_ == byte_size);
}

Project: envoy

  static void loadFromFile(const std::string& path, Protobuf::Message& message, Api::Api& api,
                           bool preserve_original_type = false) {
    MessageUtil::loadFromFile(path, message, ProtobufMessage::getStrictValidationVisitor(), api);
    if (!preserve_original_type) {
      Config::VersionConverter::eraseOriginalTypeInformation(message);
    }
  }

Project: envoy

size_t HeaderMapImpl::remove(const LowerCaseString& key) {
  auto lookup = staticLookup(key.get());
  if (lookup.has_value()) {
    const size_t old_size = headers_.size();
    removeInline(lookup.value().entry_);
    return old_size - headers_.size();
  } else {
    // TODO(mattklein123): When the lazy map is implemented we can stop using removeIf() here.
    return HeaderMapImpl::removeIf([&key](const HeaderEntry& entry) -> bool {
      return key.get() == entry.key().getStringView();
    });
  }
}

Project: envoy

void HeaderMapImpl::insertByKey(HeaderString&& key, HeaderString&& value) {
  auto lookup = staticLookup(key.getStringView());
  if (lookup.has_value()) {
    key.clear();
    if (*lookup.value().entry_ == nullptr) {
      maybeCreateInline(lookup.value().entry_, *lookup.value().key_, std::move(value));
    } else {
      const uint64_t added_size =
          appendToHeader((*lookup.value().entry_)->value(), value.getStringView());
      addSize(added_size);
      value.clear();
    }
  } else {
    addSize(key.size() + value.size());
    std::list<HeaderEntryImpl>::iterator i = headers_.insert(std::move(key), std::move(value));
    i->entry_ = i;
  }
}

Project: envoy

  size_t remove(const LowerCaseString& key) override {
    size_t headers_removed = header_map_->remove(key);
    header_map_->verifyByteSizeInternalForTest();
    return headers_removed;
  }

Project: envoy

TEST(HeaderDataConstructorTest, PresentMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
present_match: true
  )EOF";

  HeaderUtility::HeaderData header_data =
      HeaderUtility::HeaderData(parseHeaderMatcherFromYaml(yaml));

  EXPECT_EQ("test-header", header_data.name_.get());
  EXPECT_EQ(HeaderUtility::HeaderMatchType::Present, header_data.header_match_type_);
  EXPECT_EQ("", header_data.value_);
}

Project: envoy

TEST_F(ExtractorTest, TestPrefixHeaderFlexibleMatch3) {
  auto headers = TestRequestHeaderMapImpl{
      {"prefix-header", "creds={\"authLevel\": \"20\", \"CCCDDD\": \"and0X3Rva2Vu\"}"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 2);

  // Match issuer 8 with map key as: prefix-header + '"CCCDDD"'
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer8"));
  EXPECT_EQ(tokens[0]->token(), "and0X3Rva2Vu");

  // Match issuer 7 with map key as: prefix-header + 'CCCDDD'
  EXPECT_TRUE(tokens[1]->isIssuerSpecified("issuer7"));
  EXPECT_EQ(tokens[1]->token(), "and0X3Rva2Vu");
}

Project: envoy

bool Config::configToVector(const ProtobufRepeatedRule& proto_rules,
                            HeaderToMetadataRules& vector) {
  if (proto_rules.empty()) {
    ENVOY_LOG(debug, "no rules provided");
    return false;
  }

  for (const auto& entry : proto_rules) {
    vector.emplace_back(entry);
  }

  return true;
}

Project: envoy

envoy::config::route::v3::HeaderMatcher parseHeaderMatcherFromYaml(const std::string& yaml) {
  envoy::config::route::v3::HeaderMatcher header_matcher;
  TestUtility::loadFromYaml(yaml, header_matcher);
  return header_matcher;
}

Project: envoy

bool HeaderMapImpl::operator!=(const HeaderMap& rhs) const { return !operator==(rhs); }

Project: envoy

void HeaderMapImpl::iterateReverse(HeaderMap::ConstIterateCb cb) const {
  for (auto it = headers_.rbegin(); it != headers_.rend(); it++) {
    if (cb(*it) == HeaderMap::Iterate::Break) {
      break;
    }
  }
}

Project: envoy

TEST_F(ExtractorTest, TestDefaultParamLocation) {
  auto headers = TestRequestHeaderMapImpl{{":path", "/path?access_token=jwt_token"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);

  // Only the issue1 is using default header location.
  EXPECT_EQ(tokens[0]->token(), "jwt_token");
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer1"));

  // Other issuers are using custom locations
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer2"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer3"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer4"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer5"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("unknown_issuer"));

  tokens[0]->removeJwt(headers);
}

Project: envoy

    bool matchesHeaders(const HeaderMap& headers) const override {
      return HeaderUtility::matchHeaders(headers, *this);
    };

Project: envoy

absl::optional<CelValue> RequestWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();

  if (value == Headers) {
    return CelValue::CreateMap(&headers_);
  } else if (value == Time) {
    return CelValue::CreateTimestamp(absl::FromChrono(info_.startTime()));
  } else if (value == Size) {
    // it is important to make a choice whether to rely on content-length vs stream info
    // (which is not available at the time of the request headers)
    if (headers_.value_ != nullptr && headers_.value_->ContentLength() != nullptr) {
      int64_t length;
      if (absl::SimpleAtoi(headers_.value_->getContentLengthValue(), &length)) {
        return CelValue::CreateInt64(length);
      }
    } else {
      return CelValue::CreateInt64(info_.bytesReceived());
    }
  } else if (value == TotalSize) {
    return CelValue::CreateInt64(info_.bytesReceived() +
                                 (headers_.value_ ? headers_.value_->byteSize() : 0));
  } else if (value == Duration) {
    auto duration = info_.requestComplete();
    if (duration.has_value()) {
      return CelValue::CreateDuration(absl::FromChrono(duration.value()));
    }
  } else if (value == Protocol) {
    if (info_.protocol().has_value()) {
      return CelValue::CreateString(&Http::Utility::getProtocolString(info_.protocol().value()));
    } else {
      return {};
    }
  }

  if (headers_.value_ != nullptr) {
    if (value == Path) {
      return convertHeaderEntry(headers_.value_->Path());
    } else if (value == UrlPath) {
      absl::string_view path = headers_.value_->getPathValue();
      size_t query_offset = path.find('?');
      if (query_offset == absl::string_view::npos) {
        return CelValue::CreateStringView(path);
      }
      return CelValue::CreateStringView(path.substr(0, query_offset));
    } else if (value == Host) {
      return convertHeaderEntry(headers_.value_->Host());
    } else if (value == Scheme) {
      return convertHeaderEntry(headers_.value_->Scheme());
    } else if (value == Method) {
      return convertHeaderEntry(headers_.value_->Method());
    } else if (value == Referer) {
      return convertHeaderEntry(headers_.value_->getInline(referer_handle.handle()));
    } else if (value == ID) {
      return convertHeaderEntry(headers_.value_->RequestId());
    } else if (value == UserAgent) {
      return convertHeaderEntry(headers_.value_->UserAgent());
    }
  }
  return {};
}

Project: envoy

TEST(HeaderMapImplTest, HostHeader) {
  TestRequestHeaderMapImpl request_headers{{"host", "foo"}};
  EXPECT_EQ(request_headers.size(), 1);
  EXPECT_EQ(request_headers.get_(":authority"), "foo");

  TestRequestTrailerMapImpl request_trailers{{"host", "foo"}};
  EXPECT_EQ(request_trailers.size(), 1);
  EXPECT_EQ(request_trailers.get_("host"), "foo");

  TestResponseHeaderMapImpl response_headers{{"host", "foo"}};
  EXPECT_EQ(response_headers.size(), 1);
  EXPECT_EQ(response_headers.get_("host"), "foo");

  TestResponseTrailerMapImpl response_trailers{{"host", "foo"}};
  EXPECT_EQ(response_trailers.size(), 1);
  EXPECT_EQ(response_trailers.get_("host"), "foo");
}

Project: envoy

  void setReference(const LowerCaseString& key, absl::string_view value) override {
    header_map_->setReference(key, value);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

    std::list<HeaderEntryImpl>::iterator erase(std::list<HeaderEntryImpl>::iterator i) {
      if (pseudo_headers_end_ == i) {
        pseudo_headers_end_++;
      }
      return headers_.erase(i);
    }

Project: envoy

HeaderString::HeaderString(absl::string_view ref_value) : buffer_(ref_value) { ASSERT(valid()); }

Project: envoy

TEST_F(ExtractorTest, TestExtractParam) {
  auto headers = TestRequestHeaderMapImpl{
      {":path", "/path?token_param=token3&access_token=token4"},
      {"token-header", "token2"},
      {"authorization", "Bearer token1"},
      {"prefix-header", "AAAtoken5"},
  };
  JwtProvider provider;
  provider.set_issuer("foo");
  auto extractor = Extractor::create(provider);
  auto tokens = extractor->extract(headers);
  EXPECT_EQ(tokens.size(), 2);
  EXPECT_EQ(tokens[0]->token(), "token1");
  EXPECT_EQ(tokens[1]->token(), "token4");
  auto header = provider.add_from_headers();
  header->set_name("prefix-header");
  header->set_value_prefix("AAA");
  provider.add_from_params("token_param");
  extractor = Extractor::create(provider);
  tokens = extractor->extract(headers);
  EXPECT_EQ(tokens.size(), 2);
  EXPECT_EQ(tokens[0]->token(), "token5");
  EXPECT_EQ(tokens[1]->token(), "token3");
}

Project: envoy

  uint64_t byteSize() const override { return HeaderMapImpl::byteSize(); }

Project: envoy

MATCHER_P(ProtoEq, expected, "") {
  const bool equal =
      TestUtility::protoEqual(arg, expected, /*ignore_repeated_field_ordering=*/false);
  if (!equal) {
    *result_listener << "\n"
                     << "==========================Expected proto:===========================\n"
                     << expected.DebugString()
                     << "------------------is not equal to actual proto:---------------------\n"
                     << arg.DebugString()
                     << "====================================================================\n";
  }
  return equal;
}

Project: envoy

TEST(HeaderDataConstructorTest, PrefixMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
prefix_match: value
  )EOF";

  HeaderUtility::HeaderData header_data =
      HeaderUtility::HeaderData(parseHeaderMatcherFromYaml(yaml));

  EXPECT_EQ("test-header", header_data.name_.get());
  EXPECT_EQ(HeaderUtility::HeaderMatchType::Prefix, header_data.header_match_type_);
  EXPECT_EQ("value", header_data.value_);
}

Project: envoy

  static absl::optional<Handle<type>> getInlineHeader(const LowerCaseString& header_name) {
    ASSERT(mutableFinalized<type>());
    auto& map = mutableRegistrationMap<type>();
    auto entry = map.find(header_name);
    if (entry != map.end()) {
      return Handle<type>(entry);
    }
    return absl::nullopt;
  }

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, SetGetAndIterateDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
      function callMe(object)
        testPrint(type(object:dynamicMetadata()))
        object:dynamicMetadata():set("envoy.lb", "foo", "bar")
        object:dynamicMetadata():set("envoy.lb", "so", "cool")

        testPrint(object:dynamicMetadata():get("envoy.lb")["foo"])
        testPrint(object:dynamicMetadata():get("envoy.lb")["so"])

        for filter, entry in pairs(object:dynamicMetadata()) do
          for key, value in pairs(entry) do
            testPrint(string.format("'%s' '%s'", key, value))
          end
        end

        local function nRetVals(...)
          return select('#',...)
        end
        testPrint(tostring(nRetVals(object:dynamicMetadata():get("envoy.ngx"))))
      end
    )EOF"};

  InSequence s;
  setup(SCRIPT);

  StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem());
  EXPECT_EQ(0, stream_info.dynamicMetadata().filter_metadata_size());
  Filters::Common::Lua::LuaDeathRef<StreamInfoWrapper> wrapper(
      StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true);
  EXPECT_CALL(printer_, testPrint("userdata"));
  EXPECT_CALL(printer_, testPrint("bar"));
  EXPECT_CALL(printer_, testPrint("cool"));
  EXPECT_CALL(printer_, testPrint("'foo' 'bar'"));
  EXPECT_CALL(printer_, testPrint("'so' 'cool'"));
  EXPECT_CALL(printer_, testPrint("0"));
  start("callMe");

  EXPECT_EQ(1, stream_info.dynamicMetadata().filter_metadata_size());
  EXPECT_EQ("bar", stream_info.dynamicMetadata()
                       .filter_metadata()
                       .at("envoy.lb")
                       .fields()
                       .at("foo")
                       .string_value());
  wrapper.reset();
}

Project: envoy

size_t HeaderMapImpl::removeInline(HeaderEntryImpl** ptr_to_entry) {
  if (!*ptr_to_entry) {
    return 0;
  }

  HeaderEntryImpl* entry = *ptr_to_entry;
  const uint64_t size_to_subtract = entry->entry_->key().size() + entry->entry_->value().size();
  subtractSize(size_to_subtract);
  *ptr_to_entry = nullptr;
  headers_.erase(entry->entry_);
  return 1;
}

Project: envoy

TEST_P(RBACIntegrationTest, Allowed) {
  useAccessLog("%RESPONSE_CODE_DETAILS%");
  config_helper_.addFilter(RBAC_CONFIG);
  initialize();

  codec_client_ = makeHttpConnection(lookupPort("http"));

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "GET"},
          {":path", "/"},
          {":scheme", "http"},
          {":authority", "host"},
          {"x-forwarded-for", "10.0.0.1"},
      },
      1024);
  waitForNextUpstreamRequest();
  upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true);

  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("200", response->headers().getStatusValue());
  EXPECT_THAT(waitForAccessLog(access_log_name_), testing::HasSubstr("via_upstream"));
}

Project: envoy

  static std::vector<Http::HeaderMatcherSharedPtr> buildHeaderMatcherVector(
      const Protobuf::RepeatedPtrField<envoy::config::route::v3::HeaderMatcher>& header_matchers) {
    std::vector<Http::HeaderMatcherSharedPtr> ret;
    for (const auto& header_matcher : header_matchers) {
      ret.emplace_back(std::make_shared<HeaderUtility::HeaderData>(header_matcher));
    }
    return ret;
  }

Project: envoy

  size_t removeIf(const HeaderMap::HeaderMatchPredicate& predicate) override {
    return HeaderMapImpl::removeIf(predicate);
  }

Project: envoy

TEST(HeaderStringTest, All) {
  // Static LowerCaseString constructor
  {
    LowerCaseString static_string("hello");
    HeaderString string(static_string);
    EXPECT_EQ("hello", string.getStringView());
    EXPECT_EQ(static_string.get(), string.getStringView());
    EXPECT_EQ(5U, string.size());
  }

  // Static LowerCaseString operators
  {
    LowerCaseString banana("banana");
    LowerCaseString lemon("lemon");
    EXPECT_TRUE(banana < lemon);
    EXPECT_TRUE(banana != lemon);
    EXPECT_TRUE(banana == banana);
  }

  // Static std::string constructor
  {
    std::string static_string("HELLO");
    HeaderString string(static_string);
    EXPECT_EQ("HELLO", string.getStringView());
    EXPECT_EQ(static_string, string.getStringView());
    EXPECT_EQ(5U, string.size());
  }

  // Static move constructor
  {
    std::string static_string("HELLO");
    HeaderString string1(static_string);
    HeaderString string2(std::move(string1));
    EXPECT_EQ("HELLO", string2.getStringView());
    EXPECT_EQ(static_string, string1.getStringView()); // NOLINT(bugprone-use-after-move)
    EXPECT_EQ(static_string, string2.getStringView());
    EXPECT_EQ(5U, string1.size());
    EXPECT_EQ(5U, string2.size());
  }

  // Inline move constructor
  {
    HeaderString string;
    string.setCopy("hello");
    EXPECT_FALSE(string.isReference());
    HeaderString string2(std::move(string));
    EXPECT_TRUE(string.empty()); // NOLINT(bugprone-use-after-move)
    EXPECT_FALSE(string.isReference());
    EXPECT_FALSE(string2.isReference());
    string.append("world", 5);
    EXPECT_EQ("world", string.getStringView());
    EXPECT_EQ(5UL, string.size());
    EXPECT_EQ("hello", string2.getStringView());
    EXPECT_EQ(5UL, string2.size());
  }

  // Inline move large constructor
  {
    std::string large(4096, 'a');
    HeaderString string;
    string.setCopy(large);
    EXPECT_FALSE(string.isReference());
    HeaderString string2(std::move(string));
    EXPECT_TRUE(string.empty()); // NOLINT(bugprone-use-after-move)
    EXPECT_FALSE(string.isReference());
    EXPECT_FALSE(string2.isReference());
    string.append("b", 1);
    EXPECT_EQ("b", string.getStringView());
    EXPECT_EQ(1UL, string.size());
    EXPECT_EQ(large, string2.getStringView());
    EXPECT_EQ(4096UL, string2.size());
  }

  // Static to inline number.
  {
    std::string static_string("HELLO");
    HeaderString string(static_string);
    string.setInteger(5);
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ("5", string.getStringView());
  }

  // Static to inline string.
  {
    std::string static_string("HELLO");
    HeaderString string(static_string);
    string.setCopy(static_string);
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ("HELLO", string.getStringView());
  }

  // Inline rtrim removes trailing whitespace only.
  {
    const std::string data_with_leading_lws = " \t\f\v  data";
    const std::string data_with_leading_and_trailing_lws = data_with_leading_lws + " \t\f\v";
    HeaderString string;
    string.append(data_with_leading_and_trailing_lws.data(),
                  data_with_leading_and_trailing_lws.size());
    EXPECT_EQ(data_with_leading_and_trailing_lws, string.getStringView());
    string.rtrim();
    EXPECT_NE(data_with_leading_and_trailing_lws, string.getStringView());
    EXPECT_EQ(data_with_leading_lws, string.getStringView());
  }

  // Static clear() does nothing.
  {
    std::string static_string("HELLO");
    HeaderString string(static_string);
    EXPECT_TRUE(string.isReference());
    string.clear();
    EXPECT_TRUE(string.isReference());
    EXPECT_EQ("HELLO", string.getStringView());
  }

  // Static to append.
  {
    std::string static_string("HELLO");
    HeaderString string(static_string);
    EXPECT_TRUE(string.isReference());
    string.append("a", 1);
    EXPECT_EQ("HELLOa", string.getStringView());
  }

  // Copy inline
  {
    HeaderString string;
    string.setCopy("hello");
    EXPECT_EQ("hello", string.getStringView());
    EXPECT_EQ(5U, string.size());
  }

  // Copy dynamic
  {
    HeaderString string;
    std::string large_value(4096, 'a');
    string.setCopy(large_value);
    EXPECT_EQ(large_value, string.getStringView());
    EXPECT_NE(large_value.c_str(), string.getStringView().data());
    EXPECT_EQ(4096U, string.size());
  }

  // Copy twice dynamic
  {
    HeaderString string;
    std::string large_value1(4096, 'a');
    string.setCopy(large_value1);
    std::string large_value2(2048, 'b');
    string.setCopy(large_value2);
    EXPECT_EQ(large_value2, string.getStringView());
    EXPECT_NE(large_value2.c_str(), string.getStringView().data());
    EXPECT_EQ(2048U, string.size());
  }

  // Copy twice dynamic with reallocate
  {
    HeaderString string;
    std::string large_value1(4096, 'a');
    string.setCopy(large_value1);
    std::string large_value2(16384, 'b');
    string.setCopy(large_value2);
    EXPECT_EQ(large_value2, string.getStringView());
    EXPECT_NE(large_value2.c_str(), string.getStringView().data());
    EXPECT_EQ(16384U, string.size());
  }

  // Copy twice inline to dynamic
  {
    HeaderString string;
    std::string large_value1(16, 'a');
    string.setCopy(large_value1);
    std::string large_value2(16384, 'b');
    string.setCopy(large_value2);
    EXPECT_EQ(large_value2, string.getStringView());
    EXPECT_NE(large_value2.c_str(), string.getStringView().data());
    EXPECT_EQ(16384U, string.size());
  }

  // Copy, exactly filling inline capacity
  //
  // ASAN does not catch the clobber in the case where the code writes one past the
  // end of the inline buffer. To ensure coverage the next block checks that setCopy
  // is not introducing a NUL in a way that does not rely on an actual clobber getting
  // detected.
  {
    HeaderString string;
    std::string large(128, 'z');
    string.setCopy(large);
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ(string.getStringView(), large);
  }

  // Copy, exactly filling dynamic capacity
  //
  // ASAN should catch a write one past the end of the inline buffer. This test
  // forces a dynamic buffer with one copy and then fills it with the next.
  {
    HeaderString string;
    // Force dynamic vector allocation with setCopy of inline buffer size + 1.
    std::string large1(129, 'z');
    string.setCopy(large1);
    EXPECT_FALSE(string.isReference());
    // Dynamic capacity in setCopy is 2x required by the size.
    // So to fill it exactly setCopy with a total of 256 chars.
    std::string large2(256, 'z');
    string.setCopy(large2);
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ(string.getStringView(), large2);
  }

  // Append, small buffer to inline
  {
    HeaderString string;
    std::string test(128, 'a');
    string.append(test.c_str(), test.size());
    EXPECT_FALSE(string.isReference());
    string.append("a", 1);
    EXPECT_FALSE(string.isReference());
    test += 'a';
    EXPECT_EQ(test, string.getStringView());
  }

  // Append into inline twice, then shift to dynamic.
  {
    HeaderString string;
    string.append("hello", 5);
    EXPECT_EQ("hello", string.getStringView());
    EXPECT_EQ(5U, string.size());
    string.append("world", 5);
    EXPECT_EQ("helloworld", string.getStringView());
    EXPECT_EQ(10U, string.size());
    std::string large(4096, 'a');
    string.append(large.c_str(), large.size());
    large = "helloworld" + large;
    EXPECT_EQ(large, string.getStringView());
    EXPECT_EQ(4106U, string.size());
  }

  // Append, realloc close to limit with small buffer.
  {
    HeaderString string;
    std::string large(129, 'a');
    string.append(large.c_str(), large.size());
    EXPECT_FALSE(string.isReference());
    std::string large2(120, 'b');
    string.append(large2.c_str(), large2.size());
    std::string large3(32, 'c');
    string.append(large3.c_str(), large3.size());
    EXPECT_EQ((large + large2 + large3), string.getStringView());
    EXPECT_EQ(281U, string.size());
  }

  // Append, exactly filling dynamic capacity
  //
  // ASAN should catch a write one past the end of the dynamic buffer. This test
  // forces a dynamic buffer with one copy and then fills it with the next.
  {
    HeaderString string;
    // Force dynamic allocation with setCopy of inline buffer size + 1.
    std::string large1(129, 'z');
    string.setCopy(large1);
    EXPECT_FALSE(string.isReference());
    // Dynamic capacity in setCopy is 2x required by the size.
    // So to fill it exactly append 127 chars for a total of 256 chars.
    std::string large2(127, 'z');
    string.append(large2.c_str(), large2.size());
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ(string.getStringView(), large1 + large2);
  }

  // Set integer, inline
  {
    HeaderString string;
    string.setInteger(123456789);
    EXPECT_EQ("123456789", string.getStringView());
    EXPECT_EQ(9U, string.size());
  }

  // Set integer, dynamic
  {
    HeaderString string;
    std::string large(129, 'a');
    string.append(large.c_str(), large.size());
    string.setInteger(123456789);
    EXPECT_EQ("123456789", string.getStringView());
    EXPECT_EQ(9U, string.size());
    EXPECT_FALSE(string.isReference());
  }

  // Set static, switch to inline, back to static.
  {
    const std::string static_string = "hello world";
    HeaderString string;
    string.setReference(static_string);
    EXPECT_EQ(string.getStringView(), static_string);
    EXPECT_EQ(11U, string.size());
    EXPECT_TRUE(string.isReference());

    const std::string large(129, 'a');
    string.setCopy(large);
    EXPECT_NE(string.getStringView().data(), large.c_str());
    EXPECT_FALSE(string.isReference());

    string.setReference(static_string);
    EXPECT_EQ(string.getStringView(), static_string);
    EXPECT_EQ(11U, string.size());
    EXPECT_TRUE(string.isReference());
  }

  // getString
  {
    std::string static_string("HELLO");
    HeaderString headerString1(static_string);
    absl::string_view retString1 = headerString1.getStringView();
    EXPECT_EQ("HELLO", retString1);
    EXPECT_EQ(5U, retString1.size());

    HeaderString headerString2;
    absl::string_view retString2 = headerString2.getStringView();
    EXPECT_EQ(0U, retString2.size());
  }

  // inlineTransform
  {
    const std::string static_string = "HELLO";
    HeaderString string;
    string.setCopy(static_string);
    string.inlineTransform([](char c) { return static_cast<uint8_t>(tolower(c)); });
    EXPECT_FALSE(string.isReference());
    EXPECT_EQ(5U, string.size());
    EXPECT_EQ(string.getStringView(), "hello");
    string.inlineTransform(toupper);
    EXPECT_EQ(string.getStringView(), static_string);
    EXPECT_EQ(5U, string.size());
    EXPECT_FALSE(string.isReference());
  }
}

Project: envoy

static inline bool validHeaderString(absl::string_view s) {
  // If you modify this list of illegal embedded characters you will probably
  // want to change header_map_fuzz_impl_test at the same time.
  for (const char c : s) {
    switch (c) {
    case '\0':
      FALLTHRU;
    case '\r':
      FALLTHRU;
    case '\n':
      return false;
    default:
      continue;
    }
  }
  return true;
}

Project: envoy

const std::string& HeaderToMetadataFilter::decideNamespace(const std::string& nspace) const {
  return nspace.empty() ? HttpFilterNames::get().HeaderToMetadata : nspace;
}

Project: envoy

  HeadersWrapper(Protobuf::Arena& arena, const T* value) : arena_(arena), value_(value) {}

Project: envoy

  bool empty() const override { return header_map_->empty(); }

Project: envoy

  void addReferenceKey(const LowerCaseString& key, absl::string_view value) override {
    header_map_->addReferenceKey(key, value);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

  bool empty() const override { return false; }

Project: envoy

  HeaderMap::GetResult getAll(const LowerCaseString& key) const override {
    return header_map_->getAll(key);
  }

Project: envoy

TEST_F(ExtractorTest, TestDoubleCustomHeaderToken) {
  auto headers = TestRequestHeaderMapImpl{{"token-header", "jwt_token"}, {"token-header", "foo"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);
  EXPECT_EQ(tokens[0]->token(), "jwt_token,foo");
}

Project: envoy

const InlineHeaderVector& getInVec(const VariantHeader& buffer) {
  return absl::get<InlineHeaderVector>(buffer);
}

Project: envoy

TEST_F(HeaderToMetadataTest, NoCookieValue) {
  const std::string config = R"EOF(
request_rules:
  - cookie: foo
    on_header_missing:
      metadata_namespace: envoy.lb
      key: foo
      value: some_value
      type: STRING
)EOF";
  initializeFilter(config);
  Http::TestRequestHeaderMapImpl headers{{"cookie", ""}};
  std::map<std::string, std::string> expected = {{"foo", "some_value"}};

  EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected)));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
}

Project: envoy

  template <Type type> static const RegistrationMap& headers() {
    ASSERT(mutableFinalized<type>());
    return mutableRegistrationMap<type>();
  }

Project: envoy

  static void loadFromYamlAndValidate(const std::string& yaml, MessageType& message,
                                      bool preserve_original_type = false,
                                      bool avoid_boosting = false) {
    MessageUtil::loadFromYamlAndValidate(
        yaml, message, ProtobufMessage::getStrictValidationVisitor(), avoid_boosting);
    if (!preserve_original_type) {
      Config::VersionConverter::eraseOriginalTypeInformation(message);
    }
  }

Project: envoy

TEST(TestHeaderMapImplDeathTest, TestHeaderLengthChecks) {
  HeaderString value;
  value.setCopy("some;");
  EXPECT_DEATH(value.append(nullptr, std::numeric_limits<uint32_t>::max()),
               "Trying to allocate overly large headers.");

  std::string source("hello");
  HeaderString reference;
  reference.setReference(source);
  EXPECT_DEATH(reference.append(nullptr, std::numeric_limits<uint32_t>::max()),
               "Trying to allocate overly large headers.");
}

Project: envoy

  void addReferenceKey(const LowerCaseString& key, uint64_t value) override {
    header_map_->addReferenceKey(key, value);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

  void setReference(const LowerCaseString& key, absl::string_view value) override {
    HeaderMapImpl::setReference(key, value);
  }

Project: envoy

void ExtractorImpl::addQueryParamConfig(const std::string& issuer, const std::string& param) {
  auto& param_location_spec = param_locations_[param];
  param_location_spec.specified_issuers_.insert(issuer);
}

Project: envoy

TEST_F(ExtractorTest, TestNoToken) {
  auto headers = TestRequestHeaderMapImpl{};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 0);
}

Project: envoy

void HeaderString::clear() {
  if (type() == Type::Inline) {
    getInVec(buffer_).clear();
  }
}

Project: envoy

bool HeaderUtility::isConnect(const RequestHeaderMap& headers) {
  return headers.Method() && headers.Method()->value() == Http::Headers::get().MethodValues.Connect;
}

Project: envoy

TEST_F(HeaderToMetadataTest, PerRouteOverride) {
  // Global config is empty.
  initializeFilter("{}");
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-VERSION", "0xdeadbeef"}};
  std::map<std::string, std::string> expected = {{"version", "0xdeadbeef"}};

  // Setup per route config.
  envoy::extensions::filters::http::header_to_metadata::v3::Config config_proto;
  TestUtility::loadFromYaml(request_config_yaml, config_proto);
  Config per_route_config(config_proto, true);
  EXPECT_CALL(decoder_callbacks_.route_->route_entry_.virtual_host_,
              perFilterConfig(HttpFilterNames::get().HeaderToMetadata))
      .WillOnce(Return(&per_route_config));

  EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_, setDynamicMetadata("envoy.lb", MapEq(expected)));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(incoming_headers, false));
  Http::MetadataMap metadata_map{{"metadata", "metadata"}};
  EXPECT_EQ(Http::FilterMetadataStatus::Continue, filter_->decodeMetadata(metadata_map));
  Buffer::OwnedImpl data("data");
  EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data, false));
  Http::TestRequestTrailerMapImpl incoming_trailers;
  EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(incoming_trailers));
  filter_->onDestroy();
}

Project: envoy

TEST_F(HeaderToMetadataTest, NoMissingWhenHeaderIsPresent) {
  const std::string config = R"EOF(
request_rules:
  - header: x-version
    on_header_missing:
      metadata_namespace: envoy.lb
      key: version
      value: some_value
      type: STRING
)EOF";
  initializeFilter(config);
  Http::TestRequestHeaderMapImpl headers{{"x-version", "19"}};

  EXPECT_CALL(decoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_, setDynamicMetadata(_, _)).Times(0);
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(headers, false));
}

Project: envoy

void ExtractorImpl::sanitizePayloadHeaders(Http::HeaderMap& headers) const {
  for (const auto& header : forward_payload_headers_) {
    headers.remove(header);
  }
}

Project: envoy

TEST(MatchHeadersTest, HeaderPresentInverseMatch) {
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123"}};
  TestRequestHeaderMapImpl matching_headers{{"nonmatch-header", "1234"},
                                            {"other-nonmatch-header", "123.456"}};

  const std::string yaml = R"EOF(
name: match-header
present_match: true
invert_match: true
  )EOF";

  std::vector<HeaderUtility::HeaderDataPtr> header_data;
  header_data.push_back(
      std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(yaml)));
  EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers, header_data));
}

Project: envoy

  template <class MessageType> static MessageType parseYaml(const std::string& yaml) {
    MessageType message;
    TestUtility::loadFromYaml(yaml, message);
    return message;
  }

Project: envoy

void HeaderMapImpl::addSize(uint64_t size) { cached_byte_size_ += size; }

Project: envoy

  bool isIssuerSpecified(const std::string& issuer) const override {
    return specified_issuers_.find(issuer) != specified_issuers_.end();
  }

Project: envoy

StreamInfo::StreamInfo& DynamicMetadataMapWrapper::streamInfo() { return parent_.stream_info_; }

Project: envoy

  bool isReference() const { return type() == Type::Reference; }

Project: envoy

  RegisterCustomInlineHeader(const LowerCaseString& header)
      : handle_(CustomInlineHeaderRegistry::registerInlineHeader<type>(header)) {}

Project: envoy

void HeaderString::rtrim() {
  ASSERT(type() == Type::Inline);
  absl::string_view original = getStringView();
  absl::string_view rtrimmed = StringUtil::rtrim(original);
  if (original.size() != rtrimmed.size()) {
    getInVec(buffer_).resize(rtrimmed.size());
  }
}

Project: envoy

void HeaderToMetadataFilter::writeHeaderToMetadata(Http::HeaderMap& headers,
                                                   const HeaderToMetadataRules& rules,
                                                   Http::StreamFilterCallbacks& callbacks) {
  StructMap structs_by_namespace;

  for (const auto& rule : rules) {
    const auto& proto_rule = rule.rule();
    absl::optional<std::string> value = rule.selector_->extract(headers);

    if (value && proto_rule.has_on_header_present()) {
      applyKeyValue(std::move(value).value_or(""), rule, proto_rule.on_header_present(),
                    structs_by_namespace);
    } else if (!value && proto_rule.has_on_header_missing()) {
      applyKeyValue(std::move(value).value_or(""), rule, proto_rule.on_header_missing(),
                    structs_by_namespace);
    }
  }
  // Any matching rules?
  if (!structs_by_namespace.empty()) {
    for (auto const& entry : structs_by_namespace) {
      callbacks.streamInfo().setDynamicMetadata(entry.first, entry.second);
    }
  }
}

Project: envoy

    Handle(RegistrationMap::const_iterator it) : it_(it) {}

Project: envoy

  envoy::config::core::v3::Metadata parseMetadataFromYaml(const std::string& yaml_string) {
    envoy::config::core::v3::Metadata metadata;
    TestUtility::loadFromYaml(yaml_string, metadata);
    return metadata;
  }

Project: envoy

TEST(HeaderMapImplTest, CustomRegisteredHeaders) {
  TestRequestHeaderMapImpl headers;
  EXPECT_EQ(custom_header_1.handle(), custom_header_1_copy.handle());
  EXPECT_EQ(nullptr, headers.getInline(custom_header_1.handle()));
  EXPECT_EQ(nullptr, headers.getInline(custom_header_1_copy.handle()));
  headers.setInline(custom_header_1.handle(), 42);
  EXPECT_EQ("42", headers.getInlineValue(custom_header_1_copy.handle()));
  EXPECT_EQ("foo_custom_header",
            headers.getInline(custom_header_1.handle())->key().getStringView());
}

Project: envoy

HeaderString::HeaderString() : buffer_(InlineHeaderVector()) {
  ASSERT((getInVec(buffer_).capacity()) >= MaxIntegerLength);
  ASSERT(valid());
}

Project: envoy

MATCHER_P(MapEq, rhs, "") {
  const ProtobufWkt::Struct& obj = arg;
  EXPECT_TRUE(!rhs.empty());
  for (auto const& entry : rhs) {
    EXPECT_EQ(obj.fields().at(entry.first).string_value(), entry.second);
  }
  return true;
}

Project: envoy

  void initializeFilter(const std::string& yaml) {
    envoy::extensions::filters::http::header_to_metadata::v3::Config config;
    TestUtility::loadFromYaml(yaml, config);
    config_ = std::make_shared<Config>(config);
    filter_ = std::make_shared<HeaderToMetadataFilter>(config_);
    filter_->setDecoderFilterCallbacks(decoder_callbacks_);
    filter_->setEncoderFilterCallbacks(encoder_callbacks_);
  }

Project: envoy

  void setup(const std::string& script) override {
    Filters::Common::Lua::LuaWrappersTestBase<StreamInfoWrapper>::setup(script);
    state_->registerType<DynamicMetadataMapWrapper>();
    state_->registerType<DynamicMetadataMapIterator>();
  }

Project: envoy

TEST(HeaderMapImplTest, DoubleInlineAdd) {
  {
    TestRequestHeaderMapImpl headers;
    const std::string foo("foo");
    const std::string bar("bar");
    headers.addReference(Headers::get().ContentLength, foo);
    headers.addReference(Headers::get().ContentLength, bar);
    EXPECT_EQ("foo,bar", headers.getContentLengthValue());
    EXPECT_EQ(1UL, headers.size());
  }
  {
    TestRequestHeaderMapImpl headers;
    headers.addReferenceKey(Headers::get().ContentLength, "foo");
    headers.addReferenceKey(Headers::get().ContentLength, "bar");
    EXPECT_EQ("foo,bar", headers.getContentLengthValue());
    EXPECT_EQ(1UL, headers.size());
  }
  {
    TestRequestHeaderMapImpl headers;
    headers.addReferenceKey(Headers::get().ContentLength, 5);
    headers.addReferenceKey(Headers::get().ContentLength, 6);
    EXPECT_EQ("5,6", headers.getContentLengthValue());
    EXPECT_EQ(1UL, headers.size());
  }
  {
    TestRequestHeaderMapImpl headers;
    const std::string foo("foo");
    headers.addReference(Headers::get().ContentLength, foo);
    headers.addReferenceKey(Headers::get().ContentLength, 6);
    EXPECT_EQ("foo,6", headers.getContentLengthValue());
    EXPECT_EQ(1UL, headers.size());
  }
}

Project: envoy

  static void loadFromJson(const std::string& json, ProtobufWkt::Struct& message) {
    MessageUtil::loadFromJson(json, message);
  }

Project: envoy

void HeaderString::append(const char* data, uint32_t data_size) {
  // Make sure the requested memory allocation is below uint32_t::max
  const uint64_t new_capacity = static_cast<uint64_t>(data_size) + size();
  validateCapacity(new_capacity);
  ASSERT(validHeaderString(absl::string_view(data, data_size)));

  switch (type()) {
  case Type::Reference: {
    // Rather than be too clever and optimize this uncommon case, we switch to
    // Inline mode and copy.
    const absl::string_view prev = getStrView(buffer_);
    buffer_ = InlineHeaderVector();
    // Assigning new_capacity to avoid resizing when appending the new data
    getInVec(buffer_).reserve(new_capacity);
    getInVec(buffer_).assign(prev.begin(), prev.end());
    break;
  }
  case Type::Inline: {
    getInVec(buffer_).reserve(new_capacity);
    break;
  }
  }
  getInVec(buffer_).insert(getInVec(buffer_).end(), data, data + data_size);
}

Project: envoy

  int size() const override { return 0; }

Project: envoy

  absl::optional<StaticLookupResponse> staticLookup(absl::string_view key) override {
    return StaticLookupTable<Interface>::lookup(*this, key);
  }

Project: envoy

TEST(HeaderDataConstructorTest, RegexMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
regex_match: value
  )EOF";

  HeaderUtility::HeaderData header_data =
      HeaderUtility::HeaderData(parseHeaderMatcherFromYaml(yaml));

  EXPECT_EQ("test-header", header_data.name_.get());
  EXPECT_EQ(HeaderUtility::HeaderMatchType::Regex, header_data.header_match_type_);
  EXPECT_EQ("", header_data.value_);
}

Project: envoy

    std::list<HeaderEntryImpl>::const_reverse_iterator rend() const { return headers_.rend(); }