diff --git a/apisix/plugins/batch-requests.lua b/apisix/plugins/batch-requests.lua index 8927b33b5a50..6b09ffa04df6 100644 --- a/apisix/plugins/batch-requests.lua +++ b/apisix/plugins/batch-requests.lua @@ -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 @@ -224,6 +225,39 @@ 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 the first TCP port in `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. +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 + 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` + return value.port or 9080 + end + end + 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)) @@ -269,9 +303,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 diff --git a/t/plugin/batch-requests.t b/t/plugin/batch-requests.t index 298f9df11e92..d1dccc2b2d45 100644 --- a/t/plugin/batch-requests.t +++ b/t/plugin/batch-requests.t @@ -1194,3 +1194,78 @@ 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 json = require("toolkit.json") + local http = require("resty.http") + local httpc = http.new() + 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 res, err = httpc:request({ + method = "POST", + path = "/apisix/batch-requests", + headers = { + ["Host"] = "127.0.0.1", + ["Content-Type"] = "application/json", + }, + body = [=[{ + "pipeline":[ + { + "path": "/uds-b" + },{ + "path": "/uds-c", + "method": "PUT" + }] + }]=], + }) + if not res then + ngx.say("request failed: ", err) + return + end + + local body, err = res:read_body() + if not body then + ngx.say("failed to read response body: ", err) + return + end + + if res.status ~= 200 then + ngx.status = res.status + ngx.print(body) + return + end + + local data = json.decode(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