X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fweb%2Fluasrc%2Fdispatcher.lua;h=3d0db5a21e0fd0b0f6b06181ed99b59dcdd6fa76;hp=565e995d191d5fdf38367db732dac746a471baa7;hb=6e97be1e9233fe7d99818bba394c2649a4433cc7;hpb=f3deef9ec570d49795346516d34c1b42fb416fde diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua index 565e995d1..3d0db5a21 100644 --- a/libs/web/luasrc/dispatcher.lua +++ b/libs/web/luasrc/dispatcher.lua @@ -25,14 +25,18 @@ limitations under the License. ]]-- --- LuCI web dispatcher. -local fs = require "luci.fs" +local fs = require "nixio.fs" local sys = require "luci.sys" local init = require "luci.init" local util = require "luci.util" local http = require "luci.http" +local nixio = require "nixio", require "nixio.util" module("luci.dispatcher", package.seeall) context = util.threadlocal() +uci = require "luci.model.uci" +i18n = require "luci.i18n" +_M.fs = fs authenticator = {} @@ -48,11 +52,25 @@ local fi -- @return Relative URL function build_url(...) local path = {...} - local sn = http.getenv("SCRIPT_NAME") or "" + local url = { http.getenv("SCRIPT_NAME") or "" } + + local k, v for k, v in pairs(context.urltoken) do - sn = sn .. "/;" .. k .. "=" .. http.urlencode(v) + url[#url+1] = "/;" + url[#url+1] = http.urlencode(k) + url[#url+1] = "=" + url[#url+1] = http.urlencode(v) end - return sn .. ((#path > 0) and "/" .. table.concat(path, "/") or "") + + local p + for _, p in ipairs(path) do + if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then + url[#url+1] = "/" + url[#url+1] = p + end + end + + return table.concat(url, "") end --- Send a 404 error code and render the "error404" template if available. @@ -107,13 +125,21 @@ end --- Dispatch an HTTP request. -- @param request LuCI HTTP Request object -function httpdispatch(request) +function httpdispatch(request, prefix) luci.http.context.request = request - context.request = {} + + local r = {} + context.request = r 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 + for node in pathinfo:gmatch("[^/]+") do - table.insert(context.request, node) + r[#r+1] = node end local stat, err = util.coxpcall(function() @@ -128,7 +154,7 @@ end --- Dispatches a LuCI virtual path. -- @param request Virtual path function dispatch(request) - --context._disable_memtrace = require "luci.debug".trap_memtrace() + --context._disable_memtrace = require "luci.debug".trap_memtrace("l") local ctx = context ctx.path = request ctx.urltoken = ctx.urltoken or {} @@ -137,7 +163,7 @@ function dispatch(request) assert(conf.main, "/etc/config/luci seems to be corrupt, unable to find section 'main'") - local lang = conf.main.lang + local lang = conf.main.lang or "auto" if lang == "auto" then local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or "" for lpat in aclang:gmatch("[%w-]+") do @@ -147,7 +173,7 @@ function dispatch(request) break end end - end + end require "luci.i18n".setlanguage(lang) local c = ctx.tree @@ -169,7 +195,7 @@ function dispatch(request) for i, s in ipairs(request) do local tkey, tval if t then - tkey, tval = s:match(";(%w+)=(.*)") + tkey, tval = s:match(";(%w+)=([a-fA-F0-9]*)") end if tkey then @@ -199,7 +225,7 @@ function dispatch(request) end end - ctx.requestpath = freq + ctx.requestpath = ctx.requestpath or freq ctx.path = preq if track.i18n then @@ -221,7 +247,17 @@ function dispatch(request) assert(media, "No valid theme found") end - local viewns = setmetatable({}, {__index=function(table, key) + tpl.context.viewns = setmetatable({ + write = luci.http.write; + include = function(name) tpl.Template(name):render(getfenv(2)) end; + translate = function(...) return require("luci.i18n").translate(...) end; + export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; + striptags = util.striptags; + pcdata = util.pcdata; + media = media; + theme = fs.basename(media); + resource = luci.config.main.resourcebase + }, {__index=function(table, key) if key == "controller" then return build_url() elseif key == "REQUEST_URI" then @@ -230,14 +266,6 @@ function dispatch(request) return rawget(table, key) or _G[key] end end}) - tpl.context.viewns = viewns - viewns.write = luci.http.write - viewns.include = function(name) tpl.Template(name):render(getfenv(2)) end - viewns.translate = function(...) return require("luci.i18n").translate(...) end - viewns.striptags = util.striptags - viewns.media = media - viewns.theme = fs.basename(media) - viewns.resource = luci.config.main.resourcebase end track.dependent = (track.dependent ~= false) @@ -256,7 +284,7 @@ function dispatch(request) local verifytoken = false if not sess then sess = luci.http.getcookie("sysauth") - sess = sess and sess:match("^[A-F0-9]+$") + sess = sess and sess:match("^[a-f0-9]*$") verifytoken = true end @@ -264,10 +292,18 @@ function dispatch(request) local user if sdat then - sdat = loadstring(sdat)() + sdat = loadstring(sdat) + setfenv(sdat, {}) + sdat = sdat() if not verifytoken or ctx.urltoken.stok == sdat.token then user = sdat.user end + else + local eu = http.getenv("HTTP_AUTH_USER") + local ep = http.getenv("HTTP_AUTH_PASS") + if eu and ep and luci.sys.user.checkpasswd(eu, ep) then + authen = function() return eu end + end end if not util.contains(accs, user) then @@ -289,6 +325,7 @@ function dispatch(request) end luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path="..build_url()) ctx.authsession = sid + ctx.authuser = user end else luci.http.status(403, "Forbidden") @@ -296,6 +333,7 @@ function dispatch(request) end else ctx.authsession = sess + ctx.authuser = user end end @@ -355,7 +393,7 @@ end --- Generate the dispatching index using the best possible strategy. function createindex() local path = luci.util.libpath() .. "/controller/" - local suff = ".lua" + local suff = { ".lua", ".lua.gz" } if luci.util.copcall(require, "luci.fastindex") then createindex_fastindex(path, suff) @@ -366,14 +404,16 @@ end --- Generate the dispatching index using the fastindex C-indexer. -- @param path Controller base directory --- @param suffix Controller file suffix -function createindex_fastindex(path, suffix) +-- @param suffixes Controller file suffixes +function createindex_fastindex(path, suffixes) index = {} if not fi then fi = luci.fastindex.new("index") - fi.add(path .. "*" .. suffix) - fi.add(path .. "*/*" .. suffix) + for _, suffix in ipairs(suffixes) do + fi.add(path .. "*" .. suffix) + fi.add(path .. "*/*" .. suffix) + end end fi.scan() @@ -384,26 +424,27 @@ end --- Generate the dispatching index using the native file-cache based strategy. -- @param path Controller base directory --- @param suffix Controller file suffix -function createindex_plain(path, suffix) - local controllers = util.combine( - luci.fs.glob(path .. "*" .. suffix) or {}, - luci.fs.glob(path .. "*/*" .. suffix) or {} - ) +-- @param suffixes Controller file suffixes +function createindex_plain(path, suffixes) + local controllers = { } + for _, suffix in ipairs(suffixes) do + nixio.util.consume((fs.glob(path .. "*" .. suffix)), controllers) + nixio.util.consume((fs.glob(path .. "*/*" .. suffix)), controllers) + end if indexcache then - local cachedate = fs.mtime(indexcache) + local cachedate = fs.stat(indexcache, "mtime") if cachedate then local realdate = 0 for _, obj in ipairs(controllers) do - local omtime = fs.mtime(path .. "/" .. obj) + local omtime = fs.stat(path .. "/" .. obj, "mtime") realdate = (omtime and omtime > realdate) and omtime or realdate end if cachedate > realdate then assert( sys.process.info("uid") == fs.stat(indexcache, "uid") - and fs.stat(indexcache, "mode") == "rw-------", + and fs.stat(indexcache, "modestr") == "rw-------", "Fatal: Indexcache is not sane!" ) @@ -416,7 +457,11 @@ function createindex_plain(path, suffix) index = {} for i,c in ipairs(controllers) do - local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".") + local module = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".") + for _, suffix in ipairs(suffixes) do + module = module:gsub(suffix.."$", "") + end + local mod = require(module) local idx = mod.index @@ -426,8 +471,9 @@ function createindex_plain(path, suffix) end if indexcache then - fs.writefile(indexcache, util.get_bytecode(index)) - fs.chmod(indexcache, "a-rwx,u+rw") + local f = nixio.open(indexcache, "w", 600) + f:writeall(util.get_bytecode(index)) + f:close() end end @@ -447,7 +493,7 @@ function createtree() ctx.modifiers = modi -- Load default translation - require "luci.i18n".loadc("default") + require "luci.i18n".loadc("base") local scope = setmetatable({}, {__index = luci.dispatcher}) @@ -647,18 +693,22 @@ local function _cbi(self, ...) end end + local function _resolve_path(path) + return type(path) == "table" and build_url(unpack(path)) or path + end + if config.on_valid_to and state and state > 0 and state < 2 then - http.redirect(config.on_valid_to) + http.redirect(_resolve_path(config.on_valid_to)) return end if config.on_changed_to and state and state > 1 then - http.redirect(config.on_changed_to) + http.redirect(_resolve_path(config.on_changed_to)) return end if config.on_success_to and state and state > 0 then - http.redirect(config.on_success_to) + http.redirect(_resolve_path(config.on_success_to)) return end @@ -668,19 +718,60 @@ local function _cbi(self, ...) end end - local pageaction = true http.header("X-CBI-State", state or 0) + if not config.noheader then tpl.render("cbi/header", {state = state}) end + + local redirect + local messages + local applymap = false + local pageaction = true + local parsechain = { } + for i, res in ipairs(maps) do - res:render() + if res.apply_needed and res.parsechain then + local c + for _, c in ipairs(res.parsechain) do + parsechain[#parsechain+1] = c + end + applymap = true + end + + if res.redirect then + redirect = redirect or res.redirect + end + if res.pageaction == false then pageaction = false end + + if res.message then + messages = messages or { } + messages[#messages+1] = res.message + end end + + for i, res in ipairs(maps) do + res:render({ + firstmap = (i == 1), + applymap = applymap, + redirect = redirect, + messages = messages, + pageaction = pageaction, + parsechain = parsechain + }) + end + if not config.nofooter then - tpl.render("cbi/footer", {flow = config, pageaction=pageaction, state = state, autoapply = config.autoapply}) + tpl.render("cbi/footer", { + flow = config, + pageaction = pageaction, + redirect = redirect, + state = state, + autoapply = config.autoapply + }) end end