-
Notifications
You must be signed in to change notification settings - Fork 170
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rate Limit policy: allow templating using liquid #719
Rate Limit policy: allow templating using liquid #719
Conversation
t/apicast-policy-rate-limit.t
Outdated
@@ -984,3 +990,106 @@ Return 200 code. | |||
["GET /","GET /"] | |||
--- error_code eval | |||
[200, 200] | |||
|
|||
=== TEST 17: Liquid templating (jwt.aud). | |||
Return 429 code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be more descriptive.
@y-tabata Thanks for your contribution! 👍 Can you add a changelog entry, please? Something like Also, could you add some unit tests for this? I see that you added some integration tests which is good 👍 , but we also need the unit ones. You can use the ones we added for the headers policy as an example: #716 |
|
||
$ENV{TEST_NGINX_LUA_PATH} = "$Test::APIcast::spec/?.lua;$ENV{TEST_NGINX_LUA_PATH}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to resolve 'fixtures.rsa'
.
I referenced apicast-oidc.t.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I think we can find a better solution. I think these tests should make use of the fixtures
directory in t
instead of the one in spec
. However, as you said, we're doing the same in apicast-oidc.t
. We should fix this, but I think we can do it after this PR.
62e781d
to
7cbc4aa
Compare
end | ||
limiter.key_name = key_name | ||
else | ||
limiter.key_name = limiter.template_string:render(context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your solution works, but I think there's a simpler way to solve the same problem.
What we want to do is to make ngx.var.uri
and ngx.var.host
available in the liquid templates.
The regex matching is not necessary. We can achieve our goal by including new keys in the context we pass to template_string:render(context)
. If that context
includes a table with these keys uri = ngx.var.uri
and host = ngx.var.host
we'll be able to use {{ uri }}
and {{ host }}
in the config instead of {{ ngx.var.uri }}
and {{ ngx.var.host }}
.
Another option is to include ngx.var.host
in the context that we send to template_string:render()
. However, I think that when configuring this from the 3scale UI, users will find it more natural to write {{host}}
than to write {{ngx.var.host}}
. In theory, they don't even need to know that apicast is based on nginx. I had a discussion with @mikz about this in another PR: #716 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't use the regex, we have to have the list like uri = ngx.var.uri
or host = ngx.var.host
and so on.
The best place is liquid_filters
of template_string.lua
, isn't it?
Do you have any idea to avoid the "API disabled in the current context"
error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think liquid_filters
in template_string.lua
is the best place for this. Those are filters, functions like md5
that allow us to have things like {{ 'a_value' | md5 }}
in the policy config.
But uri
and host
are values, not filters. I think uri
and host
need to be included in the context passed to render
. For that, I think a possible solution is to have a table somewhere with the values we want to have available in the context. As a starting point, we could have something like:
local function context_values()
return {
uri = ngx.var.uri,
host = ngx.var.host,
-- possibly many others
}
end
_M.available_context(policies_context)
-- merge policies_context with context_values and return the result
end
Maybe we could include this in the Policy module or even in a new separate module.
If we evaluate the ngx.var*
vars in access()
, we won't see the API disabled in the current context
error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
f63f876
to
bdc32d8
Compare
end | ||
|
||
function _M.available_context(policies_context) | ||
for name, value in pairs(context_values()) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pairs
method can't be JITed, it is always better to use ipairs
and change the data structure.
In this case it is not even needed. What are you doing is mutating the passed policies_context
. That is really not expected. It is way better to return a new object.
You don't need to even copy the context table, just use metatable __index property to delegate unknown fields:
return setmetatable(context_values(), { __index = policies_context })
|
||
local function interpolate_key_name(context, limiters) | ||
for _, limiter in ipairs(limiters) do | ||
limiter.key_name = limiter.template_string:render(context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mutates the limiter
object which is shared across all requests.
You can just pass context
to build_limiters_and_keys
and use it there without storing it in the shared limiter object.
c0b91f8
to
c1ddc21
Compare
Do you have any idea to avoid |
end | ||
|
||
function _M.available_context(policies_context) | ||
return setmetatable(policies_context, { __index = context_values() }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still mutates the context. It should be the other way around. Setting the metatable of context_values
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@y-tabata the tests fail because of #719 (comment) |
c1ddc21
to
a31bc40
Compare
@mikz thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 good job!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍
Thanks for your contribution @y-tabata ! 👍
Closes #713.