mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 11:03:12 +00:00
145 lines
2.6 KiB
Lua
145 lines
2.6 KiB
Lua
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
|
|
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
|
|
if #header > LIMIT then
|
|
return
|
|
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
|