local n=ngx
local s=n.req.get_headers
local b=n.req.socket
local o,r=n.log,n.ERR
local R=type
local a,f,y=string.match,string.find,string.lower
local l=512
local _=1
local d=2
local i=3
local h=4
local function c(n)local e=n.read_line
local n,t=e(l)if not n then
return nil,t
end
local e,t=e(1)if e then
return nil,"line too long: "..n..e.."..."end
if t then
return nil,t
end
return true
end
local function F(n)local e=n.src
local n=n.size
while true do
local e,n=e:receive(n)if n and n~='closed'then
return nil,n
end
if not e then
return true
end
end
end
local function u(n)local e=n.read2boundary
local t,e=e(n.size)if e then
return nil,nil,e
end
if not t then
local e=n.src
local e=e:receive(2)if e=="--"then
local t,e=F(n)if not t then
return nil,nil,e
end
n.state=h
return"part_end"end
if e~="\r\n"then
local e,n=c(n)if not e then
return nil,nil,n
end
end
n.state=d
return"part_end"end
return"body",t
end
local function h(e)local t=e.read_line
local n,l=t(l)if l then
return nil,nil,l
end
local l,t=t(1)if l then
return nil,nil,"line too long: "..n..l.."..."end
if t then
return nil,nil,t
end
if n==""then
e.state=i
return u(e)end
local e,t=a(n,"([^: \t]+)%s*:%s*(.+)")if not e then
return'header',n
end
return'header',{e,t,n}end
local t
local function F(e)local i,l=t(e)if i~="header"or
y(l[1])~="content-disposition"or
f(l[2],'name="CSRFtoken"',1,true)==nil then
o(r,"no CSRFtoken as first data")n.exit(n.HTTP_FORBIDDEN)end
i,l=t(e)if i~="body"or
not n.ctx.session:checkCSRFtoken(l)or
t(e)~="part_end"then
o(r,"invalid CSRFtoken")n.exit(n.HTTP_FORBIDDEN)end
return t(e)end
local function l(e)local l=e.src
local i=e.size
local t=e.read2boundary
while true do
local n,e=t(i)if not n then
break
end
end
local t,i=c(e)if not t then
o(r,"no CSRFtoken as first data")n.exit(n.HTTP_FORBIDDEN)end
local t,l=l:receiveuntil("\r\n--"..e.boundary)if not t then
o(r,"no CSRFtoken as first data")n.exit(n.HTTP_FORBIDDEN)end
e.read2boundary=t
e.state=d
return F(e)end
local function n()return"eof"end
local e={l,h,u,n}t=function(n)local e=e[n.state]if e then
return e(n)end
return nil,nil,"bad state: "..n.state
end
local function o()local n,e=b()if not n then
return nil,e
end
return n
end
local function i()local n=s()["content-type"]if not n then
return nil
end
if R(n)=="table"then
n=n[1]end
local e=a(n,';%s*boundary="([^"]+)"')if e then
return e
end
return a(n,';%s*boundary=([^",;]+)')end
local function a(n,l,i)local r,e=n:receiveuntil("--"..l)if not r then
return nil,e
end
local e,o=n:receiveuntil("\r\n")if not e then
return nil,o
end
return{read=t,src=n,size=i or 4096,read2boundary=r,read_line=e,boundary=l,state=_}end
return{fromstream=function(t)local e=i()if not e then
return nil,"no boundary defined in Content-Type"end
local n,l=o()if not n then
return nil,l
end
return a(n,e,t)end}