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

void ExtractorImpl::addProvider(const JwtProvider& provider) {
  for (const auto& header : provider.from_headers()) {
    addHeaderConfig(provider.issuer(), LowerCaseString(header.name()), header.value_prefix());
  }
  for (const std::string& param : provider.from_params()) {
    addQueryParamConfig(provider.issuer(), param);
  }
  // If not specified, use default locations.
  if (provider.from_headers().empty() && provider.from_params().empty()) {
    addHeaderConfig(provider.issuer(), Http::CustomHeaders::get().Authorization,
                    JwtConstValues::get().BearerPrefix);
    addQueryParamConfig(provider.issuer(), JwtConstValues::get().AccessTokenParam);
  }
  if (!provider.forward_payload_header().empty()) {
    forward_payload_headers_.emplace_back(provider.forward_payload_header());
  }
}

Project: envoy

TEST(HeaderMapImplTest, ClearHeaderMap) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString static_key("hello");
  std::string ref_value("value");

  // Add random header and then clear.
  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());
  headers.clear();
  EXPECT_EQ(nullptr, headers.get(static_key));
  EXPECT_EQ(0UL, headers.size());
  EXPECT_EQ(headers.byteSize(), 0);
  EXPECT_TRUE(headers.empty());

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

  // Add mixture of headers.
  headers.addReference(static_key, ref_value);
  headers.setContentLength(5);
  headers.addCopy(static_key, "new_value");
  EXPECT_EQ(3UL, headers.size());
  EXPECT_FALSE(headers.empty());
  headers.clear();
  EXPECT_EQ(nullptr, headers.ContentLength());
  EXPECT_EQ(0UL, headers.size());
  EXPECT_EQ(headers.byteSize(), 0);
  EXPECT_TRUE(headers.empty());
}

Project: envoy

TEST(HeaderMapImplTest, ValidHeaderString) {
  EXPECT_TRUE(validHeaderString("abc"));
  EXPECT_FALSE(validHeaderString(absl::string_view("a\000bc", 4)));
  EXPECT_FALSE(validHeaderString("abc\n"));
}

Project: envoy

template <> HeaderMapImpl::StaticLookupTable<RequestTrailerMap>::StaticLookupTable() {
  finalizeTable();
}

Project: envoy

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

Project: envoy

  void SetUp() override {
    TestUtility::loadFromYaml(ExampleConfig, config_);
    JwtProviderList providers;
    for (const auto& it : config_.providers()) {
      providers.emplace_back(&it.second);
    }
    extractor_ = Extractor::create(providers);
  }

Project: envoy

HeaderString::HeaderString(HeaderString&& move_value) noexcept
    : buffer_(std::move(move_value.buffer_)) {
  move_value.clear();
  ASSERT(valid());
}

Project: envoy

TEST_F(HeaderToMetadataTest, HeaderNotPresent) {
  const std::string config = R"EOF(
request_rules:
  - header: x-version
    on_header_present:
      metadata_namespace: envoy.lb
      key: version
      type: STRING
)EOF";
  initializeFilter(config);
  Http::TestRequestHeaderMapImpl incoming_headers;

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

Project: envoy

    static size_t size() {
      // The size of the lookup table is finalized when the singleton lookup table is created. This
      // allows for late binding of custom headers as well as envoy header prefix changes. This
      // does mean that once the first header map is created of this type, no further changes are
      // possible.
      // TODO(mattklein123): If we decide to keep this implementation, it is conceivable that header
      // maps could be created by an API factory that is owned by the listener/HCM, thus making
      // O(1) header delivery over xDS possible.
      return ConstSingleton<StaticLookupTable>::get().size_;
    }

Project: envoy

int DynamicMetadataMapWrapper::luaSet(lua_State* state) {
  if (iterator_.get() != nullptr) {
    luaL_error(state, "dynamic metadata map cannot be modified while iterating");
  }

  const char* filter_name = luaL_checkstring(state, 2);
  const char* key = luaL_checkstring(state, 3);

  // MetadataMapHelper::loadValue will convert the value on top of the Lua stack,
  // so push a copy of the 3rd arg ("value") to the top.
  lua_pushvalue(state, 4);

  ProtobufWkt::Struct value;
  (*value.mutable_fields())[key] = Filters::Common::Lua::MetadataMapHelper::loadValue(state);
  streamInfo().setDynamicMetadata(filter_name, value);

  // Pop the copy of the metadata value from the stack.
  lua_pop(state, 1);
  return 0;
}

Project: envoy

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

Project: envoy

TEST_F(HeaderToMetadataTest, ProtobufValueTypeInBadBase64UrlTest) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-authenticated
    on_header_present:
      key: auth
      type: PROTOBUF_VALUE
      encode: BASE64
)EOF";
  initializeFilter(response_config_yaml);
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-authenticated", "invalid"}};

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

Project: envoy

TEST_F(HeaderToMetadataTest, RejectBothCookieHeader) {
  const std::string config = R"EOF(
request_rules:
  - header: x-something
    cookie: something-else
    on_header_present:
      key: something
      value: else
      type: STRING
    remove: false

)EOF";
  auto expected = "Cannot specify both header and cookie";
  EXPECT_THROW_WITH_MESSAGE(initializeFilter(config), EnvoyException, expected);
}

Project: envoy

  template <Type type> static RegistrationMap& mutableRegistrationMap() {
    MUTABLE_CONSTRUCT_ON_FIRST_USE(RegistrationMap);
  }

Project: envoy

int HeaderMapWrapper::luaGet(lua_State* state) {
  const char* key = luaL_checkstring(state, 2);
  const auto value =
      Http::HeaderUtility::getAllOfHeaderAsString(headers_, Http::LowerCaseString(key));
  if (value.result().has_value()) {
    lua_pushlstring(state, value.result().value().data(), value.result().value().length());
    return 1;
  } else {
    return 0;
  }
}

Project: envoy

TEST_P(RBACIntegrationTest, Denied) {
  useAccessLog("%RESPONSE_CODE_DETAILS%");
  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);
  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("403", response->headers().getStatusValue());
  EXPECT_THAT(waitForAccessLog(access_log_name_),
              testing::HasSubstr("rbac_access_denied_matched_policy[none]"));
}

Project: envoy

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

Project: envoy

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

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

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

Project: envoy

TEST_P(RBACIntegrationTest, PathIgnoreCase) {
  config_helper_.addFilter(RBAC_CONFIG_WITH_PATH_IGNORE_CASE_MATCH);
  initialize();

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

  const std::vector<std::string> paths{"/ignore_case", "/IGNORE_CASE", "/ignore_CASE"};

  for (const auto& path : paths) {
    auto response = codec_client_->makeRequestWithBody(
        Http::TestRequestHeaderMapImpl{
            {":method", "POST"},
            {":path", 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

TEST_F(LuaHeaderMapWrapperTest, Methods) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:add("HELLO", "WORLD")
      testPrint(object:get("hELLo"))

      object:add("header1", "")
      object:add("header2", "foo")

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

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

      object:add("header3", "foo")
      object:add("header3", "bar")
      testPrint(object:get("header3"))
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers;
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; });
  EXPECT_CALL(printer_, testPrint("WORLD"));
  EXPECT_CALL(printer_, testPrint("'hello' 'WORLD'"));
  EXPECT_CALL(printer_, testPrint("'header1' ''"));
  EXPECT_CALL(printer_, testPrint("'header2' 'foo'"));
  EXPECT_CALL(printer_, testPrint("'hello' 'WORLD'"));
  EXPECT_CALL(printer_, testPrint("'header2' 'foo'"));
  EXPECT_CALL(printer_, testPrint("foo,bar"));
  start("callMe");
}

Project: envoy

void HeaderMapImpl::iterate(HeaderMap::ConstIterateCb cb) const {
  for (const HeaderEntryImpl& header : headers_) {
    if (cb(header) == HeaderMap::Iterate::Break) {
      break;
    }
  }
}

Project: envoy

HeaderString::HeaderString(const LowerCaseString& ref_value)
    : buffer_(absl::string_view(ref_value.get().c_str(), ref_value.get().size())) {
  ASSERT(valid());
}

Project: envoy

TEST(MatchHeadersTest, MayMatchOneOrMoreRequestHeader) {
  TestRequestHeaderMapImpl headers{{"some-header", "a"}, {"other-header", "b"}};

  const std::string yaml = R"EOF(
name: match-header
regex_match: (a|b)
  )EOF";

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

  headers.addCopy("match-header", "a");
  // With a single "match-header" this regex will match.
  EXPECT_TRUE(HeaderUtility::matchHeaders(headers, header_data));

  headers.addCopy("match-header", "b");
  // With two "match-header" we now logically have "a,b" as the value, so the regex will not match.
  EXPECT_FALSE(HeaderUtility::matchHeaders(headers, header_data));

  header_data[0] = std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(R"EOF(
name: match-header
exact_match: a,b
  )EOF"));
  // Make sure that an exact match on "a,b" does in fact work.
  EXPECT_TRUE(HeaderUtility::matchHeaders(headers, header_data));

  TestScopedRuntime runtime;
  Runtime::LoaderSingleton::getExisting()->mergeValues(
      {{"envoy.reloadable_features.http_match_on_all_headers", "false"}});
  // Flipping runtime to false should make "a,b" no longer match because we will match on the first
  // header only.
  EXPECT_FALSE(HeaderUtility::matchHeaders(headers, header_data));

  header_data[0] = std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(R"EOF(
name: match-header
exact_match: a
  )EOF"));
  // With runtime off, exact match on "a" should pass.
  EXPECT_TRUE(HeaderUtility::matchHeaders(headers, header_data));
}

Project: envoy

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

Project: envoy

    const HeaderString& value() const override { return value_; }

Project: envoy

TEST(HeaderMapImplTest, MoveIntoInline) {
  TestRequestHeaderMapImpl headers;
  HeaderString key;
  key.setCopy(Headers::get().EnvoyRetryOn.get());
  HeaderString value;
  value.setCopy("hello");
  headers.addViaMove(std::move(key), std::move(value));
  EXPECT_EQ("x-envoy-retry-on", headers.EnvoyRetryOn()->key().getStringView());
  EXPECT_EQ("hello", headers.getEnvoyRetryOnValue());

  HeaderString key2;
  key2.setCopy(Headers::get().EnvoyRetryOn.get());
  HeaderString value2;
  value2.setCopy("there");
  headers.addViaMove(std::move(key2), std::move(value2));
  EXPECT_EQ("x-envoy-retry-on", headers.EnvoyRetryOn()->key().getStringView());
  EXPECT_EQ("hello,there", headers.getEnvoyRetryOnValue());
}

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, ModifyAfterIteration) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      for key, value in pairs(object) do
        testPrint(string.format("'%s' '%s'", key, value))
      end

      object:add("hello", "world")

      for key, value in pairs(object) do
        testPrint(string.format("'%s' '%s'", key, value))
      end
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers{{"foo", "bar"}};
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; });
  EXPECT_CALL(printer_, testPrint("'foo' 'bar'"));
  EXPECT_CALL(printer_, testPrint("'foo' 'bar'"));
  EXPECT_CALL(printer_, testPrint("'hello' 'world'"));
  start("callMe");
}

Project: envoy

TEST_F(HeaderToMetadataTest, HeaderValueTooLong) {
  initializeFilter(request_config_yaml);
  auto length = Envoy::Extensions::HttpFilters::HeaderToMetadataFilter::MAX_HEADER_VALUE_LEN + 1;
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-VERSION", std::string(length, 'x')}};

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

Project: envoy

void HeaderMapImpl::addCopy(const LowerCaseString& key, absl::string_view value) {
  // In the case that the header is appended, we will perform a needless copy of the key and value.
  // This is done on purpose to keep the code simple and should be rare.
  HeaderString new_key;
  new_key.setCopy(key.get());
  HeaderString new_value;
  new_value.setCopy(value);
  insertByKey(std::move(new_key), std::move(new_value));
  ASSERT(new_key.empty());   // NOLINT(bugprone-use-after-move)
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
}

Project: envoy

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

Project: envoy

  getVersionStringFromApiVersion(envoy::config::core::v3::ApiVersion api_version) {
    switch (api_version) {
    case envoy::config::core::v3::ApiVersion::AUTO:
      return "AUTO";
    case envoy::config::core::v3::ApiVersion::V2:
      return "V2";
    case envoy::config::core::v3::ApiVersion::V3:
      return "V3";
    default:
      NOT_REACHED_GCOVR_EXCL_LINE;
    }
  }

Project: envoy

  ResponseTrailerMapImpl() { clearInline(); }

Project: envoy

  ResponseWrapper(Protobuf::Arena& arena, const Http::ResponseHeaderMap* headers,
                  const Http::ResponseTrailerMap* trailers, const StreamInfo::StreamInfo& info)
      : headers_(arena, headers), trailers_(arena, trailers), info_(info) {}

Project: envoy

absl::optional<CelValue> ResponseWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();
  if (value == Code) {
    auto code = info_.responseCode();
    if (code.has_value()) {
      return CelValue::CreateInt64(code.value());
    }
    return {};
  } else if (value == Size) {
    return CelValue::CreateInt64(info_.bytesSent());
  } else if (value == Headers) {
    return CelValue::CreateMap(&headers_);
  } else if (value == Trailers) {
    return CelValue::CreateMap(&trailers_);
  } else if (value == Flags) {
    return CelValue::CreateInt64(info_.responseFlags());
  } else if (value == GrpcStatus) {
    auto const& optional_status = Grpc::Common::getGrpcStatus(
        trailers_.value_ ? *trailers_.value_ : *Http::StaticEmptyHeaders::get().response_trailers,
        headers_.value_ ? *headers_.value_ : *Http::StaticEmptyHeaders::get().response_headers,
        info_);
    if (optional_status.has_value()) {
      return CelValue::CreateInt64(optional_status.value());
    }
    return {};
  } else if (value == TotalSize) {
    return CelValue::CreateInt64(info_.bytesSent() +
                                 (headers_.value_ ? headers_.value_->byteSize() : 0) +
                                 (trailers_.value_ ? trailers_.value_->byteSize() : 0));
  } else if (value == CodeDetails) {
    const absl::optional<std::string>& details = info_.responseCodeDetails();
    if (details.has_value()) {
      return CelValue::CreateString(&details.value());
    }
    return {};
  }
  return {};
}

Project: envoy

absl::optional<std::string> HeaderValueSelector::extract(Http::HeaderMap& map) const {
  const auto header_value = Http::HeaderUtility::getAllOfHeaderAsString(map, header_);
  if (!header_value.result().has_value()) {
    return absl::nullopt;
  }
  // Catch the value in the header before removing.
  absl::optional<std::string> value = std::string(header_value.result().value());
  if (remove_) {
    map.remove(header_);
  }
  return value;
}

Project: envoy

TEST(HeaderMapImplTest, SetCopyNewBehavior) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString foo("hello");
  headers.setCopy(foo, "world");
  EXPECT_EQ("world", headers.get(foo)->value().getStringView());

  // Overwrite value.
  headers.setCopy(foo, "monde");
  EXPECT_EQ("monde", headers.get(foo)->value().getStringView());

  // Add another foo header.
  headers.addCopy(foo, "monde2");
  EXPECT_EQ(headers.size(), 2);

  // The foo header is overridden.
  headers.setCopy(foo, "override-monde");
  EXPECT_EQ(headers.size(), 1);

  HeaderAndValueCb cb;

  InSequence seq;
  EXPECT_CALL(cb, Call("hello", "override-monde"));
  headers.iterate(cb.asIterateCb());

  // Test setting an empty string and then overriding.
  EXPECT_EQ(1UL, headers.remove(foo));
  EXPECT_EQ(headers.size(), 0);
  const std::string empty;
  headers.setCopy(foo, empty);
  EXPECT_EQ(headers.size(), 1);
  headers.setCopy(foo, "not-empty");
  EXPECT_EQ(headers.get(foo)->value().getStringView(), "not-empty");

  // Use setCopy with inline headers both indirectly and directly.
  headers.clear();
  EXPECT_EQ(headers.size(), 0);
  headers.setCopy(Headers::get().Path, "/");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/");
  headers.setPath("/foo");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/foo");
}

Project: envoy

TEST(HeaderMapImplTest, DoubleInlineSet) {
  TestRequestHeaderMapImpl headers;
  headers.setReferenceKey(Headers::get().ContentType, "blah");
  headers.setReferenceKey(Headers::get().ContentType, "text/html");
  EXPECT_EQ("text/html", headers.getContentTypeValue());
  EXPECT_EQ(1UL, headers.size());
}

Project: envoy

TEST(HeaderMapImplTest, TestInlineHeaderAdd) {
  TestRequestHeaderMapImpl foo;
  foo.addCopy(LowerCaseString(":path"), "GET");
  EXPECT_EQ(foo.size(), 1);
  EXPECT_TRUE(foo.Path() != nullptr);
}

Project: envoy

int StreamInfoWrapper::luaDownstreamSslConnection(lua_State* state) {
  const auto& ssl = stream_info_.downstreamSslConnection();
  if (ssl != nullptr) {
    if (downstream_ssl_connection_.get() != nullptr) {
      downstream_ssl_connection_.pushStack();
    } else {
      downstream_ssl_connection_.reset(
          Filters::Common::Lua::SslConnectionWrapper::create(state, *ssl), true);
    }
  } else {
    lua_pushnil(state);
  }
  return 1;
}

Project: envoy

  const std::string& get() const { return string_; }

Project: envoy

TEST_F(HeaderToMetadataTest, StringTypeInBase64UrlTest) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-authenticated
    on_header_present:
      key: auth
      type: STRING
      encode: BASE64
)EOF";
  initializeFilter(response_config_yaml);
  std::string data = "Non-ascii-characters";
  const auto encoded = Base64::encode(data.c_str(), data.size());
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-authenticated", encoded}};
  std::map<std::string, std::string> expected = {{"auth", data}};
  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));
}

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, DontFinishIteration) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      iterator = pairs(object)
      key, value = iterator()
      iterator2 = pairs(object)
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers{{"foo", "bar"}, {"hello", "world"}};
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; });
  EXPECT_THROW_WITH_MESSAGE(
      start("callMe"), Filters::Common::Lua::LuaException,
      "[string \"...\"]:5: cannot create a second iterator before completing the first");
}

Project: envoy

    HeaderLocationSpec(const Http::LowerCaseString& header, const std::string& value_prefix)
        : header_(header), value_prefix_(value_prefix) {}

Project: envoy

    void operator=(GetResult&& rhs) noexcept { result_ = std::move(rhs.result_); }

Project: envoy

  void iterate(HeaderMap::ConstIterateCb cb) const override { HeaderMapImpl::iterate(cb); }

Project: envoy

  void addReferenceKey(const LowerCaseString& key, uint64_t value) override {
    HeaderMapImpl::addReferenceKey(key, value);
  }

Project: envoy

const HeaderEntry* HeaderMapImpl::get(const LowerCaseString& key) const {
  const auto result = getAll(key);
  return result.empty() ? nullptr : result[0];
}

Project: envoy

collectAllHeaders(std::vector<std::pair<absl::string_view, absl::string_view>>* dest) {
  return [dest](const HeaderEntry& header) -> HeaderMap::Iterate {
    dest->push_back(std::make_pair(header.key().getStringView(), header.value().getStringView()));
    return HeaderMap::Iterate::Continue;
  };
};

Project: envoy

void HeaderMapImpl::subtractSize(uint64_t size) {
  ASSERT(cached_byte_size_ >= size);
  cached_byte_size_ -= size;
}

Project: envoy

TEST_F(HeaderToMetadataTest, BasicRequestDoubleHeadersTest) {
  initializeFilter(request_config_yaml);
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-VERSION", "foo"}, {"X-VERSION", "bar"}};
  std::map<std::string, std::string> expected = {{"version", "foo,bar"}};

  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

  RequestWrapper(Protobuf::Arena& arena, const Http::RequestHeaderMap* headers,
                 const StreamInfo::StreamInfo& info)
      : headers_(arena, headers), info_(info) {}

Project: envoy

HeaderMapIterator::HeaderMapIterator(HeaderMapWrapper& parent) : parent_(parent) {
  entries_.reserve(parent_.headers_.size());
  parent_.headers_.iterate([this](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate {
    entries_.push_back(&header);
    return Http::HeaderMap::Iterate::Continue;
  });
}

Project: envoy

  void iterateReverse(HeaderMap::ConstIterateCb cb) const override {
    header_map_->iterateReverse(cb);
  }

Project: envoy

TEST(HeaderMapImplTest, RemovePrefix) {
  // These will match.
  LowerCaseString key1 = LowerCaseString("X-prefix-foo");
  LowerCaseString key3 = LowerCaseString("X-Prefix-");
  LowerCaseString key5 = LowerCaseString("x-prefix-eep");
  // These will not.
  LowerCaseString key2 = LowerCaseString(" x-prefix-foo");
  LowerCaseString key4 = LowerCaseString("y-x-prefix-foo");

  TestRequestHeaderMapImpl headers;
  headers.addReference(key1, "value");
  headers.addReference(key2, "value");
  headers.addReference(key3, "value");
  headers.addReference(key4, "value");
  headers.addReference(key5, "value");

  // Test removing the first header, middle headers, and the end header.
  EXPECT_EQ(3UL, headers.removePrefix(LowerCaseString("x-prefix-")));
  EXPECT_EQ(nullptr, headers.get(key1));
  EXPECT_NE(nullptr, headers.get(key2));
  EXPECT_EQ(nullptr, headers.get(key3));
  EXPECT_NE(nullptr, headers.get(key4));
  EXPECT_EQ(nullptr, headers.get(key5));

  // Try to remove headers with no prefix match.
  EXPECT_EQ(0UL, headers.removePrefix(LowerCaseString("foo")));

  // Remove all headers.
  EXPECT_EQ(2UL, headers.removePrefix(LowerCaseString("")));
  EXPECT_EQ(nullptr, headers.get(key2));
  EXPECT_EQ(nullptr, headers.get(key4));

  // Add inline and remove by prefix
  headers.setContentLength(5);
  EXPECT_EQ("5", headers.getContentLengthValue());
  EXPECT_EQ(1UL, headers.size());
  EXPECT_FALSE(headers.empty());
  EXPECT_EQ(1UL, headers.removePrefix(LowerCaseString("content")));
  EXPECT_EQ(nullptr, headers.ContentLength());
}

Project: envoy

void HeaderUtility::stripPortFromHost(RequestHeaderMap& headers, uint32_t listener_port) {

  if (headers.getMethodValue() == Http::Headers::get().MethodValues.Connect) {
    // According to RFC 2817 Connect method should have port part in host header.
    // In this case we won't strip it even if configured to do so.
    return;
  }
  const absl::string_view original_host = headers.getHostValue();
  const absl::string_view::size_type port_start = original_host.rfind(':');
  if (port_start == absl::string_view::npos) {
    return;
  }
  // According to RFC3986 v6 address is always enclosed in "[]". section 3.2.2.
  const auto v6_end_index = original_host.rfind("]");
  if (v6_end_index == absl::string_view::npos || v6_end_index < port_start) {
    if ((port_start + 1) > original_host.size()) {
      return;
    }
    const absl::string_view port_str = original_host.substr(port_start + 1);
    uint32_t port = 0;
    if (!absl::SimpleAtoi(port_str, &port)) {
      return;
    }
    if (port != listener_port) {
      // We would strip ports only if they are the same, as local port of the listener.
      return;
    }
    const absl::string_view host = original_host.substr(0, port_start);
    headers.setHost(host);
  }
}

Project: envoy

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

Project: envoy

    template <class Key> bool isPseudoHeader(const Key& key) {
      return !key.getStringView().empty() && key.getStringView()[0] == ':';
    }

Project: envoy

  size_t remove(const std::string& key) { return remove(LowerCaseString(key)); }

Project: envoy

TEST(MatchHeadersTest, HeaderSafeRegexMatch) {
  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
safe_regex_match:
  google_re2: {}
  regex: \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

void HeaderString::setInteger(uint64_t value) {
  // Initialize the size to the max length, copy the actual data, and then
  // reduce the size (but not the capacity) as needed
  // Note: instead of using the inner_buffer, attempted the following:
  // resize buffer_ to MaxIntegerLength, apply StringUtil::itoa to the buffer_.data(), and then
  // resize buffer_ to int_length (the number of digits in value).
  // However it was slower than the following approach.
  char inner_buffer[MaxIntegerLength];
  const uint32_t int_length = StringUtil::itoa(inner_buffer, MaxIntegerLength, value);

  if (type() == Type::Reference) {
    // Switching from Type::Reference to Type::Inline
    buffer_ = InlineHeaderVector();
  }
  ASSERT((getInVec(buffer_).capacity()) > MaxIntegerLength);
  getInVec(buffer_).assign(inner_buffer, inner_buffer + int_length);
}

Project: envoy

  RequestHeaderMapImpl() { clearInline(); }

Project: envoy

TEST_F(HeaderToMetadataTest, ConfigIsCached) {
  // 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_TRUE(getConfig()->doRequest());
  EXPECT_TRUE(getConfig()->doRequest());
}

Project: envoy

  const google::api::expr::runtime::CelList* ListKeys() const override {
    NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
  }

Project: envoy

ActivationPtr createActivation(Protobuf::Arena& arena, const StreamInfo::StreamInfo& info,
                               const Http::RequestHeaderMap* request_headers,
                               const Http::ResponseHeaderMap* response_headers,
                               const Http::ResponseTrailerMap* response_trailers) {
  auto activation = std::make_unique<Activation>();
  activation->InsertValueProducer(Request,
                                  std::make_unique<RequestWrapper>(arena, request_headers, info));
  activation->InsertValueProducer(Response, std::make_unique<ResponseWrapper>(
                                                arena, response_headers, response_trailers, info));
  activation->InsertValueProducer(Connection, std::make_unique<ConnectionWrapper>(info));
  activation->InsertValueProducer(Upstream, std::make_unique<UpstreamWrapper>(info));
  activation->InsertValueProducer(Source, std::make_unique<PeerWrapper>(info, false));
  activation->InsertValueProducer(Destination, std::make_unique<PeerWrapper>(info, true));
  activation->InsertValueProducer(Metadata,
                                  std::make_unique<MetadataProducer>(info.dynamicMetadata()));
  activation->InsertValueProducer(FilterState,
                                  std::make_unique<FilterStateWrapper>(info.filterState()));
  return activation;
}

Project: envoy

TEST_P(RBACIntegrationTest, DeniedWithDenyAction) {
  useAccessLog("%RESPONSE_CODE_DETAILS%");
  config_helper_.addFilter(RBAC_CONFIG_WITH_DENY_ACTION);
  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);
  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("403", response->headers().getStatusValue());
  // Note the whitespace in the policy id is replaced by '_'.
  EXPECT_THAT(waitForAccessLog(access_log_name_),
              testing::HasSubstr("rbac_access_denied_matched_policy[deny_policy]"));
}

Project: envoy

TEST_P(RBACIntegrationTest, HeaderMatchConditionDuplicateHeaderNoMatch) {
  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"},
          {"xxx", "zzz"},
      },
      1024);
  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("403", response->headers().getStatusValue());
}

Project: envoy

  std::string get_(const LowerCaseString& key) const {
    const HeaderEntry* header = get(key);
    if (!header) {
      return EMPTY_STRING;
    } else {
      return std::string(header->value().getStringView());
    }
  }

Project: envoy

    void clear() {
      headers_.clear();
      pseudo_headers_end_ = headers_.end();
    }

Project: envoy

uint64_t HeaderMapImpl::appendToHeader(HeaderString& header, absl::string_view data,
                                       absl::string_view delimiter) {
  if (data.empty()) {
    return 0;
  }
  uint64_t byte_size = 0;
  if (!header.empty()) {
    header.append(delimiter.data(), delimiter.size());
    byte_size += delimiter.size();
  }
  header.append(data.data(), data.size());
  return data.size() + byte_size;
}

Project: envoy

  static Handle<type> registerInlineHeader(const LowerCaseString& header_name) {
    static size_t inline_header_index = 0;

    ASSERT(!mutableFinalized<type>());
    auto& map = mutableRegistrationMap<type>();
    auto entry = map.find(header_name);
    if (entry == map.end()) {
      map[header_name] = inline_header_index++;
    }
    return Handle<type>(map.find(header_name));
  }

Project: envoy

Http::FilterHeadersStatus HeaderToMetadataFilter::decodeHeaders(Http::RequestHeaderMap& headers,
                                                                bool) {
  const auto* config = getConfig();
  if (config->doRequest()) {
    writeHeaderToMetadata(headers, config->requestRules(), *decoder_callbacks_);
  }

  return Http::FilterHeadersStatus::Continue;
}

Project: envoy

  bool valid() const { return validHeaderString(string_); }

Project: envoy

  const HeaderEntry* getInline(Handle handle) const override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    return constInlineHeaders()[handle.it_->second];
  }

Project: envoy

  LowerCaseString(const LowerCaseString& rhs) : string_(rhs.string_) { ASSERT(valid()); }

Project: envoy

TEST(HeaderIsValidTest, ValidHeaderValuesAreAccepted) {
  EXPECT_TRUE(HeaderUtility::headerValueIsValid("some-value"));
  EXPECT_TRUE(HeaderUtility::headerValueIsValid("Some Other Value"));
}

Project: envoy

absl::optional<CelValue> evaluate(const Expression& expr, Protobuf::Arena& arena,
                                  const StreamInfo::StreamInfo& info,
                                  const Http::RequestHeaderMap* request_headers,
                                  const Http::ResponseHeaderMap* response_headers,
                                  const Http::ResponseTrailerMap* response_trailers) {
  auto activation =
      createActivation(arena, info, request_headers, response_headers, response_trailers);
  auto eval_status = expr.Evaluate(*activation, &arena);
  if (!eval_status.ok()) {
    return {};
  }

  return eval_status.value();
}

Project: envoy

absl::string_view ExtractorImpl::extractJWT(absl::string_view value_str,
                                            absl::string_view::size_type after) const {
  const auto starting = value_str.find_first_of(ConstantBase64UrlEncodingCharsPlusDot, after);
  if (starting == value_str.npos) {
    return value_str;
  }
  // There should be two dots (periods; 0x2e) inside the string, but we don't verify that here
  auto ending = value_str.find_first_not_of(ConstantBase64UrlEncodingCharsPlusDot, starting);
  if (ending == value_str.npos) { // Base64Url-encoded string occupies the rest of the line
    return value_str.substr(starting);
  }
  return value_str.substr(starting, ending - starting);
}

Project: envoy

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

  const std::string yaml = R"EOF(
name: match-header
regex_match: \d{3}
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 setInline(Handle handle, uint64_t value) override {
    header_map_->setInline(handle, value);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

void validateCapacity(uint64_t new_capacity) {
  // If the resizing will cause buffer overflow due to hitting uint32_t::max, an OOM is likely
  // imminent. Fast-fail rather than allow a buffer overflow attack (issue #1421)
  RELEASE_ASSERT(new_capacity <= std::numeric_limits<uint32_t>::max(),
                 "Trying to allocate overly large headers.");
}

Project: envoy

HeaderMap::GetResult HeaderMapImpl::getAll(const LowerCaseString& key) const {
  return HeaderMap::GetResult(const_cast<HeaderMapImpl*>(this)->getExisting(key));
}

Project: envoy

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

Project: envoy

absl::optional<CelValue> convertHeaderEntry(const Http::HeaderEntry* header) {
  if (header == nullptr) {
    return {};
  }
  return CelValue::CreateStringView(header->value().getStringView());
}

Project: envoy

TEST(MatchHeadersTest, HeaderExactMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "match-value"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "other-value"},
                                              {"other-header", "match-value"}};
  const std::string yaml = R"EOF(
name: match-header
exact_match: match-value
  )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

    size_t size() const { return result_.size(); }

Project: envoy

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

Project: envoy

int HeaderMapWrapper::luaAdd(lua_State* state) {
  checkModifiable(state);

  const char* key = luaL_checkstring(state, 2);
  const char* value = luaL_checkstring(state, 3);
  headers_.addCopy(Http::LowerCaseString(key), value);
  return 0;
}

Project: envoy

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

  // Match with additional path elements.
  {
    Http::TestRequestHeaderMapImpl headers{{":path", "/cluster-prod-001/x/y"}};
    std::map<std::string, std::string> expected = {{"cluster", "cluster-prod-001"}};

    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));
  }

  // Match with no additional path elements.
  {
    Http::TestRequestHeaderMapImpl headers{{":path", "/cluster-prod-001"}};
    std::map<std::string, std::string> expected = {{"cluster", "cluster-prod-001"}};

    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{{":path", "/foo"}};
    std::map<std::string, std::string> expected = {{"cluster", "/foo"}};

    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 with additional path elements.
  {
    Http::TestRequestHeaderMapImpl headers{{":path", "/foo/bar?x=2"}};
    std::map<std::string, std::string> expected = {{"cluster", "/foo/bar?x=2"}};

    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, TestCustomHeaderToken) {
  auto headers = TestRequestHeaderMapImpl{{"token-header", "jwt_token"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);

  // Only issuer2 and issuer4 are using "token-header" location
  EXPECT_EQ(tokens[0]->token(), "jwt_token");
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer2"));
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer4"));

  // Other issuers are not allowed from "token-header"
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer1"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer3"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer5"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("unknown_issuer"));

  // Test token remove
  tokens[0]->removeJwt(headers);
  EXPECT_FALSE(headers.get(Http::LowerCaseString("token-header")));
}

Project: envoy

  getVersionedServiceFullName(const std::string& service_full_name_template,
                              envoy::config::core::v3::ApiVersion api_version,
                              bool use_alpha = false,
                              const std::string& service_namespace = EMPTY_STRING) {
    switch (api_version) {
    case envoy::config::core::v3::ApiVersion::AUTO:
      FALLTHRU;
    case envoy::config::core::v3::ApiVersion::V2:
      return fmt::format(service_full_name_template, use_alpha ? "v2alpha" : "v2",
                         service_namespace);

    case envoy::config::core::v3::ApiVersion::V3:
      return fmt::format(service_full_name_template, "v3", service_namespace);
    default:
      NOT_REACHED_GCOVR_EXCL_LINE;
    }
  }

Project: envoy

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

Project: envoy

TEST(HeaderMapImplTest, InlineInsert) {
  TestRequestHeaderMapImpl headers;
  EXPECT_TRUE(headers.empty());
  EXPECT_EQ(0, headers.size());
  EXPECT_EQ(nullptr, headers.Host());
  headers.setHost("hello");
  EXPECT_FALSE(headers.empty());
  EXPECT_EQ(1, headers.size());
  EXPECT_EQ(":authority", headers.Host()->key().getStringView());
  EXPECT_EQ("hello", headers.getHostValue());
  EXPECT_EQ("hello", headers.get(Headers::get().Host)->value().getStringView());
}

Project: envoy

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

Project: envoy

  void setReferenceInline(Handle handle, absl::string_view value) override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
    updateSize(entry.value().size(), value.size());
    entry.value().setReference(value);
  }

Project: envoy

TEST(HeaderMapImplTest, RemoveIf) {
  LowerCaseString key1 = LowerCaseString("X-postfix-foo");
  LowerCaseString key2 = LowerCaseString("X-postfix-");
  LowerCaseString key3 = LowerCaseString("x-postfix-eep");

  TestRequestHeaderMapImpl headers;
  headers.addReference(key1, "value");
  headers.addReference(key2, "value");
  headers.addReference(key3, "value");

  EXPECT_EQ(0UL, headers.removeIf([](const HeaderEntry&) -> bool { return false; }));

  EXPECT_EQ(2UL, headers.removeIf([](const HeaderEntry& entry) -> bool {
    return absl::EndsWith(entry.key().getStringView(), "foo") ||
           absl::EndsWith(entry.key().getStringView(), "eep");
  }));

  TestRequestHeaderMapImpl expected{{"X-postfix-", "value"}};
  EXPECT_EQ(expected, headers);
}

Project: envoy

MATCHER_P(DecodedResourcesEq, expected, "") {
  const bool equal = std::equal(arg.begin(), arg.end(), expected.begin(), expected.end(),
                                TestUtility::decodedResourceEq);
  if (!equal) {
    const auto format_resources =
        [](const std::vector<Config::DecodedResourceRef>& resources) -> std::string {
      std::vector<std::string> resource_strs;
      std::transform(
          resources.begin(), resources.end(), std::back_inserter(resource_strs),
          [](const Config::DecodedResourceRef& resource) -> std::string {
            return fmt::format(
                "<name: {}, aliases: {}, version: {}, resource: {}>", resource.get().name(),
                absl::StrJoin(resource.get().aliases(), ","), resource.get().version(),
                resource.get().hasResource() ? resource.get().resource().DebugString() : "(none)");
          });
      return absl::StrJoin(resource_strs, ", ");
    };
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected resources:") << "\n"
                     << format_resources(expected) << "\n"
                     << TestUtility::addLeftAndRightPadding("are not equal to actual resources:")
                     << "\n"
                     << format_resources(arg) << "\n"
                     << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

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

  // The way iteration works is we create an iteration wrapper that snaps pointers to all of
  // the headers. We don't allow modification while an iterator is active. This means that
  // currently if a script breaks out of iteration, further modifications will not be possible
  // because we don't know if they may resume iteration in the future and it isn't safe. There
  // are potentially better ways of handling this but due to GC of the iterator it's very
  // difficult to control safety without tracking every allocated iterator and invalidating them
  // if the map is modified.
  iterator_.reset(HeaderMapIterator::create(state, *this), true);
  lua_pushcclosure(state, HeaderMapIterator::static_luaPairsIterator, 1);
  return 1;
}

Project: envoy

  const HeaderEntry& hostHeaderEntry(const std::string& host_value, bool set_connect = false) {
    headers_.setHost(host_value);
    if (set_connect) {
      headers_.setMethod(Http::Headers::get().MethodValues.Connect);
    }
    return *headers_.Host();
  }

Project: envoy

  bool operator==(const HeaderMap& rhs) const override { return header_map_->operator==(rhs); }

Project: envoy

ExtractorImpl::ExtractorImpl(const JwtProvider& provider) { addProvider(provider); }

Project: envoy

  void clear() override { HeaderMapImpl::clear(); }

Project: envoy

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

Project: envoy

  const HeaderEntry* getInline(Handle handle) const override {
    return header_map_->getInline(handle);
  }

Project: envoy

  TestHeaderMapImplBase(const std::initializer_list<std::pair<std::string, std::string>>& values) {
    for (auto& value : values) {
      header_map_->addCopy(LowerCaseString(value.first), value.second);
    }
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, ModifyAfterIterationForDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:dynamicMetadata():set("envoy.lb", "hello", "world")
      for filter, entry in pairs(object:dynamicMetadata()) do
        testPrint(filter)
        for key, value in pairs(entry) do
          testPrint(string.format("'%s' '%s'", key, value))
        end
      end

      object:dynamicMetadata():set("envoy.lb", "hello", "envoy")
      object:dynamicMetadata():set("envoy.proxy", "proto", "grpc")
      for filter, entry in pairs(object:dynamicMetadata()) do
        testPrint(filter)
        for key, value in pairs(entry) do
          testPrint(string.format("'%s' '%s'", key, value))
        end
      end
    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("envoy.lb"));
  EXPECT_CALL(printer_, testPrint("'hello' 'world'"));
  EXPECT_CALL(printer_, testPrint("envoy.proxy"));
  EXPECT_CALL(printer_, testPrint("'proto' 'grpc'"));
  EXPECT_CALL(printer_, testPrint("envoy.lb"));
  EXPECT_CALL(printer_, testPrint("'hello' 'envoy'"));
  start("callMe");
}

Project: envoy

  HeaderEntryImpl** inlineHeaders() override { return inline_headers_; }

Project: envoy

  template <class MessageType> static void validate(const MessageType& message) {
    MessageUtil::validate(message, ProtobufMessage::getStrictValidationVisitor());
  }

Project: envoy

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

Project: envoy

    const HeaderEntry* operator[](size_t i) const { return result_[i]; }

Project: envoy

createHeaderMap(const std::initializer_list<std::pair<LowerCaseString, std::string>>& values) {
  auto new_header_map = T::create();
  HeaderMapImpl::initFromInitList(*new_header_map, values.begin(), values.end());
  return new_header_map;
}

Project: envoy

TEST(Context, ResponseAttributes) {
  NiceMock<StreamInfo::MockStreamInfo> info;
  NiceMock<StreamInfo::MockStreamInfo> empty_info;
  const std::string header_name = "test-header";
  const std::string trailer_name = "test-trailer";
  const std::string grpc_status = "grpc-status";
  Http::TestResponseHeaderMapImpl header_map{{header_name, "a"}};
  Http::TestResponseTrailerMapImpl trailer_map{{trailer_name, "b"}, {grpc_status, "8"}};
  Protobuf::Arena arena;
  ResponseWrapper response(arena, &header_map, &trailer_map, info);
  ResponseWrapper empty_response(arena, nullptr, nullptr, empty_info);

  EXPECT_CALL(info, responseCode()).WillRepeatedly(Return(404));
  EXPECT_CALL(info, bytesSent()).WillRepeatedly(Return(123));
  EXPECT_CALL(info, responseFlags()).WillRepeatedly(Return(0x1));

  const absl::optional<std::string> code_details = "unauthorized";
  EXPECT_CALL(info, responseCodeDetails()).WillRepeatedly(ReturnRef(code_details));

  {
    auto value = response[CelValue::CreateStringView(Undefined)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = response[CelValue::CreateInt64(13)];
    EXPECT_FALSE(value.has_value());
  }

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

  {
    auto value = response[CelValue::CreateStringView(TotalSize)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(160, value.value().Int64OrDie());
  }

  {
    auto value = empty_response[CelValue::CreateStringView(TotalSize)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(0, value.value().Int64OrDie());
  }

  {
    auto value = response[CelValue::CreateStringView(Code)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(404, value.value().Int64OrDie());
  }

  {
    auto value = response[CelValue::CreateStringView(CodeDetails)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(code_details.value(), value.value().StringOrDie().value());
  }

  {
    auto value = response[CelValue::CreateStringView(Headers)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsMap());
    auto& map = *value.value().MapOrDie();
    EXPECT_FALSE(map.empty());
    EXPECT_EQ(1, map.size());

    auto header = map[CelValue::CreateStringView(header_name)];
    EXPECT_TRUE(header.has_value());
    ASSERT_TRUE(header.value().IsString());
    EXPECT_EQ("a", header.value().StringOrDie().value());

    auto missing = map[CelValue::CreateStringView(Undefined)];
    EXPECT_FALSE(missing.has_value());
  }

  {
    auto value = response[CelValue::CreateStringView(Trailers)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsMap());
    auto& map = *value.value().MapOrDie();
    EXPECT_FALSE(map.empty());
    EXPECT_EQ(2, map.size());

    auto header = map[CelValue::CreateString(&trailer_name)];
    EXPECT_TRUE(header.has_value());
    ASSERT_TRUE(header.value().IsString());
    EXPECT_EQ("b", header.value().StringOrDie().value());
  }

  {
    auto value = response[CelValue::CreateStringView(Flags)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(0x1, value.value().Int64OrDie());
  }

  {
    auto value = response[CelValue::CreateStringView(GrpcStatus)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(0x8, value.value().Int64OrDie());
  }

  {
    auto value = empty_response[CelValue::CreateStringView(GrpcStatus)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = empty_response[CelValue::CreateStringView(Code)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = empty_response[CelValue::CreateStringView(CodeDetails)];
    EXPECT_FALSE(value.has_value());
  }

  {
    Http::TestResponseHeaderMapImpl header_map{{header_name, "a"}, {grpc_status, "7"}};
    Http::TestResponseTrailerMapImpl trailer_map{{trailer_name, "b"}};
    Protobuf::Arena arena;
    ResponseWrapper response_header_status(arena, &header_map, &trailer_map, info);
    auto value = response_header_status[CelValue::CreateStringView(GrpcStatus)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(0x7, value.value().Int64OrDie());
  }
  {
    Http::TestResponseHeaderMapImpl header_map{{header_name, "a"}};
    Http::TestResponseTrailerMapImpl trailer_map{{trailer_name, "b"}};
    Protobuf::Arena arena;
    ResponseWrapper response_no_status(arena, &header_map, &trailer_map, info);
    auto value = response_no_status[CelValue::CreateStringView(GrpcStatus)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(0xc, value.value().Int64OrDie()); // http:404 -> grpc:12
  }
  {
    NiceMock<StreamInfo::MockStreamInfo> info_without_code;
    Http::TestResponseHeaderMapImpl header_map{{header_name, "a"}};
    Http::TestResponseTrailerMapImpl trailer_map{{trailer_name, "b"}};
    Protobuf::Arena arena;
    ResponseWrapper response_no_status(arena, &header_map, &trailer_map, info_without_code);
    auto value = response_no_status[CelValue::CreateStringView(GrpcStatus)];
    EXPECT_FALSE(value.has_value());
  }
}

Project: envoy

  void iterate(HeaderMap::ConstIterateCb cb) const override { header_map_->iterate(cb); }

Project: envoy

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

Project: envoy

    HeaderString& value() override { return value_; }

Project: envoy

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

Project: envoy

int HeaderMapIterator::luaPairsIterator(lua_State* state) {
  if (current_ == entries_.size()) {
    parent_.iterator_.reset();
    return 0;
  } else {
    const absl::string_view key_view(entries_[current_]->key().getStringView());
    lua_pushlstring(state, key_view.data(), key_view.length());
    const absl::string_view value_view(entries_[current_]->value().getStringView());
    lua_pushlstring(state, value_view.data(), value_view.length());
    current_++;
    return 2;
  }
}

Project: envoy

  static std::string getProtobufBinaryStringFromMessage(const Protobuf::Message& message) {
    std::string pb_binary_str;
    pb_binary_str.reserve(message.ByteSizeLong());
    message.SerializeToString(&pb_binary_str);
    return pb_binary_str;
  }

Project: envoy

  TestHeaderMapImplBase(const HeaderMap& rhs) {
    HeaderMapImpl::copyFrom(*header_map_, rhs);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

HeaderMapImplUtility::getAllHeaderMapImplInfo() {
  std::vector<HeaderMapImplUtility::HeaderMapImplInfo> ret;
  ret.push_back(makeHeaderMapImplInfo<RequestHeaderMapImpl>("request header map"));
  ret.push_back(makeHeaderMapImplInfo<RequestTrailerMapImpl>("request trailer map"));
  ret.push_back(makeHeaderMapImplInfo<ResponseHeaderMapImpl>("response header map"));
  ret.push_back(makeHeaderMapImplInfo<ResponseTrailerMapImpl>("response trailer map"));
  return ret;
}

Project: envoy

  bool empty() const override { return value_ == nullptr ? true : value_->empty(); }

Project: envoy

TEST(HeaderDataConstructorTest, RangeMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
range_match:
  start: 0
  end: -10
  )EOF";

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

  EXPECT_EQ("test-header", header_data.name_.get());
  EXPECT_EQ(HeaderUtility::HeaderMatchType::Range, header_data.header_match_type_);
  EXPECT_EQ("", header_data.value_);
  EXPECT_EQ(0, header_data.range_.start());
  EXPECT_EQ(-10, header_data.range_.end());
}

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, BadTypesInTableForDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:dynamicMetadata():set("envoy.lb", "hello", {x="world", y=function(a, b) end})
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem());
  Filters::Common::Lua::LuaDeathRef<StreamInfoWrapper> wrapper(
      StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true);
  EXPECT_THROW_WITH_MESSAGE(start("callMe"), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:3: unexpected type 'function' in dynamicMetadata");
}

Project: envoy

bool HeaderUtility::headerNameContainsUnderscore(const absl::string_view header_name) {
  return header_name.find('_') != absl::string_view::npos;
}

Project: envoy

HeaderString::Type HeaderString::type() const {
  // buffer_.index() is correlated with the order of Reference and Inline in the
  // enum.
  ASSERT(buffer_.index() == 0 || buffer_.index() == 1);
  ASSERT((buffer_.index() == 0 && absl::holds_alternative<absl::string_view>(buffer_)) ||
         (buffer_.index() != 0));
  ASSERT((buffer_.index() == 1 && absl::holds_alternative<InlineHeaderVector>(buffer_)) ||
         (buffer_.index() != 1));
  return Type(buffer_.index());
}

Project: envoy

TEST(MatchHeadersTest, HeaderSuffixInverseMatch) {
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}};
  TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}};

  const std::string yaml = R"EOF(
name: match-header
suffix_match: value
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

TEST_F(LuaStreamInfoWrapperTest, ReturnCurrentProtocol) {
  expectToPrintCurrentProtocol(Http::Protocol::Http10);
  expectToPrintCurrentProtocol(Http::Protocol::Http11);
  expectToPrintCurrentProtocol(Http::Protocol::Http2);
}

Project: envoy

int StreamInfoWrapper::luaDynamicMetadata(lua_State* state) {
  if (dynamic_metadata_wrapper_.get() != nullptr) {
    dynamic_metadata_wrapper_.pushStack();
  } else {
    dynamic_metadata_wrapper_.reset(DynamicMetadataMapWrapper::create(state, *this), true);
  }
  return 1;
}

Project: envoy

TEST_P(RBACIntegrationTest, DeniedWithPrefixRule) {
  config_helper_.addConfigModifier(
      [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
             cfg) { cfg.mutable_normalize_path()->set_value(false); });
  config_helper_.addFilter(RBAC_CONFIG_WITH_PREFIX_MATCH);
  initialize();

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

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "POST"},
          {":path", "/foo/../bar"},
          {":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>::iterator end() { return headers_.end(); }

Project: envoy

ExtractorImpl::ExtractorImpl(const JwtProviderList& providers) {
  for (const auto& provider : providers) {
    ASSERT(provider);
    addProvider(*provider);
  }
}

Project: envoy

  PeerWrapper(const StreamInfo::StreamInfo& info, bool local) : info_(info), local_(local) {}

Project: envoy

  const HeaderEntryImpl* const* constInlineHeaders() const override { return inline_headers_; }

Project: envoy

TEST(MatchHeadersTest, HeaderSuffixMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}};

  const std::string yaml = R"EOF(
name: match-header
suffix_match: value
  )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

  HeaderMap::GetResult getAll(const LowerCaseString& key) const override {
    return HeaderMapImpl::getAll(key);
  }

Project: envoy

    bool operator==(const Handle& rhs) const { return it_ == rhs.it_; }

Project: envoy

TEST(HeaderDataConstructorTest, GetAllOfHeader) {
  TestRequestHeaderMapImpl headers{
      {"foo", "val1"}, {"bar", "bar2"}, {"foo", "eep, bar"}, {"foo", ""}};

  std::vector<absl::string_view> foo_out;
  Http::HeaderUtility::getAllOfHeader(headers, "foo", foo_out);
  ASSERT_EQ(foo_out.size(), 3);
  ASSERT_EQ(foo_out[0], "val1");
  ASSERT_EQ(foo_out[1], "eep, bar");
  ASSERT_EQ(foo_out[2], "");

  std::vector<absl::string_view> bar_out;
  Http::HeaderUtility::getAllOfHeader(headers, "bar", bar_out);
  ASSERT_EQ(bar_out.size(), 1);
  ASSERT_EQ(bar_out[0], "bar2");

  std::vector<absl::string_view> eep_out;
  Http::HeaderUtility::getAllOfHeader(headers, "eep", eep_out);
  ASSERT_EQ(eep_out.size(), 0);
}

Project: envoy

Rule::Rule(const ProtoRule& rule) : rule_(rule) {
  // Ensure only one of header and cookie is specified.
  // TODO(radha13): remove this once we are on v4 and these fields are folded into a oneof.
  if (!rule.cookie().empty() && !rule.header().empty()) {
    throw EnvoyException("Cannot specify both header and cookie");
  }

  // Initialize the shared pointer.
  if (!rule.header().empty()) {
    selector_ =
        std::make_shared<HeaderValueSelector>(Http::LowerCaseString(rule.header()), rule.remove());
  } else if (!rule.cookie().empty()) {
    selector_ = std::make_shared<CookieValueSelector>(rule.cookie());
  } else {
    throw EnvoyException("One of Cookie or Header option needs to be specified");
  }

  // Rule must have at least one of the `on_header_*` fields set.
  if (!rule.has_on_header_present() && !rule.has_on_header_missing()) {
    const auto& error = fmt::format("header to metadata filter: rule for {} has neither "
                                    "`on_header_present` nor `on_header_missing` set",
                                    selector_->toString());
    throw EnvoyException(error);
  }

  // Ensure value and regex_value_rewrite are not mixed.
  // TODO(rgs1): remove this once we are on v4 and these fields are folded into a oneof.
  if (!rule.on_header_present().value().empty() &&
      rule.on_header_present().has_regex_value_rewrite()) {
    throw EnvoyException("Cannot specify both value and regex_value_rewrite");
  }

  // Remove field is un-supported for cookie.
  if (!rule.cookie().empty() && rule.remove()) {
    throw EnvoyException("Cannot specify remove for cookie");
  }

  if (rule.has_on_header_missing() && rule.on_header_missing().value().empty()) {
    throw EnvoyException("Cannot specify on_header_missing rule with an empty value");
  }

  if (rule.on_header_present().has_regex_value_rewrite()) {
    const auto& rewrite_spec = rule.on_header_present().regex_value_rewrite();
    regex_rewrite_ = Regex::Utility::parseRegex(rewrite_spec.pattern());
    regex_rewrite_substitution_ = rewrite_spec.substitution();
  }
}

Project: envoy

TEST_F(ExtractorTest, TestPrefixHeaderMatch) {
  auto headers = TestRequestHeaderMapImpl{{"prefix-header", "AAABBBjwt_token"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 2);

  // Match issuer 5 with map key as: prefix-header + AAA
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer5"));
  EXPECT_EQ(tokens[0]->token(), "BBBjwt_token");

  // Match issuer 6 with map key as: prefix-header + AAABBB which is after AAA
  EXPECT_TRUE(tokens[1]->isIssuerSpecified("issuer6"));
  EXPECT_EQ(tokens[1]->token(), "jwt_token");

  // Test token remove
  tokens[0]->removeJwt(headers);
  EXPECT_FALSE(headers.get(Http::LowerCaseString("prefix-header")));
}

Project: envoy

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

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

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

Project: envoy

DEFINE_PROTO_FUZZER(const test::extensions::filters::common::expr::EvaluatorTestCase& input) {
  // Create builder without constant folding.
  static Expr::BuilderPtr builder = Expr::createBuilder(nullptr);
  std::unique_ptr<TestStreamInfo> stream_info;

  try {
    // Validate that the input has an expression.
    TestUtility::validate(input);
    // Create stream_info to test against, this may catch exceptions from invalid addresses.
    stream_info = Fuzz::fromStreamInfo(input.stream_info());
  } catch (const EnvoyException& e) {
    ENVOY_LOG_MISC(debug, "EnvoyException: {}", e.what());
    return;
  }

  auto request_headers = Fuzz::fromHeaders<Http::TestRequestHeaderMapImpl>(input.request_headers());
  auto response_headers =
      Fuzz::fromHeaders<Http::TestResponseHeaderMapImpl>(input.response_headers());
  auto response_trailers = Fuzz::fromHeaders<Http::TestResponseTrailerMapImpl>(input.trailers());

  try {
    // Create the CEL expression.
    Expr::ExpressionPtr expr = Expr::createExpression(*builder, input.expression());

    // Evaluate the CEL expression.
    Protobuf::Arena arena;
    Expr::evaluate(*expr, arena, *stream_info, &request_headers, &response_headers,
                   &response_trailers);
  } catch (const CelException& e) {
    ENVOY_LOG_MISC(debug, "CelException: {}", e.what());
  }
}

Project: envoy

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

  const std::string yaml = R"EOF(
name: match-header
present_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

TEST(HeaderMapImplTest, TestRequestHeaderMapImplyCopy) {
  TestRequestHeaderMapImpl foo;
  foo.addCopy(LowerCaseString("foo"), "bar");
  auto headers = std::make_unique<TestRequestHeaderMapImpl>(foo);
  EXPECT_EQ("bar", headers->get(LowerCaseString("foo"))->value().getStringView());
  TestRequestHeaderMapImpl baz{{"foo", "baz"}};
  baz = *headers;
  EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))->value().getStringView());
  const TestRequestHeaderMapImpl& baz2 = baz;
  baz = baz2;
  EXPECT_EQ("bar", baz.get(LowerCaseString("foo"))->value().getStringView());
}

Project: envoy

TEST_F(HeaderUtilityTest, RemovePortsFromHostConnect) {
  const std::vector<std::pair<std::string, std::string>> host_headers{
      {"localhost:443", "localhost:443"},
  };
  for (const auto& host_pair : host_headers) {
    auto& host_header = hostHeaderEntry(host_pair.first, true);
    HeaderUtility::stripPortFromHost(headers_, 443);
    EXPECT_EQ(host_header.value().getStringView(), host_pair.second);
  }
}

Project: envoy

bool HeaderUtility::isEnvoyInternalRequest(const RequestHeaderMap& headers) {
  const HeaderEntry* internal_request_header = headers.EnvoyInternalRequest();
  return internal_request_header != nullptr &&
         internal_request_header->value() == Headers::get().EnvoyInternalRequestValues.True;
}

Project: envoy

const Config* HeaderToMetadataFilter::getConfig() const {
  // Cached config pointer.
  if (effective_config_) {
    return effective_config_;
  }

  effective_config_ = Http::Utility::resolveMostSpecificPerFilterConfig<Config>(
      HttpFilterNames::get().HeaderToMetadata, decoder_callbacks_->route());
  if (effective_config_) {
    return effective_config_;
  }

  effective_config_ = config_.get();
  return effective_config_;
}

Project: envoy

TEST(MatchHeadersTest, HeaderPresence) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "value"}};
  TestRequestHeaderMapImpl unmatching_headers{{"other-header", "value"}};
  const std::string yaml = R"EOF(
name: match-header
  )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

  FilterStateWrapper(const StreamInfo::FilterState& filter_state) : filter_state_(filter_state) {}

Project: envoy

  static void jsonConvert(const Protobuf::Message& source, Protobuf::Message& dest) {
    // Explicit round-tripping to support conversions inside tests between arbitrary messages as a
    // convenience.
    ProtobufWkt::Struct tmp;
    MessageUtil::jsonConvert(source, tmp);
    MessageUtil::jsonConvert(tmp, ProtobufMessage::getStrictValidationVisitor(), dest);
  }

Project: envoy

  const std::string& token() const override { return token_; }

Project: envoy

TEST_P(RBACIntegrationTest, RbacPrefixRuleUseNormalizePath) {
  config_helper_.addConfigModifier(
      [](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
             cfg) { cfg.mutable_normalize_path()->set_value(true); });
  config_helper_.addFilter(RBAC_CONFIG_WITH_PREFIX_MATCH);
  initialize();

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

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

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

Project: envoy

void HeaderMapImpl::clear() {
  clearInline();
  headers_.clear();
  cached_byte_size_ = 0;
}

Project: envoy

TEST_F(HeaderToMetadataTest, EmptyHeaderValue) {
  initializeFilter(request_config_yaml);
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-VERSION", ""}};

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

Project: envoy

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

Project: envoy

MATCHER_P(ProtoEqIgnoreRepeatedFieldOrdering, expected, "") {
  const bool equal =
      TestUtility::protoEqual(arg, expected, /*ignore_repeated_field_ordering=*/true);
  if (!equal) {
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected proto:") << "\n"
                     << expected.DebugString()
                     << TestUtility::addLeftAndRightPadding("is not equal to actual proto:") << "\n"
                     << arg.DebugString()
                     << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

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

Project: envoy

TEST_F(HeaderToMetadataTest, OnMissingWhenHeaderIsPresent) {
  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", ""}};

  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

absl::optional<CelValue> extractSslInfo(const Ssl::ConnectionInfo& ssl_info,
                                        absl::string_view value) {
  if (value == TLSVersion) {
    return CelValue::CreateString(&ssl_info.tlsVersion());
  } else if (value == SubjectLocalCertificate) {
    return CelValue::CreateString(&ssl_info.subjectLocalCertificate());
  } else if (value == SubjectPeerCertificate) {
    return CelValue::CreateString(&ssl_info.subjectPeerCertificate());
  } else if (value == URISanLocalCertificate) {
    if (!ssl_info.uriSanLocalCertificate().empty()) {
      return CelValue::CreateString(&ssl_info.uriSanLocalCertificate()[0]);
    }
  } else if (value == URISanPeerCertificate) {
    if (!ssl_info.uriSanPeerCertificate().empty()) {
      return CelValue::CreateString(&ssl_info.uriSanPeerCertificate()[0]);
    }
  } else if (value == DNSSanLocalCertificate) {
    if (!ssl_info.dnsSansLocalCertificate().empty()) {
      return CelValue::CreateString(&ssl_info.dnsSansLocalCertificate()[0]);
    }
  } else if (value == DNSSanPeerCertificate) {
    if (!ssl_info.dnsSansPeerCertificate().empty()) {
      return CelValue::CreateString(&ssl_info.dnsSansPeerCertificate()[0]);
    }
  }
  return {};
}

Project: envoy

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

  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

TEST_F(HeaderToMetadataTest, RejectInvalidRule) {
  const std::string config = R"EOF(
request_rules:
  - header: x-something
)EOF";
  auto expected = "header to metadata filter: rule for header 'x-something' has neither "
                  "`on_header_present` nor `on_header_missing` set";
  EXPECT_THROW_WITH_MESSAGE(initializeFilter(config), EnvoyException, expected);
}

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, ModifyDuringIteration) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      for key, value in pairs(object) do
        object:add("hello", "world")
      end
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers{{"foo", "bar"}};
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; });
  EXPECT_THROW_WITH_MESSAGE(start("callMe"), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:4: header map cannot be modified while iterating");
}

Project: envoy

TEST(MatchHeadersTest, HeaderPrefixInverseMatch) {
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "value123"}};
  TestRequestHeaderMapImpl matching_headers{{"match-header", "123value"}};

  const std::string yaml = R"EOF(
name: match-header
prefix_match: value
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

TEST_F(ExtractorTest, TestDefaultHeaderLocationWithValidJWT) {
  auto headers =
      TestRequestHeaderMapImpl{{absl::StrCat("Authorization"), absl::StrCat("Bearer ", GoodToken)}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);

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

Project: envoy

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

Project: envoy

int StreamInfoWrapper::luaProtocol(lua_State* state) {
  lua_pushstring(state, Http::Utility::getProtocolString(stream_info_.protocol().value()).c_str());
  return 1;
}

Project: envoy

  JwtHeaderLocation(const std::string& token, const absl::node_hash_set<std::string>& issuers,
                    const LowerCaseString& header)
      : JwtLocationBase(token, issuers), header_(header) {}

Project: envoy

TEST(HeaderMapImplTest, AllInlineHeaders) {
  {
    auto header_map = RequestHeaderMapImpl::create();
    INLINE_REQ_HEADERS(TEST_INLINE_HEADER_FUNCS)
    INLINE_REQ_RESP_HEADERS(TEST_INLINE_HEADER_FUNCS)
  }
  {
      // No request trailer O(1) headers.
  } {
    auto header_map = ResponseHeaderMapImpl::create();
    INLINE_RESP_HEADERS(TEST_INLINE_HEADER_FUNCS)
    INLINE_REQ_RESP_HEADERS(TEST_INLINE_HEADER_FUNCS)
    INLINE_RESP_HEADERS_TRAILERS(TEST_INLINE_HEADER_FUNCS)
  }
  {
    auto header_map = ResponseTrailerMapImpl::create();
    INLINE_RESP_HEADERS_TRAILERS(TEST_INLINE_HEADER_FUNCS)
  }
}

Project: envoy

  static bool decodedResourceEq(const Config::DecodedResource& lhs,
                                const Config::DecodedResource& rhs) {
    return lhs.name() == rhs.name() && lhs.aliases() == rhs.aliases() &&
           lhs.version() == rhs.version() && lhs.hasResource() == rhs.hasResource() &&
           (!lhs.hasResource() || protoEqual(lhs.resource(), rhs.resource()));
  }

Project: envoy

TEST(MatchHeadersTest, HeaderPrefixMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "value123"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123value"}};

  const std::string yaml = R"EOF(
name: match-header
prefix_match: value
  )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 <Type type> static bool& mutableFinalized() { MUTABLE_CONSTRUCT_ON_FIRST_USE(bool); }

Project: envoy

HeaderMapImpl::HeaderEntryImpl& HeaderMapImpl::maybeCreateInline(HeaderEntryImpl** entry,
                                                                 const LowerCaseString& key) {
  if (*entry) {
    return **entry;
  }

  addSize(key.get().size());
  std::list<HeaderEntryImpl>::iterator i = headers_.insert(key);
  i->entry_ = i;
  *entry = &(*i);
  return **entry;
}

Project: envoy

TEST_F(HeaderToMetadataTest, RejectRemoveForCookie) {
  const std::string config = R"EOF(
request_rules:
  - cookie: cookie
    on_header_present:
      metadata_namespace: envoy.lb
      key: version
      type: STRING
    remove: true
)EOF";
  auto expected = "Cannot specify remove for cookie";
  EXPECT_THROW_WITH_MESSAGE(initializeFilter(config), EnvoyException, expected);
}

Project: envoy

  assertRepeatedPtrFieldEqual(const Protobuf::RepeatedPtrField<ProtoType>& lhs,
                              const Protobuf::RepeatedPtrField<ProtoType>& rhs,
                              bool ignore_ordering = false) {
    if (!repeatedPtrFieldEqual(lhs, rhs, ignore_ordering)) {
      return AssertionFailure() << RepeatedPtrUtil::debugString(lhs) << " does not match "
                                << RepeatedPtrUtil::debugString(rhs);
    }

    return AssertionSuccess();
  }

Project: envoy

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

Project: envoy

  decodeResources(const Protobuf::RepeatedPtrField<ProtobufWkt::Any>& resources,
                  const std::string& version, const std::string& name_field = "name") {
    TestOpaqueResourceDecoderImpl<MessageType> resource_decoder(name_field);
    return Config::DecodedResourcesWrapper(resource_decoder, resources, version);
  }

Project: envoy

TEST(HeaderAddTest, HeaderAdd) {
  TestRequestHeaderMapImpl headers{{"myheader1", "123value"}};
  TestRequestHeaderMapImpl headers_to_add{{"myheader2", "456value"}};

  HeaderUtility::addHeaders(headers, headers_to_add);

  headers_to_add.iterate([&headers](const Http::HeaderEntry& entry) -> Http::HeaderMap::Iterate {
    Http::LowerCaseString lower_key{std::string(entry.key().getStringView())};
    EXPECT_EQ(entry.value().getStringView(), headers.get(lower_key)->value().getStringView());
    return Http::HeaderMap::Iterate::Continue;
  });
}

Project: envoy

TEST(Context, ConnectionAttributes) {
  NiceMock<StreamInfo::MockStreamInfo> info;
  std::shared_ptr<NiceMock<Envoy::Upstream::MockHostDescription>> upstream_host(
      new NiceMock<Envoy::Upstream::MockHostDescription>());
  auto downstream_ssl_info = std::make_shared<NiceMock<Ssl::MockConnectionInfo>>();
  auto upstream_ssl_info = std::make_shared<NiceMock<Ssl::MockConnectionInfo>>();
  ConnectionWrapper connection(info);
  UpstreamWrapper upstream(info);
  PeerWrapper source(info, false);
  PeerWrapper destination(info, true);

  Network::Address::InstanceConstSharedPtr local =
      Network::Utility::parseInternetAddress("1.2.3.4", 123, false);
  Network::Address::InstanceConstSharedPtr remote =
      Network::Utility::parseInternetAddress("10.20.30.40", 456, false);
  Network::Address::InstanceConstSharedPtr upstream_address =
      Network::Utility::parseInternetAddress("10.1.2.3", 679, false);
  Network::Address::InstanceConstSharedPtr upstream_local_address =
      Network::Utility::parseInternetAddress("10.1.2.3", 1000, false);
  const std::string sni_name = "kittens.com";
  EXPECT_CALL(info, downstreamLocalAddress()).WillRepeatedly(ReturnRef(local));
  EXPECT_CALL(info, downstreamRemoteAddress()).WillRepeatedly(ReturnRef(remote));
  EXPECT_CALL(info, downstreamSslConnection()).WillRepeatedly(Return(downstream_ssl_info));
  EXPECT_CALL(info, upstreamSslConnection()).WillRepeatedly(Return(upstream_ssl_info));
  EXPECT_CALL(info, upstreamHost()).WillRepeatedly(Return(upstream_host));
  EXPECT_CALL(info, requestedServerName()).WillRepeatedly(ReturnRef(sni_name));
  EXPECT_CALL(info, upstreamLocalAddress()).WillRepeatedly(ReturnRef(upstream_local_address));
  const std::string upstream_transport_failure_reason = "ConnectionTermination";
  EXPECT_CALL(info, upstreamTransportFailureReason())
      .WillRepeatedly(ReturnRef(upstream_transport_failure_reason));
  EXPECT_CALL(*downstream_ssl_info, peerCertificatePresented()).WillRepeatedly(Return(true));
  EXPECT_CALL(*upstream_host, address()).WillRepeatedly(Return(upstream_address));

  const std::string tls_version = "TLSv1";
  EXPECT_CALL(*downstream_ssl_info, tlsVersion()).WillRepeatedly(ReturnRef(tls_version));
  EXPECT_CALL(*upstream_ssl_info, tlsVersion()).WillRepeatedly(ReturnRef(tls_version));
  std::vector<std::string> dns_sans_peer = {"www.peer.com"};
  EXPECT_CALL(*downstream_ssl_info, dnsSansPeerCertificate()).WillRepeatedly(Return(dns_sans_peer));
  EXPECT_CALL(*upstream_ssl_info, dnsSansPeerCertificate()).WillRepeatedly(Return(dns_sans_peer));
  std::vector<std::string> dns_sans_local = {"www.local.com"};
  EXPECT_CALL(*downstream_ssl_info, dnsSansLocalCertificate())
      .WillRepeatedly(Return(dns_sans_local));
  EXPECT_CALL(*upstream_ssl_info, dnsSansLocalCertificate()).WillRepeatedly(Return(dns_sans_local));
  std::vector<std::string> uri_sans_peer = {"www.peer.com/uri"};
  EXPECT_CALL(*downstream_ssl_info, uriSanPeerCertificate()).WillRepeatedly(Return(uri_sans_peer));
  EXPECT_CALL(*upstream_ssl_info, uriSanPeerCertificate()).WillRepeatedly(Return(uri_sans_peer));
  std::vector<std::string> uri_sans_local = {"www.local.com/uri"};
  EXPECT_CALL(*downstream_ssl_info, uriSanLocalCertificate())
      .WillRepeatedly(Return(uri_sans_local));
  EXPECT_CALL(*upstream_ssl_info, uriSanLocalCertificate()).WillRepeatedly(Return(uri_sans_local));
  const std::string subject_local = "local.com";
  EXPECT_CALL(*downstream_ssl_info, subjectLocalCertificate())
      .WillRepeatedly(ReturnRef(subject_local));
  EXPECT_CALL(*upstream_ssl_info, subjectLocalCertificate())
      .WillRepeatedly(ReturnRef(subject_local));
  const std::string subject_peer = "peer.com";
  EXPECT_CALL(*downstream_ssl_info, subjectPeerCertificate())
      .WillRepeatedly(ReturnRef(subject_peer));
  EXPECT_CALL(*upstream_ssl_info, subjectPeerCertificate()).WillRepeatedly(ReturnRef(subject_peer));

  {
    auto value = connection[CelValue::CreateStringView(Undefined)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = connection[CelValue::CreateInt64(13)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = source[CelValue::CreateStringView(Undefined)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = source[CelValue::CreateInt64(13)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = destination[CelValue::CreateStringView(Address)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("1.2.3.4:123", value.value().StringOrDie().value());
  }

  {
    auto value = destination[CelValue::CreateStringView(Port)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(123, value.value().Int64OrDie());
  }

  {
    auto value = source[CelValue::CreateStringView(Address)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("10.20.30.40:456", value.value().StringOrDie().value());
  }

  {
    auto value = source[CelValue::CreateStringView(Port)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(456, value.value().Int64OrDie());
  }

  {
    auto value = upstream[CelValue::CreateStringView(Address)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("10.1.2.3:679", value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(Port)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    EXPECT_EQ(679, value.value().Int64OrDie());
  }

  {
    auto value = connection[CelValue::CreateStringView(MTLS)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsBool());
    EXPECT_TRUE(value.value().BoolOrDie());
  }

  {
    auto value = connection[CelValue::CreateStringView(RequestedServerName)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(sni_name, value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(TLSVersion)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(tls_version, value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(DNSSanLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(dns_sans_local[0], value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(DNSSanPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(dns_sans_peer[0], value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(URISanLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(uri_sans_local[0], value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(URISanPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(uri_sans_peer[0], value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(SubjectLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(subject_local, value.value().StringOrDie().value());
  }

  {
    auto value = connection[CelValue::CreateStringView(SubjectPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(subject_peer, value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(TLSVersion)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(tls_version, value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(DNSSanLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(dns_sans_local[0], value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(DNSSanPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(dns_sans_peer[0], value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(URISanLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(uri_sans_local[0], value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(URISanPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(uri_sans_peer[0], value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(SubjectLocalCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(subject_local, value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(SubjectPeerCertificate)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(subject_peer, value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(UpstreamLocalAddress)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(upstream_local_address->asStringView(), value.value().StringOrDie().value());
  }

  {
    auto value = upstream[CelValue::CreateStringView(UpstreamTransportFailureReason)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ(upstream_transport_failure_reason, value.value().StringOrDie().value());
  }
}

Project: envoy

TEST_F(HeaderToMetadataTest, RejectEmptyHeader) {
  const std::string config = R"EOF(
request_rules:
  - header: ""

)EOF";
  auto expected = "One of Cookie or Header option needs to be specified";
  EXPECT_THROW_WITH_MESSAGE(initializeFilter(config), EnvoyException, expected);
}

Project: envoy

TEST(MatchHeadersTest, HeaderExactMatchInverse) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "other-value"},
                                            {"other-header", "match-value"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "match-value"}};

  const std::string yaml = R"EOF(
name: match-header
exact_match: match-value
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

TEST(HeaderDataConstructorTest, ContainsMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
contains_match: somevalueinside
  )EOF";

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

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

Project: envoy

HeaderUtility::requestHeadersValid(const RequestHeaderMap& headers) {
  // Make sure the host is valid.
  if (headers.Host() && !HeaderUtility::authorityIsValid(headers.Host()->value().getStringView())) {
    return SharedResponseCodeDetails::get().InvalidAuthority;
  }
  return absl::nullopt;
}

Project: envoy

TEST(Context, RequestAttributes) {
  NiceMock<StreamInfo::MockStreamInfo> info;
  NiceMock<StreamInfo::MockStreamInfo> empty_info;
  Http::TestRequestHeaderMapImpl header_map{
      {":method", "POST"},           {":scheme", "http"},      {":path", "/meow?yes=1"},
      {":authority", "kittens.com"}, {"referer", "dogs.com"},  {"user-agent", "envoy-mobile"},
      {"content-length", "10"},      {"x-request-id", "blah"}, {"double-header", "foo"},
      {"double-header", "bar"}};
  Protobuf::Arena arena;
  RequestWrapper request(arena, &header_map, info);
  RequestWrapper empty_request(arena, nullptr, empty_info);

  EXPECT_CALL(info, bytesReceived()).WillRepeatedly(Return(10));
  // "2018-04-03T23:06:09.123Z".
  const SystemTime start_time(std::chrono::milliseconds(1522796769123));
  EXPECT_CALL(info, startTime()).WillRepeatedly(Return(start_time));
  absl::optional<std::chrono::nanoseconds> dur = std::chrono::nanoseconds(15000000);
  EXPECT_CALL(info, requestComplete()).WillRepeatedly(Return(dur));
  EXPECT_CALL(info, protocol()).WillRepeatedly(Return(Http::Protocol::Http2));

  // stub methods
  EXPECT_EQ(0, request.size());
  EXPECT_FALSE(request.empty());

  {
    auto value = request[CelValue::CreateStringView(Undefined)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = request[CelValue::CreateInt64(13)];
    EXPECT_FALSE(value.has_value());
  }

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

  {
    auto value = empty_request[CelValue::CreateStringView(Scheme)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = request[CelValue::CreateStringView(Host)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("kittens.com", value.value().StringOrDie().value());
  }

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

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

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

  {
    auto value = request[CelValue::CreateStringView(Referer)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("dogs.com", value.value().StringOrDie().value());
  }

  {
    auto value = request[CelValue::CreateStringView(UserAgent)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsString());
    EXPECT_EQ("envoy-mobile", value.value().StringOrDie().value());
  }

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

  {
    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(TotalSize)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    // this includes the headers size
    EXPECT_EQ(170, value.value().Int64OrDie());
  }

  {
    auto value = empty_request[CelValue::CreateStringView(TotalSize)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsInt64());
    // this includes the headers size
    EXPECT_EQ(0, value.value().Int64OrDie());
  }

  {
    auto value = request[CelValue::CreateStringView(Time)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsTimestamp());
    EXPECT_EQ("2018-04-03T23:06:09.123+00:00", absl::FormatTime(value.value().TimestampOrDie()));
  }

  {
    auto value = request[CelValue::CreateStringView(Headers)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsMap());
    auto& map = *value.value().MapOrDie();
    EXPECT_FALSE(map.empty());
    EXPECT_EQ(10, map.size());

    auto header = map[CelValue::CreateStringView(Referer)];
    EXPECT_TRUE(header.has_value());
    ASSERT_TRUE(header.value().IsString());
    EXPECT_EQ("dogs.com", header.value().StringOrDie().value());

    auto header2 = map[CelValue::CreateStringView("double-header")];
    EXPECT_TRUE(header2.has_value());
    ASSERT_TRUE(header2.value().IsString());
    EXPECT_EQ("foo,bar", header2.value().StringOrDie().value());
  }

  {
    auto value = request[CelValue::CreateStringView(Duration)];
    EXPECT_TRUE(value.has_value());
    ASSERT_TRUE(value.value().IsDuration());
    EXPECT_EQ("15ms", absl::FormatDuration(value.value().DurationOrDie()));
  }

  {
    auto value = empty_request[CelValue::CreateStringView(Duration)];
    EXPECT_FALSE(value.has_value());
  }

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

  {
    auto value = empty_request[CelValue::CreateStringView(Protocol)];
    EXPECT_FALSE(value.has_value());
  }
}

Project: envoy

  TestHeaderMapImplBase& operator=(const TestHeaderMapImplBase& rhs) {
    if (this == &rhs) {
      return *this;
    }
    clear();
    HeaderMapImpl::copyFrom(*header_map_, rhs);
    header_map_->verifyByteSizeInternalForTest();
    return *this;
  }

Project: envoy

void HeaderMapImpl::dumpState(std::ostream& os, int indent_level) const {
  iterate([&os,
           spaces = spacesForLevel(indent_level)](const HeaderEntry& header) -> HeaderMap::Iterate {
    os << spaces << "'" << header.key().getStringView() << "', '" << header.value().getStringView()
       << "'\n";
    return HeaderMap::Iterate::Continue;
  });
}

Project: envoy

TEST_F(HeaderUtilityTest, RemovePortsFromHost) {
  const std::vector<std::pair<std::string, std::string>> host_headers{
      {"localhost", "localhost"},           // w/o port part
      {"localhost:443", "localhost"},       // name w/ port
      {"", ""},                             // empty
      {":443", ""},                         // just port
      {"192.168.1.1", "192.168.1.1"},       // ipv4
      {"192.168.1.1:443", "192.168.1.1"},   // ipv4 w/ port
      {"[fc00::1]:443", "[fc00::1]"},       // ipv6 w/ port
      {"[fc00::1]", "[fc00::1]"},           // ipv6
      {":", ":"},                           // malformed string #1
      {"]:", "]:"},                         // malformed string #2
      {":abc", ":abc"},                     // malformed string #3
      {"localhost:80", "localhost:80"},     // port not matching w/ hostname
      {"192.168.1.1:80", "192.168.1.1:80"}, // port not matching w/ ipv4
      {"[fc00::1]:80", "[fc00::1]:80"}      // port not matching w/ ipv6
  };

  for (const auto& host_pair : host_headers) {
    auto& host_header = hostHeaderEntry(host_pair.first);
    HeaderUtility::stripPortFromHost(headers_, 443);
    EXPECT_EQ(host_header.value().getStringView(), host_pair.second);
  }
}

Project: envoy

  absl::string_view getInlineValue(Handle handle) const {
    const auto header = getInline(handle);
    if (header != nullptr) {
      return header->value().getStringView();
    }
    return {};
  }

Project: envoy

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

Project: envoy

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

  EXPECT_CALL(encoder_callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_));
  EXPECT_CALL(req_info_,
              setDynamicMetadata(HttpFilterNames::get().HeaderToMetadata, MapEq(expected)));
  Http::TestResponseHeaderMapImpl continue_response{{":status", "100"}};
  EXPECT_EQ(Http::FilterHeadersStatus::Continue,
            filter_->encode100ContinueHeaders(continue_response));
  EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->encodeHeaders(incoming_headers, false));
  EXPECT_EQ(empty_headers, incoming_headers);
  Http::MetadataMap metadata_map{{"metadata", "metadata"}};
  EXPECT_EQ(Http::FilterMetadataStatus::Continue, filter_->encodeMetadata(metadata_map));
  Buffer::OwnedImpl data("data");
  EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->encodeData(data, false));
  Http::TestResponseTrailerMapImpl incoming_trailers;
  EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->encodeTrailers(incoming_trailers));
}

Project: envoy

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

Project: envoy

  static bool repeatedPtrFieldEqual(const Protobuf::RepeatedPtrField<ProtoType>& lhs,
                                    const Protobuf::RepeatedPtrField<ProtoType>& rhs,
                                    bool ignore_ordering = false) {
    if (lhs.size() != rhs.size()) {
      return false;
    }

    if (!ignore_ordering) {
      for (int i = 0; i < lhs.size(); ++i) {
        if (!TestUtility::protoEqual(lhs[i], rhs[i], /*ignore_ordering=*/false)) {
          return false;
        }
      }

      return true;
    }
    using ProtoList = std::list<std::unique_ptr<const Protobuf::Message>>;
    // Iterate through using protoEqual as ignore_ordering is true, and fields
    // in the sub-protos may also be out of order.
    ProtoList lhs_list =
        RepeatedPtrUtil::convertToConstMessagePtrContainer<ProtoType, ProtoList>(lhs);
    ProtoList rhs_list =
        RepeatedPtrUtil::convertToConstMessagePtrContainer<ProtoType, ProtoList>(rhs);
    while (!lhs_list.empty()) {
      bool found = false;
      for (auto it = rhs_list.begin(); it != rhs_list.end(); ++it) {
        if (TestUtility::protoEqual(*lhs_list.front(), **it,
                                    /*ignore_ordering=*/true)) {
          lhs_list.pop_front();
          rhs_list.erase(it);
          found = true;
          break;
        }
      }
      if (!found) {
        return false;
      }
    }
    return true;
  }

Project: envoy

MATCHER_P2(ProtoEqIgnoringField, expected, ignored_field, "") {
  const bool equal = TestUtility::protoEqualIgnoringField(arg, expected, ignored_field);
  if (!equal) {
    std::string but_ignoring = absl::StrCat("(but ignoring ", ignored_field, ")");
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected proto:") << "\n"
                     << TestUtility::addLeftAndRightPadding(but_ignoring) << "\n"
                     << expected.DebugString()
                     << TestUtility::addLeftAndRightPadding("is not equal to actual proto:") << "\n"
                     << arg.DebugString()
                     << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

TEST(MatchHeadersTest, MustMatchAllHeaderData) {
  TestRequestHeaderMapImpl matching_headers_1{{"match-header-A", "1"}, {"match-header-B", "2"}};
  TestRequestHeaderMapImpl matching_headers_2{
      {"match-header-A", "3"}, {"match-header-B", "4"}, {"match-header-C", "5"}};
  TestRequestHeaderMapImpl unmatching_headers_1{{"match-header-A", "6"}};
  TestRequestHeaderMapImpl unmatching_headers_2{{"match-header-B", "7"}};
  TestRequestHeaderMapImpl unmatching_headers_3{{"match-header-A", "8"}, {"match-header-C", "9"}};
  TestRequestHeaderMapImpl unmatching_headers_4{{"match-header-C", "10"}, {"match-header-D", "11"}};

  const std::string yamlA = R"EOF(
name: match-header-A
  )EOF";

  const std::string yamlB = R"EOF(
name: match-header-B
  )EOF";

  std::vector<HeaderUtility::HeaderDataPtr> header_data;
  header_data.push_back(
      std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(yamlA)));
  header_data.push_back(
      std::make_unique<HeaderUtility::HeaderData>(parseHeaderMatcherFromYaml(yamlB)));
  EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_1, header_data));
  EXPECT_TRUE(HeaderUtility::matchHeaders(matching_headers_2, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_1, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_2, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_3, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(unmatching_headers_4, header_data));
}

Project: envoy

  static bool protoEqualIgnoringField(const Protobuf::Message& lhs, const Protobuf::Message& rhs,
                                      const std::string& field_to_ignore) {
    Protobuf::util::MessageDifferencer differencer;
    const Protobuf::FieldDescriptor* ignored_field =
        lhs.GetDescriptor()->FindFieldByName(field_to_ignore);
    ASSERT(ignored_field != nullptr, "Field name to ignore not found.");
    differencer.IgnoreField(ignored_field);
    return differencer.Compare(lhs, rhs);
  }

Project: envoy

HeaderToMetadataFilter::HeaderToMetadataFilter(const ConfigSharedPtr config) : config_(config) {}

Project: envoy

  ConnectionWrapper(const StreamInfo::StreamInfo& info) : info_(info) {}

Project: envoy

    static absl::optional<StaticLookupResponse> lookup(HeaderMapImpl& header_map,
                                                       absl::string_view key) {
      const auto& entry = ConstSingleton<StaticLookupTable>::get().find(key);
      if (entry != nullptr) {
        return entry(header_map);
      } else {
        return absl::nullopt;
      }
    }

Project: envoy

  size_t size() const override { return header_map_->size(); }

Project: envoy

TEST(MatchHeadersTest, HeaderContainsInverseMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}};

  const std::string yaml = R"EOF(
name: match-header
contains_match: onevalue
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(unmatching_headers, header_data));
  EXPECT_FALSE(HeaderUtility::matchHeaders(matching_headers, header_data));
}

Project: envoy

  uint64_t byteSize() const override { return header_map_->byteSize(); }

Project: envoy

void HeaderToMetadataFilter::setEncoderFilterCallbacks(
    Http::StreamEncoderFilterCallbacks& callbacks) {
  encoder_callbacks_ = &callbacks;
}

Project: envoy

  static const envoy::type::matcher::v3::StringMatcher createRegexMatcher(std::string str) {
    envoy::type::matcher::v3::StringMatcher matcher;
    matcher.set_hidden_envoy_deprecated_regex(str);
    return matcher;
  }

Project: envoy

  void addCopy(const std::string& key, const std::string& value) {
    addCopy(LowerCaseString(key), value);
  }

Project: envoy

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

Project: envoy

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

Project: envoy

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

Project: envoy

TEST(HeaderDataConstructorTest, InvertMatchSpecifier) {
  const std::string yaml = R"EOF(
name: test-header
exact_match: value
invert_match: true
)EOF";

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

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

Project: envoy

  absl::optional<CelValue> operator[](CelValue key) const override {
    if (value_ == nullptr || !key.IsString()) {
      return {};
    }
    auto str = std::string(key.StringOrDie().value());
    if (!Http::validHeaderString(str)) {
      // Reject key if it is an invalid header string
      return {};
    }
    return convertHeaderEntry(
        arena_, Http::HeaderUtility::getAllOfHeaderAsString(*value_, Http::LowerCaseString(str)));
  }

Project: envoy

TEST(Context, FilterStateAttributes) {
  StreamInfo::FilterStateImpl filter_state(StreamInfo::FilterState::LifeSpan::FilterChain);
  FilterStateWrapper wrapper(filter_state);
  ProtobufWkt::Arena arena;
  wrapper.Produce(&arena);

  const std::string key = "filter_state_key";
  const std::string serialized = "filter_state_value";
  const std::string missing = "missing_key";

  auto accessor = std::make_shared<Envoy::Router::StringAccessorImpl>(serialized);
  filter_state.setData(key, accessor, StreamInfo::FilterState::StateType::ReadOnly);

  {
    auto value = wrapper[CelValue::CreateStringView(missing)];
    EXPECT_FALSE(value.has_value());
  }

  {
    auto value = wrapper[CelValue::CreateStringView(key)];
    EXPECT_TRUE(value.has_value());
    EXPECT_TRUE(value.value().IsBytes());
    EXPECT_EQ(serialized, value.value().BytesOrDie().value());
  }
}

Project: envoy

    HeaderList() : pseudo_headers_end_(headers_.end()) {}

Project: envoy

TEST(HeaderMapImplTest, RemoveHost) {
  TestRequestHeaderMapImpl headers;
  headers.setHost("foo");
  EXPECT_EQ("foo", headers.get_("host"));
  EXPECT_EQ("foo", headers.get_(":authority"));
  // Make sure that when we remove by "host" without using the inline functions, the mapping to
  // ":authority" still takes place.
  // https://github.com/envoyproxy/envoy/pull/12160
  EXPECT_EQ(1UL, headers.remove("host"));
  EXPECT_EQ("", headers.get_("host"));
  EXPECT_EQ("", headers.get_(":authority"));
  EXPECT_EQ(nullptr, headers.Host());
}

Project: envoy

void HeaderMapImpl::appendCopy(const LowerCaseString& key, absl::string_view value) {
  // TODO(#9221): converge on and document a policy for coalescing multiple headers.
  auto entry = getExisting(key);
  if (!entry.empty()) {
    const uint64_t added_size = appendToHeader(entry[0]->value(), value);
    addSize(added_size);
  } else {
    addCopy(key, value);
  }
}

Project: envoy

TEST(HeaderDataConstructorTest, NoSpecifierSet) {
  const std::string yaml = R"EOF(
name: test-header
  )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_);
}

Project: envoy

  size_t size() const override { return HeaderMapImpl::size(); }

Project: envoy

TEST_F(ExtractorTest, TestDefaultHeaderLocation) {
  auto headers = TestRequestHeaderMapImpl{{"Authorization", "Bearer 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"));

  // Test token remove
  tokens[0]->removeJwt(headers);
  EXPECT_FALSE(headers.has(Http::CustomHeaders::get().Authorization));
}

Project: envoy

  void clearInline() override { memset(inline_headers_, 0, inlineHeadersSize()); }

Project: envoy

TEST(HeaderIsValidTest, HeaderNameContainsUnderscore) {
  EXPECT_FALSE(HeaderUtility::headerNameContainsUnderscore("cookie"));
  EXPECT_FALSE(HeaderUtility::headerNameContainsUnderscore("x-something"));
  EXPECT_TRUE(HeaderUtility::headerNameContainsUnderscore("_cookie"));
  EXPECT_TRUE(HeaderUtility::headerNameContainsUnderscore("cookie_"));
  EXPECT_TRUE(HeaderUtility::headerNameContainsUnderscore("x_something"));
}

Project: envoy

Config::Config(const envoy::extensions::filters::http::header_to_metadata::v3::Config config,
               const bool per_route) {
  request_set_ = Config::configToVector(config.request_rules(), request_rules_);
  response_set_ = Config::configToVector(config.response_rules(), response_rules_);

  // Note: empty configs are fine for the global config, which would be the case for enabling
  //       the filter globally without rules and then applying them at the virtual host or
  //       route level. At the virtual or route level, it makes no sense to have an empty
  //       config so we throw an error.
  if (per_route && !response_set_ && !request_set_) {
    throw EnvoyException("header_to_metadata_filter: Per filter configs must at least specify "
                         "either request or response rules");
  }
}

Project: envoy

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

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

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "POST"},
          {":path", "/path"},
          {":scheme", "http"},
          {":authority", "host"},
          {"xxx", "yyy"},
          {"xxx", "zzz"},
      },
      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 bool jsonStringEqual(const std::string& lhs, const std::string& rhs) {
    return protoEqual(jsonToStruct(lhs), jsonToStruct(rhs));
  }

Project: envoy

  template <class Type> static Type flipOrder(const Type& bytes) {
    Type result{0};
    Type data = bytes;
    for (Type i = 0; i < sizeof(Type); i++) {
      result <<= 8;
      result |= (data & Type(0xFF));
      data >>= 8;
    }
    return result;
  }

Project: envoy

TEST(HeaderMapImplTest, IterateReverse) {
  TestRequestHeaderMapImpl headers;
  headers.addCopy(LowerCaseString("hello"), "world");
  headers.addCopy(LowerCaseString("foo"), "bar");
  LowerCaseString world_key("world");
  headers.setReferenceKey(world_key, "hello");

  HeaderAndValueCb cb;

  InSequence seq;
  EXPECT_CALL(cb, Call("world", "hello"));
  EXPECT_CALL(cb, Call("foo", "bar"));
  // no "hello"
  headers.iterateReverse([&cb](const Http::HeaderEntry& header) -> HeaderMap::Iterate {
    cb.Call(std::string(header.key().getStringView()), std::string(header.value().getStringView()));
    if (header.key().getStringView() != "foo") {
      return HeaderMap::Iterate::Continue;
    } else {
      return HeaderMap::Iterate::Break;
    }
  });
}

Project: envoy

  size_t size() const { return headers_.size(); }

Project: envoy

  static Config::DecodedResourcesWrapper decodeResources(std::vector<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

void HeaderUtility::getAllOfHeader(const HeaderMap& headers, absl::string_view key,
                                   std::vector<absl::string_view>& out) {
  headers.iterate([key = LowerCaseString(std::string(key)),
                   &out](const HeaderEntry& header) -> HeaderMap::Iterate {
    if (header.key() == key.get().c_str()) {
      out.emplace_back(header.value().getStringView());
    }
    return HeaderMap::Iterate::Continue;
  });
}

Project: envoy

bool HeaderUtility::shouldCloseConnection(Http::Protocol protocol,
                                          const RequestOrResponseHeaderMap& headers) {
  // HTTP/1.0 defaults to single-use connections. Make sure the connection will be closed unless
  // Keep-Alive is present.
  if (protocol == Protocol::Http10 &&
      (!headers.Connection() ||
       !Envoy::StringUtil::caseFindToken(headers.Connection()->value().getStringView(), ",",
                                         Http::Headers::get().ConnectionValues.KeepAlive))) {
    return true;
  }

  if (protocol == Protocol::Http11 && headers.Connection() &&
      Envoy::StringUtil::caseFindToken(headers.Connection()->value().getStringView(), ",",
                                       Http::Headers::get().ConnectionValues.Close)) {
    return true;
  }

  // Note: Proxy-Connection is not a standard header, but is supported here
  // since it is supported by http-parser the underlying parser for http
  // requests.
  if (protocol < Protocol::Http2 && headers.ProxyConnection() &&
      Envoy::StringUtil::caseFindToken(headers.ProxyConnection()->value().getStringView(), ",",
                                       Http::Headers::get().ConnectionValues.Close)) {
    return true;
  }
  return false;
}

Project: envoy

TEST(HeaderMapImplTest, SetRemovesAllValues) {
  TestRequestHeaderMapImpl headers;

  LowerCaseString key1("hello");
  LowerCaseString key2("olleh");
  std::string ref_value1("world");
  std::string ref_value2("planet");
  std::string ref_value3("globe");
  std::string ref_value4("earth");
  std::string ref_value5("blue marble");

  headers.addReference(key1, ref_value1);
  headers.addReference(key2, ref_value2);
  headers.addReference(key1, ref_value3);
  headers.addReference(key1, ref_value4);

  {
    HeaderAndValueCb cb;

    InSequence seq;
    EXPECT_CALL(cb, Call("hello", "world"));
    EXPECT_CALL(cb, Call("olleh", "planet"));
    EXPECT_CALL(cb, Call("hello", "globe"));
    EXPECT_CALL(cb, Call("hello", "earth"));

    headers.iterate(cb.asIterateCb());
  }

  headers.setReference(key1, ref_value5); // set moves key to end

  {
    HeaderAndValueCb cb;

    InSequence seq;
    EXPECT_CALL(cb, Call("olleh", "planet"));
    EXPECT_CALL(cb, Call("hello", "blue marble"));

    headers.iterate(cb.asIterateCb());
  }
}

Project: envoy

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

Project: envoy

  size_t removeInline(Handle handle) override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    return HeaderMapImpl::removeInline(&inlineHeaders()[handle.it_->second]);
  }

Project: envoy

bool HeaderUtility::matchHeaders(const HeaderMap& request_headers,
                                 const std::vector<HeaderDataPtr>& config_headers) {
  // No headers to match is considered a match.
  if (!config_headers.empty()) {
    for (const HeaderDataPtr& cfg_header_data : config_headers) {
      if (!matchHeaders(request_headers, *cfg_header_data)) {
        return false;
      }
    }
  }

  return true;
}

Project: envoy

  ResponseHeaderMapImpl() { clearInline(); }

Project: envoy

bool matches(const Expression& expr, const StreamInfo::StreamInfo& info,
             const Http::RequestHeaderMap& headers) {
  Protobuf::Arena arena;
  auto eval_status = Expr::evaluate(expr, arena, info, &headers, nullptr, nullptr);
  if (!eval_status.has_value()) {
    return false;
  }
  auto result = eval_status.value();
  return result.IsBool() ? result.BoolOrDie() : false;
}

Project: envoy

  ipTestParamsToString(const ::testing::TestParamInfo<Network::Address::IpVersion>& params) {
    return params.param == Network::Address::IpVersion::v4 ? "IPv4" : "IPv6";
  }

Project: envoy

TEST(HeaderMapImplTest, SetReferenceKey) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString foo("hello");
  headers.setReferenceKey(foo, "world");
  EXPECT_NE("world", headers.get(foo)->value().getStringView().data());
  EXPECT_EQ("world", headers.get(foo)->value().getStringView());

  headers.setReferenceKey(foo, "monde");
  EXPECT_NE("monde", headers.get(foo)->value().getStringView().data());
  EXPECT_EQ("monde", headers.get(foo)->value().getStringView());
}

Project: envoy

void ExtractorImpl::addHeaderConfig(const std::string& issuer, const LowerCaseString& header_name,
                                    const std::string& value_prefix) {
  ENVOY_LOG(debug, "addHeaderConfig for issuer {} at {}", issuer, header_name.get());
  const std::string map_key = header_name.get() + value_prefix;
  auto& header_location_spec = header_locations_[map_key];
  if (!header_location_spec) {
    header_location_spec = std::make_unique<HeaderLocationSpec>(header_name, value_prefix);
  }
  header_location_spec->specified_issuers_.insert(issuer);
}

Project: envoy

  size_t removeInline(Handle handle) override {
    const size_t rc = header_map_->removeInline(handle);
    header_map_->verifyByteSizeInternalForTest();
    return rc;
  }

Project: envoy

  decodeResources(const envoy::service::discovery::v3::DiscoveryResponse& resources,
                  const std::string& name_field = "name") {
    return decodeResources<MessageType>(resources.resources(), resources.version_info(),
                                        name_field);
  }

Project: envoy

HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) {
  // Constructing a header map implementation will force the custom headers and sizing to be
  // finalized, so do that first.
  auto header_map = T::create();

  HeaderMapImplUtility::HeaderMapImplInfo info;
  info.name_ = std::string(name);
  info.size_ = T::inlineHeadersSize() + sizeof(T);
  for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) {
    info.registered_headers_.push_back(header.first.get());
  }
  return info;
}

Project: envoy

TEST_F(HeaderToMetadataTest, MultipleHeadersMatch) {
  const std::string python_yaml = R"EOF(
request_rules:
  - header: x-version
    on_header_present:
      key: version
      metadata_namespace: envoy.lb
      type: STRING
  - header: x-python-version
    on_header_present:
      key: python_version
      metadata_namespace: envoy.lb
      type: STRING
)EOF";
  initializeFilter(python_yaml);
  Http::TestRequestHeaderMapImpl incoming_headers{
      {"X-VERSION", "v4.0"},
      {"X-PYTHON-VERSION", "3.7"},
      {"X-IGNORE", "nothing"},
  };
  std::map<std::string, std::string> expected = {{"version", "v4.0"}, {"python_version", "3.7"}};

  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));
}

Project: envoy

  bool ready_ ABSL_GUARDED_BY(mutex_){false};

Project: envoy

MATCHER_P(JsonStringEq, expected, "") {
  const bool equal = TestUtility::jsonStringEqual(arg, expected);
  if (!equal) {
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected JSON string:") << "\n"
                     << expected
                     << TestUtility::addLeftAndRightPadding("is not equal to actual JSON string:")
                     << "\n"
                     << arg << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

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

Project: envoy

HeaderUtility::HeaderData::HeaderData(const envoy::config::route::v3::HeaderMatcher& config)
    : name_(config.name()), invert_match_(config.invert_match()) {
  switch (config.header_match_specifier_case()) {
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kExactMatch:
    header_match_type_ = HeaderMatchType::Value;
    value_ = config.exact_match();
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::
      kHiddenEnvoyDeprecatedRegexMatch:
    header_match_type_ = HeaderMatchType::Regex;
    regex_ = Regex::Utility::parseStdRegexAsCompiledMatcher(
        config.hidden_envoy_deprecated_regex_match());
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kSafeRegexMatch:
    header_match_type_ = HeaderMatchType::Regex;
    regex_ = Regex::Utility::parseRegex(config.safe_regex_match());
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kRangeMatch:
    header_match_type_ = HeaderMatchType::Range;
    range_.set_start(config.range_match().start());
    range_.set_end(config.range_match().end());
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kPresentMatch:
    header_match_type_ = HeaderMatchType::Present;
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kPrefixMatch:
    header_match_type_ = HeaderMatchType::Prefix;
    value_ = config.prefix_match();
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kSuffixMatch:
    header_match_type_ = HeaderMatchType::Suffix;
    value_ = config.suffix_match();
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::kContainsMatch:
    header_match_type_ = HeaderMatchType::Contains;
    value_ = config.contains_match();
    break;
  case envoy::config::route::v3::HeaderMatcher::HeaderMatchSpecifierCase::
      HEADER_MATCH_SPECIFIER_NOT_SET:
    FALLTHRU;
  default:
    header_match_type_ = HeaderMatchType::Present;
    break;
  }
}

Project: envoy

  HeaderMap::ConstIterateCb asIterateCb() {
    return [this](const Http::HeaderEntry& header) -> HeaderMap::Iterate {
      Call(std::string(header.key().getStringView()), std::string(header.value().getStringView()));
      return HeaderMap::Iterate::Continue;
    };
  }

Project: envoy

void HeaderMapImpl::copyFrom(HeaderMap& lhs, const HeaderMap& header_map) {
  header_map.iterate([&lhs](const HeaderEntry& header) -> HeaderMap::Iterate {
    // TODO(mattklein123) PERF: Avoid copying here if not necessary.
    HeaderString key_string;
    key_string.setCopy(header.key().getStringView());
    HeaderString value_string;
    value_string.setCopy(header.value().getStringView());

    lhs.addViaMove(std::move(key_string), std::move(value_string));
    return HeaderMap::Iterate::Continue;
  });
}

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, DontFinishIterationForDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:dynamicMetadata():set("envoy.lb", "foo", "bar")
      iterator = pairs(object:dynamicMetadata())
      key, value = iterator()
      iterator2 = pairs(object:dynamicMetadata())
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem());
  Filters::Common::Lua::LuaDeathRef<StreamInfoWrapper> wrapper(
      StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true);
  EXPECT_THROW_WITH_MESSAGE(
      start("callMe"), Filters::Common::Lua::LuaException,
      "[string \"...\"]:6: cannot create a second iterator before completing the first");
}

Project: envoy

  const HeaderEntry* get(const LowerCaseString& key) const override {
    return HeaderMapImpl::get(key);
  }

Project: envoy

TEST_F(HeaderToMetadataTest, DefaultEndpointsTest) {
  initializeFilter(request_config_yaml);
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-FOO", "bar"}};
  std::map<std::string, std::string> expected = {{"default", "true"}};

  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));
}

Project: envoy

TEST(HeaderMapImplTest, AddCopy) {
  TestRequestHeaderMapImpl headers;

  // Start with a string value.
  std::unique_ptr<LowerCaseString> lcKeyPtr(new LowerCaseString("hello"));
  headers.addCopy(*lcKeyPtr, "world");

  const HeaderString& value = headers.get(*lcKeyPtr)->value();

  EXPECT_EQ("world", value.getStringView());
  EXPECT_EQ(5UL, value.size());

  lcKeyPtr.reset();

  const HeaderString& value2 = headers.get(LowerCaseString("hello"))->value();

  EXPECT_EQ("world", value2.getStringView());
  EXPECT_EQ(5UL, value2.size());
  EXPECT_EQ(value.getStringView(), value2.getStringView());
  EXPECT_EQ(1UL, headers.size());

  // Repeat with an int value.
  //
  // addReferenceKey and addCopy can both add multiple instances of a
  // given header, so we need to delete the old "hello" header.
  // Test that removing will return 0 byte size.
  EXPECT_EQ(1UL, headers.remove(LowerCaseString("hello")));
  EXPECT_EQ(headers.byteSize(), 0);

  // Build "hello" with string concatenation to make it unlikely that the
  // compiler is just reusing the same string constant for everything.
  lcKeyPtr = std::make_unique<LowerCaseString>(std::string("he") + "llo");
  EXPECT_STREQ("hello", lcKeyPtr->get().c_str());

  headers.addCopy(*lcKeyPtr, 42);

  const HeaderString& value3 = headers.get(*lcKeyPtr)->value();

  EXPECT_EQ("42", value3.getStringView());
  EXPECT_EQ(2UL, value3.size());

  lcKeyPtr.reset();

  const HeaderString& value4 = headers.get(LowerCaseString("hello"))->value();

  EXPECT_EQ("42", value4.getStringView());
  EXPECT_EQ(2UL, value4.size());
  EXPECT_EQ(1UL, headers.size());

  // Here, again, we'll build yet another key string.
  LowerCaseString lcKey3(std::string("he") + "ll" + "o");
  EXPECT_STREQ("hello", lcKey3.get().c_str());

  EXPECT_EQ("42", headers.get(lcKey3)->value().getStringView());
  EXPECT_EQ(2UL, headers.get(lcKey3)->value().size());

  LowerCaseString envoy_retry_on("x-envoy-retry-on");
  headers.addCopy(envoy_retry_on, "max-age=1345");
  EXPECT_EQ("max-age=1345", headers.get(envoy_retry_on)->value().getStringView());
  EXPECT_EQ("max-age=1345", headers.getEnvoyRetryOnValue());
  headers.addCopy(envoy_retry_on, "public");
  EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)->value().getStringView());
  headers.addCopy(envoy_retry_on, "");
  EXPECT_EQ("max-age=1345,public", headers.get(envoy_retry_on)->value().getStringView());
  headers.addCopy(envoy_retry_on, 123);
  EXPECT_EQ("max-age=1345,public,123", headers.get(envoy_retry_on)->value().getStringView());
  headers.addCopy(envoy_retry_on, std::numeric_limits<uint64_t>::max());
  EXPECT_EQ("max-age=1345,public,123,18446744073709551615",
            headers.get(envoy_retry_on)->value().getStringView());
}

Project: envoy

  CelValue Produce(ProtobufWkt::Arena* arena) override {
    // Producer is unique per evaluation arena since activation is re-created.
    arena_ = arena;
    return CelValue::CreateMap(this);
  }

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, SetGetComplexDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
      function callMe(object)
        object:dynamicMetadata():set("envoy.lb", "foo", {x=1234, y="baz", z=true})
        object:dynamicMetadata():set("envoy.lb", "so", {"cool", "and", "dynamic", true})

        testPrint(tostring(object:dynamicMetadata():get("envoy.lb")["foo"].x))
        testPrint(object:dynamicMetadata():get("envoy.lb")["foo"].y)
        testPrint(tostring(object:dynamicMetadata():get("envoy.lb")["foo"].z))
        testPrint(object:dynamicMetadata():get("envoy.lb")["so"][1])
        testPrint(object:dynamicMetadata():get("envoy.lb")["so"][2])
        testPrint(object:dynamicMetadata():get("envoy.lb")["so"][3])
        testPrint(tostring(object:dynamicMetadata():get("envoy.lb")["so"][4]))
      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("1234"));
  EXPECT_CALL(printer_, testPrint("baz"));
  EXPECT_CALL(printer_, testPrint("true"));
  EXPECT_CALL(printer_, testPrint("cool"));
  EXPECT_CALL(printer_, testPrint("and"));
  EXPECT_CALL(printer_, testPrint("dynamic"));
  EXPECT_CALL(printer_, testPrint("true"));
  start("callMe");

  EXPECT_EQ(1, stream_info.dynamicMetadata().filter_metadata_size());
  const ProtobufWkt::Struct& meta_foo = stream_info.dynamicMetadata()
                                            .filter_metadata()
                                            .at("envoy.lb")
                                            .fields()
                                            .at("foo")
                                            .struct_value();

  EXPECT_EQ(1234.0, meta_foo.fields().at("x").number_value());
  EXPECT_EQ("baz", meta_foo.fields().at("y").string_value());
  EXPECT_EQ(true, meta_foo.fields().at("z").bool_value());

  const ProtobufWkt::ListValue& meta_so =
      stream_info.dynamicMetadata().filter_metadata().at("envoy.lb").fields().at("so").list_value();

  EXPECT_EQ(4, meta_so.values_size());
  EXPECT_EQ("cool", meta_so.values(0).string_value());
  EXPECT_EQ("and", meta_so.values(1).string_value());
  EXPECT_EQ("dynamic", meta_so.values(2).string_value());
  EXPECT_EQ(true, meta_so.values(3).bool_value());

  wrapper.reset();
}

Project: envoy

  MetadataProducer(const envoy::config::core::v3::Metadata& metadata) : metadata_(metadata) {}

Project: envoy

  RequestTrailerMapImpl() { clearInline(); }

Project: envoy

  TestHeaderMapImplBase(const TestHeaderMapImplBase& rhs)
      : TestHeaderMapImplBase(*rhs.header_map_) {}

Project: envoy

template <> HeaderMapImpl::StaticLookupTable<ResponseTrailerMap>::StaticLookupTable() {
#define REGISTER_RESPONSE_TRAILER(name)                                                            \
  CustomInlineHeaderRegistry::registerInlineHeader<ResponseTrailerMap::header_map_type>(           \
      Headers::get().name);
  INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_TRAILER)

  finalizeTable();
}

Project: envoy

TEST(HeaderMapImplTest, Equality) {
  TestRequestHeaderMapImpl headers1;
  TestRequestHeaderMapImpl headers2;
  EXPECT_EQ(headers1, headers2);

  headers1.addCopy(LowerCaseString("hello"), "world");
  EXPECT_FALSE(headers1 == headers2);

  headers2.addCopy(LowerCaseString("foo"), "bar");
  EXPECT_FALSE(headers1 == headers2);
}

Project: envoy

TEST_P(RBACIntegrationTest, PathWithQueryAndFragment) {
  config_helper_.addFilter(RBAC_CONFIG_WITH_PATH_EXACT_MATCH);
  initialize();

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

  const std::vector<std::string> paths{"/allow", "/allow?p1=v1&p2=v2", "/allow?p1=v1#seg"};

  for (const auto& path : paths) {
    auto response = codec_client_->makeRequestWithBody(
        Http::TestRequestHeaderMapImpl{
            {":method", "POST"},
            {":path", 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 operator!=(const HeaderMap& rhs) const override { return header_map_->operator!=(rhs); }

Project: envoy

    explicit GetResult(NonConstGetResult&& result) : result_(std::move(result)) {}

Project: envoy

  UpstreamWrapper(const StreamInfo::StreamInfo& info) : info_(info) {}

Project: envoy

TEST(HeaderMapImplTest, TestHeaderList) {
  std::array<std::string, 2> keys{Headers::get().Path.get(), "hello"};
  std::array<std::string, 2> values{"/", "world"};

  auto headers = TestRequestHeaderMapImpl({{keys[0], values[0]}, {keys[1], values[1]}});
  HeaderListView header_list(headers);
  auto to_string_views =
      [](const HeaderListView::HeaderStringRefs& strs) -> std::vector<absl::string_view> {
    std::vector<absl::string_view> str_views(strs.size());
    std::transform(strs.begin(), strs.end(), str_views.begin(),
                   [](auto value) -> absl::string_view { return value.get().getStringView(); });
    return str_views;
  };

  EXPECT_THAT(to_string_views(header_list.keys()), ElementsAre(":path", "hello"));
  EXPECT_THAT(to_string_views(header_list.values()), ElementsAre("/", "world"));
}

Project: envoy

TEST_F(ExtractorTest, TestWrongHeaderToken) {
  auto headers = TestRequestHeaderMapImpl{{"wrong-token-header", "jwt_token"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 0);
}

Project: envoy

    std::list<HeaderEntryImpl>::iterator insert(Key&& key, Value&&... value) {
      const bool is_pseudo_header = isPseudoHeader(key);
      std::list<HeaderEntryImpl>::iterator i =
          headers_.emplace(is_pseudo_header ? pseudo_headers_end_ : headers_.end(),
                           std::forward<Key>(key), std::forward<Value>(value)...);
      if (!is_pseudo_header && pseudo_headers_end_ == headers_.end()) {
        pseudo_headers_end_ = i;
      }
      return i;
    }

Project: envoy

  void setInline(Handle handle, absl::string_view value) override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
    updateSize(entry.value().size(), value.size());
    entry.value().setCopy(value);
  }

Project: envoy

bool HeaderToMetadataFilter::addMetadata(StructMap& map, const std::string& meta_namespace,
                                         const std::string& key, std::string value, ValueType type,
                                         ValueEncode encode) const {
  ProtobufWkt::Value val;

  ASSERT(!value.empty());

  if (value.size() >= MAX_HEADER_VALUE_LEN) {
    // Too long, go away.
    ENVOY_LOG(debug, "metadata value is too long");
    return false;
  }

  if (encode == envoy::extensions::filters::http::header_to_metadata::v3::Config::BASE64) {
    value = Base64::decodeWithoutPadding(value);
    if (value.empty()) {
      ENVOY_LOG(debug, "Base64 decode failed");
      return false;
    }
  }

  // Sane enough, add the key/value.
  switch (type) {
  case envoy::extensions::filters::http::header_to_metadata::v3::Config::STRING:
    val.set_string_value(std::move(value));
    break;
  case envoy::extensions::filters::http::header_to_metadata::v3::Config::NUMBER: {
    double dval;
    if (absl::SimpleAtod(StringUtil::trim(value), &dval)) {
      val.set_number_value(dval);
    } else {
      ENVOY_LOG(debug, "value to number conversion failed");
      return false;
    }
    break;
  }
  case envoy::extensions::filters::http::header_to_metadata::v3::Config::PROTOBUF_VALUE: {
    if (!val.ParseFromString(value)) {
      ENVOY_LOG(debug, "parse from decoded string failed");
      return false;
    }
    break;
  }
  default:
    NOT_REACHED_GCOVR_EXCL_LINE;
  }

  // Have we seen this namespace before?
  auto namespace_iter = map.find(meta_namespace);
  if (namespace_iter == map.end()) {
    map[meta_namespace] = ProtobufWkt::Struct();
    namespace_iter = map.find(meta_namespace);
  }

  auto& keyval = namespace_iter->second;
  (*keyval.mutable_fields())[key] = val;

  return true;
}

Project: envoy

  template <typename T> static T findByName(const std::vector<T>& v, const std::string& name) {
    auto pos = std::find_if(v.begin(), v.end(),
                            [&name](const T& stat) -> bool { return stat->name() == name; });
    if (pos == v.end()) {
      return nullptr;
    }
    return *pos;
  }

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, ModifiableMethods) {
  const std::string SCRIPT{R"EOF(
    function shouldBeOk(object)
      object:get("hELLo")
      for key, value in pairs(object) do
      end
    end

    function shouldFailRemove(object)
      object:remove("foo")
    end

    function shouldFailAdd(object)
      object:add("foo")
    end

    function shouldFailReplace(object)
      object:replace("foo")
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers;
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return false; });
  start("shouldBeOk");

  setup(SCRIPT);
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return false; });
  EXPECT_THROW_WITH_MESSAGE(start("shouldFailRemove"), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:9: header map can no longer be modified");

  setup(SCRIPT);
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return false; });
  EXPECT_THROW_WITH_MESSAGE(start("shouldFailAdd"), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:13: header map can no longer be modified");

  setup(SCRIPT);
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return false; });
  EXPECT_THROW_WITH_MESSAGE(start("shouldFailReplace"), Filters::Common::Lua::LuaException,
                            "[string \"...\"]:17: header map can no longer be modified");
}

Project: envoy

bool HeaderUtility::isConnectResponse(const RequestHeaderMap* request_headers,
                                      const ResponseHeaderMap& response_headers) {
  return request_headers && isConnect(*request_headers) &&
         static_cast<Http::Code>(Http::Utility::getResponseStatus(response_headers)) ==
             Http::Code::OK;
}

Project: envoy

int HeaderMapWrapper::luaRemove(lua_State* state) {
  checkModifiable(state);

  const char* key = luaL_checkstring(state, 2);
  headers_.remove(Http::LowerCaseString(key));
  return 0;
}

Project: envoy

absl::string_view HeaderString::getStringView() const {
  if (type() == Type::Reference) {
    return getStrView(buffer_);
  }
  ASSERT(type() == Type::Inline);
  return {getInVec(buffer_).data(), getInVec(buffer_).size()};
}

Project: envoy

void HeaderMapImpl::addReference(const LowerCaseString& key, absl::string_view value) {
  HeaderString ref_key(key);
  HeaderString ref_value(value);
  insertByKey(std::move(ref_key), std::move(ref_value));
}

Project: envoy

  const Config* getConfig() { return filter_->getConfig(); }

Project: envoy

makeHeaderMap(const std::initializer_list<std::pair<std::string, std::string>>& values) {
  return std::make_unique<T, const std::initializer_list<std::pair<std::string, std::string>>&>(
      values);
}

Project: envoy

  void appendInline(Handle handle, absl::string_view data, absl::string_view delimiter) override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
    addSize(HeaderMapImpl::appendToHeader(entry.value(), data, delimiter));
  }

Project: envoy

  void removeJwt(Http::HeaderMap&) const override {
    // TODO(qiwzhang): remove JWT from parameter.
  }

Project: envoy

TEST(HeaderIsValidTest, IsConnect) {
  EXPECT_TRUE(HeaderUtility::isConnect(Http::TestRequestHeaderMapImpl{{":method", "CONNECT"}}));
  EXPECT_FALSE(HeaderUtility::isConnect(Http::TestRequestHeaderMapImpl{{":method", "GET"}}));
  EXPECT_FALSE(HeaderUtility::isConnect(Http::TestRequestHeaderMapImpl{}));
}

Project: envoy

void HeaderToMetadataFilter::applyKeyValue(std::string&& value, const Rule& rule,
                                           const KeyValuePair& keyval, StructMap& np) {
  if (!keyval.value().empty()) {
    value = keyval.value();
  } else {
    const auto& matcher = rule.regexRewrite();
    if (matcher != nullptr) {
      value = matcher->replaceAll(value, rule.regexSubstitution());
    }
  }
  if (!value.empty()) {
    const auto& nspace = decideNamespace(keyval.metadata_namespace());
    addMetadata(np, nspace, keyval.key(), value, keyval.type(), keyval.encode());
  } else {
    ENVOY_LOG(debug, "value is empty, not adding metadata");
  }
}

Project: envoy

TEST(HeaderMapImplTest, Iterate) {
  TestRequestHeaderMapImpl headers;
  headers.addCopy(LowerCaseString("hello"), "world");
  headers.addCopy(LowerCaseString("foo"), "xxx");
  headers.addCopy(LowerCaseString("world"), "hello");
  LowerCaseString foo_key("foo");
  headers.setReferenceKey(foo_key, "bar"); // set moves key to end

  HeaderAndValueCb cb;

  InSequence seq;
  EXPECT_CALL(cb, Call("hello", "world"));
  EXPECT_CALL(cb, Call("world", "hello"));
  EXPECT_CALL(cb, Call("foo", "bar"));
  headers.iterate(cb.asIterateCb());
}

Project: envoy

TEST(HeaderMapImplTest, DoubleCookieAdd) {
  TestRequestHeaderMapImpl headers;
  const std::string foo("foo");
  const std::string bar("bar");
  const LowerCaseString& set_cookie = Http::Headers::get().SetCookie;
  headers.addReference(set_cookie, foo);
  headers.addReference(set_cookie, bar);
  EXPECT_EQ(2UL, headers.size());

  std::vector<absl::string_view> out;
  Http::HeaderUtility::getAllOfHeader(headers, "set-cookie", out);
  ASSERT_EQ(out.size(), 2);
  ASSERT_EQ(out[0], "foo");
  ASSERT_EQ(out[1], "bar");
}

Project: envoy

  static const envoy::type::matcher::v3::StringMatcher createExactMatcher(std::string str) {
    envoy::type::matcher::v3::StringMatcher matcher;
    matcher.set_exact(str);
    return matcher;
  }

Project: envoy

  bool operator!=(const char* rhs) const {
    return getStringView() != absl::NullSafeStringView(rhs);
  }

Project: envoy

TEST_F(HeaderToMetadataTest, ProtobufValueTypeInBase64UrlTest) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-authenticated
    on_header_present:
      key: auth
      type: PROTOBUF_VALUE
      encode: BASE64
)EOF";
  initializeFilter(response_config_yaml);

  ProtobufWkt::Value value;
  auto* s = value.mutable_struct_value();

  ProtobufWkt::Value v;
  v.set_string_value("blafoo");
  (*s->mutable_fields())["k1"] = v;
  v.set_number_value(2019.07);
  (*s->mutable_fields())["k2"] = v;
  v.set_bool_value(true);
  (*s->mutable_fields())["k3"] = v;

  std::string data;
  ASSERT_TRUE(value.SerializeToString(&data));
  const auto encoded = Base64::encode(data.c_str(), data.size());
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-authenticated", encoded}};
  std::map<std::string, ProtobufWkt::Value> expected = {{"auth", value}};

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

Project: envoy

void HeaderToMetadataFilter::setDecoderFilterCallbacks(
    Http::StreamDecoderFilterCallbacks& callbacks) {
  decoder_callbacks_ = &callbacks;
}

Project: envoy

template <class T> std::unique_ptr<T> createHeaderMap(const HeaderMap& rhs) {
  // TODO(mattklein123): Use of this function allows copying a request header map into a response
  // header map, etc. which is probably not what we want. Unfortunately, we do this on purpose in
  // a few places when dealing with gRPC headers/trailers conversions so it's not trivial to remove.
  // We should revisit this to figure how to make this a bit safer as a non-intentional conversion
  // may have surprising results with different O(1) headers, implementations, etc.
  auto new_header_map = T::create();
  HeaderMapImpl::copyFrom(*new_header_map, rhs);
  return new_header_map;
}

Project: envoy

  void addCopy(const LowerCaseString& key, uint64_t value) override {
    HeaderMapImpl::addCopy(key, value);
  }

Project: envoy

MATCHER_P(Percent, rhs, "") {
  envoy::type::v3::FractionalPercent expected;
  expected.set_numerator(rhs);
  expected.set_denominator(envoy::type::v3::FractionalPercent::HUNDRED);
  return TestUtility::protoEqual(expected, arg, /*ignore_repeated_field_ordering=*/false);
}

Project: envoy

TEST(HeaderMapImplTest, AddReferenceKey) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString foo("hello");
  headers.addReferenceKey(foo, "world");
  EXPECT_NE("world", headers.get(foo)->value().getStringView().data());
  EXPECT_EQ("world", headers.get(foo)->value().getStringView());
}

Project: envoy

absl::optional<std::string> CookieValueSelector::extract(Http::HeaderMap& map) const {
  std::string value = Envoy::Http::Utility::parseCookieValue(map, cookie_);
  if (!value.empty()) {
    return absl::optional<std::string>(std::move(value));
  }
  return absl::nullopt;
}

Project: envoy

TEST_F(HeaderToMetadataTest, BasicRequestTest) {
  initializeFilter(request_config_yaml);
  Http::TestRequestHeaderMapImpl incoming_headers{{"X-VERSION", "0xdeadbeef"}};
  std::map<std::string, std::string> expected = {{"version", "0xdeadbeef"}};

  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

  void setInline(Handle handle, uint64_t value) override {
    ASSERT(handle.it_->second < inlineHeadersSize());
    HeaderEntry& entry = maybeCreateInline(&inlineHeaders()[handle.it_->second], handle.it_->first);
    subtractSize(entry.value().size());
    entry.value().setInteger(value);
    addSize(entry.value().size());
  }

Project: envoy

TEST(HeaderMapImplTest, SetCopyOldBehavior) {
  TestScopedRuntime runtime;
  Runtime::LoaderSingleton::getExisting()->mergeValues(
      {{"envoy.reloadable_features.http_set_copy_replace_all_headers", "false"}});

  TestRequestHeaderMapImpl headers;
  LowerCaseString foo("hello");
  headers.setCopy(foo, "world");
  EXPECT_EQ("world", headers.get(foo)->value().getStringView());

  // Overwrite value.
  headers.setCopy(foo, "monde");
  EXPECT_EQ("monde", headers.get(foo)->value().getStringView());

  // Add another foo header.
  headers.addCopy(foo, "monde2");
  EXPECT_EQ(headers.size(), 2);

  // Only the first foo header is overridden.
  headers.setCopy(foo, "override-monde");
  EXPECT_EQ(headers.size(), 2);

  HeaderAndValueCb cb;

  InSequence seq;
  EXPECT_CALL(cb, Call("hello", "override-monde"));
  EXPECT_CALL(cb, Call("hello", "monde2"));
  headers.iterate(cb.asIterateCb());

  // Test setting an empty string and then overriding.
  EXPECT_EQ(2UL, headers.remove(foo));
  EXPECT_EQ(headers.size(), 0);
  const std::string empty;
  headers.setCopy(foo, empty);
  EXPECT_EQ(headers.size(), 1);
  headers.setCopy(foo, "not-empty");
  EXPECT_EQ(headers.get(foo)->value().getStringView(), "not-empty");

  // Use setCopy with inline headers both indirectly and directly.
  headers.clear();
  EXPECT_EQ(headers.size(), 0);
  headers.setCopy(Headers::get().Path, "/");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/");
  headers.setPath("/foo");
  EXPECT_EQ(headers.size(), 1);
  EXPECT_EQ(headers.getPathValue(), "/foo");
}

Project: envoy

  void expectToPrintCurrentProtocol(const absl::optional<Envoy::Http::Protocol>& protocol) {
    const std::string SCRIPT{R"EOF(
      function callMe(object)
        testPrint(string.format("'%s'", object:protocol()))
      end
    )EOF"};

    InSequence s;
    setup(SCRIPT);

    NiceMock<Envoy::StreamInfo::MockStreamInfo> stream_info;
    ON_CALL(stream_info, protocol()).WillByDefault(ReturnPointee(&protocol));
    Filters::Common::Lua::LuaDeathRef<StreamInfoWrapper> wrapper(
        StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true);
    EXPECT_CALL(printer_,
                testPrint(fmt::format("'{}'", Http::Utility::getProtocolString(protocol.value()))));
    start("callMe");
    wrapper.reset();
  }

Project: envoy

  bool operator<(const LowerCaseString& rhs) const { return string_.compare(rhs.string_) < 0; }

Project: envoy

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

Project: envoy

TEST(HeaderMapImplTest, CreateHeaderMapFromIterator) {
  std::vector<std::pair<LowerCaseString, std::string>> iter_headers{
      {LowerCaseString(Headers::get().Path), "/"}, {LowerCaseString("hello"), "world"}};
  auto headers = createHeaderMap<RequestHeaderMapImpl>(iter_headers.cbegin(), iter_headers.cend());
  EXPECT_EQ("/", headers->get(LowerCaseString(":path"))->value().getStringView());
  EXPECT_EQ("world", headers->get(LowerCaseString("hello"))->value().getStringView());
  EXPECT_EQ(nullptr, headers->get(LowerCaseString("foo")));
}

Project: envoy

TEST_F(ExtractorTest, TestPrefixHeaderNotMatch) {
  auto headers = TestRequestHeaderMapImpl{{"prefix-header", "jwt_token"}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 0);
}

Project: envoy

void HeaderMapImpl::setReferenceKey(const LowerCaseString& key, absl::string_view value) {
  remove(key);
  addReferenceKey(key, value);
}

Project: envoy

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

Project: envoy

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

Project: envoy

void HeaderMapImpl::HeaderEntryImpl::value(absl::string_view value) { value_.setCopy(value); }

Project: envoy

    template <class UnaryPredicate> void remove_if(UnaryPredicate p) {
      headers_.remove_if([&](const HeaderEntryImpl& entry) {
        const bool to_remove = p(entry);
        if (to_remove) {
          if (pseudo_headers_end_ == entry.entry_) {
            pseudo_headers_end_++;
          }
        }
        return to_remove;
      });
    }

Project: envoy

  friend std::ostream& operator<<(std::ostream& os, const HeaderMap& headers) {
    headers.dumpState(os);
    return os;
  }

Project: envoy

  static bool protoEqual(const Protobuf::Message& lhs, const Protobuf::Message& rhs,
                         bool ignore_repeated_field_ordering = false) {
    Protobuf::util::MessageDifferencer differencer;
    differencer.set_message_field_comparison(Protobuf::util::MessageDifferencer::EQUIVALENT);
    if (ignore_repeated_field_ordering) {
      differencer.set_repeated_field_comparison(Protobuf::util::MessageDifferencer::AS_SET);
    }
    return differencer.Compare(lhs, rhs);
  }

Project: envoy

void HeaderMapImpl::updateSize(uint64_t from_size, uint64_t to_size) {
  ASSERT(cached_byte_size_ >= from_size);
  cached_byte_size_ -= from_size;
  cached_byte_size_ += to_size;
}

Project: envoy

void HeaderMapImpl::setCopy(const LowerCaseString& key, absl::string_view value) {
  if (!Runtime::runtimeFeatureEnabled(
          "envoy.reloadable_features.http_set_copy_replace_all_headers")) {
    auto entry = getExisting(key);
    if (!entry.empty()) {
      updateSize(entry[0]->value().size(), value.size());
      entry[0]->value(value);
    } else {
      addCopy(key, value);
    }
  } else {
    remove(key);
    addCopy(key, value);
  }
}

Project: envoy

void HeaderMapWrapper::checkModifiable(lua_State* state) {
  if (iterator_.get() != nullptr) {
    luaL_error(state, "header map cannot be modified while iterating");
  }

  if (!cb_()) {
    luaL_error(state, "header map can no longer be modified");
  }
}

Project: envoy

bool HeaderUtility::matchHeaders(const HeaderMap& request_headers, const HeaderData& header_data) {
  const auto header_value = getAllOfHeaderAsString(request_headers, header_data.name_);

  if (!header_value.result().has_value()) {
    return header_data.invert_match_ && header_data.header_match_type_ == HeaderMatchType::Present;
  }

  bool match;
  switch (header_data.header_match_type_) {
  case HeaderMatchType::Value:
    match = header_data.value_.empty() || header_value.result().value() == header_data.value_;
    break;
  case HeaderMatchType::Regex:
    match = header_data.regex_->match(header_value.result().value());
    break;
  case HeaderMatchType::Range: {
    int64_t header_int_value = 0;
    match = absl::SimpleAtoi(header_value.result().value(), &header_int_value) &&
            header_int_value >= header_data.range_.start() &&
            header_int_value < header_data.range_.end();
    break;
  }
  case HeaderMatchType::Present:
    match = true;
    break;
  case HeaderMatchType::Prefix:
    match = absl::StartsWith(header_value.result().value(), header_data.value_);
    break;
  case HeaderMatchType::Suffix:
    match = absl::EndsWith(header_value.result().value(), header_data.value_);
    break;
  case HeaderMatchType::Contains:
    match = absl::StrContains(header_value.result().value(), header_data.value_);
    break;
  default:
    NOT_REACHED_GCOVR_EXCL_LINE;
  }

  return match != header_data.invert_match_;
}

Project: envoy

TEST(HeaderMapImplTest, Get) {
  {
    auto headers = TestRequestHeaderMapImpl({{Headers::get().Path.get(), "/"}, {"hello", "world"}});
    EXPECT_EQ("/", headers.get(LowerCaseString(":path"))->value().getStringView());
    EXPECT_EQ("world", headers.get(LowerCaseString("hello"))->value().getStringView());
    EXPECT_EQ(nullptr, headers.get(LowerCaseString("foo")));
  }

  {
    auto headers = TestRequestHeaderMapImpl({{Headers::get().Path.get(), "/"}, {"hello", "world"}});
    // There is not HeaderMap method to set a header and copy both the key and value.
    const LowerCaseString path(":path");
    headers.setReferenceKey(path, "/new_path");
    EXPECT_EQ("/new_path", headers.get(LowerCaseString(":path"))->value().getStringView());
    const LowerCaseString foo("hello");
    headers.setReferenceKey(foo, "world2");
    EXPECT_EQ("world2", headers.get(foo)->value().getStringView());
    EXPECT_EQ(nullptr, headers.get(LowerCaseString("foo")));
  }
}

Project: envoy

void HeaderUtility::addHeaders(HeaderMap& headers, const HeaderMap& headers_to_add) {
  headers_to_add.iterate([&headers](const HeaderEntry& header) -> HeaderMap::Iterate {
    HeaderString k;
    k.setCopy(header.key().getStringView());
    HeaderString v;
    v.setCopy(header.value().getStringView());
    headers.addViaMove(std::move(k), std::move(v));
    return HeaderMap::Iterate::Continue;
  });
}

Project: envoy

template <> HeaderMapImpl::StaticLookupTable<ResponseHeaderMap>::StaticLookupTable() {
#define REGISTER_RESPONSE_HEADER(name)                                                             \
  CustomInlineHeaderRegistry::registerInlineHeader<ResponseHeaderMap::header_map_type>(            \
      Headers::get().name);
  INLINE_RESP_HEADERS(REGISTER_RESPONSE_HEADER)
  INLINE_REQ_RESP_HEADERS(REGISTER_RESPONSE_HEADER)
  INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_HEADER)

  finalizeTable();
}

Project: envoy

int HeaderMapWrapper::luaReplace(lua_State* state) {
  checkModifiable(state);

  const char* key = luaL_checkstring(state, 2);
  const char* value = luaL_checkstring(state, 3);
  const Http::LowerCaseString lower_key(key);

  headers_.setCopy(lower_key, value);

  return 0;
}

Project: envoy

TEST_F(LuaStreamInfoWrapperTest, ModifyDuringIterationForDynamicMetadata) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:dynamicMetadata():set("envoy.lb", "hello", "world")
      for key, value in pairs(object:dynamicMetadata()) do
        object:dynamicMetadata():set("envoy.lb", "hello", "envoy")
      end
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  StreamInfo::StreamInfoImpl stream_info(Http::Protocol::Http2, test_time_.timeSystem());
  Filters::Common::Lua::LuaDeathRef<StreamInfoWrapper> wrapper(
      StreamInfoWrapper::create(coroutine_->luaState(), stream_info), true);
  EXPECT_THROW_WITH_MESSAGE(
      start("callMe"), Filters::Common::Lua::LuaException,
      "[string \"...\"]:5: dynamic metadata map cannot be modified while iterating");
}

Project: envoy

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

Project: envoy

TEST(HeaderMapImplTest, PseudoHeaderOrder) {
  HeaderAndValueCb cb;

  {
    LowerCaseString foo("hello");
    Http::TestRequestHeaderMapImpl headers{};
    EXPECT_EQ(0UL, headers.size());
    EXPECT_TRUE(headers.empty());

    headers.addReferenceKey(foo, "world");
    EXPECT_EQ(1UL, headers.size());
    EXPECT_FALSE(headers.empty());

    headers.setReferenceKey(Headers::get().ContentType, "text/html");
    EXPECT_EQ(2UL, headers.size());
    EXPECT_FALSE(headers.empty());

    // Pseudo header gets inserted before non-pseudo headers
    headers.setReferenceKey(Headers::get().Method, "PUT");
    EXPECT_EQ(3UL, headers.size());
    EXPECT_FALSE(headers.empty());

    InSequence seq;
    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call("hello", "world"));
    EXPECT_CALL(cb, Call("content-type", "text/html"));

    headers.iterate(cb.asIterateCb());

    // Removal of the header before which pseudo-headers are inserted
    EXPECT_EQ(1UL, headers.remove(foo));
    EXPECT_EQ(2UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call("content-type", "text/html"));

    headers.iterate(cb.asIterateCb());

    // Next pseudo-header goes after other pseudo-headers, but before normal headers
    headers.setReferenceKey(Headers::get().Path, "/test");
    EXPECT_EQ(3UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call(":path", "/test"));
    EXPECT_CALL(cb, Call("content-type", "text/html"));

    headers.iterate(cb.asIterateCb());

    // Removing the last normal header
    EXPECT_EQ(1UL, headers.remove(Headers::get().ContentType));
    EXPECT_EQ(2UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call(":path", "/test"));

    headers.iterate(cb.asIterateCb());

    // Adding a new pseudo-header after removing the last normal header
    headers.setReferenceKey(Headers::get().Host, "host");
    EXPECT_EQ(3UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call(":path", "/test"));
    EXPECT_CALL(cb, Call(":authority", "host"));

    headers.iterate(cb.asIterateCb());

    // Adding the first normal header
    headers.setReferenceKey(Headers::get().ContentType, "text/html");
    EXPECT_EQ(4UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":method", "PUT"));
    EXPECT_CALL(cb, Call(":path", "/test"));
    EXPECT_CALL(cb, Call(":authority", "host"));
    EXPECT_CALL(cb, Call("content-type", "text/html"));

    headers.iterate(cb.asIterateCb());

    // Removing all pseudo-headers
    EXPECT_EQ(1UL, headers.remove(Headers::get().Path));
    EXPECT_EQ(1UL, headers.remove(Headers::get().Method));
    EXPECT_EQ(1UL, headers.remove(Headers::get().Host));
    EXPECT_EQ(1UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call("content-type", "text/html"));

    headers.iterate(cb.asIterateCb());

    // Removing all headers
    EXPECT_EQ(1UL, headers.remove(Headers::get().ContentType));
    EXPECT_EQ(0UL, headers.size());
    EXPECT_TRUE(headers.empty());

    // Adding a lone pseudo-header
    headers.setReferenceKey(Headers::get().Status, "200");
    EXPECT_EQ(1UL, headers.size());
    EXPECT_FALSE(headers.empty());

    EXPECT_CALL(cb, Call(":status", "200"));

    headers.iterate(cb.asIterateCb());
  }

  // Starting with a normal header
  {
    auto headers = TestRequestHeaderMapImpl({{Headers::get().ContentType.get(), "text/plain"},
                                             {Headers::get().Method.get(), "GET"},
                                             {Headers::get().Path.get(), "/"},
                                             {"hello", "world"},
                                             {Headers::get().Host.get(), "host"}});

    InSequence seq;
    EXPECT_CALL(cb, Call(":method", "GET"));
    EXPECT_CALL(cb, Call(":path", "/"));
    EXPECT_CALL(cb, Call(":authority", "host"));
    EXPECT_CALL(cb, Call("content-type", "text/plain"));
    EXPECT_CALL(cb, Call("hello", "world"));

    headers.iterate(cb.asIterateCb());
  }

  // Starting with a pseudo-header
  {
    auto headers = TestRequestHeaderMapImpl({{Headers::get().Path.get(), "/"},
                                             {Headers::get().ContentType.get(), "text/plain"},
                                             {Headers::get().Method.get(), "GET"},
                                             {"hello", "world"},
                                             {Headers::get().Host.get(), "host"}});

    InSequence seq;
    EXPECT_CALL(cb, Call(":path", "/"));
    EXPECT_CALL(cb, Call(":method", "GET"));
    EXPECT_CALL(cb, Call(":authority", "host"));
    EXPECT_CALL(cb, Call("content-type", "text/plain"));
    EXPECT_CALL(cb, Call("hello", "world"));

    headers.iterate(cb.asIterateCb());
  }
}

Project: envoy

  LowerCaseString(LowerCaseString&& rhs) noexcept : string_(std::move(rhs.string_)) {
    ASSERT(valid());
  }

Project: envoy

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

Project: envoy

TEST_F(HeaderToMetadataTest, HeaderIsPresentButRegexEmptiesIt) {
  const std::string config = R"EOF(
request_rules:
  - header: x-version
    on_header_present:
      metadata_namespace: envoy.lb
      key: cluster
      regex_value_rewrite:
        pattern:
          google_re2: {}
          regex: "^foo"
        substitution: ""
    on_header_missing:
      metadata_namespace: envoy.lb
      key: version
      value: some_value
      type: STRING
)EOF";
  initializeFilter(config);
  Http::TestRequestHeaderMapImpl headers{{"x-version", "foo"}};

  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

Http::FilterHeadersStatus HeaderToMetadataFilter::encodeHeaders(Http::ResponseHeaderMap& headers,
                                                                bool) {
  const auto* config = getConfig();
  if (config->doResponse()) {
    writeHeaderToMetadata(headers, config->responseRules(), *encoder_callbacks_);
  }
  return Http::FilterHeadersStatus::Continue;
}

Project: envoy

absl::optional<CelValue> UpstreamWrapper::operator[](CelValue key) const {
  if (!key.IsString()) {
    return {};
  }
  auto value = key.StringOrDie().value();
  if (value == Address) {
    auto upstream_host = info_.upstreamHost();
    if (upstream_host != nullptr && upstream_host->address() != nullptr) {
      return CelValue::CreateStringView(upstream_host->address()->asStringView());
    }
  } else if (value == Port) {
    auto upstream_host = info_.upstreamHost();
    if (upstream_host != nullptr && upstream_host->address() != nullptr &&
        upstream_host->address()->ip() != nullptr) {
      return CelValue::CreateInt64(upstream_host->address()->ip()->port());
    }
  } else if (value == UpstreamLocalAddress) {
    auto upstream_local_address = info_.upstreamLocalAddress();
    if (upstream_local_address != nullptr) {
      return CelValue::CreateStringView(upstream_local_address->asStringView());
    }
  } else if (value == UpstreamTransportFailureReason) {
    return CelValue::CreateStringView(info_.upstreamTransportFailureReason());
  }

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

  return {};
}

Project: envoy

  void appendInline(Handle handle, absl::string_view data, absl::string_view delimiter) override {
    header_map_->appendInline(handle, data, delimiter);
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

TEST(MatchHeadersTest, HeaderRangeMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "-1"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "0"},
                                              {"match-header", "somestring"},
                                              {"match-header", "10.9"},
                                              {"match-header", "-1somestring"}};
  const std::string yaml = R"EOF(
name: match-header
range_match:
  start: -10
  end: 0
  )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

  static inline MessageType anyConvert(const ProtobufWkt::Any& message) {
    return MessageUtil::anyConvert<MessageType>(message);
  }

Project: envoy

  void iterateReverse(HeaderMap::ConstIterateCb cb) const override {
    HeaderMapImpl::iterateReverse(cb);
  }

Project: envoy

TEST(HeaderMapImplTest, TestAppendHeader) {
  // Test appending to a string with a value.
  {
    TestRequestHeaderMapImpl headers;
    LowerCaseString foo("key1");
    headers.addCopy(foo, "some;");
    headers.appendCopy(foo, "test");
    EXPECT_EQ(headers.get(foo)->value().getStringView(), "some;,test");
  }

  // Test appending to an empty string.
  {
    TestRequestHeaderMapImpl headers;
    LowerCaseString key2("key2");
    headers.appendCopy(key2, "my tag data");
    EXPECT_EQ(headers.get(key2)->value().getStringView(), "my tag data");
  }

  // Test empty data case.
  {
    TestRequestHeaderMapImpl headers;
    LowerCaseString key3("key3");
    headers.addCopy(key3, "empty");
    headers.appendCopy(key3, "");
    EXPECT_EQ(headers.get(key3)->value().getStringView(), "empty");
  }
  // Regression test for appending to an empty string with a short string, then
  // setting integer.
  {
    TestRequestHeaderMapImpl headers;
    const std::string empty;
    headers.setPath(empty);
    // Append with default delimiter.
    headers.appendPath(" ", ",");
    headers.setPath(0);
    EXPECT_EQ("0", headers.getPathValue());
    EXPECT_EQ(1U, headers.Path()->value().size());
  }
  // Test append for inline headers using this method and append##name.
  {
    TestRequestHeaderMapImpl headers;
    headers.addCopy(Headers::get().Via, "1.0 fred");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred");
    headers.appendCopy(Headers::get().Via, "1.1 p.example.net");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred,1.1 p.example.net");
    headers.appendVia("1.1 new.example.net", ",");
    EXPECT_EQ(headers.getViaValue(), "1.0 fred,1.1 p.example.net,1.1 new.example.net");
  }
}

Project: envoy

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

  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

    absl::optional<absl::string_view> result() const {
      // This is safe for move/copy of this class as the backing string will be moved or copied.
      // Otherwise result_ is valid. The assert verifies that both are empty or only 1 is set.
      ASSERT((!result_.has_value() && result_backing_string_.empty()) ||
             (result_.has_value() ^ !result_backing_string_.empty()));
      return !result_backing_string_.empty() ? result_backing_string_ : result_;
    }

Project: envoy

TEST(Context, EmptyHeadersAttributes) {
  Protobuf::Arena arena;
  HeadersWrapper<Http::RequestHeaderMap> headers(arena, nullptr);
  auto header = headers[CelValue::CreateStringView(Referer)];
  EXPECT_FALSE(header.has_value());
  EXPECT_EQ(0, headers.size());
  EXPECT_TRUE(headers.empty());
}

Project: envoy

TEST_F(LuaHeaderMapWrapperTest, Replace) {
  const std::string SCRIPT{R"EOF(
    function callMe(object)
      object:replace(":path", "/new_path")
      object:replace("other_header", "other_header_value")
      object:replace("new_header", "new_header_value")
    end
  )EOF"};

  InSequence s;
  setup(SCRIPT);

  Http::TestRequestHeaderMapImpl headers{{":path", "/"}, {"other_header", "hello"}};
  HeaderMapWrapper::create(coroutine_->luaState(), headers, []() { return true; });
  start("callMe");

  EXPECT_EQ((Http::TestRequestHeaderMapImpl{{":path", "/new_path"},
                                            {"other_header", "other_header_value"},
                                            {"new_header", "new_header_value"}}),
            headers);
}

Project: envoy

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

Project: envoy

TEST_P(RBACIntegrationTest, DeniedHeadReply) {
  config_helper_.addFilter(RBAC_CONFIG);
  initialize();

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

  auto response = codec_client_->makeRequestWithBody(
      Http::TestRequestHeaderMapImpl{
          {":method", "HEAD"},
          {":path", "/"},
          {":scheme", "http"},
          {":authority", "host"},
          {"x-forwarded-for", "10.0.0.1"},
      },
      1024);
  response->waitForEndStream();
  ASSERT_TRUE(response->complete());
  EXPECT_EQ("403", response->headers().getStatusValue());
  ASSERT_TRUE(response->headers().ContentLength());
  EXPECT_NE("0", response->headers().getContentLengthValue());
  EXPECT_THAT(response->body(), ::testing::IsEmpty());
}

Project: envoy

int PublicKeyWrapper::luaGet(lua_State* state) {
  if (public_key_.empty()) {
    lua_pushnil(state);
  } else {
    lua_pushstring(state, public_key_.c_str());
  }
  return 1;
}

Project: envoy

HeaderUtility::getAllOfHeaderAsString(const HeaderMap& headers, const Http::LowerCaseString& key) {
  GetAllOfHeaderAsStringResult result;
  const auto header_value = headers.getAll(key);

  if (header_value.empty()) {
    // Empty for clarity. Avoid handling the empty case in the block below if the runtime feature
    // is disabled.
  } else if (header_value.size() == 1 ||
             !Runtime::runtimeFeatureEnabled(
                 "envoy.reloadable_features.http_match_on_all_headers")) {
    result.result_ = header_value[0]->value().getStringView();
  } else {
    // In this case we concatenate all found headers using a ',' delimiter before performing the
    // final match. We use an InlinedVector of absl::string_view to invoke the optimized join
    // algorithm. This requires a copying phase before we invoke join. The 3 used as the inline
    // size has been arbitrarily chosen.
    // TODO(mattklein123): Do we need to normalize any whitespace here?
    absl::InlinedVector<absl::string_view, 3> string_view_vector;
    string_view_vector.reserve(header_value.size());
    for (size_t i = 0; i < header_value.size(); i++) {
      string_view_vector.push_back(header_value[i]->value().getStringView());
    }
    result.result_backing_string_ = absl::StrJoin(string_view_vector, ",");
  }

  return result;
}

Project: envoy

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

  std::vector<std::pair<absl::string_view, absl::string_view>> rhs_headers;
  rhs_headers.reserve(rhs.size());
  rhs.iterate(collectAllHeaders(&rhs_headers));

  auto i = headers_.begin();
  auto j = rhs_headers.begin();
  for (; i != headers_.end(); ++i, ++j) {
    if (i->key() != j->first || i->value() != j->second) {
      return false;
    }
  }

  return true;
}

Project: envoy

TEST_F(ExtractorTest, TestPrefixHeaderFlexibleMatch2) {
  auto headers =
      TestRequestHeaderMapImpl{{"prefix-header", "CCCDDD=\"and0X3Rva2Vu\",comment=\"fish tag\""}};
  auto tokens = extractor_->extract(headers);
  EXPECT_EQ(tokens.size(), 1);

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

Project: envoy

TEST(MatchHeadersTest, HeaderContainsMatch) {
  TestRequestHeaderMapImpl matching_headers{{"match-header", "123onevalue456"}};
  TestRequestHeaderMapImpl unmatching_headers{{"match-header", "123anothervalue456"}};

  const std::string yaml = R"EOF(
name: match-header
contains_match: onevalue
  )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

  static std::string uniqueFilename() {
    return absl::StrCat(getpid(), "_", std::chrono::system_clock::now().time_since_epoch().count());
  }

Project: envoy

size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) {
  return HeaderMapImpl::removeIf([&prefix](const HeaderEntry& entry) -> bool {
    return absl::StartsWith(entry.key().getStringView(), prefix.get());
  });
}

Project: envoy

TEST(HeaderMapImplTest, LargeCharInHeader) {
  TestRequestHeaderMapImpl headers;
  LowerCaseString static_key("\x90hello");
  std::string ref_value("value");
  headers.addReference(static_key, ref_value);
  EXPECT_EQ("value", headers.get(static_key)->value().getStringView());
}

Project: envoy

  void removeJwt(Http::HeaderMap& headers) const override { headers.remove(header_); }

Project: envoy

  template <Type type> static void finalize() {
    ASSERT(!mutableFinalized<type>());
    mutableFinalized<type>() = true;
  }

Project: envoy

TEST(HeaderIsValidTest, AuthorityIsValid) {
  EXPECT_TRUE(HeaderUtility::authorityIsValid("strangebutlegal$-%&'"));
  EXPECT_FALSE(HeaderUtility::authorityIsValid("illegal{}"));
}

Project: envoy

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

Project: envoy

convertHeaderEntry(Protobuf::Arena& arena,
                   Http::HeaderUtility::GetAllOfHeaderAsStringResult&& result) {
  if (!result.result().has_value()) {
    return {};
  } else if (!result.backingString().empty()) {
    return CelValue::CreateString(
        Protobuf::Arena::Create<std::string>(&arena, result.backingString()));
  } else {
    return CelValue::CreateStringView(result.result().value());
  }
}

Project: envoy

template <class T, class It> std::unique_ptr<T> createHeaderMap(It begin, It end) {
  auto new_header_map = T::create();
  HeaderMapImpl::initFromInitList(*new_header_map, begin, end);
  return new_header_map;
}

Project: envoy

size_t HeaderMapImpl::removeIf(const HeaderMap::HeaderMatchPredicate& predicate) {
  const size_t old_size = headers_.size();
  headers_.remove_if([&predicate, this](const HeaderEntryImpl& entry) {
    const bool to_remove = predicate(entry);
    if (to_remove) {
      // If this header should be removed, make sure any references in the
      // static lookup table are cleared as well.
      auto lookup = staticLookup(entry.key().getStringView());
      if (lookup.has_value()) {
        if (lookup.value().entry_) {
          const uint32_t key_value_size =
              (*lookup.value().entry_)->key().size() + (*lookup.value().entry_)->value().size();
          subtractSize(key_value_size);
          *lookup.value().entry_ = nullptr;
        }
      } else {
        subtractSize(entry.key().size() + entry.value().size());
      }
    }
    return to_remove;
  });
  return old_size - headers_.size();
}

Project: envoy

TEST_F(HeaderToMetadataTest, BadProtobufValueTypeInBase64UrlTest) {
  const std::string response_config_yaml = R"EOF(
response_rules:
  - header: x-authenticated
    on_header_present:
      key: auth
      type: PROTOBUF_VALUE
      encode: BASE64
)EOF";
  initializeFilter(response_config_yaml);
  std::string data = "invalid";
  const auto encoded = Base64::encode(data.c_str(), data.size());
  Http::TestResponseHeaderMapImpl incoming_headers{{"x-authenticated", encoded}};

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

Project: envoy

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

Project: envoy

ExtractorImpl::extract(const Http::RequestHeaderMap& headers) const {
  std::vector<JwtLocationConstPtr> tokens;

  // Check header locations first
  for (const auto& location_it : header_locations_) {
    const auto& location_spec = location_it.second;
    ENVOY_LOG(debug, "extract {}", location_it.first);
    const auto result =
        Http::HeaderUtility::getAllOfHeaderAsString(headers, location_spec->header_);
    if (result.result().has_value()) {
      auto value_str = result.result().value();
      if (!location_spec->value_prefix_.empty()) {
        const auto pos = value_str.find(location_spec->value_prefix_);
        if (pos == absl::string_view::npos) {
          // value_prefix not found anywhere in value_str, so skip
          continue;
        }
        value_str = extractJWT(value_str, pos + location_spec->value_prefix_.length());
      }
      tokens.push_back(std::make_unique<const JwtHeaderLocation>(
          std::string(value_str), location_spec->specified_issuers_, location_spec->header_));
    }
  }

  // If no query parameter locations specified, or Path() is null, bail out
  if (param_locations_.empty() || headers.Path() == nullptr) {
    return tokens;
  }

  // Check query parameter locations.
  const auto& params = Http::Utility::parseAndDecodeQueryString(headers.getPathValue());
  for (const auto& location_it : param_locations_) {
    const auto& param_key = location_it.first;
    const auto& location_spec = location_it.second;
    const auto& it = params.find(param_key);
    if (it != params.end()) {
      tokens.push_back(std::make_unique<const JwtParamLocation>(
          it->second, location_spec.specified_issuers_, param_key));
    }
  }
  return tokens;
}

Project: envoy

  template <typename UnaryOperation> void inlineTransform(UnaryOperation&& unary_op) {
    ASSERT(type() == Type::Inline);
    std::transform(absl::get<InlineHeaderVector>(buffer_).begin(),
                   absl::get<InlineHeaderVector>(buffer_).end(),
                   absl::get<InlineHeaderVector>(buffer_).begin(), unary_op);
  }

Project: envoy

    const HeaderString& key() const override { return key_; }

Project: envoy

BuilderPtr createBuilder(Protobuf::Arena* arena) {
  google::api::expr::runtime::InterpreterOptions options;

  // Security-oriented defaults
  options.enable_comprehension = false;
  options.enable_regex = true;
  options.regex_max_program_size = 100;
  options.enable_string_conversion = false;
  options.enable_string_concat = false;
  options.enable_list_concat = false;

  // Enable constant folding (performance optimization)
  if (arena != nullptr) {
    options.constant_folding = true;
    options.constant_arena = arena;
  }

  auto builder = google::api::expr::runtime::CreateCelExpressionBuilder(options);
  auto register_status =
      google::api::expr::runtime::RegisterBuiltinFunctions(builder->GetRegistry(), options);
  if (!register_status.ok()) {
    throw CelException(
        absl::StrCat("failed to register built-in functions: ", register_status.message()));
  }
  return builder;
}

Project: envoy

  static std::string getVersionedMethodPath(const std::string& service_full_name_template,
                                            absl::string_view method_name,
                                            envoy::config::core::v3::ApiVersion api_version,
                                            bool use_alpha = false,
                                            const std::string& service_namespace = EMPTY_STRING) {
    return absl::StrCat("/",
                        getVersionedServiceFullName(service_full_name_template, api_version,
                                                    use_alpha, service_namespace),
                        "/", method_name);
  }

Project: envoy

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

Project: envoy

  static Config::DecodedResourcesWrapper decodeResources(
      const Protobuf::RepeatedPtrField<envoy::service::discovery::v3::Resource>& resources,
      const std::string& name_field = "name") {
    Config::DecodedResourcesWrapper decoded_resources;
    TestOpaqueResourceDecoderImpl<MessageType> resource_decoder(name_field);
    for (const auto& resource : resources) {
      decoded_resources.owned_resources_.emplace_back(
          new Config::DecodedResourceImpl(resource_decoder, resource));
      decoded_resources.refvec_.emplace_back(*decoded_resources.owned_resources_.back());
    }
    return decoded_resources;
  }

Project: envoy

MATCHER_P(HeaderMapEqualIgnoreOrder, expected, "") {
  const bool equal = TestUtility::headerMapEqualIgnoreOrder(*arg, *expected);
  if (!equal) {
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected header map:") << "\n"
                     << *expected
                     << TestUtility::addLeftAndRightPadding("is not equal to actual header map:")
                     << "\n"
                     << *arg << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

    TestOpaqueResourceDecoderImpl(absl::string_view name_field)
        : Config::OpaqueResourceDecoderImpl<Current>(ProtobufMessage::getStrictValidationVisitor(),
                                                     name_field) {}

Project: envoy

  const HeaderEntry* get(const LowerCaseString& key) const override {
    return header_map_->get(key);
  }

Project: envoy

  std::string get_(const std::string& key) const { return get_(LowerCaseString(key)); }

Project: envoy

MATCHER_P(RepeatedProtoEq, expected, "") {
  const bool equal = TestUtility::repeatedPtrFieldEqual(arg, expected);
  if (!equal) {
    *result_listener << "\n"
                     << TestUtility::addLeftAndRightPadding("Expected repeated:") << "\n"
                     << RepeatedPtrUtil::debugString(expected) << "\n"
                     << TestUtility::addLeftAndRightPadding("is not equal to actual repeated:")
                     << "\n"
                     << RepeatedPtrUtil::debugString(arg) << "\n"
                     << TestUtility::addLeftAndRightPadding("") // line full of padding
                     << "\n";
  }
  return equal;
}

Project: envoy

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

Project: envoy

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

  // Both issuer3 and issuer4 have specified this custom query location.
  EXPECT_EQ(tokens[0]->token(), "jwt_token");
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer3"));
  EXPECT_TRUE(tokens[0]->isIssuerSpecified("issuer4"));

  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer1"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer2"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("issuer5"));
  EXPECT_FALSE(tokens[0]->isIssuerSpecified("unknown_issuer"));

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

Project: envoy

  static size_t inlineHeadersSize() {
    return StaticLookupTable<Interface>::size() * sizeof(HeaderEntryImpl*);
  }

Project: envoy

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

Project: envoy

  bool operator==(const char* rhs) const {
    return getStringView() == absl::NullSafeStringView(rhs);
  }

Project: envoy

  CelValue Produce(ProtobufWkt::Arena* arena) override {
    return CelValue::CreateMessage(&metadata_, arena);
  }

Project: envoy

TEST_F(HeaderToMetadataTest, PerRouteEmtpyRules) {
  envoy::extensions::filters::http::header_to_metadata::v3::Config config_proto;
  EXPECT_THROW(std::make_shared<Config>(config_proto, true), EnvoyException);
}

Project: envoy

void HeaderMapImpl::addReferenceKey(const LowerCaseString& key, absl::string_view value) {
  HeaderString ref_key(key);
  HeaderString new_value;
  new_value.setCopy(value);
  insertByKey(std::move(ref_key), std::move(new_value));
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
}

Project: envoy

  void addViaMove(HeaderString&& key, HeaderString&& value) override {
    header_map_->addViaMove(std::move(key), std::move(value));
    header_map_->verifyByteSizeInternalForTest();
  }

Project: envoy

void HeaderMapImpl::addCopy(const LowerCaseString& key, uint64_t value) {
  // In the case that the header is appended, we will perform a needless copy of the key and value.
  // This is done on purpose to keep the code simple and should be rare.
  HeaderString new_key;
  new_key.setCopy(key.get());
  HeaderString new_value;
  new_value.setInteger(value);
  insertByKey(std::move(new_key), std::move(new_value));
  ASSERT(new_key.empty());   // NOLINT(bugprone-use-after-move)
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
}

Project: envoy

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

Project: envoy

  static const envoy::type::matcher::v3::StringMatcher createPrefixMatcher(std::string str) {
    envoy::type::matcher::v3::StringMatcher matcher;
    matcher.set_prefix(str);
    return matcher;
  }