123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- local table = table
- local type = type
- local M = {}
- local LIMIT = 8192
- local function chunksize(readbytes, body)
- while true do
- local f,e = body:find("\r\n",1,true)
- if f then
- return tonumber(body:sub(1,f-1),16), body:sub(e+1)
- end
- if #body > 128 then
- -- pervent the attacker send very long stream without \r\n
- return
- end
- body = body .. readbytes()
- end
- end
- local function readcrln(readbytes, body)
- if #body >= 2 then
- if body:sub(1,2) ~= "\r\n" then
- return
- end
- return body:sub(3)
- else
- body = body .. readbytes(2-#body)
- if body ~= "\r\n" then
- return
- end
- return ""
- end
- end
- function M.recvheader(readbytes, lines, header)
- if #header >= 2 then
- if header:find "^\r\n" then
- return header:sub(3)
- end
- end
- local result
- local e = header:find("\r\n\r\n", 1, true)
- if e then
- result = header:sub(e+4)
- else
- while true do
- local bytes = readbytes()
- header = header .. bytes
- if #header > LIMIT then
- return
- end
- e = header:find("\r\n\r\n", -#bytes-3, true)
- if e then
- result = header:sub(e+4)
- break
- end
- if header:find "^\r\n" then
- return header:sub(3)
- end
- end
- end
- for v in header:gmatch("(.-)\r\n") do
- if v == "" then
- break
- end
- table.insert(lines, v)
- end
- return result
- end
- function M.parseheader(lines, from, header)
- local name, value
- for i=from,#lines do
- local line = lines[i]
- if line:byte(1) == 9 then -- tab, append last line
- if name == nil then
- return
- end
- header[name] = header[name] .. line:sub(2)
- else
- name, value = line:match "^(.-):%s*(.*)"
- if name == nil or value == nil then
- return
- end
- name = name:lower()
- if header[name] then
- local v = header[name]
- if type(v) == "table" then
- table.insert(v, value)
- else
- header[name] = { v , value }
- end
- else
- header[name] = value
- end
- end
- end
- return header
- end
- function M.recvchunkedbody(readbytes, bodylimit, header, body)
- local result = ""
- local size = 0
- while true do
- local sz
- sz , body = chunksize(readbytes, body)
- if not sz then
- return
- end
- if sz == 0 then
- break
- end
- size = size + sz
- if bodylimit and size > bodylimit then
- return
- end
- if #body >= sz then
- result = result .. body:sub(1,sz)
- body = body:sub(sz+1)
- else
- result = result .. body .. readbytes(sz - #body)
- body = ""
- end
- body = readcrln(readbytes, body)
- if not body then
- return
- end
- end
- local tmpline = {}
- body = M.recvheader(readbytes, tmpline, body)
- if not body then
- return
- end
- header = M.parseheader(tmpline,1,header)
- return result, header
- end
- return M
|