Skip to content
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

"Rewrite URL captures" policy #827

Merged
merged 8 commits into from
Aug 3, 2018
Merged

"Rewrite URL captures" policy #827

merged 8 commits into from
Aug 3, 2018

Conversation

davidor
Copy link
Contributor

@davidor davidor commented Jul 30, 2018

Closes #711 (first use case)

After the discussion in #711, I think that implementing the first use case of that issue with a new policy seems reasonable. We need something for the next release, although in the future, we might be able to do something better as we add more features to the conditional policy.

Regarding the name of the policy, I'm open to suggestions. I can't think of a good name for it 🤔

@davidor davidor requested a review from a team as a code owner July 30, 2018 15:49
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 2 }
],
"policy_chain": [
{ "name": "apicast.policy.apicast" },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change these tests so they use the Echo policy instead. I think that will simplify the code.

I'll keep just one with the APIcast policy just to make sure that there are not any problems when combining it with the new policy.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love that 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that we can't do that because the Echo policy uses ngx.say(ngx.var.request), so it just works with the original request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the upstream policy pointing to the echo endpoint? That is still simpler than APIcast + dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the echo policy requires more work because we are only interested in checking the path and the query args, but the echo returns more data.

In the end, I opted for deleting the APIcast policy from the chain and adding an upstream policy that redirects all the request to the upstream defining in the config. I think this is the simplest solution.

I kept one of the tests I had with the APIcast policy just to make sure that both policies can be combined without any problems.

local replaced_template = replace_in_template(
self.named_args, matches, self.template)

local uri, raw_params = unpack(re_split(replaced_template, '\\?'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unpack can't be JITed so this should not be in the hot path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And instead of '\\?' you can use [[\?]], but that might be just my preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the unpack.
I don't have a strong preference on \\? vs [[\?]] so I changed it.

local res = template

for i, arg in ipairs(args) do
res = re_gsub(res, "{" .. arg .. "}", vals[i], 'oj')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is allocating 3 strings in a loop. Better to use string.format and even better to do this during policy initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. It turns out that we always use the result of this wrapped between "{" and "}" so I concatenate them in extract_named_args which is only called from .new().

local params_split = re_split(string_params, '&')

for _, param in ipairs(params_split) do
local name, val = unpack(re_split(param, '='))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another unpack in a loop. This will prevent JIT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 👍

local function string_params_to_table(string_params)
local res = {}

local params_split = re_split(string_params, '&')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe good to extract re_split into own function split that will always pass oj flags.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, that way we won't forget to add oj. Fixed 👍

So it can be used from other policies, and not just from the URL
rewriting one.
local params_split = split(string_params, '&')

for _, param in ipairs(params_split) do
local parts = split(param, '=') -- avoid unpack, not jitted.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to limit the number of parts you want by setting the max results parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

local parts = split(param, '=') -- avoid unpack, not jitted.
local name = parts[1]
local val = parts[2]
res[name] = val
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LuaJIT performance guide says it is better not to create short lived temporary variables like these and just use the tuple:

res[parts[1]] = parts[2]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that defining those vars helps readability. I doubt this will have a noticeable impact.

local function set_query_params(new_params)
local query_params = QueryParams.new()

for arg, value in pairs(new_params) do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pairs is not JITed. Does it need to be key valued table? Integer indexed could be JITed.

end

local function uri_and_params_from_template(template)
local parts = split(template, [[\?]]) -- avoid unpack, not jitted.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it might need to limit the results too.

@davidor
Copy link
Contributor Author

davidor commented Aug 1, 2018

@mikz Regarding the name of the policy, do you have any suggestions?

@davidor davidor force-pushed the named-args-policy branch 2 times, most recently from 1d797ad to d9c7b97 Compare August 1, 2018 10:15
@davidor
Copy link
Contributor Author

davidor commented Aug 1, 2018

I addressed all your comments @mikz

end

-- Returns a list of named args extracted from a match_rule.
-- For example, for the rule /{abc}/{def}?{ghi}=1, it returns this list:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, do you think it makes sense to use just {} instead of {{ }} to match with the liquid syntax?

Copy link
Contributor Author

@davidor davidor Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think {} is better in this case because it's the same format that we are using for the mapping rules.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thats fair point. And for the replacement ? Shouldn't we just pass it through liquid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. That would only replace the code we have in replace_in_template which is not problematic, in my opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I'm thinking about consistency. If push people everywhere to use liquid, then it would make sense to stick to it. I have no hard feelings one way or the other, just want to avoid confused people that can't use what they do everywhere else.

But it will not be hard to migrate. Just adding the template_type. So if you have no feelings one way or the other then lets merge this 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather leave this one as it is, at least for now 👍

function _M.new(config)
local self = new(config)

self.matchers = {}
Copy link
Contributor

@mikz mikz Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for the future. Using tab_new(#config.transformations, 0) would save table expansion because it would preallocate slots in the table for each matcher.

Copy link
Contributor

@mikz mikz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is great! 👍

My only opened question is if we should make this look like liquid.

And regarding the name, I personally think this is fine, but @3scale/product should have say in this.

@mikz mikz requested a review from a team August 3, 2018 09:15
@davidor davidor merged commit 6324e2b into master Aug 3, 2018
@davidor davidor deleted the named-args-policy branch August 3, 2018 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants