Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
23 changes: 14 additions & 9 deletions docs/configuration/http_conn_man/route_config/rate_limits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Generic Key


descriptor_value
*(required, string)* The value to use in the descriptor entry.
*(required, string)* The value to use in the descriptor entry.

The following descriptor entry is appended to the descriptor:

Expand All @@ -157,22 +157,27 @@ Header Value Match
{
"type": "header_value_match",
"descriptor_value" : "...",
"expect_match" : "...",
"headers" : []
}


descriptor_value
*(required, string)* The value to use in the descriptor entry.
*(required, string)* The value to use in the descriptor entry.

:ref:`headers<config_http_conn_man_route_table_route_headers>`
*(required, array)* Specifies a set of headers that the rate limit action should match on. The
action will check the request's headers against all the specified headers in the config. A match
will happen if all the headers in the config are present in the request with the same values (or
based on presence if the ``value`` field is not in the config).
expect_match
*(optional, boolean)* If set to true, the action will append a descriptor entry when the request
matches the :ref:`headers<config_http_conn_man_route_table_route_headers>`. If set to false,
the action will append a descriptor entry when the request does not match the
:ref:`headers<config_http_conn_man_route_table_route_headers>`. The default value is true.

The following descriptor entry is appended to the descriptor if the request matches the headers
specified in the action config:
:ref:`headers<config_http_conn_man_route_table_route_headers>`
*(required, array)* Specifies a set of headers that the rate limit action should match on. The
action will check the request's headers against all the specified headers in the config. A match
will happen if all the headers in the config are present in the request with the same values (or
based on presence if the ``value`` field is not in the config).

The following descriptor entry is appended to the descriptor:
.. code-block:: cpp

("header_match", "<descriptor_value>")
Expand Down
1 change: 1 addition & 0 deletions source/common/json/config_schemas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ const std::string Json::Schema::HTTP_RATE_LIMITS_CONFIGURATION_SCHEMA(R"EOF(
"enum" : ["header_value_match"]
},
"descriptor_value" : {"type" : "string"},
"expect_match" : {"type" : "boolean"},
"headers" : {
"type" : "array",
"minItems" : 1,
Expand Down
5 changes: 3 additions & 2 deletions source/common/router/router_ratelimit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ bool GenericKeyAction::populateDescriptor(const Router::RouteEntry&,
}

HeaderValueMatchAction::HeaderValueMatchAction(const Json::Object& action)
: descriptor_value_(action.getString("descriptor_value")) {
: descriptor_value_(action.getString("descriptor_value")),
expect_match_(action.getBoolean("expect_match", true)) {
std::vector<Json::ObjectPtr> config_headers = action.getObjectArray("headers");
for (const Json::ObjectPtr& header_map : config_headers) {
action_headers_.push_back(*header_map);
Expand All @@ -73,7 +74,7 @@ bool HeaderValueMatchAction::populateDescriptor(const Router::RouteEntry&,
::RateLimit::Descriptor& descriptor,
const std::string&, const Http::HeaderMap& headers,
const std::string&) const {
if (ConfigUtility::matchHeaders(headers, action_headers_)) {
if (expect_match_ == ConfigUtility::matchHeaders(headers, action_headers_)) {
descriptor.entries_.push_back({"header_match", descriptor_value_});
return true;
} else {
Expand Down
1 change: 1 addition & 0 deletions source/common/router/router_ratelimit.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class HeaderValueMatchAction : public RateLimitAction {

private:
const std::string descriptor_value_;
const bool expect_match_;
std::vector<Router::ConfigUtility::HeaderData> action_headers_;
};

Expand Down
57 changes: 56 additions & 1 deletion test/common/router/router_ratelimit_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,62 @@ TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchNoMatch) {
)EOF";

SetUpTest(json);
Http::TestHeaderMapImpl header{{"x-header-name", "fake_value"}};
Http::TestHeaderMapImpl header{{"x-header-name", "not_same_value"}};

rate_limit_entry_->populateDescriptors(route_, descriptors_, "", header, "");
EXPECT_TRUE(descriptors_.empty());
}

TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchHeadersNotPresent) {
std::string json = R"EOF(
{
"actions": [
{
"type": "header_value_match",
"descriptor_value": "fake_value",
"expect_match": false,
"headers": [
{
"name": "x-header-name",
"value": "test_value",
"regex": false
}
]
}
]
}
)EOF";

SetUpTest(json);
Http::TestHeaderMapImpl header{{"x-header-name", "not_same_value"}};

rate_limit_entry_->populateDescriptors(route_, descriptors_, "", header, "");
EXPECT_THAT(std::vector<::RateLimit::Descriptor>({{{{"header_match", "fake_value"}}}}),
testing::ContainerEq(descriptors_));
}

TEST_F(RateLimitPolicyEntryTest, HeaderValueMatchHeadersPresent) {
std::string json = R"EOF(
{
"actions": [
{
"type": "header_value_match",
"descriptor_value": "fake_value",
"expect_match": false,
"headers": [
{
"name": "x-header-name",
"value": "test_value",
"regex": false
}
]
}
]
}
)EOF";

SetUpTest(json);
Http::TestHeaderMapImpl header{{"x-header-name", "test_value"}};

rate_limit_entry_->populateDescriptors(route_, descriptors_, "", header, "");
EXPECT_TRUE(descriptors_.empty());
Expand Down