Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
std = "ngx_lua"
unused_args = false
redefined = false
max_line_length = false
31 changes: 6 additions & 25 deletions spec/multipart_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ Content-Type: text/plain

local with_array_all = res:get_all_as_arrays()
assert.truthy(with_array_all)
with_array = with_array_all["files"]
local with_array = with_array_all["files"]
assert.truthy(with_array)
assert.are.same({
"... contents of file1.txt ...",
Expand All @@ -367,7 +367,6 @@ Content-Type: text/plain
local body = "--\n"
local res = Multipart(body, content_type)
assert.truthy(res)
local internal_data = res._data
local all = res:get_all()
assert.are.same(0, table_size(all))
end)
Expand Down Expand Up @@ -892,7 +891,6 @@ Content-Type: text/plain
hello
--AaB03x--]]

local res = Multipart(body, content_type)

local new_body = table.concat({
'--' .. Multipart.RANDOM_BOUNDARY,
Expand Down Expand Up @@ -1017,33 +1015,16 @@ Content-Type: image/jpeg
assert.are.same(6, table_size(all_with_headers))
assert.are.same("... contents of file1.txt ...", all_with_headers["files"][1].value)
assert.are.same("... contents of file2.txt ...", all_with_headers["files"][2].value)
assert.are.same("submit-name", all_with_headers["submit-name"][1].headers["name"])
assert.are.same("form-data", all_with_headers["submit-name"][1].headers["content-disposition"])
assert.are.same('form-data; name="submit-name"', all_with_headers["submit-name"][1].headers["content-disposition"])
assert.are.same("... contents of simple.txt ...", all_with_headers["files-utf8"][1].value)
assert.are.same("files-utf8", all_with_headers["files-utf8"][1].headers["name"])
assert.are.same("attachment", all_with_headers["files-utf8"][1].headers["content-disposition"])
assert.are.same("simple.txt", all_with_headers["files-utf8"][1].headers["filename"])
assert.are.same({
charset = 'UTF-8',
lang = '',
value = '例子.txt'
}, all_with_headers["files-utf8"][1].headers["filename*"])
assert.are.same("uploadFile", all_with_headers["uploadFile"][1].headers["name"])
assert.are.same("form-data", all_with_headers["uploadFile"][1].headers["content-disposition"])
assert.are.same([[attachment; name="files-utf8"; filename="simple.txt"; filename*=UTF-8''%E4%BE%8B%E5%AD%90.txt]], all_with_headers["files-utf8"][1].headers["content-disposition"])
assert.are.same([[form-data; name="uploadFile"; filename*=UTF-8''%E3%83%95%E3%82%A7%E3%83%8B%E3%83%83%E3%82%AF%E3%82%B9.jpg]], all_with_headers["uploadFile"][1].headers["content-disposition"])
assert.are.same("... contents of uploadFile.jpg ...", all_with_headers["uploadFile"][1].value)
assert.are.same({
charset = 'UTF-8',
lang = '',
value = 'フェニックス.jpg'
}, all_with_headers["uploadFile"][1].headers["filename*"])

assert.are.same('form-data; name="files"; filename="file1.txt"', all_with_headers["files"][1].headers["content-disposition"])
assert.are.same('form-data; name="files"', all_with_headers["files"][2].headers["content-disposition"])

assert.are.same("files", all_with_headers["files"][1].headers["name"])
assert.are.same("form-data", all_with_headers["files"][1].headers["content-disposition"])
assert.are.same("file1.txt", all_with_headers["files"][1].headers["filename"])
assert.are.same("Larry", all_with_headers["submit-name"][1].value)
assert.are.same("world :)", all_with_headers["hello"][1].value)
assert.are.same("world2 :)", all_with_headers["hello2"][1].value)
assert.are.same("... contents of simple.txt ...", all_with_headers["files-utf8"][1].value)
assert.are.same("... contents of uploadFile.jpg ...", all_with_headers["uploadFile"][1].value)
end)
69 changes: 21 additions & 48 deletions src/multipart.lua
Original file line number Diff line number Diff line change
Expand Up @@ -284,61 +284,34 @@ function MultipartData:get_as_array(name)
return vals
end


local req_headers_mt = {
__index = function (tb, key)
key = key:lower()
local value = rawget(tb, key)
if value == nil and key:find('_', 1, true) then
value = rawget(tb, key:gsub('_', '-'))
end
return value
end
}

local function parse_headers(headers)
local results = {}
for _, header in ipairs(headers) do
for v in header:gmatch("[^;]+") do
-- clean up whitespace around the part
v = v:match("^%s*(.-)%s*$")

-- match key="value" pattern
local key, value = string.match(v, "([^=]+)=\"([^\"]*)")
if key and value then
-- clean up whitespace around key
key = key:match("^%s*(.-)%s*$")
results[key:lower()] = value
else
-- match key=value pattern without quotes (for RFC 5987 extended parameters)
key, value = string.match(v, "([^=]+)=([^%s]*)")
if key and value then
key = key:match("^%s*(.-)%s*$")
local lower_key = key:lower()

-- Handle RFC 5987 encoded parameters (like filename*)
if lower_key:match("%*$") then
-- Parse charset'lang'encoded-value format
local charset, lang, encoded = value:match("([^']*)'([^']*)'(.+)")
if charset and encoded then
-- URL decode the encoded value
local decoded = encoded:gsub("%%(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end)
results[lower_key] = {
charset = charset,
lang = lang or "",
value = decoded
}
else
results[lower_key] = value
end
else
results[lower_key] = value
end
end
end

-- match key:value pattern without quotes (for header values)
key, value = string.match(v, "([^:]+):%s*(.+)")
if key and value then
-- clean up whitespace around key
key = key:match("^%s*(.-)%s*$")
results[key:lower()] = value
end
-- match key:value pattern without quotes (for header values)
local key, value = string.match(header, "([^:]+):%s*(.+)")
if key and value then
-- clean up whitespace around key
key = key:match("^%s*(.-)%s*$")
results[key:lower()] = value
end
end
return results

return setmetatable(results, req_headers_mt)
end


function MultipartData:get_with_headers_as_array(name)
local vals = {}

Expand Down
Loading