Skip to content

Commit 54fb2d5

Browse files
committed
feat(active) support map headers
1 parent 00a1b12 commit 54fb2d5

File tree

2 files changed

+223
-6
lines changed

2 files changed

+223
-6
lines changed

lib/resty/healthcheck.lua

+71-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,46 @@ local ngx_worker_pid = ngx.worker.pid
4242
local ssl = require("ngx.ssl")
4343
local resty_timer = require "resty.timer"
4444

45+
local new_tab
46+
local nkeys
47+
local is_array
48+
49+
do
50+
local pcall = pcall
51+
local ok
52+
53+
ok, new_tab = pcall(require, "table.new")
54+
if not ok then
55+
new_tab = function () return {} end
56+
end
57+
58+
-- OpenResty branch of LuaJIT New API
59+
ok, nkeys = pcall(require, "table.nkeys")
60+
if not ok then
61+
nkeys = function (tab)
62+
local count = 0
63+
for _, v in pairs(tab) do
64+
if v ~= nil then
65+
count = count + 1
66+
end
67+
end
68+
return count
69+
end
70+
end
71+
72+
ok, is_array = pcall(require, "table.isarray")
73+
if not ok then
74+
is_array = function(t)
75+
for k in pairs(t) do
76+
if type(k) ~= "number" or math.floor(k) ~= k then
77+
return false
78+
end
79+
end
80+
return true
81+
end
82+
end
83+
end
84+
4585
-- constants
4686
local EVENT_SOURCE_PREFIX = "lua-resty-healthcheck"
4787
local LOG_PREFIX = "[healthcheck] "
@@ -867,9 +907,36 @@ function checker:run_single_check(ip, port, hostname, hostheader)
867907
end
868908

869909
local req_headers = self.checks.active.headers
870-
local headers = table.concat(req_headers, "\r\n")
871-
if #headers > 0 then
872-
headers = headers .. "\r\n"
910+
local headers
911+
if self.checks.active._headers_str then
912+
headers = self.checks.active._headers_str
913+
else
914+
local headers_length = nkeys(req_headers)
915+
if headers_length > 0 then
916+
if is_array(req_headers) then
917+
self:log(WARN, "array headers is deprecated")
918+
headers = table.concat(req_headers, "\r\n")
919+
else
920+
headers = new_tab(0, headers_length)
921+
local idx = 0
922+
for key, values in pairs(req_headers) do
923+
if type(values) == "table" then
924+
for _, value in ipairs(values) do
925+
idx = idx + 1
926+
headers[idx] = key .. ": " .. tostring(value)
927+
end
928+
else
929+
idx = idx + 1
930+
headers[idx] = key .. ": " .. tostring(values)
931+
end
932+
end
933+
headers = table.concat(headers, "\r\n")
934+
end
935+
if #headers > 0 then
936+
headers = headers .. "\r\n"
937+
end
938+
end
939+
self.checks.active._headers_str = headers or ""
873940
end
874941

875942
local path = self.checks.active.http_path
@@ -1308,7 +1375,7 @@ end
13081375
-- * `checks.active.concurrency`: number of targets to check concurrently
13091376
-- * `checks.active.http_path`: path to use in `GET` HTTP request to run on active checks
13101377
-- * `checks.active.https_verify_certificate`: boolean indicating whether to verify the HTTPS certificate
1311-
-- * `checks.active.hheaders`: an array of headers (no hash-table! must be pre-formatted)
1378+
-- * `checks.active.headers`: one or more lists of values indexed by header name
13121379
-- * `checks.active.healthy.interval`: interval between checks for healthy targets (in seconds)
13131380
-- * `checks.active.healthy.http_statuses`: which HTTP statuses to consider a success
13141381
-- * `checks.active.healthy.successes`: number of successes to consider a target healthy

t/20-req-headers.t

+152-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ run_tests();
1515

1616
__DATA__
1717

18-
=== TEST 1: headers: {"User-Agent", "curl/7.29.0"}
18+
=== TEST 1: headers: {"User-Agent: curl/7.29.0"}
1919
--- http_config eval
2020
qq{
2121
$::HttpConfig
@@ -65,7 +65,7 @@ Host: 127.0.0.1
6565
6666
6767
68-
=== TEST 2: headers: {"User-Agent", "curl"}
68+
=== TEST 2: headers: {"User-Agent: curl"}
6969
--- http_config eval
7070
qq{
7171
$::HttpConfig
@@ -112,3 +112,153 @@ checking healthy targets: #1
112112
GET /status HTTP/1.0
113113
User-Agent: curl
114114
Host: 127.0.0.1
115+
116+
117+
=== TEST 3: headers: { ["User-Agent"] = "curl" }
118+
--- http_config eval
119+
qq{
120+
$::HttpConfig
121+
122+
server {
123+
listen 2112;
124+
location = /status {
125+
return 200;
126+
}
127+
}
128+
}
129+
--- config
130+
location = /t {
131+
content_by_lua_block {
132+
local we = require "resty.worker.events"
133+
assert(we.configure{ shm = "my_worker_events", interval = 0.1 })
134+
local healthcheck = require("resty.healthcheck")
135+
local checker = healthcheck.new({
136+
name = "testing",
137+
shm_name = "test_shm",
138+
checks = {
139+
active = {
140+
http_path = "/status",
141+
healthy = {
142+
interval = 0.1
143+
},
144+
headers = { ["User-Agent"] = "curl" }
145+
}
146+
}
147+
})
148+
ngx.sleep(0.2) -- wait twice the interval
149+
local ok, err = checker:add_target("127.0.0.1", 2112, nil, true)
150+
ngx.say(ok)
151+
ngx.sleep(0.2) -- wait twice the interval
152+
}
153+
}
154+
--- request
155+
GET /t
156+
--- response_body
157+
true
158+
--- error_log
159+
checking healthy targets: nothing to do
160+
checking healthy targets: #1
161+
GET /status HTTP/1.0
162+
User-Agent: curl
163+
Host: 127.0.0.1
164+
165+
166+
167+
=== TEST 4: headers: { ["User-Agent"] = {"curl"} }
168+
--- http_config eval
169+
qq{
170+
$::HttpConfig
171+
172+
server {
173+
listen 2112;
174+
location = /status {
175+
return 200;
176+
}
177+
}
178+
}
179+
--- config
180+
location = /t {
181+
content_by_lua_block {
182+
local we = require "resty.worker.events"
183+
assert(we.configure{ shm = "my_worker_events", interval = 0.1 })
184+
local healthcheck = require("resty.healthcheck")
185+
local checker = healthcheck.new({
186+
name = "testing",
187+
shm_name = "test_shm",
188+
checks = {
189+
active = {
190+
http_path = "/status",
191+
healthy = {
192+
interval = 0.1
193+
},
194+
headers = { ["User-Agent"] = {"curl"} }
195+
}
196+
}
197+
})
198+
ngx.sleep(0.2) -- wait twice the interval
199+
local ok, err = checker:add_target("127.0.0.1", 2112, nil, true)
200+
ngx.say(ok)
201+
ngx.sleep(0.2) -- wait twice the interval
202+
}
203+
}
204+
--- request
205+
GET /t
206+
--- response_body
207+
true
208+
--- error_log
209+
checking healthy targets: nothing to do
210+
checking healthy targets: #1
211+
GET /status HTTP/1.0
212+
User-Agent: curl
213+
Host: 127.0.0.1
214+
215+
216+
217+
=== TEST 5: headers: { ["User-Agent"] = {"curl", "nginx"} }
218+
--- http_config eval
219+
qq{
220+
$::HttpConfig
221+
222+
server {
223+
listen 2112;
224+
location = /status {
225+
return 200;
226+
}
227+
}
228+
}
229+
--- config
230+
location = /t {
231+
content_by_lua_block {
232+
local we = require "resty.worker.events"
233+
assert(we.configure{ shm = "my_worker_events", interval = 0.1 })
234+
local healthcheck = require("resty.healthcheck")
235+
local checker = healthcheck.new({
236+
name = "testing",
237+
shm_name = "test_shm",
238+
checks = {
239+
active = {
240+
http_path = "/status",
241+
healthy = {
242+
interval = 0.1
243+
},
244+
headers = { ["User-Agent"] = {"curl", "nginx"} }
245+
}
246+
}
247+
})
248+
ngx.sleep(0.2) -- wait twice the interval
249+
local ok, err = checker:add_target("127.0.0.1", 2112, nil, true)
250+
ngx.say(ok)
251+
ngx.sleep(0.2) -- wait twice the interval
252+
}
253+
}
254+
--- request
255+
GET /t
256+
--- response_body
257+
true
258+
--- error_log
259+
checking healthy targets: nothing to do
260+
checking healthy targets: #1
261+
GET /status HTTP/1.0
262+
User-Agent: curl
263+
User-Agent: nginx
264+
Host: 127.0.0.1

0 commit comments

Comments
 (0)