luci启动的流程

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

luci启动的流程
1、uhttpd Web server的根⽬录在/etc/config/uhttpd⽂件中指定为www,主页⾯为/www/index.html,
2、index.html中指定cgi程序启动脚本为/cgi-bin/luci
3、/cgi-bin/luci脚本,指定缓存路径为/tmp/luci-indexcache,指定cgi启动接⼝为/usr/lib/lua/luci/sgi/cgi.lua的run()函数
注:可以rm -rf /tmp/luci* 来删除luci的备份⽂件,这样可以清除缓存,执⾏修改后的操作。

cgi启动流程
run()函数作为CGI程序的启动⼊⼝,代码解析如下
function run()
-- 获取web请求,放于变量r中(包括环境变量,请求数据,出错处理接⼝)
local r = luci.http.Request(
luci.sys.getenv(),
limitsource(io.stdin, tonumber(luci.sys.getenv("CONTENT_LENGTH"))),
ltn12.sink.file(io.stderr)
)
--创建⼀个协同程序
local x = coroutine.create(luci.dispatcher.httpdispatch)
local hcache = ""
local active = true
--查看协同程序x的协同状态
while coroutine.status(x) ~= "dead" do
local res, id, data1, data2 = coroutine.resume(x, r)
if not res then
print("Status: 500 Internal Server Error")
print("Content-Type: text/plain\n")
print(id)
break;
end
-- HTTP的响应报⽂通过io.write()⽅式写在stdout上,
-- 在由uhttpd架构将这些数据传递给⽗进程,
-- 通过tcp连接返回给client端。

if active then
if id == 1 then
-- 填写HTTP响应状态⾏
io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\r\n")
elseif id == 2 then
-- 准备报⽂头header
hcache = hcache .. data1 .. ": " .. data2 .. "\r\n"
elseif id == 3 then
-- 填写header、blank到stdout上
io.write(hcache)
io.write("\r\n")
elseif id == 4 then
-- 填写body
io.write(tostring(data1 or ""))
elseif id == 5 then
-- 关闭io接⼝,EOF
io.flush()
io.close()
active = false
elseif id == 6 then
data1:copyz(nixio.stdout, data2)
data1:close()
end
end
end
dispatcher启动流程
在上述run()函数中,创建了⼀个协同程序,调⽤httpdispatch()函数,⽽这个函数位于dispatcher.lua中。

通过后续的介绍也可以发现,luci真正的主体部分都在dispatcher.lua脚本⾥,本⼩节主要对httpdispatch()和dispatch()函数进⾏介绍。

(注:在版本机dispatcher.lua的同⽬录下有⼀个dispatcher.luadoc⽂件,⾥⾯介绍dispatcher.lua的参数说明,仅供参考。


1、httpdispatch():解析请求,获得HTTP request请求参数
// /usr/lib/lua/luci/dispatch.lua
function httpdispatch(request, prefix)
http.context.request = request
local r = {}
context.request = r
--解析HTTP request,获取请求路径,并传⼊dispatch()函数进⾏处理
local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true)
if prefix then
for _, node in ipairs(prefix) do
r[#r+1] = node
end
end
local node
for node in pathinfo:gmatch("[^/%z]+") do
r[#r+1] = node
end
determine_request_language()
local stat, err = util.coxpcall(function()
dispatch(context.request)
end, error500)
http.close()
--context._disable_memtrace()
end
2、dispatch():解析请求节点,调度⽹页显⽰,分为以下四个部分:
(1)创建节点树node-tree,解析请求路径,获取节点树节点
createtree()函数主要从controller⽬录下寻找.lua⽂件,并且调⽤每个lua⽂件中的index()函数。

这些index函数通过
entry(path,target,title,order)函数定义了菜单栏的每个⼦菜单选项,包括⼦菜单的节点位置path、调度⾏为target、页⾯标题title以及节点顺序order。

当解析完index()下的node节点,对应⽣成⼀个node-tree。

-- Build the index before if it does not exist yet.
function createtree()
if not index then
createindex()
end
local ctx = context
local tree = {nodes={}, inreq=true}
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
local scope = setmetatable({}, {__index = luci.dispatcher})
for k, v in pairs(index) do
scope._NAME = k
setfenv(v, scope)
v()
return tree
end
(2)认证
if type(auth) == "table" and type(auth.methods) == "table" and #auth.methods > 0 then
local sid, sdat, sacl
for _, method in ipairs(auth.methods) do
sid, sdat, sacl = check_authentication(method)
if sid and sdat and sacl then
break
end
end
if not (sid and sdat and sacl) and auth.login then
local user = http.getenv("HTTP_AUTH_USER")
local pass = http.getenv("HTTP_AUTH_PASS")
if user == nil and pass == nil then
user = http.formvalue("luci_username")
pass = http.formvalue("luci_password")
end
if user and pass then
sid, sdat, sacl = session_setup(user, pass)
end
if not sid then
context.path = {}
http.status(403, "Forbidden")
http.header("X-LuCI-Login-Required", "yes")
local scope = { duser = "root", fuser = user }
local ok, res = util.copcall(tpl.render_string, [[<% include("themes/" .. theme .. "/sysauth") %>]], scope) if ok then
return res
end
return tpl.render("sysauth", scope)
end
http.header("Set-Cookie", 'sysauth=%s; path=%s; SameSite=Strict; HttpOnly%s' %{
sid, build_url(), http.getenv("HTTPS") == "on" and "; secure" or ""
})
http.redirect(build_url(unpack(ctx.requestpath)))
return
end
if not sid or not sdat or not sacl then
http.status(403, "Forbidden")
http.header("X-LuCI-Login-Required", "yes")
return
end
ctx.authsession = sid
ctx.authtoken = sdat.token
ctx.authuser = ername
ctx.authacl = sacl
end
if #required_path_acls > 0 then
local perm = check_acl_depends(required_path_acls, ctx.authacl and ctx.authacl["access-group"])
if perm == nil then
http.status(403, "Forbidden")
end
page.readonly = not perm
end
local action = (page and type(page.action) == "table") and page.action or {}
if action.type == "arcombine" then
action = (#requested_path_args > 0) and action.targets[2] or action.targets[1]
end
if cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then
luci.http.status(200, "OK")
luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*")
luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
return
end
if require_post_security(action) then
if not test_post_security() then
return
end
end
(3)会根据action.type处理相应的动作,每个controller下的lua⽂件的index函数会⽣成页⾯的菜单栏并定义各个页⾯的调⽤⽅法if action.type == "view" then
tpl.render("view", { view = action.path })
elseif action.type == "call" then
local ok, mod = util.copcall(require, action.module)
if not ok then
error500(mod)
return
end
...
elseif action.type == "alias" then
...
elseif action.type == "rewrite" then
...
elseif action.type == "template" then
tpl.render(action.path, getfenv(1))
elseif action.type == "cbi" then
_cbi({ config = action.config, model = action.path }, unpack(requested_path_args))
elseif action.type == "form" then
_form({ model = action.path }, unpack(requested_path_args))
else
local root = find_subnode(menu, {}, true)
if not root then
error404("No root node was registered, this usually happens if no module was installed.\n" ..
"Install luci-mod-admin-full and retry. " ..
"If the module is already installed, try removing the /tmp/luci-indexcache file.")
else
error404("No page is registered at '/" .. table.concat(requested_path_full, "/") .. "'.\n" ..
"If this url belongs to an extension, make sure it is properly installed.\n" ..
"If the extension was recently installed, try removing the /tmp/luci-indexcache file.")
end
end
end。

相关文档
最新文档