Skip to content

Commit

Permalink
Fix(plugins/request-size-limiting): Check the file size when the requ…
Browse files Browse the repository at this point in the history
…est body buffered to a temporary file
  • Loading branch information
yankun-li-kong committed Jun 26, 2024
1 parent 68925dd commit bc7a16c
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
message: "request-size-limiting check the file size when the request body buffered to a temporary file."
type: bugfix
scope: "Plugin"
10 changes: 10 additions & 0 deletions kong/plugins/request-size-limiting/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
local strip = require("kong.tools.string").strip
local kong_meta = require "kong.meta"
local tonumber = tonumber
local lfs = require "lfs"


local RequestSizeLimitingHandler = {}
Expand Down Expand Up @@ -52,6 +53,15 @@ function RequestSizeLimitingHandler:access(conf)
local data = kong.request.get_raw_body()
if data then
check_size(#data, conf.allowed_payload_size, headers, conf.size_unit)
else
-- Check the file size when the request body buffered to a temporary file
local body_filepath = ngx.req.get_body_file()
if body_filepath then
local file_size = lfs.attributes(body_filepath, "size")
check_size(file_size, conf.allowed_payload_size, headers, conf.size_unit)
else
kong.log.warn("missing request body")
end
end
end
end
Expand Down
211 changes: 145 additions & 66 deletions spec/03-plugins/12-request-size-limiting/01-access_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local unit_multiplication_factor = handler.unit_multiplication_factor

local TEST_SIZE = 2
local MB = 2^20
local KB = 2^10


for _, strategy in helpers.each_strategy() do
Expand Down Expand Up @@ -179,81 +180,158 @@ for _, strategy in helpers.each_strategy() do
end
end)

describe("without Content-Length", function()
it("works if size is lower than limit", function()
local body = string.rep("a", (TEST_SIZE * MB))
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test"
}
})
assert.res_status(200, res)
end)
describe("without Content-Length(chunked request body)", function()
describe("[request body size > nginx_http_client_body_buffer_size]", function()
it("works if size is lower than limit", function()
local str_len = TEST_SIZE * MB
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
assert.res_status(200, res)
end)

it("works if size is lower than limit and Expect header", function()
local body = string.rep("a", (TEST_SIZE * MB))
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Expect"] = "100-continue"
}
})
assert.res_status(200, res)
end)
it("works if size is lower than limit and Expect header", function()
local str_len = TEST_SIZE * MB
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Expect"] = "100-continue",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
assert.res_status(200, res)
end)

it("blocks if size is greater than limit", function()
local body = string.rep("a", (TEST_SIZE * MB) + 1)
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test"
}
})
local body = assert.res_status(413, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
it("blocks if size is greater than limit", function()
local str_len = (TEST_SIZE * MB) + 1
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
local body = assert.res_status(413, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
end)

it("blocks if size is greater than limit and Expect header", function()
local str_len = (TEST_SIZE * MB) + 1
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Expect"] = "100-continue",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
local body = assert.res_status(417, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
end)
end)

it("blocks if size is greater than limit and Expect header", function()
local body = string.rep("a", (TEST_SIZE * MB) + 1)
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit.test",
["Expect"] = "100-continue"
}
})
local body = assert.res_status(417, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
describe("[request body size < nginx_http_client_body_buffer_size]", function()
it("works if size is lower than limit", function()
local str_len = TEST_SIZE * KB
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit_kilobytes.test",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
assert.res_status(200, res)
end)

it("works if size is lower than limit and Expect header", function()
local str_len = TEST_SIZE * KB
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit_kilobytes.test",
["Expect"] = "100-continue",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
assert.res_status(200, res)
end)

it("blocks if size is greater than limit", function()
local str_len = (TEST_SIZE * KB) + 1
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit_kilobytes.test",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
local body = assert.res_status(413, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
end)

it("blocks if size is greater than limit and Expect header", function()
local str_len = (TEST_SIZE * KB) + 1
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = "limit_kilobytes.test",
["Expect"] = "100-continue",
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
local body = assert.res_status(417, res)
local json = cjson.decode(body)
assert.not_nil(json)
assert.matches("Request size limit exceeded", json.message)
end)
end)

for _, unit in ipairs(size_units) do
it("blocks if size is greater than limit when unit in " .. unit, function()
local body = string.rep("a", (TEST_SIZE * unit_multiplication_factor[unit]) + 1)
local str_len = (TEST_SIZE * unit_multiplication_factor[unit]) + 1
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = string.format("limit_%s.test", unit),
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
local body = assert.res_status(413, res)
Expand All @@ -265,14 +343,15 @@ for _, strategy in helpers.each_strategy() do

for _, unit in ipairs(size_units) do
it("works if size is less than limit when unit in " .. unit, function()
local body = string.rep("a", (TEST_SIZE * unit_multiplication_factor[unit]))
local str_len = (TEST_SIZE * unit_multiplication_factor[unit])
local body = string.format("%x", str_len) .. "\r\n" .. string.rep("a", str_len) .. "\r\n0\r\n\r\n"
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
body = body,
headers = {
["Host"] = string.format("limit_%s.test", unit),
["Transfer-Encoding"] = "chunked", -- lua-resty-http do not add content-length when client send chunked request body
}
})
assert.res_status(200, res)
Expand All @@ -284,7 +363,7 @@ for _, strategy in helpers.each_strategy() do
it("blocks if header is not provided", function()
local res = assert(proxy_client:request {
dont_add_content_length = true,
method = "GET", -- if POST, then lua-rsty-http adds content-length anyway
method = "GET", -- if POST, then lua-resty-http adds content-length anyway
path = "/request",
headers = {
["Host"] = "required.test",
Expand Down

0 comments on commit bc7a16c

Please sign in to comment.