Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/envoy/http/header_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,13 @@ class HeaderMap {
*/
virtual size_t remove(const LowerCaseString& key) PURE;

/**
* Remove all instances of headers where the header matches the predicate.
* @param predicate supplies the predicate to match headers against.
* @return the number of headers removed.
*/
virtual size_t removeIf(const std::function<bool(const HeaderEntry&)>& predicate) PURE;

/**
* Remove all instances of headers where the key begins with the supplied prefix.
* @param prefix supplies the prefix to match header keys against.
Expand Down
36 changes: 15 additions & 21 deletions source/common/http/header_map_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -483,28 +483,10 @@ void HeaderMapImpl::clear() {
cached_byte_size_ = 0;
}

size_t HeaderMapImpl::remove(const LowerCaseString& key) {
size_t HeaderMapImpl::removeIf(const std::function<bool(const HeaderEntry&)>& predicate) {
Comment thread
mattklein123 marked this conversation as resolved.
Outdated
const size_t old_size = headers_.size();
auto lookup = staticLookup(key.get());
if (lookup.has_value()) {
removeInline(lookup.value().entry_);
} else {
for (auto i = headers_.begin(); i != headers_.end();) {
if (i->key() == key.get().c_str()) {
subtractSize(i->key().size() + i->value().size());
i = headers_.erase(i);
} else {
++i;
}
}
}
return old_size - headers_.size();
}

size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) {
const size_t old_size = headers_.size();
headers_.remove_if([&prefix, this](const HeaderEntryImpl& entry) {
bool to_remove = absl::StartsWith(entry.key().getStringView(), prefix.get());
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.
Expand All @@ -525,6 +507,18 @@ size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) {
return old_size - headers_.size();
}

size_t HeaderMapImpl::remove(const LowerCaseString& key) {
return HeaderMapImpl::removeIf([&key](const HeaderEntry& entry) -> bool {
return key.get() == entry.key().getStringView();
});
}

size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) {
return HeaderMapImpl::removeIf([&prefix](const HeaderEntry& entry) -> bool {
return absl::StartsWith(entry.key().getStringView(), prefix.get());
Comment thread
mattklein123 marked this conversation as resolved.
});
}

void HeaderMapImpl::dumpState(std::ostream& os, int indent_level) const {
iterate([&os,
spaces = spacesForLevel(indent_level)](const HeaderEntry& header) -> HeaderMap::Iterate {
Expand Down
4 changes: 4 additions & 0 deletions source/common/http/header_map_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class HeaderMapImpl : NonCopyable {
void iterateReverse(HeaderMap::ConstIterateCb cb) const;
void clear();
size_t remove(const LowerCaseString& key);
size_t removeIf(const std::function<bool(const HeaderEntry&)>& predicate);
size_t removePrefix(const LowerCaseString& key);
size_t size() const { return headers_.size(); }
bool empty() const { return headers_.empty(); }
Expand Down Expand Up @@ -304,6 +305,9 @@ template <class Interface> class TypedHeaderMapImpl : public HeaderMapImpl, publ
}
void clear() override { HeaderMapImpl::clear(); }
size_t remove(const LowerCaseString& key) override { return HeaderMapImpl::remove(key); }
size_t removeIf(const std::function<bool(const HeaderEntry&)>& predicate) override {
return HeaderMapImpl::removeIf(predicate);
}
size_t removePrefix(const LowerCaseString& key) override {
return HeaderMapImpl::removePrefix(key);
}
Expand Down
25 changes: 23 additions & 2 deletions test/common/http/header_map_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,28 @@ TEST(HeaderMapImplTest, Remove) {
EXPECT_EQ(0UL, headers.remove(Headers::get().ContentLength));
}

TEST(HeaderMapImplTest, RemoveRegex) {
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);
}

TEST(HeaderMapImplTest, RemovePrefix) {
// These will match.
LowerCaseString key1 = LowerCaseString("X-prefix-foo");
LowerCaseString key3 = LowerCaseString("X-Prefix-");
Expand Down Expand Up @@ -552,7 +573,7 @@ TEST(HeaderMapImplTest, RemoveRegex) {
EXPECT_EQ(nullptr, headers.get(key2));
EXPECT_EQ(nullptr, headers.get(key4));

// Add inline and remove by regex
// Add inline and remove by prefix
headers.setContentLength(5);
EXPECT_EQ("5", headers.getContentLengthValue());
EXPECT_EQ(1UL, headers.size());
Expand Down
5 changes: 5 additions & 0 deletions test/test_common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,11 @@ template <class Interface, class Impl> class TestHeaderMapImplBase : public Inte
header_map_->verifyByteSizeInternalForTest();
return headers_removed;
}
size_t removeIf(const std::function<bool(const HeaderEntry&)>& predicate) override {
size_t headers_removed = header_map_->removeIf(predicate);
header_map_->verifyByteSizeInternalForTest();
return headers_removed;
}
size_t removePrefix(const LowerCaseString& key) override {
size_t headers_removed = header_map_->removePrefix(key);
header_map_->verifyByteSizeInternalForTest();
Expand Down