diff --git a/utils.lua b/utils.lua index b35e619..193aed0 100644 --- a/utils.lua +++ b/utils.lua @@ -67,20 +67,33 @@ end --- @return string name the name of the form field. --- @return string? content_type the content type of the attached file, or nil if entry is not a file. --- @return string data the value of the entry. +--- We are doing some severe assumptions here. +--- - Firstly we assume that if the first line of a header doesn't start with +--- `Content-Disposition`, it is invalid and we can ignore it. +--- - Secondly we assume that in the headers, any `CR` is always gonna be +--- followed by a `LF` thus we only check for CR and advance by 2 when found +--- - Thirdly we assume that the only headers that can matter are +--- `Content-Disposition` (for the field name) and `Content-Type` (if this is a +--- file upload for the type of the uploaded file. +--- - Fourthly we assume a field name can't contain a double quote _m.parse_form_entry = function(entry) - local name, content_type, data - local _, end_of_header = entry:find("\r\n\r\n") - for dataline in entry:gmatch("(.-)\r\n") do - if dataline:sub(1, 19) == "Content-Disposition" then - name = dataline:match("name=\"(.*)\"") + local cursor = 3 + local name, ctype + while true do + if entry:sub(cursor, cursor) == "\r" then + cursor = cursor + 2 + break + elseif entry:sub(cursor, cursor+18) == 'Content-Disposition' then + cursor = cursor + 38 + name = string.match(entry, "(.*)\"", cursor) + cursor = cursor + #name + 1 --[[ the closing quote ]] + 2 --[[ CRLF ]] + elseif entry:sub(cursor, cursor+11) == 'Content-Type' then + cursor = cursor + 14 + ctype = string.match(entry, "(.*)\r", cursor) + cursor = cursor + #ctype + 2 --[[ CRLF ]] end - if dataline:sub(1, 12) == "Content-Type" then - content_type = dataline:match("Content-Type: (.*)\r\n") - end - if dataline == "" then break end end - data = entry:sub(end_of_header + 1) - return name, content_type, data + return name, ctype, entry:sub(cursor, -1) end return _m