local http = require "luci.http"
module("luci.dispatcher", package.seeall)
-context = luci.util.threadlocal()
+context = util.threadlocal()
authenticator = {}
-- @param ... Virtual path
-- @return Relative URL
function build_url(...)
- return luci.http.getenv("SCRIPT_NAME") .. "/" .. table.concat(arg, "/")
+ return context.scriptname .. "/" .. table.concat(arg, "/")
end
--- Send a 404 error code and render the "error404" template if available.
--context._disable_memtrace = require "luci.debug".trap_memtrace()
local ctx = context
ctx.path = request
+ ctx.scriptname = luci.http.getenv("SCRIPT_NAME") or ""
+ ctx.urltoken = ctx.urltoken or {}
require "luci.i18n".setlanguage(require "luci.config".main.lang)
ctx.args = args
ctx.requestargs = ctx.requestargs or args
local n
+ local t = true
+ local token = ctx.urltoken
+ local preq = {}
for i, s in ipairs(request) do
- c = c.nodes[s]
- n = i
- if not c then
- break
+ local tkey, tval
+ if t then
+ tkey, tval = s:match(";(%w+)=(.*)")
end
- util.update(track, c)
+ if tkey then
+ token[tkey] = tval
+ else
+ t = false
+ preq[#preq+1] = s
+ c = c.nodes[s]
+ n = i
+ if not c then
+ break
+ end
+
+ util.update(track, c)
- if c.leaf then
- break
+ if c.leaf then
+ break
+ end
end
end
end
end
+ for k, v in pairs(token) do
+ ctx.scriptname = ctx.scriptname .. "/;" .. k .. "=" ..
+ http.urlencode(v)
+ end
+
+ ctx.path = preq
+
if track.i18n then
require("luci.i18n").loadc(track.i18n)
end
assert(media, "No valid theme found")
end
- local viewns = setmetatable({}, {__index=_G})
+ local viewns = setmetatable({}, {__index=function(table, key)
+ if key == "controller" then
+ return ctx.scriptname
+ elseif key == "REQUEST_URI" then
+ return ctx.scriptname .. "/" .. table.concat(ctx.requested, "/")
+ else
+ 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.controller = luci.http.getenv("SCRIPT_NAME")
viewns.media = media
viewns.theme = fs.basename(media)
viewns.resource = luci.config.main.resourcebase
- viewns.REQUEST_URI = (luci.http.getenv("SCRIPT_NAME") or "") .. (luci.http.getenv("PATH_INFO") or "")
end
track.dependent = (track.dependent ~= false)
local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth
- local sess = ctx.authsession or luci.http.getcookie("sysauth")
- sess = sess and sess:match("^[A-F0-9]+$")
- local user = sauth.read(sess)
+ local sess = ctx.authsession
+ local verifytoken = true
+ if not sess then
+ sess = luci.http.getcookie("sysauth")
+ sess = sess and sess:match("^[A-F0-9]+$")
+ end
+
+ local sdat = sauth.read(sess)
+ local user
+
+ if sdat then
+ sdat = loadstring(sdat)()
+ if not verifytoken or ctx.urltoken.stok == sdat.token then
+ user = sdat.user
+ end
+ end
if not util.contains(accs, user) then
if authen then
local sid = sess or luci.sys.uniqueid(16)
luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path=/")
if not sess then
- sauth.write(sid, user)
+ local token = luci.sys.uniqueid(16)
+ sauth.write(sid, util.get_bytecode({
+ user=user,
+ token=token,
+ secret=luci.sys.uniqueid(16)
+ }))
+ ctx.scriptname = ctx.scriptname .. "/;stok="..token
end
ctx.authsession = sid
end
luci.http.status(403, "Forbidden")
return
end
+ else
+ ctx.authsession = sess
end
end
-- @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 {}
+ )
+
if indexcache then
local cachedate = fs.mtime(indexcache)
- if cachedate and cachedate > fs.mtime(path) then
+ if cachedate then
+ local realdate = 0
+ for _, obj in ipairs(controllers) do
+ local omtime = fs.mtime(path .. "/" .. obj)
+ realdate = (omtime and omtime > realdate) and omtime or realdate
+ end
- assert(
- sys.process.info("uid") == fs.stat(indexcache, "uid")
- and fs.stat(indexcache, "mode") == "rw-------",
- "Fatal: Indexcache is not sane!"
- )
+ if cachedate > realdate then
+ assert(
+ sys.process.info("uid") == fs.stat(indexcache, "uid")
+ and fs.stat(indexcache, "mode") == "rw-------",
+ "Fatal: Indexcache is not sane!"
+ )
- index = loadfile(indexcache)()
- return index
+ index = loadfile(indexcache)()
+ return index
+ end
end
end
index = {}
- local controllers = util.combine(
- luci.fs.glob(path .. "*" .. suffix) or {},
- luci.fs.glob(path .. "*/*" .. suffix) or {}
- )
-
for i,c in ipairs(controllers) do
local module = "luci.controller." .. c:sub(#path+1, #c-#suffix):gsub("/", ".")
local mod = require(module)
local ctx = context
local tree = {nodes={}}
+ local modi = {}
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
+ ctx.modifiers = modi
-- Load default translation
require "luci.i18n".loadc("default")
v()
end
+ local function modisort(a,b)
+ return modi[a].order < modi[b].order
+ end
+
+ for _, v in util.spairs(modi, modisort) do
+ scope._NAME = v.module
+ setfenv(v.func, scope)
+ v.func()
+ end
+
return tree
end
+--- Register a tree modifier.
+-- @param func Modifier function
+-- @param order Modifier order value (optional)
+function modifier(func, order)
+ context.modifiers[#context.modifiers+1] = {
+ func = func,
+ order = order or 0,
+ module
+ = getfenv(2)._NAME
+ }
+end
+
--- Clone a node of the dispatching tree to another position.
-- @param path Virtual path destination
-- @param clone Virtual path source
local c = _create_node({...})
c.module = getfenv(2)._NAME
- c.path = arg
c.auto = nil
return c
local c = cache[name]
if not c then
+ local new = {nodes={}, auto=true, path=util.clone(path)}
local last = table.remove(path)
+
c = _create_node(path, cache)
- local new = {nodes={}, auto=true}
c.nodes[last] = new
cache[name] = new
end
end
+ if config.on_valid_to and state and state > 0 and state < 2 then
+ luci.http.redirect(config.on_valid_to)
+ return
+ end
+
+ if config.on_changed_to and state and state > 1 then
+ luci.http.redirect(config.on_changed_to)
+ return
+ end
+
+ if config.on_success_to and state and state > 0 then
+ luci.http.redirect(config.on_success_to)
+ return
+ end
+
if config.state_handler then
if not config.state_handler(state, maps) then
return