diff --git a/CHANGELOG.md b/CHANGELOG.md index e203f97c7..90aee7b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Decoded JWTs are now exposed in the policies context by the APIcast policy [PR #718](https://github.com/3scale/apicast/pull/718) - Upgraded OpenResty to 1.13.6.2, uses OpenSSL 1.1 [PR #733](https://github.com/3scale/apicast/pull/733) - Use forked `resty.limit.count` that uses increments instead of decrements [PR #758](https://github.com/3scale/apicast/pull/758) +- The regular expression for mapping rules has been changed, so that special characters are accepted in the wildcard values for path [PR #717](https://github.com/3scale/apicast/pull/714) ### Fixed diff --git a/gateway/src/apicast/mapping_rule.lua b/gateway/src/apicast/mapping_rule.lua index 9a175dec3..1bd4c01f0 100644 --- a/gateway/src/apicast/mapping_rule.lua +++ b/gateway/src/apicast/mapping_rule.lua @@ -11,6 +11,7 @@ local type = type local format = string.format local re_match = ngx.re.match local insert = table.insert +local re_gsub = ngx.re.gsub local _M = {} @@ -27,7 +28,11 @@ local function hash_to_array(hash) end local function regexpify(pattern) - return pattern:gsub('?.*', ''):gsub("{.-}", '([\\w_.-]+)'):gsub("%.", "\\.") + pattern = re_gsub(pattern, [[\?.*]], '', 'oj') + -- dollar sign is escaped by another $, see https://github.com/openresty/lua-nginx-module#ngxresub + pattern = re_gsub(pattern, [[\{.+?\}]], [[([\w-.~%!$$&'()*+,;=@:]+)]], 'oj') + pattern = re_gsub(pattern, [[\.]], [[\.]], 'oj') + return pattern end local regex_variable = '\\{[-\\w_]+\\}' diff --git a/spec/mapping_rule_spec.lua b/spec/mapping_rule_spec.lua index f95aba75e..39b11c966 100644 --- a/spec/mapping_rule_spec.lua +++ b/spec/mapping_rule_spec.lua @@ -79,5 +79,20 @@ describe('mapping_rule', function() local match = mapping_rule:matches('POST', '/def', { x = 'y' }) assert.is_false(match) end) + + it('returns true when wildcard value has special characters: @ : % etc.', function() + local mapping_rule = MappingRule.from_proxy_rule({ + http_method = 'GET', + pattern = '/foo/{wildcard}/bar', + querystring_parameters = { }, + metric_system_name = 'hits', + delta = 1 + }) + + assert.is_true(mapping_rule:matches('GET', '/foo/a@b/bar')) + assert.is_true(mapping_rule:matches('GET', '/foo/a:b/bar')) + assert.is_true(mapping_rule:matches('GET', "/foo/a%b/bar")) + end) + end) end)