Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion apisix/plugins/batch-requests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ local plugin = require("apisix.plugin")
local ngx = ngx
local ipairs = ipairs
local pairs = pairs
local type = type
local str_find = core.string.find
local str_lower = string.lower

Expand Down Expand Up @@ -224,6 +225,50 @@ local function set_common_query(data)
end


-- When the request is received on a unix domain socket, $server_port is an
-- empty string, so we fall back to a TCP port from `apisix.node_listen`.
-- The value read from the local conf is not normalized by the CLI, so it can
-- be a plain port number, or an array of port numbers or `{ip, port}` tables.
-- An entry bound to a specific address is only used as a last resort, as the
-- loopback connect below targets 127.0.0.1 and would otherwise be refused.
local function get_loopback_port()
local server_port = ngx.var.server_port
if server_port and server_port ~= "" then
return server_port
end

local local_conf = core.config.local_conf()
local node_listen = core.table.try_read_attr(local_conf, "apisix", "node_listen")
if type(node_listen) == "number" then
return node_listen
end

if type(node_listen) == "table" then
local bound_port
for _, value in ipairs(node_listen) do
if type(value) == "number" then
return value
end

if type(value) == "table" then
-- the port defaults to 9080 if not set, see `apisix/cli/ops.lua`
local port = value.port or 9080
local ip = value.ip
if ip == nil or ip == "0.0.0.0" or ip == "127.0.0.1" then
return port
end

bound_port = bound_port or port
end
end

return bound_port
end

return nil
end


local function batch_requests(ctx)
local metadata = plugin.plugin_metadata(plugin_name)
core.log.info("metadata: ", core.json.delay_encode(metadata))
Expand Down Expand Up @@ -269,9 +314,17 @@ local function batch_requests(ctx)
}
end

local server_port = get_loopback_port()
if not server_port then
return 503, {
error_msg = "this APISIX instance doesn't listen on a TCP port, " ..
"but the batch-requests plugin needs one to loop back requests"
}
end

local httpc = http.new()
httpc:set_timeout(data.timeout)
local ok, err = httpc:connect("127.0.0.1", ngx.var.server_port)
local ok, err = httpc:connect("127.0.0.1", server_port)
if not ok then
return 500, {error_msg = "connect to apisix failed: " .. err}
end
Expand Down
130 changes: 130 additions & 0 deletions t/plugin/batch-requests.t
Original file line number Diff line number Diff line change
Expand Up @@ -1194,3 +1194,133 @@ qr/property \\"path\\" is required/
GET /t
--- response_body
passed



=== TEST 31: aggregate requests arriving via a unix domain socket
--- config
listen unix:$TEST_NGINX_HTML_DIR/apisix.sock;

location = /t {
content_by_lua_block {
local core = require("apisix.core")
local json = require("toolkit.json")
local http = require("resty.http")
local httpc = http.new()
httpc:set_timeout(2000)
local ok, err = httpc:connect("unix:$TEST_NGINX_HTML_DIR/apisix.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end

local body = core.json.encode({
pipeline = {
{path = "/uds-b"},
{path = "/uds-c", method = "PUT"},
}
})

local res, err = httpc:request({
method = "POST",
path = "/apisix/batch-requests",
headers = {
["Host"] = "127.0.0.1",
["Content-Type"] = "application/json",
},
body = body,
})
if not res then
ngx.say("request failed: ", err)
return
end

local resp_body, err = res:read_body()
if not resp_body then
ngx.say("failed to read response body: ", err)
return
end

if res.status ~= 200 then
ngx.status = res.status
ngx.print(resp_body)
return
end

local data = json.decode(resp_body)
for _, resp in ipairs(data) do
ngx.say(resp.status, " ", resp.body)
end
}
}

location = /uds-b {
content_by_lua_block {
ngx.print("B")
}
}
location = /uds-c {
content_by_lua_block {
ngx.status = 201
ngx.print("C")
}
}
--- request
GET /t
--- response_body
200 B
201 C



=== TEST 32: no TCP port to loop back through
--- yaml_config
apisix:
node_listen: []
enable_resolv_search_opt: false
trusted_addresses:
- "127.0.0.1"
--- config
listen unix:$TEST_NGINX_HTML_DIR/apisix.sock;

location = /t {
content_by_lua_block {
local core = require("apisix.core")
local http = require("resty.http")
local httpc = http.new()
httpc:set_timeout(2000)
local ok, err = httpc:connect("unix:$TEST_NGINX_HTML_DIR/apisix.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end

local body = core.json.encode({pipeline = {{path = "/uds-b"}}})
local res, err = httpc:request({
method = "POST",
path = "/apisix/batch-requests",
headers = {
["Host"] = "127.0.0.1",
["Content-Type"] = "application/json",
},
body = body,
})
if not res then
ngx.say("request failed: ", err)
return
end

local resp_body = res:read_body()
ngx.say(res.status, " ", resp_body)
}
}

location = /uds-b {
content_by_lua_block {
ngx.print("B")
}
}
--- request
GET /t
--- response_body_like
503 .*doesn't listen on a TCP port.*
Loading