|
| 1 | +--- Headers policy |
| 2 | +-- This policy allows to include custom headers that will be sent to the |
| 3 | +-- upstream as well as modify or delete the ones included in the original |
| 4 | +-- request. |
| 5 | +-- Similarly, this policy also allows to add, modify, and delete the headers |
| 6 | +-- included in the response. |
| 7 | + |
| 8 | +local ipairs = ipairs |
| 9 | +local type = type |
| 10 | +local insert = table.insert |
| 11 | + |
| 12 | +local policy = require('apicast.policy') |
| 13 | +local _M = policy.new('Headers policy') |
| 14 | + |
| 15 | +local new = _M.new |
| 16 | + |
| 17 | +local function new_header_value(current_value, value_to_add) |
| 18 | + local new_value = current_value or {} |
| 19 | + |
| 20 | + if type(new_value) == 'string' then |
| 21 | + new_value = { new_value } |
| 22 | + end |
| 23 | + |
| 24 | + insert(new_value, value_to_add) |
| 25 | + return new_value |
| 26 | +end |
| 27 | + |
| 28 | +local function push_request_header(header_name, value, req_headers) |
| 29 | + local new_value = new_header_value(req_headers[header_name], value) |
| 30 | + ngx.req.set_header(header_name, new_value) |
| 31 | +end |
| 32 | + |
| 33 | +local function set_request_header(header_name, value) |
| 34 | + ngx.req.set_header(header_name, value) |
| 35 | +end |
| 36 | + |
| 37 | +local function add_request_header(header_name, value, req_headers) |
| 38 | + if req_headers[header_name] then |
| 39 | + push_request_header(header_name, value, req_headers) |
| 40 | + end |
| 41 | +end |
| 42 | + |
| 43 | +local function push_resp_header(header_name, value) |
| 44 | + local new_value = new_header_value(ngx.header[header_name], value) |
| 45 | + ngx.header[header_name] = new_value |
| 46 | +end |
| 47 | + |
| 48 | +local function set_resp_header(header_name, value) |
| 49 | + ngx.header[header_name] = value |
| 50 | +end |
| 51 | + |
| 52 | +local function add_resp_header(header_name, value) |
| 53 | + if ngx.header[header_name] then |
| 54 | + push_resp_header(header_name, value) |
| 55 | + end |
| 56 | +end |
| 57 | + |
| 58 | +local command_functions = { |
| 59 | + request = { |
| 60 | + push = push_request_header, |
| 61 | + add = add_request_header, |
| 62 | + set = set_request_header |
| 63 | + }, |
| 64 | + response = { |
| 65 | + push = push_resp_header, |
| 66 | + add = add_resp_header, |
| 67 | + set = set_resp_header |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +-- header_type can be 'request' or 'response'. |
| 72 | +local function run_commands(commands, header_type, ...) |
| 73 | + for _, command in ipairs(commands) do |
| 74 | + local command_func = command_functions[header_type][command.op] |
| 75 | + command_func(command.header, command.value, ...) |
| 76 | + end |
| 77 | +end |
| 78 | + |
| 79 | +-- Initialize the config so we do not have to check for nulls in the rest of |
| 80 | +-- the code. |
| 81 | +local function init_config(config) |
| 82 | + local res = config or {} |
| 83 | + res.request = res.request or {} |
| 84 | + res.response = res.response or {} |
| 85 | + return res |
| 86 | +end |
| 87 | + |
| 88 | +--- Initialize a Headers policy |
| 89 | +-- @tparam[opt] table config |
| 90 | +-- @field[opt] request Table with the operations to apply to the request headers |
| 91 | +-- @field[opt] response Table with the operations to apply to the response headers |
| 92 | +-- Each operation is a table with three elements: |
| 93 | +-- 1) op: can be 'add', 'set' or 'push'. |
| 94 | +-- 2) header |
| 95 | +-- 3) value |
| 96 | +-- The push operation: |
| 97 | +-- 1) When the header is not set, creates it with the given value. |
| 98 | +-- 2) When the header is set, it creates a new header with the same name and |
| 99 | +-- the given value. |
| 100 | +-- The set operation: |
| 101 | +-- 1) When the header is not set, creates it with the given value. |
| 102 | +-- 2) When the header is set, replaces its value with the given one. |
| 103 | +-- 3) Deletes a header when the value is "". |
| 104 | +-- The add operation: |
| 105 | +-- 1) When the header is not set, it does nothing. |
| 106 | +-- 2) When the header is set, it creates a new header with the same name and |
| 107 | +-- the given value. |
| 108 | +function _M.new(config) |
| 109 | + local self = new() |
| 110 | + self.config = init_config(config) |
| 111 | + return self |
| 112 | +end |
| 113 | + |
| 114 | +function _M:rewrite() |
| 115 | + -- This is here to avoid calling ngx.req.get_headers() in every command |
| 116 | + -- applied to the request headers. |
| 117 | + local req_headers = ngx.req.get_headers() or {} |
| 118 | + run_commands(self.config.request, 'request', req_headers) |
| 119 | +end |
| 120 | + |
| 121 | +function _M:header_filter() |
| 122 | + run_commands(self.config.response, 'response') |
| 123 | +end |
| 124 | + |
| 125 | +return _M |
0 commit comments