202 lines
4.9 KiB
Plaintext
202 lines
4.9 KiB
Plaintext
--:Minify:--
|
|
local kernel = ...
|
|
|
|
local handler = {}
|
|
|
|
local http = kernel.apis.http
|
|
|
|
kernel.cct.httpqueue = kernel.cct.httpqueue or {}
|
|
kernel.cct.httpresponse = kernel.cct.httpresponse or {}
|
|
kernel.cct.httperror = kernel.cct.httperror or {}
|
|
|
|
local function parseRawRequest(raw, address)
|
|
local headerEnd = raw:find("\r\n\r\n", 1, true)
|
|
|
|
local headerPart
|
|
local body = ""
|
|
|
|
if headerEnd then
|
|
headerPart = raw:sub(1, headerEnd - 1)
|
|
body = raw:sub(headerEnd + 4)
|
|
else
|
|
headerPart = raw
|
|
end
|
|
|
|
local lines = {}
|
|
|
|
for line in headerPart:gmatch("[^\r\n]+") do
|
|
lines[#lines + 1] = line
|
|
end
|
|
|
|
if #lines == 0 then
|
|
return nil, "EINVAL"
|
|
end
|
|
|
|
local split=string.split(lines[1], " ")
|
|
if #split~=3 then
|
|
return nil, "EINVAL"
|
|
end
|
|
local method, path, ver = table.unpack(split)
|
|
|
|
local headers = {}
|
|
|
|
for i = 2, #lines do
|
|
local k, v = lines[i]:match("^([^:]+):%s*(.*)$")
|
|
if k then
|
|
headers[k] = v
|
|
end
|
|
end
|
|
|
|
if path:sub(1,1)~="/" then
|
|
return nil, "EINVAL"
|
|
end
|
|
local url = address..path
|
|
|
|
local req = {
|
|
url = url,
|
|
method = method,
|
|
headers = headers
|
|
}
|
|
|
|
if body ~= "" then
|
|
req.body = body
|
|
end
|
|
|
|
return req, url
|
|
end
|
|
|
|
local function buildResponse(resp)
|
|
if not resp then
|
|
return nil, "EINVAL"
|
|
end
|
|
|
|
local code, msg = resp.getResponseCode()
|
|
local headers = resp.getResponseHeaders()
|
|
local body = resp.readAll() or ""
|
|
resp.close()
|
|
|
|
local out = {
|
|
"HTTP/1.1 " ..
|
|
tostring(code) ..
|
|
" " ..
|
|
tostring(msg or "")
|
|
}
|
|
|
|
for i,v in pairs(headers) do
|
|
out[#out+1] = i..": "..v
|
|
end
|
|
|
|
out[#out + 1] = ""
|
|
out[#out + 1] = body
|
|
|
|
return table.concat(out, "\r\n")
|
|
end
|
|
|
|
function handler.connect(fd, address)
|
|
local fdo = kernel.currentTask.fd[fd]
|
|
|
|
if not fdo then
|
|
return nil, "EBADF"
|
|
end
|
|
|
|
fdo.handle.write = function(raw)
|
|
local req, url = parseRawRequest(raw, address)
|
|
|
|
if not req then
|
|
return nil, url
|
|
end
|
|
|
|
kernel.cct.httpqueue[url] = true
|
|
local ok, err = http.request(req)
|
|
|
|
if not ok then
|
|
kernel.cct.httpqueue[url] = nil
|
|
return nil, err
|
|
end
|
|
if fdo.socket.active then
|
|
fdo.socket.content=nil
|
|
fdo.socket.file.close()
|
|
fdo.socket.file=nil
|
|
end
|
|
fdo.socket.active=true
|
|
fdo.socket.url=url
|
|
|
|
return true
|
|
end
|
|
|
|
fdo.handle.read = function(count)
|
|
if not fdo.socket.active then
|
|
return
|
|
end
|
|
|
|
if not kernel.cct.httpqueue[fdo.socket.url] then
|
|
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
|
kernel.cct.httpqueue[fdo.socket.url]=nil
|
|
kernel.cct.httpresponse[fdo.socket.url]=nil
|
|
end
|
|
|
|
if not fdo.socket.file then
|
|
kernel.currentTask.io=function()
|
|
if not kernel.cct.httpqueue[fdo.socket.url] then
|
|
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
|
kernel.cct.httpqueue[fdo.socket.url]=nil
|
|
kernel.cct.httpresponse[fdo.socket.url]=nil
|
|
return fdo.socket.file.read(count)
|
|
end
|
|
end
|
|
kernel.currentTask.status="D"
|
|
return
|
|
else
|
|
return fdo.socket.file.read(count)
|
|
end
|
|
end
|
|
|
|
fdo.handle.seek = function(whence, offset)
|
|
if not fdo.socket.active then
|
|
return
|
|
end
|
|
|
|
if not kernel.cct.httpqueue[fdo.socket.url] then
|
|
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
|
kernel.cct.httpqueue[fdo.socket.url]=nil
|
|
kernel.cct.httpresponse[fdo.socket.url]=nil
|
|
end
|
|
|
|
if not fdo.socket.file then
|
|
kernel.currentTask.io=function()
|
|
if not kernel.cct.httpqueue[fdo.socket.url] then
|
|
fdo.socket.file=kernel.sfile(buildResponse(kernel.cct.httpresponse[fdo.socket.url]))
|
|
kernel.cct.httpqueue[fdo.socket.url]=nil
|
|
kernel.cct.httpresponse[fdo.socket.url]=nil
|
|
return fdo.socket.file.seek(whence, offset)
|
|
end
|
|
end
|
|
kernel.currentTask.status="D"
|
|
return
|
|
else
|
|
return fdo.socket.file.seek(whence, offset)
|
|
end
|
|
end
|
|
|
|
fdo.handle.close = function()
|
|
fdo.socket.file.close()
|
|
fdo.socket.active=false
|
|
kernel.cct.httpqueue[fdo.socket.url] = nil
|
|
kernel.cct.httpresponse[fdo.socket.url] = nil
|
|
kernel.cct.httperror[fdo.socket.url] = nil
|
|
|
|
return true
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
kernel.socket.registerProtocal(
|
|
"http://",
|
|
handler
|
|
)
|
|
|
|
kernel.socket.registerProtocal(
|
|
"https://",
|
|
handler
|
|
) |