-
Notifications
You must be signed in to change notification settings - Fork 29
support multipart/form #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
zhucebuliaopx
wants to merge
25
commits into
tokers:master
Choose a base branch
from
zhucebuliaopx:develop
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
541017d
support set multipart/form file
zhucebuliaopx 0ee96a5
fix add content-length
zhucebuliaopx 513cb46
update README
zhucebuliaopx 1588a79
Merge tag '0.0.1' into develop
zhucebuliaopx 3e7fe23
Merge branch 'release/0.0.1'
zhucebuliaopx 8633569
local var
zhucebuliaopx 51bd31a
fix code style
zhucebuliaopx fedcf9e
Merge tag '0.0.2' into develop
zhucebuliaopx a84db7e
Merge branch 'release/0.0.2'
zhucebuliaopx 8a23a08
remove git address,once upstream merage my pr,so could install lua-mu…
zhucebuliaopx b38e3fd
Merge tag '0.0.3' into develop
zhucebuliaopx 4a19a63
Merge branch 'release/0.0.3'
zhucebuliaopx 3e46a90
add test example and fix code style
zhucebuliaopx b57d2ff
Merge branch 'release/0.0.4'
zhucebuliaopx 51bf1e4
Merge tag '0.0.4' into develop
zhucebuliaopx 117b669
del unnecessary local var
zhucebuliaopx 3a47469
fix code style
zhucebuliaopx 4c445cf
update multipart code
zhucebuliaopx 158f7a3
fix code style
zhucebuliaopx 0a8ebf4
fix code style && update test case
zhucebuliaopx e104658
Merge branch 'feature/0.0.2' into develop
zhucebuliaopx 1cc478d
remove dependencies by Kong\lua-multipart && update readme
zhucebuliaopx aae1b4f
fix files body with userdata fp
zhucebuliaopx 868162e
fix iter_base_func is_array
zhucebuliaopx 2a9c604
local var error
zhucebuliaopx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,4 +39,7 @@ luac.out | |
*.x86_64 | ||
*.hex | ||
|
||
#develop env | ||
.idea | ||
|
||
t/servroot/* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,328 @@ | ||
|
||
local setmetatable = setmetatable | ||
local tostring = tostring | ||
local insert = table.insert | ||
local remove = table.remove | ||
local concat = table.concat | ||
local ipairs = ipairs | ||
local pairs = pairs | ||
local match = string.match | ||
local find = string.find | ||
local sub = string.sub | ||
|
||
|
||
local RANDOM_BOUNDARY = sub(tostring({}), 10) | ||
|
||
|
||
local MultipartData = { RANDOM_BOUNDARY = RANDOM_BOUNDARY} | ||
|
||
|
||
MultipartData.__index = MultipartData | ||
|
||
|
||
setmetatable(MultipartData, { | ||
__call = function (cls, ...) | ||
return cls.new(...) | ||
end, | ||
}) | ||
|
||
|
||
local function is_header(value) | ||
return match(value, "(%S+):%s*(%S+)") | ||
end | ||
|
||
|
||
local function table_size(t) | ||
local res = 0 | ||
|
||
if t then | ||
for _,_ in pairs(t) do | ||
res = res + 1 | ||
end | ||
end | ||
|
||
return res | ||
end | ||
|
||
-- Create a table representation of multipart/data body | ||
-- | ||
-- @param {string} body The multipart/data string body | ||
-- @param {string} boundary The multipart/data boundary | ||
-- @return {table} Lua representation of the body | ||
local function decode(body, boundary) | ||
local result = { | ||
data = {}, | ||
indexes = {}, | ||
} | ||
|
||
if not boundary then | ||
return result | ||
end | ||
|
||
local part_name | ||
local part_index = 1 | ||
local part_headers = {} | ||
local part_value = {} | ||
local part_value_ct = 0 | ||
|
||
local end_boundary_length = boundary and #boundary + 2 | ||
local processing_part_value = false | ||
|
||
local position = 1 | ||
local done = false | ||
|
||
repeat | ||
local s = find(body, "[\r\n]", position) | ||
|
||
local line | ||
|
||
if s then | ||
line = sub(body, position, s - 1) | ||
position = s + 1 | ||
|
||
else | ||
if position == 1 then | ||
line = body | ||
|
||
else | ||
line = sub(body, position) | ||
end | ||
|
||
done = true | ||
end | ||
|
||
if line == "" then | ||
if s and processing_part_value then | ||
part_value_ct = part_value_ct + 1 | ||
part_value[part_value_ct] = sub(body, s, s) | ||
end | ||
|
||
else | ||
if sub(line, 1, 2) == "--" and sub(line, 3, end_boundary_length) == boundary then | ||
processing_part_value = false | ||
|
||
if part_name ~= nil then | ||
if part_value[part_value_ct] == "\n" then | ||
part_value[part_value_ct] = nil | ||
end | ||
|
||
if part_value[part_value_ct - 1] == "\r" then | ||
part_value[part_value_ct - 1] = nil | ||
end | ||
|
||
result.data[part_index] = { | ||
name = part_name, | ||
headers = part_headers, | ||
value = concat(part_value) | ||
} | ||
|
||
result.indexes[part_name] = part_index | ||
|
||
-- Reset fields for the next part | ||
part_headers = {} | ||
part_value = {} | ||
part_value_ct = 0 | ||
part_name = nil | ||
part_index = part_index + 1 | ||
end | ||
|
||
else | ||
--Beginning of part | ||
if not processing_part_value and line:sub(1, 19):lower() == "content-disposition" then | ||
-- Extract part_name | ||
for v in line:gmatch("[^;]+") do | ||
if not is_header(v) then -- If it's not content disposition part | ||
local pos = v:match("^%s*[Nn][Aa][Mm][Ee]=()") | ||
if pos then | ||
local current_value = v:match("^%s*([^=]*)", pos):gsub("%s*$", "") | ||
part_name = sub(current_value, 2, #current_value - 1) | ||
end | ||
end | ||
end | ||
|
||
insert(part_headers, line) | ||
|
||
if s and sub(body, s, s + 3) == "\r\n\r\n" then | ||
processing_part_value = true | ||
position = s + 4 | ||
end | ||
|
||
elseif not processing_part_value and is_header(line) then | ||
insert(part_headers, line) | ||
|
||
if s and sub(body, s, s + 3) == "\r\n\r\n" then | ||
processing_part_value = true | ||
position = s + 4 | ||
end | ||
|
||
else | ||
processing_part_value = true | ||
|
||
-- The value part begins | ||
part_value_ct = part_value_ct + 1 | ||
part_value[part_value_ct] = line | ||
|
||
if s then | ||
part_value_ct = part_value_ct + 1 | ||
part_value[part_value_ct] = sub(body, s, s) | ||
end | ||
end | ||
end | ||
end | ||
|
||
until done | ||
|
||
if part_name ~= nil then | ||
result.data[part_index] = { | ||
name = part_name, | ||
headers = part_headers, | ||
value = concat(part_value) | ||
} | ||
|
||
result.indexes[part_name] = part_index | ||
end | ||
|
||
return result | ||
end | ||
|
||
-- Creates a multipart/data body from a table | ||
-- | ||
-- @param {table} t The table that contains the multipart/data body properties | ||
-- @param {boundary} boundary The multipart/data boundary to use | ||
-- @return {string} The multipart/data string body | ||
local function encode(t, boundary) | ||
if not boundary then | ||
boundary = RANDOM_BOUNDARY | ||
end | ||
|
||
local result = {} | ||
local i = 0 | ||
|
||
for _, v in ipairs(t.data) do | ||
if v.value then | ||
result[i + 1] = "--" | ||
result[i + 2] = boundary | ||
result[i + 3] = "\r\n" | ||
|
||
i = i + 3 | ||
|
||
for _, header in ipairs(v.headers) do | ||
result[i + 1] = header | ||
result[i + 2] = "\r\n" | ||
|
||
i = i + 2 | ||
end | ||
|
||
result[i + 1] = "\r\n" | ||
result[i + 2] = v.value | ||
result[i + 3] = "\r\n" | ||
|
||
i = i + 3 | ||
end | ||
end | ||
|
||
if i == 0 then | ||
return "" | ||
end | ||
|
||
result[i + 1] = "--" | ||
result[i + 2] = boundary | ||
result[i + 3] = "--\r\n" | ||
|
||
return concat(result) | ||
end | ||
|
||
|
||
function MultipartData.new(data, content_type) | ||
local instance = setmetatable({}, MultipartData) | ||
|
||
if content_type then | ||
local boundary = match(content_type, ";%s*boundary=(%S+)") | ||
if boundary then | ||
if (sub(boundary, 1, 1) == '"' and sub(boundary, -1) == '"') or | ||
(sub(boundary, 1, 1) == "'" and sub(boundary, -1) == "'") then | ||
boundary = sub(boundary, 2, -2) | ||
end | ||
|
||
if boundary ~= "" then | ||
instance._boundary = boundary | ||
end | ||
end | ||
end | ||
|
||
instance._data = decode(data or "", instance._boundary) | ||
|
||
return instance | ||
end | ||
|
||
|
||
function MultipartData:get(name) | ||
return self._data.data[self._data.indexes[name]] | ||
end | ||
|
||
|
||
function MultipartData:get_all() | ||
local result = {} | ||
|
||
for k, v in pairs(self._data.indexes) do | ||
result[k] = self._data.data[v].value | ||
end | ||
|
||
return result | ||
end | ||
|
||
|
||
function MultipartData:set_simple(name, value, filename, content_type) | ||
local headers = {'Content-Disposition: form-data; name="' , name , '"'} | ||
if filename then | ||
headers[4] = '; filename="' | ||
headers[5] = filename | ||
headers[6] = '"' | ||
end | ||
if content_type then | ||
headers[7] = "\r\ncontent-type: " | ||
headers[8] = content_type | ||
end | ||
headers = concat(headers) | ||
if self._data.indexes[name] then | ||
self._data.data[self._data.indexes[name]] = { | ||
name = name, | ||
value = value, | ||
headers = {headers} | ||
} | ||
|
||
else | ||
local part_index = table_size(self._data.indexes) + 1 | ||
self._data.indexes[name] = part_index | ||
self._data.data[part_index] = { | ||
name = name, | ||
value = value, | ||
headers = {headers} | ||
} | ||
end | ||
end | ||
|
||
|
||
function MultipartData:delete(name) | ||
local index = self._data.indexes[name] | ||
|
||
if index then | ||
remove(self._data.data, index) | ||
self._data.indexes[name] = nil | ||
|
||
-- need to recount index | ||
for key, value in pairs(self._data.indexes) do | ||
if value > index then | ||
self._data.indexes[key] = value - 1 | ||
end | ||
end | ||
end | ||
end | ||
|
||
|
||
function MultipartData:tostring() | ||
return encode(self._data, self._boundary) | ||
end | ||
|
||
|
||
return MultipartData |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,10 +70,23 @@ local function prepare(url_parts, session, config) | |
local json = config.json | ||
local body = config.body | ||
|
||
local files = config.files | ||
|
||
if json then | ||
content = cjson.encode(json) | ||
headers["content-length"] = #content | ||
headers["content-type"] = "application/json" | ||
|
||
elseif files and is_tab(files) then | ||
local content_type = headers["content-type"] | ||
if not content_type then | ||
content_type = "multipart/form-data; boundary=" .. util.choose_boundary() | ||
end | ||
local multipart_body = util.make_multipart_body(files, content_type) | ||
headers["content-type"] = content_type | ||
headers["content-length"] = #multipart_body | ||
content = multipart_body | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto, leave an empty line here. |
||
|
||
else | ||
content = body | ||
if is_func(body) then | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to leave an empty line here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok