diff --git a/fserv/package.cfg b/fserv/package.cfg new file mode 100644 index 0000000..ab76c70 --- /dev/null +++ b/fserv/package.cfg @@ -0,0 +1,3 @@ +{["name"]="fserv", + ["description"]="FRequest server daemon", + ["authors"]="Izaya"} diff --git a/fserv/service/fserv.lua b/fserv/service/fserv.lua new file mode 100644 index 0000000..fdb9323 --- /dev/null +++ b/fserv/service/fserv.lua @@ -0,0 +1,107 @@ +local minitel = require "minitel" +local serial = require "serialization" + +local cfg = {["path"]="/boot/srv/frequest",["port"]=70} + +local function loadConfig(cfgpath) + local f=io.open(cfgpath or "/boot/cfg/fserv.cfg","rb") + if f then + local ncfg = serial.unserialize(f:read("*a")) + f:close() + for k,v in pairs(ncfg) do + cfg[k] = v + end + end +end + +local function fileHandler(socket,rtype,path) + syslog(string.format("[%s:%d] %s %s",socket.addr,socket.port,rtype,path),syslog.info,"fserv") + if rtype == "t" then + if fs.exists(path) and fs.isDirectory(path) then + socket:write("d") + for _,file in ipairs(fs.list(path)) do + socket:write(file.."\n") + end + elseif fs.exists(path) and not fs.isDirectory(path) then + local f,err = io.open(path,"rb") + if f then + socket:write("y") + while true do + local c = f:read(4096) + if not c or c == "" then break end + socket:write(c) + end + else + socket:write("fFailed to open file: "..err) + end + else + socket:write("nFile not found") + end + elseif rtype == "s" then + if fs.exists(path) then + local ftype = "f" + if fs.isDirectory(path) then + ftype = "d" + end + socket:write(string.format("y%s\n%d",ftype,fs.size(path))) + else + socket:write("nFile not found.") + end + else + socket:write("fUnknown request type") + end +end +local function httpHandler(socket,rtype,path) + local tPath = fs.segments(path) + local proto = table.remove(tPath,1) + local url = string.format("%s://%s",proto,table.concat(tPath,"/")) + local request = component.invoke(component.list("internet")(),"request",url) + repeat + coroutine.yield() + until request.finishConnect() + local code, message, headers = request.response() + if code < 200 or code > 299 then + socket:write(string.format("f%d\n%s",code,message)) + else + socket:write("y") + local data = "" + repeat + coroutine.yield() + data = request.read() + if data then + socket:write(data) + end + until not data + end +end + +local function socketHandler(socket) + return function() + local line = nil + repeat + coroutine.yield() + line = socket:read() + until line + local rtype, path = line:match("(.)(.+)") + if fs.segments(path)[1] == "http" or fs.segments(path)[1] == "https" then + httpHandler(socket,rtype,path) + else + path = (cfg.path .. "/" .. path:gsub("../","")):gsub("/+","/") + fileHandler(socket,rtype,path) + end + socket:close() + end +end + +local function fileServer() + while true do + os.spawn(socketHandler(minitel.listen(70)),"fserv worker process") + end +end + +function start(cfgpath) + loadConfig(cfgpath) + return os.spawn(fileServer,"fserv") +end + +return {start=start}