diff --git a/CHANGELOG.md b/CHANGELOG.md index fb134f6e2..9b223c182 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Decrease nginx timer resolution to improve performance and enable PCRE JIT [PR #543](https://github.com/3scale/apicast/pull/543) - Moved `proxy_pass` into new internal location `@upstream` [PR #535](https://github.com/3scale/apicast/pull/535) - Split 3scale authorization to rewrite and access phase [PR #556](https://github.com/3scale/apicast/pull/556) +- Extract `mapping_rule` module from the `configuration` module [PR #571](https://github.com/3scale/apicast/pull/571) ## [3.2.0-alpha2] - 2017-11-30 diff --git a/gateway/src/apicast/configuration.lua b/gateway/src/apicast/configuration.lua index 771343d22..8d1b4ce7a 100644 --- a/gateway/src/apicast/configuration.lua +++ b/gateway/src/apicast/configuration.lua @@ -5,20 +5,18 @@ local _M = { local len = string.len local pairs = pairs local type = type -local error = error local tostring = tostring local next = next local lower = string.lower local insert = table.insert local setmetatable = setmetatable -local re_match = ngx.re.match -local inspect = require 'inspect' local re = require 'ngx.re' local env = require 'resty.env' local resty_url = require 'resty.url' local util = require 'apicast.util' local policy_chain = require 'apicast.policy_chain' +local mapping_rule = require 'apicast.mapping_rule' local mt = { __index = _M, __tostring = function() return 'Configuration' end } @@ -30,54 +28,6 @@ local function map(func, tbl) return newtbl end -local function regexpify(path) - return path:gsub('?.*', ''):gsub("{.-}", '([\\w_.-]+)'):gsub("%.", "\\.") -end - -local regex_variable = '\\{[-\\w_]+\\}' - -local function hash_to_array(hash) - local array = {} - for k,v in pairs(hash or {}) do - insert(array, { k, v }) - end - return array -end - -local function check_querystring_params(params, args) - local match = true - - for i=1, #params do - local param = params[i][1] - local expected = params[i][2] - local m, err = re_match(expected, regex_variable, 'oj') - local value = args[param] - - if m then - if not value then -- regex variable have to have some value - ngx.log(ngx.DEBUG, 'check query params ', param, ' value missing ', expected) - match = false - break - end - else - if err then ngx.log(ngx.ERR, 'check match error ', err) end - - -- if many values were passed use the last one - if type(value) == 'table' then - value = value[#value] - end - - if value ~= expected then -- normal variables have to have exact value - ngx.log(ngx.DEBUG, 'check query params does not match ', param, ' value ' , value, ' == ', expected) - match = false - break - end - end - end - - return match -end - local Service = require 'apicast.configuration.service' local noop = function() end @@ -158,21 +108,7 @@ function _M.parse_service(service) app_id = lower(proxy.auth_app_id or 'app_id'), app_key = lower(proxy.auth_app_key or 'app_key') -- TODO: use App-Key if location is headers }, - rules = map(function(proxy_rule) - local querystring_parameters = hash_to_array(proxy_rule.querystring_parameters) - - return { - method = proxy_rule.http_method, - pattern = proxy_rule.pattern, - regexpified_pattern = regexpify(proxy_rule.pattern), - parameters = proxy_rule.parameters, - querystring_params = function(args) - return check_querystring_params(querystring_parameters, args) - end, - system_name = proxy_rule.metric_system_name or error('missing metric name of rule ' .. inspect(proxy_rule)), - delta = proxy_rule.delta - } - end, proxy.proxy_rules or {}), + rules = map(mapping_rule.from_proxy_rule, proxy.proxy_rules or {}), -- I'm not happy about this, but we need a way how to serialize back the object for the management API. -- And returning the original back is the easiest option for now. diff --git a/gateway/src/apicast/mapping_rule.lua b/gateway/src/apicast/mapping_rule.lua new file mode 100644 index 000000000..3401d015a --- /dev/null +++ b/gateway/src/apicast/mapping_rule.lua @@ -0,0 +1,112 @@ +--- Mapping rule +-- @module mapping_rule +-- A mapping rule consists of a pattern used to match requests. It also defines +-- a metric and a value that indicates how to increase the usage of a metric +-- when there is a match. + +local setmetatable = setmetatable +local pairs = pairs +local error = error +local type = type +local re_match = ngx.re.match +local insert = table.insert + +local _M = {} + +local mt = { __index = _M } + +local function hash_to_array(hash) + local array = {} + + for k,v in pairs(hash or {}) do + insert(array, { k, v }) + end + + return array +end + +local function regexpify(path) + return path:gsub('?.*', ''):gsub("{.-}", '([\\w_.-]+)'):gsub("%.", "\\.") +end + +local regex_variable = '\\{[-\\w_]+\\}' + +local function check_querystring_params(params, args) + local match = true + + for i=1, #params do + local param = params[i][1] + local expected = params[i][2] + local m, err = re_match(expected, regex_variable, 'oj') + local value = args[param] + + if m then + if not value then -- regex variable have to have some value + ngx.log(ngx.DEBUG, 'check query params ', param, + ' value missing ', expected) + match = false + break + end + else + if err then ngx.log(ngx.ERR, 'check match error ', err) end + + -- if many values were passed use the last one + if type(value) == 'table' then + value = value[#value] + end + + if value ~= expected then -- normal variables have to have exact value + ngx.log(ngx.DEBUG, 'check query params does not match ', + param, ' value ' , value, ' == ', expected) + match = false + break + end + end + end + + return match +end + +local function new(http_method, pattern, params, querystring_params, metric, delta) + local self = setmetatable({}, mt) + + local querystring_parameters = hash_to_array(querystring_params) + + self.method = http_method + self.pattern = pattern + self.regexpified_pattern = regexpify(pattern) + self.parameters = params + self.system_name = metric or error('missing metric name of rule') + self.delta = delta + + self.querystring_params = function(args) + return check_querystring_params(querystring_parameters, args) + end + + return self +end + +--- Initializes a mapping rule from a proxy rule of the service configuration. +-- +-- @tparam table proxy_rule Proxy rule from the service configuration. +-- @tfield string http_method HTTP method (GET, POST, etc.). +-- @tfield string pattern Pattern used to match a request. +-- @tfield table parameters Parameters of the pattern. +-- @tfield table querystring_parameters Table with the params of the request +-- and its values. +-- @tfield string metric_system_name Name of the metric. +-- @tfield integer delta The usage of the metric will be increased by this +-- value. +-- @treturn mapping_rule New mapping rule. +function _M.from_proxy_rule(proxy_rule) + return new( + proxy_rule.http_method, + proxy_rule.pattern, + proxy_rule.parameters, + proxy_rule.querystring_parameters, + proxy_rule.metric_system_name, + proxy_rule.delta + ) +end + +return _M