From 20207c8108b85f8481375315ea324153589276ec Mon Sep 17 00:00:00 2001 From: YuanSheng Wang Date: Wed, 29 Jul 2020 19:24:27 +0800 Subject: [PATCH] bugfix: read the request body from the temporary file if it was cached. (#1863) --- apisix/admin/init.lua | 8 +++-- apisix/core/request.lua | 53 +++++++++++++++++++++++++++-- t/admin/routes.t | 75 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua index 158ba926fb3a..71cb25e56286 100644 --- a/apisix/admin/init.lua +++ b/apisix/admin/init.lua @@ -26,6 +26,7 @@ local require = require local reload_event = "/apisix/admin/plugins/reload" local ipairs = ipairs local events +local MAX_REQ_BODY = 1024 * 1024 * 1.5 -- 1.5 MiB local viewer_methods = { @@ -117,8 +118,11 @@ local function run() core.response.exit(404) end - ngx.req.read_body() - local req_body = ngx.req.get_body_data() + local req_body, err = core.request.get_body(MAX_REQ_BODY) + if err then + core.log.error("failed to read request body: ", err) + core.response.exit(400, {error_msg = "invalid request body: " .. err}) + end if req_body then local data, err = core.json.decode(req_body) diff --git a/apisix/core/request.lua b/apisix/core/request.lua index 1148234738c2..7fe8cdd9633c 100644 --- a/apisix/core/request.lua +++ b/apisix/core/request.lua @@ -14,14 +14,21 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- + +local lfs = require("lfs") local ngx = ngx local get_headers = ngx.req.get_headers local tonumber = tonumber local error = error local type = type local str_fmt = string.format +local io_open = io.open +local req_read_body = ngx.req.read_body +local req_get_body_data = ngx.req.get_body_data +local req_get_body_file = ngx.req.get_body_file + -local _M = {version = 0.1} +local _M = {} local function _headers(ctx) @@ -94,7 +101,49 @@ function _M.get_remote_client_port(ctx) ctx = ngx.ctx.api_ctx end return tonumber(ctx.var.remote_port) - end +end + + +local function get_file(file_name) + local f, err = io_open(file_name, 'r') + if not f then + return nil, err + end + + local req_body = f:read("*all") + f:close() + return req_body +end + + +function _M.get_body(max_size) + req_read_body() + + local req_body = req_get_body_data() + if req_body then + return req_body + end + + local file_name = req_get_body_file() + if not file_name then + return nil + end + + if max_size then + local size, err = lfs.attributes (file_name, "size") + if not size then + return nil, err + end + + if size > max_size then + return nil, "request size " .. size .. " is greater than the " + .. "maximum size " .. max_size .. " allowed" + end + end + + local req_body, err = get_file(file_name) + return req_body, err +end return _M diff --git a/t/admin/routes.t b/t/admin/routes.t index 0e0d198892a7..1ec272d2e327 100644 --- a/t/admin/routes.t +++ b/t/admin/routes.t @@ -1882,6 +1882,79 @@ GET /t } } --- request -GET /t +GET /t --- response_headers Content-Type: application/json + + + +=== TEST 52: set route with size 36k (temporary file to store request body) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + + local core = require("apisix.core") + local s = string.rep("a", 1024 * 35) + local req_body = [[{ + "upstream": { + "nodes": { + "]] .. s .. [[": 1 + }, + "type": "roundrobin" + }, + "uri": "/index.html" + }]] + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, req_body) + + if code >= 300 then + ngx.status = code + end + + ngx.say("req size: ", #req_body) + ngx.say(body) + } + } +--- request +GET /t +--- response_body +req size: 36066 +passed +--- error_log +a client request body is buffered to a temporary file + + + +=== TEST 53: route size more than 1.5 MiB +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local s = string.rep( "a", 1024 * 1024 * 1.6 ) + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin" + }, + "desc": "]] .. s .. [[", + "uri": "/index.html" + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- request +GET /t +--- error_code: 400 +--- response_body +{"error_msg":"invalid request body: request size 1678025 is greater than the maximum size 1572864 allowed"} +--- error_log +failed to read request body: request size 1678025 is greater than the maximum size 1572864 allowed