2015-01-16 22:38:38 +00:00
|
|
|
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
2015-10-06 13:53:35 +00:00
|
|
|
-- Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org>
|
2015-01-16 22:38:38 +00:00
|
|
|
-- Licensed to the public under the Apache License 2.0.
|
2008-07-29 20:32:02 +00:00
|
|
|
|
2009-07-19 00:24:58 +00:00
|
|
|
local fs = require "nixio.fs"
|
2008-08-29 23:26:01 +00:00
|
|
|
local sys = require "luci.sys"
|
|
|
|
local util = require "luci.util"
|
|
|
|
local http = require "luci.http"
|
2009-06-21 13:42:26 +00:00
|
|
|
local nixio = require "nixio", require "nixio.util"
|
2008-03-02 21:52:58 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
module("luci.dispatcher", package.seeall)
|
2008-11-29 21:58:39 +00:00
|
|
|
context = util.threadlocal()
|
2009-11-10 16:02:48 +00:00
|
|
|
uci = require "luci.model.uci"
|
2009-11-29 13:46:04 +00:00
|
|
|
i18n = require "luci.i18n"
|
2009-11-14 18:41:16 +00:00
|
|
|
_M.fs = fs
|
2008-03-29 18:22:21 +00:00
|
|
|
|
2008-08-10 12:58:05 +00:00
|
|
|
authenticator = {}
|
|
|
|
|
2008-05-26 12:16:16 +00:00
|
|
|
-- Index table
|
2008-06-14 14:12:12 +00:00
|
|
|
local index = nil
|
2008-05-26 12:16:16 +00:00
|
|
|
|
2008-06-02 15:36:13 +00:00
|
|
|
-- Fastindex
|
|
|
|
local fi
|
|
|
|
|
2008-05-05 19:27:30 +00:00
|
|
|
|
2008-05-29 13:51:32 +00:00
|
|
|
function build_url(...)
|
2008-12-15 10:40:45 +00:00
|
|
|
local path = {...}
|
2010-11-13 13:50:54 +00:00
|
|
|
local url = { http.getenv("SCRIPT_NAME") or "" }
|
|
|
|
|
|
|
|
local k, v
|
2008-12-15 10:40:45 +00:00
|
|
|
for k, v in pairs(context.urltoken) do
|
2010-11-13 13:50:54 +00:00
|
|
|
url[#url+1] = "/;"
|
|
|
|
url[#url+1] = http.urlencode(k)
|
|
|
|
url[#url+1] = "="
|
|
|
|
url[#url+1] = http.urlencode(v)
|
2008-12-15 10:40:45 +00:00
|
|
|
end
|
2010-11-13 13:50:54 +00:00
|
|
|
|
|
|
|
local p
|
|
|
|
for _, p in ipairs(path) do
|
2010-11-13 20:50:20 +00:00
|
|
|
if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then
|
2010-11-13 13:50:54 +00:00
|
|
|
url[#url+1] = "/"
|
|
|
|
url[#url+1] = p
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return table.concat(url, "")
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
|
|
|
|
2011-10-26 00:24:17 +00:00
|
|
|
function node_visible(node)
|
|
|
|
if node then
|
|
|
|
return not (
|
|
|
|
(not node.title or #node.title == 0) or
|
|
|
|
(not node.target or node.hidden == true) or
|
|
|
|
(type(node.target) == "table" and node.target.type == "firstchild" and
|
|
|
|
(type(node.nodes) ~= "table" or not next(node.nodes)))
|
|
|
|
)
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function node_childs(node)
|
2011-10-26 03:04:41 +00:00
|
|
|
local rv = { }
|
|
|
|
if node then
|
|
|
|
local k, v
|
|
|
|
for k, v in util.spairs(node.nodes,
|
|
|
|
function(a, b)
|
|
|
|
return (node.nodes[a].order or 100)
|
|
|
|
< (node.nodes[b].order or 100)
|
|
|
|
end)
|
|
|
|
do
|
|
|
|
if node_visible(v) then
|
|
|
|
rv[#rv+1] = k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return rv
|
2011-10-26 00:24:17 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
2008-03-02 21:52:58 +00:00
|
|
|
function error404(message)
|
2015-01-15 15:32:03 +00:00
|
|
|
http.status(404, "Not Found")
|
2008-03-02 21:52:58 +00:00
|
|
|
message = message or "Not Found"
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2008-05-25 17:00:30 +00:00
|
|
|
require("luci.template")
|
2015-01-15 15:32:03 +00:00
|
|
|
if not util.copcall(luci.template.render, "error404") then
|
|
|
|
http.prepare_content("text/plain")
|
|
|
|
http.write(message)
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
return false
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function error500(message)
|
2015-01-15 15:32:03 +00:00
|
|
|
util.perror(message)
|
2009-02-09 13:17:26 +00:00
|
|
|
if not context.template_header_sent then
|
2015-01-15 15:32:03 +00:00
|
|
|
http.status(500, "Internal Server Error")
|
|
|
|
http.prepare_content("text/plain")
|
|
|
|
http.write(message)
|
2009-02-09 13:17:26 +00:00
|
|
|
else
|
|
|
|
require("luci.template")
|
2015-01-15 15:32:03 +00:00
|
|
|
if not util.copcall(luci.template.render, "error500", {message=message}) then
|
|
|
|
http.prepare_content("text/plain")
|
|
|
|
http.write(message)
|
2009-02-09 13:17:26 +00:00
|
|
|
end
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
return false
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
|
|
|
|
2008-08-22 22:13:54 +00:00
|
|
|
function authenticator.htmlauth(validator, accs, default)
|
2015-01-15 15:32:03 +00:00
|
|
|
local user = http.formvalue("luci_username")
|
|
|
|
local pass = http.formvalue("luci_password")
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-08-10 12:58:05 +00:00
|
|
|
if user and validator(user, pass) then
|
|
|
|
return user
|
2008-06-28 16:03:54 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2015-10-20 22:31:27 +00:00
|
|
|
require("luci.i18n")
|
|
|
|
require("luci.template")
|
|
|
|
context.path = {}
|
|
|
|
http.status(403, "Forbidden")
|
|
|
|
luci.template.render("sysauth", {duser=default, fuser=user})
|
2015-01-26 16:31:21 +00:00
|
|
|
|
2008-08-10 12:58:05 +00:00
|
|
|
return false
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-06-28 16:03:54 +00:00
|
|
|
end
|
|
|
|
|
2009-07-25 12:45:38 +00:00
|
|
|
function httpdispatch(request, prefix)
|
2015-01-15 15:32:03 +00:00
|
|
|
http.context.request = request
|
2009-07-25 12:45:38 +00:00
|
|
|
|
|
|
|
local r = {}
|
|
|
|
context.request = r
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
context.urltoken = {}
|
2011-10-26 00:24:17 +00:00
|
|
|
|
2009-01-20 19:40:14 +00:00
|
|
|
local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true)
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2009-07-25 12:45:38 +00:00
|
|
|
if prefix then
|
|
|
|
for _, node in ipairs(prefix) do
|
|
|
|
r[#r+1] = node
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-06-06 15:50:21 +00:00
|
|
|
for node in pathinfo:gmatch("[^/]+") do
|
2015-10-20 22:31:27 +00:00
|
|
|
r[#r+1] = node
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2009-02-26 16:45:01 +00:00
|
|
|
local stat, err = util.coxpcall(function()
|
2009-07-24 15:45:29 +00:00
|
|
|
dispatch(context.request)
|
2009-02-26 16:45:01 +00:00
|
|
|
end, error500)
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2015-01-15 15:32:03 +00:00
|
|
|
http.close()
|
2008-09-05 20:32:20 +00:00
|
|
|
|
|
|
|
--context._disable_memtrace()
|
2008-05-04 20:53:31 +00:00
|
|
|
end
|
|
|
|
|
2015-10-20 18:58:30 +00:00
|
|
|
local function require_post_security(target)
|
|
|
|
if type(target) == "table" then
|
|
|
|
if type(target.post) == "table" then
|
|
|
|
local param_name, required_val, request_val
|
|
|
|
|
|
|
|
for param_name, required_val in pairs(target.post) do
|
|
|
|
request_val = http.formvalue(param_name)
|
|
|
|
|
|
|
|
if (type(required_val) == "string" and
|
|
|
|
request_val ~= required_val) or
|
|
|
|
(required_val == true and
|
|
|
|
(request_val == nil or request_val == ""))
|
|
|
|
then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
return (target.post == true)
|
|
|
|
end
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2009-07-24 15:45:29 +00:00
|
|
|
function dispatch(request)
|
2009-07-23 11:32:22 +00:00
|
|
|
--context._disable_memtrace = require "luci.debug".trap_memtrace("l")
|
2008-08-29 23:26:01 +00:00
|
|
|
local ctx = context
|
|
|
|
ctx.path = request
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2009-01-14 23:47:56 +00:00
|
|
|
local conf = require "luci.config"
|
2009-03-14 01:16:03 +00:00
|
|
|
assert(conf.main,
|
|
|
|
"/etc/config/luci seems to be corrupt, unable to find section 'main'")
|
|
|
|
|
2010-04-16 19:05:05 +00:00
|
|
|
local lang = conf.main.lang or "auto"
|
2009-01-14 23:47:56 +00:00
|
|
|
if lang == "auto" then
|
|
|
|
local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or ""
|
2009-01-30 15:29:14 +00:00
|
|
|
for lpat in aclang:gmatch("[%w-]+") do
|
|
|
|
lpat = lpat and lpat:gsub("-", "_")
|
2009-01-14 23:47:56 +00:00
|
|
|
if conf.languages[lpat] then
|
|
|
|
lang = lpat
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2010-04-16 19:05:05 +00:00
|
|
|
end
|
2009-01-14 23:47:56 +00:00
|
|
|
require "luci.i18n".setlanguage(lang)
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2009-07-23 03:25:27 +00:00
|
|
|
local c = ctx.tree
|
|
|
|
local stat
|
2009-07-24 15:45:29 +00:00
|
|
|
if not c then
|
|
|
|
c = createtree()
|
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
local track = {}
|
2008-08-07 19:03:25 +00:00
|
|
|
local args = {}
|
2008-11-01 18:49:41 +00:00
|
|
|
ctx.args = args
|
|
|
|
ctx.requestargs = ctx.requestargs or args
|
2008-08-07 19:03:25 +00:00
|
|
|
local n
|
2008-12-14 21:43:10 +00:00
|
|
|
local token = ctx.urltoken
|
|
|
|
local preq = {}
|
2009-01-04 15:45:57 +00:00
|
|
|
local freq = {}
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
for i, s in ipairs(request) do
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
preq[#preq+1] = s
|
|
|
|
freq[#freq+1] = s
|
|
|
|
c = c.nodes[s]
|
|
|
|
n = i
|
|
|
|
if not c then
|
|
|
|
break
|
2008-05-24 22:58:45 +00:00
|
|
|
end
|
|
|
|
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
util.update(track, c)
|
2008-09-23 00:10:51 +00:00
|
|
|
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
if c.leaf then
|
|
|
|
break
|
2008-08-22 21:52:36 +00:00
|
|
|
end
|
2008-05-04 20:53:31 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2008-08-07 19:03:25 +00:00
|
|
|
if c and c.leaf then
|
|
|
|
for j=n+1, #request do
|
2009-01-04 15:45:57 +00:00
|
|
|
args[#args+1] = request[j]
|
|
|
|
freq[#freq+1] = request[j]
|
2008-08-07 19:03:25 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-09-11 10:46:06 +00:00
|
|
|
ctx.requestpath = ctx.requestpath or freq
|
2008-12-14 21:43:10 +00:00
|
|
|
ctx.path = preq
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
if track.i18n then
|
2011-08-12 12:34:13 +00:00
|
|
|
i18n.loadc(track.i18n)
|
2008-05-04 20:53:31 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-05-26 09:45:12 +00:00
|
|
|
-- Init template engine
|
2008-10-10 14:37:53 +00:00
|
|
|
if (c and c.index) or not track.notemplate then
|
2008-08-29 23:26:01 +00:00
|
|
|
local tpl = require("luci.template")
|
2008-10-19 20:49:10 +00:00
|
|
|
local media = track.mediaurlbase or luci.config.main.mediaurlbase
|
2009-08-07 15:16:14 +00:00
|
|
|
if not pcall(tpl.Template, "themes/%s/header" % fs.basename(media)) then
|
2008-09-29 15:38:13 +00:00
|
|
|
media = nil
|
|
|
|
for name, theme in pairs(luci.config.themes) do
|
|
|
|
if name:sub(1,1) ~= "." and pcall(tpl.Template,
|
|
|
|
"themes/%s/header" % fs.basename(theme)) then
|
|
|
|
media = theme
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assert(media, "No valid theme found")
|
|
|
|
end
|
|
|
|
|
2011-10-30 15:00:54 +00:00
|
|
|
local function _ifattr(cond, key, val)
|
2011-10-26 02:17:45 +00:00
|
|
|
if cond then
|
2011-10-30 15:00:54 +00:00
|
|
|
local env = getfenv(3)
|
|
|
|
local scope = (type(env.self) == "table") and env.self
|
2011-10-26 02:17:45 +00:00
|
|
|
return string.format(
|
|
|
|
' %s="%s"', tostring(key),
|
2015-01-15 15:32:03 +00:00
|
|
|
util.pcdata(tostring( val
|
2011-10-26 02:17:45 +00:00
|
|
|
or (type(env[key]) ~= "function" and env[key])
|
2011-10-30 15:00:54 +00:00
|
|
|
or (scope and type(scope[key]) ~= "function" and scope[key])
|
2011-10-26 02:17:45 +00:00
|
|
|
or "" ))
|
|
|
|
)
|
|
|
|
else
|
|
|
|
return ''
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-07-23 03:25:27 +00:00
|
|
|
tpl.context.viewns = setmetatable({
|
2015-01-15 15:32:03 +00:00
|
|
|
write = http.write;
|
2009-07-24 15:45:29 +00:00
|
|
|
include = function(name) tpl.Template(name):render(getfenv(2)) end;
|
2011-08-12 11:13:39 +00:00
|
|
|
translate = i18n.translate;
|
2012-08-14 15:31:26 +00:00
|
|
|
translatef = i18n.translatef;
|
2010-10-15 16:12:07 +00:00
|
|
|
export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end;
|
2009-07-24 15:45:29 +00:00
|
|
|
striptags = util.striptags;
|
2009-10-31 15:42:07 +00:00
|
|
|
pcdata = util.pcdata;
|
2009-07-24 15:45:29 +00:00
|
|
|
media = media;
|
|
|
|
theme = fs.basename(media);
|
2011-10-26 02:17:45 +00:00
|
|
|
resource = luci.config.main.resourcebase;
|
2011-10-30 15:00:54 +00:00
|
|
|
ifattr = function(...) return _ifattr(...) end;
|
|
|
|
attr = function(...) return _ifattr(true, ...) end;
|
2015-10-07 11:03:42 +00:00
|
|
|
url = build_url;
|
2009-07-23 03:25:27 +00:00
|
|
|
}, {__index=function(table, key)
|
2008-12-14 21:43:10 +00:00
|
|
|
if key == "controller" then
|
2008-12-15 10:40:45 +00:00
|
|
|
return build_url()
|
2008-12-14 21:43:10 +00:00
|
|
|
elseif key == "REQUEST_URI" then
|
2009-01-04 15:45:57 +00:00
|
|
|
return build_url(unpack(ctx.requestpath))
|
2015-10-20 22:31:27 +00:00
|
|
|
elseif key == "token" then
|
|
|
|
return ctx.authtoken
|
2008-12-14 21:43:10 +00:00
|
|
|
else
|
|
|
|
return rawget(table, key) or _G[key]
|
|
|
|
end
|
|
|
|
end})
|
2008-07-17 16:02:29 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-09-05 14:34:59 +00:00
|
|
|
track.dependent = (track.dependent ~= false)
|
2011-07-20 23:57:32 +00:00
|
|
|
assert(not track.dependent or not track.auto,
|
|
|
|
"Access Violation\nThe page at '" .. table.concat(request, "/") .. "/' " ..
|
|
|
|
"has no parent node so the access to this location has been denied.\n" ..
|
|
|
|
"This is a software bug, please report this message at " ..
|
|
|
|
"http://luci.subsignal.org/trac/newticket"
|
|
|
|
)
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-06-28 16:03:54 +00:00
|
|
|
if track.sysauth then
|
2008-08-22 20:04:04 +00:00
|
|
|
local authen = type(track.sysauth_authenticator) == "function"
|
|
|
|
and track.sysauth_authenticator
|
|
|
|
or authenticator[track.sysauth_authenticator]
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-06-28 16:03:54 +00:00
|
|
|
local def = (type(track.sysauth) == "string") and track.sysauth
|
|
|
|
local accs = def and {track.sysauth} or track.sysauth
|
2008-12-14 21:43:10 +00:00
|
|
|
local sess = ctx.authsession
|
|
|
|
if not sess then
|
2015-01-15 15:32:03 +00:00
|
|
|
sess = http.getcookie("sysauth")
|
2009-07-25 10:47:26 +00:00
|
|
|
sess = sess and sess:match("^[a-f0-9]*$")
|
2008-12-14 21:43:10 +00:00
|
|
|
end
|
|
|
|
|
2015-01-15 09:55:53 +00:00
|
|
|
local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values
|
2015-10-20 22:31:27 +00:00
|
|
|
local user, token
|
2008-12-14 21:43:10 +00:00
|
|
|
|
|
|
|
if sdat then
|
2015-10-20 22:31:27 +00:00
|
|
|
user = sdat.user
|
|
|
|
token = sdat.token
|
2009-07-25 10:47:26 +00:00
|
|
|
else
|
|
|
|
local eu = http.getenv("HTTP_AUTH_USER")
|
|
|
|
local ep = http.getenv("HTTP_AUTH_PASS")
|
2015-01-16 20:34:30 +00:00
|
|
|
if eu and ep and sys.user.checkpasswd(eu, ep) then
|
2009-07-25 10:47:26 +00:00
|
|
|
authen = function() return eu end
|
|
|
|
end
|
2008-12-14 21:43:10 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
if not util.contains(accs, user) then
|
2008-08-10 12:58:05 +00:00
|
|
|
if authen then
|
2015-01-16 20:34:30 +00:00
|
|
|
local user, sess = authen(sys.user.checkpasswd, accs, def)
|
2015-02-09 15:30:11 +00:00
|
|
|
local token
|
2008-08-29 23:26:01 +00:00
|
|
|
if not user or not util.contains(accs, user) then
|
2008-08-10 12:58:05 +00:00
|
|
|
return
|
|
|
|
else
|
2008-08-26 00:53:28 +00:00
|
|
|
if not sess then
|
2015-02-09 12:03:44 +00:00
|
|
|
local sdat = util.ubus("session", "create", { timeout = tonumber(luci.config.sauth.sessiontime) })
|
2015-01-15 09:55:53 +00:00
|
|
|
if sdat then
|
2015-02-09 15:30:11 +00:00
|
|
|
token = sys.uniqueid(16)
|
2015-01-15 09:55:53 +00:00
|
|
|
util.ubus("session", "set", {
|
|
|
|
ubus_rpc_session = sdat.ubus_rpc_session,
|
|
|
|
values = {
|
|
|
|
user = user,
|
|
|
|
token = token,
|
2015-01-16 20:34:30 +00:00
|
|
|
section = sys.uniqueid(16)
|
2015-01-15 09:55:53 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
sess = sdat.ubus_rpc_session
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-02-09 15:30:11 +00:00
|
|
|
if sess and token then
|
|
|
|
http.header("Set-Cookie", 'sysauth=%s; path=%s/' %{
|
|
|
|
sess, build_url()
|
|
|
|
})
|
|
|
|
|
2015-01-15 09:55:53 +00:00
|
|
|
ctx.authsession = sess
|
2015-10-20 22:31:27 +00:00
|
|
|
ctx.authtoken = token
|
2015-01-15 09:55:53 +00:00
|
|
|
ctx.authuser = user
|
2015-02-09 15:30:11 +00:00
|
|
|
|
|
|
|
http.redirect(build_url(unpack(ctx.requestpath)))
|
2008-08-26 00:53:28 +00:00
|
|
|
end
|
2008-08-10 12:58:05 +00:00
|
|
|
end
|
|
|
|
else
|
2015-01-15 15:32:03 +00:00
|
|
|
http.status(403, "Forbidden")
|
2008-06-28 16:03:54 +00:00
|
|
|
return
|
|
|
|
end
|
2008-12-14 21:43:10 +00:00
|
|
|
else
|
|
|
|
ctx.authsession = sess
|
2015-10-20 22:31:27 +00:00
|
|
|
ctx.authtoken = token
|
2009-09-11 10:46:06 +00:00
|
|
|
ctx.authuser = user
|
2008-06-28 16:03:54 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-10-20 18:58:30 +00:00
|
|
|
if c and require_post_security(c.target) then
|
2015-10-06 13:53:35 +00:00
|
|
|
if http.getenv("REQUEST_METHOD") ~= "POST" then
|
|
|
|
http.status(405, "Method Not Allowed")
|
|
|
|
http.header("Allow", "POST")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2015-10-20 22:31:27 +00:00
|
|
|
if http.formvalue("token") ~= ctx.authtoken then
|
2015-10-06 13:53:35 +00:00
|
|
|
http.status(403, "Forbidden")
|
|
|
|
luci.template.render("csrftoken")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-06-28 16:03:54 +00:00
|
|
|
if track.setgroup then
|
2015-01-16 20:34:30 +00:00
|
|
|
sys.process.setgroup(track.setgroup)
|
2008-06-28 16:03:54 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
if track.setuser then
|
2015-02-09 11:14:20 +00:00
|
|
|
-- trigger ubus connection before dropping root privs
|
|
|
|
util.ubus()
|
|
|
|
|
2015-01-16 20:34:30 +00:00
|
|
|
sys.process.setuser(track.setuser)
|
2008-06-28 16:03:54 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local target = nil
|
|
|
|
if c then
|
|
|
|
if type(c.target) == "function" then
|
|
|
|
target = c.target
|
|
|
|
elseif type(c.target) == "table" then
|
|
|
|
target = c.target.target
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if c and (c.index or type(target) == "function") then
|
2008-10-11 11:30:43 +00:00
|
|
|
ctx.dispatched = c
|
|
|
|
ctx.requested = ctx.requested or ctx.dispatched
|
|
|
|
end
|
|
|
|
|
2008-10-10 14:37:53 +00:00
|
|
|
if c and c.index then
|
|
|
|
local tpl = require "luci.template"
|
2008-10-11 11:30:43 +00:00
|
|
|
|
|
|
|
if util.copcall(tpl.render, "indexer", {}) then
|
2008-10-10 14:37:53 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
if type(target) == "function" then
|
2008-08-29 23:26:01 +00:00
|
|
|
util.copcall(function()
|
2009-01-04 15:45:57 +00:00
|
|
|
local oldenv = getfenv(target)
|
2008-09-05 18:35:09 +00:00
|
|
|
local module = require(c.module)
|
|
|
|
local env = setmetatable({}, {__index=
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-09-05 18:35:09 +00:00
|
|
|
function(tbl, key)
|
2008-09-23 00:10:51 +00:00
|
|
|
return rawget(tbl, key) or module[key] or oldenv[key]
|
2008-09-05 18:35:09 +00:00
|
|
|
end})
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
setfenv(target, env)
|
2008-08-29 23:26:01 +00:00
|
|
|
end)
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2011-07-21 01:04:53 +00:00
|
|
|
local ok, err
|
2009-01-04 15:45:57 +00:00
|
|
|
if type(c.target) == "table" then
|
2011-07-21 01:04:53 +00:00
|
|
|
ok, err = util.copcall(target, c.target, unpack(args))
|
2009-01-04 15:45:57 +00:00
|
|
|
else
|
2011-07-21 01:04:53 +00:00
|
|
|
ok, err = util.copcall(target, unpack(args))
|
2009-01-04 15:45:57 +00:00
|
|
|
end
|
2011-07-21 01:04:53 +00:00
|
|
|
assert(ok,
|
|
|
|
"Failed to execute " .. (type(c.target) == "function" and "function" or c.target.type or "unknown") ..
|
|
|
|
" dispatcher target for entry '/" .. table.concat(request, "/") .. "'.\n" ..
|
|
|
|
"The called action terminated with an exception:\n" .. tostring(err or "(unknown)"))
|
2008-03-21 19:30:53 +00:00
|
|
|
else
|
2011-07-20 23:57:32 +00:00
|
|
|
local root = node()
|
|
|
|
if not root or not root.target then
|
|
|
|
error404("No root node was registered, this usually happens if no module was installed.\n" ..
|
2011-10-21 17:22:48 +00:00
|
|
|
"Install luci-mod-admin-full and retry. " ..
|
2011-07-20 23:57:32 +00:00
|
|
|
"If the module is already installed, try removing the /tmp/luci-indexcache file.")
|
|
|
|
else
|
2011-07-21 01:04:53 +00:00
|
|
|
error404("No page is registered at '/" .. table.concat(request, "/") .. "'.\n" ..
|
2011-07-20 23:57:32 +00:00
|
|
|
"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
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
function createindex()
|
2015-01-15 15:32:03 +00:00
|
|
|
local controllers = { }
|
|
|
|
local base = "%s/controller/" % util.libpath()
|
|
|
|
local _, path
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2015-01-15 15:32:03 +00:00
|
|
|
for path in (fs.glob("%s*.lua" % base) or function() end) do
|
|
|
|
controllers[#controllers+1] = path
|
2008-05-26 09:45:12 +00:00
|
|
|
end
|
|
|
|
|
2015-01-15 15:32:03 +00:00
|
|
|
for path in (fs.glob("%s*/*.lua" % base) or function() end) do
|
|
|
|
controllers[#controllers+1] = path
|
2009-04-04 22:54:16 +00:00
|
|
|
end
|
2008-11-05 14:10:02 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
if indexcache then
|
2009-07-19 00:24:58 +00:00
|
|
|
local cachedate = fs.stat(indexcache, "mtime")
|
2008-11-05 14:10:02 +00:00
|
|
|
if cachedate then
|
|
|
|
local realdate = 0
|
|
|
|
for _, obj in ipairs(controllers) do
|
2011-07-18 14:50:39 +00:00
|
|
|
local omtime = fs.stat(obj, "mtime")
|
2008-11-05 14:10:02 +00:00
|
|
|
realdate = (omtime and omtime > realdate) and omtime or realdate
|
|
|
|
end
|
2008-09-01 16:05:34 +00:00
|
|
|
|
2015-01-15 15:32:03 +00:00
|
|
|
if cachedate > realdate and sys.process.info("uid") == 0 then
|
2008-11-05 14:10:02 +00:00
|
|
|
assert(
|
|
|
|
sys.process.info("uid") == fs.stat(indexcache, "uid")
|
2009-06-21 13:42:26 +00:00
|
|
|
and fs.stat(indexcache, "modestr") == "rw-------",
|
2008-11-05 14:10:02 +00:00
|
|
|
"Fatal: Indexcache is not sane!"
|
|
|
|
)
|
2008-09-01 16:05:34 +00:00
|
|
|
|
2008-11-05 14:10:02 +00:00
|
|
|
index = loadfile(indexcache)()
|
|
|
|
return index
|
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
end
|
2008-08-29 23:26:01 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2009-07-24 15:45:29 +00:00
|
|
|
index = {}
|
2008-06-02 15:36:13 +00:00
|
|
|
|
2015-01-15 15:32:03 +00:00
|
|
|
for _, path in ipairs(controllers) do
|
|
|
|
local modname = "luci.controller." .. path:sub(#base+1, #path-4):gsub("/", ".")
|
2010-12-12 20:16:13 +00:00
|
|
|
local mod = require(modname)
|
2011-07-21 01:04:53 +00:00
|
|
|
assert(mod ~= true,
|
|
|
|
"Invalid controller file found\n" ..
|
2015-01-15 15:32:03 +00:00
|
|
|
"The file '" .. path .. "' contains an invalid module line.\n" ..
|
2011-07-21 01:04:53 +00:00
|
|
|
"Please verify whether the module name is set to '" .. modname ..
|
|
|
|
"' - It must correspond to the file path!")
|
2011-10-26 00:24:17 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
local idx = mod.index
|
2011-07-21 01:04:53 +00:00
|
|
|
assert(type(idx) == "function",
|
|
|
|
"Invalid controller file found\n" ..
|
2015-01-15 15:32:03 +00:00
|
|
|
"The file '" .. path .. "' contains no index() function.\n" ..
|
2011-07-21 01:04:53 +00:00
|
|
|
"Please make sure that the controller contains a valid " ..
|
|
|
|
"index function and verify the spelling!")
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2011-07-21 01:04:53 +00:00
|
|
|
index[modname] = idx
|
2008-08-29 23:26:01 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
if indexcache then
|
2009-06-21 13:42:26 +00:00
|
|
|
local f = nixio.open(indexcache, "w", 600)
|
|
|
|
f:writeall(util.get_bytecode(index))
|
|
|
|
f:close()
|
2008-06-02 15:36:05 +00:00
|
|
|
end
|
2008-03-21 19:30:53 +00:00
|
|
|
end
|
|
|
|
|
2008-07-29 20:32:02 +00:00
|
|
|
-- Build the index before if it does not exist yet.
|
2008-05-26 12:16:16 +00:00
|
|
|
function createtree()
|
2009-07-24 15:45:29 +00:00
|
|
|
if not index then
|
|
|
|
createindex()
|
2009-07-23 03:25:27 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2009-07-24 15:45:29 +00:00
|
|
|
local ctx = context
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
local tree = {nodes={}, inreq=true}
|
2009-07-24 15:45:29 +00:00
|
|
|
local modi = {}
|
|
|
|
|
|
|
|
ctx.treecache = setmetatable({}, {__mode="v"})
|
|
|
|
ctx.tree = tree
|
2008-11-11 18:55:07 +00:00
|
|
|
ctx.modifiers = modi
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-05-31 08:04:49 +00:00
|
|
|
-- Load default translation
|
2009-11-01 14:24:04 +00:00
|
|
|
require "luci.i18n".loadc("base")
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-09-05 19:17:48 +00:00
|
|
|
local scope = setmetatable({}, {__index = luci.dispatcher})
|
2008-05-26 12:16:16 +00:00
|
|
|
|
2009-07-24 15:45:29 +00:00
|
|
|
for k, v in pairs(index) do
|
2008-05-31 08:04:49 +00:00
|
|
|
scope._NAME = k
|
|
|
|
setfenv(v, scope)
|
2009-07-24 15:45:29 +00:00
|
|
|
v()
|
2008-05-26 12:16:16 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-11-11 18:55:07 +00:00
|
|
|
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)
|
2009-07-24 15:45:29 +00:00
|
|
|
v.func()
|
2008-11-11 18:55:07 +00:00
|
|
|
end
|
|
|
|
|
2009-07-24 15:45:29 +00:00
|
|
|
return tree
|
2008-05-26 12:16:16 +00:00
|
|
|
end
|
|
|
|
|
2008-11-11 18:55:07 +00:00
|
|
|
function modifier(func, order)
|
|
|
|
context.modifiers[#context.modifiers+1] = {
|
|
|
|
func = func,
|
|
|
|
order = order or 0,
|
2008-11-29 21:21:43 +00:00
|
|
|
module
|
|
|
|
= getfenv(2)._NAME
|
2008-11-11 18:55:07 +00:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2008-06-02 20:16:05 +00:00
|
|
|
function assign(path, clone, title, order)
|
2008-06-29 14:43:06 +00:00
|
|
|
local obj = node(unpack(path))
|
2008-06-02 20:16:05 +00:00
|
|
|
obj.nodes = nil
|
|
|
|
obj.module = nil
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-06-02 20:16:05 +00:00
|
|
|
obj.title = title
|
|
|
|
obj.order = order
|
2008-06-06 15:50:21 +00:00
|
|
|
|
2008-09-15 16:50:55 +00:00
|
|
|
setmetatable(obj, {__index = _create_node(clone)})
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-06-02 20:16:05 +00:00
|
|
|
return obj
|
|
|
|
end
|
2008-05-22 17:21:30 +00:00
|
|
|
|
2008-06-02 20:16:05 +00:00
|
|
|
function entry(path, target, title, order)
|
2008-06-29 14:42:53 +00:00
|
|
|
local c = node(unpack(path))
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-05-22 17:21:30 +00:00
|
|
|
c.target = target
|
|
|
|
c.title = title
|
|
|
|
c.order = order
|
2008-05-27 20:39:48 +00:00
|
|
|
c.module = getfenv(2)._NAME
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2008-05-22 17:21:30 +00:00
|
|
|
return c
|
|
|
|
end
|
2008-05-04 20:53:31 +00:00
|
|
|
|
2009-02-26 17:08:41 +00:00
|
|
|
-- enabling the node.
|
|
|
|
function get(...)
|
|
|
|
return _create_node({...})
|
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
function node(...)
|
2008-09-15 16:50:55 +00:00
|
|
|
local c = _create_node({...})
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2008-06-06 15:50:21 +00:00
|
|
|
c.module = getfenv(2)._NAME
|
2008-07-17 16:02:29 +00:00
|
|
|
c.auto = nil
|
2008-06-04 22:41:58 +00:00
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
return c
|
|
|
|
end
|
|
|
|
|
2011-08-12 11:04:42 +00:00
|
|
|
function _create_node(path)
|
2008-08-29 23:26:01 +00:00
|
|
|
if #path == 0 then
|
|
|
|
return context.tree
|
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
local name = table.concat(path, ".")
|
2011-08-12 11:04:42 +00:00
|
|
|
local c = context.treecache[name]
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-08-29 23:26:01 +00:00
|
|
|
if not c then
|
|
|
|
local last = table.remove(path)
|
2011-08-12 11:04:42 +00:00
|
|
|
local parent = _create_node(path)
|
2008-11-16 13:52:50 +00:00
|
|
|
|
2011-08-12 11:04:42 +00:00
|
|
|
c = {nodes={}, auto=true}
|
[PATCH] Allow smarter node creation based on visibility during createtree
As I've brought up on the mailing list thread "High latency caused by full tree creation", there is a large amount of delay per LuCI request which is spent building the node tree in createtree(). Most nodes created aren't
needed for the view presented to the user and only serve to consume memory and CPU time during a page load.
My idea is to provide an easy mechanism for index()ers to determine which needs to be created and what isn't. Due to the constraints of the standard LuCI web interface, this optimization needs to establish a few rules:
* The page requested must have its node created
* All parents of the page being requested must be created, so the children inherit the track
* All the top-level nodes "Status", "System", "Services", "Network" (and others added by extensions) must be created in order to have their top-level tabs in the UI
* All peers of second-level nodes need to be created as well for the same reason, to display their links on the subindexes
To make this easy to implement in each controller, the attached patch adds an "inreq" field to each created node to indicate if it lies on the request path. To satisfy the "top level node" requirement, we always
add the top level node, then check its inreq property if the top-level node is not "in request", then the controller can exit index() early.
2011-08-12 11:05:59 +00:00
|
|
|
-- the node is "in request" if the request path matches
|
|
|
|
-- at least up to the length of the node path
|
|
|
|
if parent.inreq and context.path[#path+1] == last then
|
|
|
|
c.inreq = true
|
|
|
|
end
|
2011-08-12 11:04:42 +00:00
|
|
|
parent.nodes[last] = c
|
|
|
|
context.treecache[name] = c
|
2008-08-29 23:26:01 +00:00
|
|
|
end
|
2011-08-12 11:04:42 +00:00
|
|
|
return c
|
2008-08-29 23:26:01 +00:00
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
-- Subdispatchers --
|
2008-07-29 20:32:02 +00:00
|
|
|
|
2011-10-25 22:48:43 +00:00
|
|
|
function _firstchild()
|
|
|
|
local path = { unpack(context.path) }
|
|
|
|
local name = table.concat(path, ".")
|
|
|
|
local node = context.treecache[name]
|
|
|
|
|
|
|
|
local lowest
|
|
|
|
if node and node.nodes and next(node.nodes) then
|
|
|
|
local k, v
|
|
|
|
for k, v in pairs(node.nodes) do
|
|
|
|
if not lowest or
|
|
|
|
(v.order or 100) < (node.nodes[lowest].order or 100)
|
|
|
|
then
|
|
|
|
lowest = k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert(lowest ~= nil,
|
|
|
|
"The requested node contains no childs, unable to redispatch")
|
|
|
|
|
|
|
|
path[#path+1] = lowest
|
|
|
|
dispatch(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
function firstchild()
|
|
|
|
return { type = "firstchild", target = _firstchild }
|
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
function alias(...)
|
2008-10-30 19:09:52 +00:00
|
|
|
local req = {...}
|
|
|
|
return function(...)
|
|
|
|
for _, r in ipairs({...}) do
|
|
|
|
req[#req+1] = r
|
|
|
|
end
|
|
|
|
|
2008-06-14 14:12:12 +00:00
|
|
|
dispatch(req)
|
2008-05-04 20:53:31 +00:00
|
|
|
end
|
2008-03-21 19:30:53 +00:00
|
|
|
end
|
|
|
|
|
2008-05-29 19:18:49 +00:00
|
|
|
function rewrite(n, ...)
|
2008-10-30 19:09:52 +00:00
|
|
|
local req = {...}
|
|
|
|
return function(...)
|
|
|
|
local dispatched = util.clone(context.dispatched)
|
|
|
|
|
2008-09-23 00:10:51 +00:00
|
|
|
for i=1,n do
|
2008-10-30 19:09:52 +00:00
|
|
|
table.remove(dispatched, 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
for i, r in ipairs(req) do
|
|
|
|
table.insert(dispatched, i, r)
|
2008-05-29 19:18:49 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-10-30 19:09:52 +00:00
|
|
|
for _, r in ipairs({...}) do
|
|
|
|
dispatched[#dispatched+1] = r
|
2008-05-29 19:18:49 +00:00
|
|
|
end
|
2008-09-23 00:10:51 +00:00
|
|
|
|
2008-10-30 19:09:52 +00:00
|
|
|
dispatch(dispatched)
|
2008-05-29 19:18:49 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
|
|
|
|
local function _call(self, ...)
|
2011-11-30 12:50:32 +00:00
|
|
|
local func = getfenv()[self.name]
|
|
|
|
assert(func ~= nil,
|
|
|
|
'Cannot resolve function "' .. self.name .. '". Is it misspelled or local?')
|
|
|
|
|
|
|
|
assert(type(func) == "function",
|
|
|
|
'The symbol "' .. self.name .. '" does not refer to a function but data ' ..
|
|
|
|
'of type "' .. type(func) .. '".')
|
|
|
|
|
2009-02-09 13:17:26 +00:00
|
|
|
if #self.argv > 0 then
|
2011-11-30 12:50:32 +00:00
|
|
|
return func(unpack(self.argv), ...)
|
2009-01-04 15:45:57 +00:00
|
|
|
else
|
2011-11-30 12:50:32 +00:00
|
|
|
return func(...)
|
2009-01-04 15:45:57 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-06-14 14:12:12 +00:00
|
|
|
function call(name, ...)
|
2009-01-04 15:45:57 +00:00
|
|
|
return {type = "call", argv = {...}, name = name, target = _call}
|
|
|
|
end
|
|
|
|
|
2015-10-20 18:58:30 +00:00
|
|
|
function post_on(params, name, ...)
|
2015-10-06 13:53:35 +00:00
|
|
|
return {
|
|
|
|
type = "call",
|
2015-10-20 18:58:30 +00:00
|
|
|
post = params,
|
2015-10-06 13:53:35 +00:00
|
|
|
argv = { ... },
|
|
|
|
name = name,
|
|
|
|
target = _call
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2015-10-20 18:58:30 +00:00
|
|
|
function post(...)
|
|
|
|
return post_on(true, ...)
|
|
|
|
end
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
|
|
|
|
local _template = function(self, ...)
|
|
|
|
require "luci.template".render(self.view)
|
2008-05-27 20:39:48 +00:00
|
|
|
end
|
|
|
|
|
2008-05-22 14:04:03 +00:00
|
|
|
function template(name)
|
2009-01-04 15:45:57 +00:00
|
|
|
return {type = "template", view = name, target = _template}
|
2008-05-22 14:04:03 +00:00
|
|
|
end
|
2008-05-04 20:53:31 +00:00
|
|
|
|
2008-08-29 20:36:45 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local function _cbi(self, ...)
|
|
|
|
local cbi = require "luci.cbi"
|
|
|
|
local tpl = require "luci.template"
|
|
|
|
local http = require "luci.http"
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local config = self.config or {}
|
|
|
|
local maps = cbi.load(self.model, ...)
|
2008-10-20 22:35:11 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local state = nil
|
2008-05-24 22:58:45 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
for i, res in ipairs(maps) do
|
2009-04-03 18:08:25 +00:00
|
|
|
res.flow = config
|
2009-01-04 15:45:57 +00:00
|
|
|
local cstate = res:parse()
|
2009-03-07 16:28:27 +00:00
|
|
|
if cstate and (not state or cstate < state) then
|
2009-01-04 15:45:57 +00:00
|
|
|
state = cstate
|
2008-11-05 21:12:19 +00:00
|
|
|
end
|
2009-01-04 15:45:57 +00:00
|
|
|
end
|
2008-11-05 21:12:19 +00:00
|
|
|
|
2009-06-20 07:14:36 +00:00
|
|
|
local function _resolve_path(path)
|
|
|
|
return type(path) == "table" and build_url(unpack(path)) or path
|
|
|
|
end
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
if config.on_valid_to and state and state > 0 and state < 2 then
|
2009-06-20 07:14:36 +00:00
|
|
|
http.redirect(_resolve_path(config.on_valid_to))
|
2009-01-04 15:45:57 +00:00
|
|
|
return
|
|
|
|
end
|
2008-11-02 13:26:41 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
if config.on_changed_to and state and state > 1 then
|
2009-06-20 07:14:36 +00:00
|
|
|
http.redirect(_resolve_path(config.on_changed_to))
|
2009-01-04 15:45:57 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if config.on_success_to and state and state > 0 then
|
2009-06-20 07:14:36 +00:00
|
|
|
http.redirect(_resolve_path(config.on_success_to))
|
2009-01-04 15:45:57 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if config.state_handler then
|
|
|
|
if not config.state_handler(state, maps) then
|
|
|
|
return
|
2008-11-01 18:32:02 +00:00
|
|
|
end
|
2009-01-04 15:45:57 +00:00
|
|
|
end
|
2008-11-01 18:32:02 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
http.header("X-CBI-State", state or 0)
|
2010-11-22 00:32:54 +00:00
|
|
|
|
2009-03-27 00:10:17 +00:00
|
|
|
if not config.noheader then
|
|
|
|
tpl.render("cbi/header", {state = state})
|
|
|
|
end
|
2010-11-22 00:32:54 +00:00
|
|
|
|
|
|
|
local redirect
|
2010-11-27 18:17:15 +00:00
|
|
|
local messages
|
2010-11-22 00:32:54 +00:00
|
|
|
local applymap = false
|
|
|
|
local pageaction = true
|
|
|
|
local parsechain = { }
|
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
for i, res in ipairs(maps) do
|
2010-11-22 00:32:54 +00:00
|
|
|
if res.apply_needed and res.parsechain then
|
|
|
|
local c
|
|
|
|
for _, c in ipairs(res.parsechain) do
|
|
|
|
parsechain[#parsechain+1] = c
|
|
|
|
end
|
|
|
|
applymap = true
|
2008-07-15 13:17:28 +00:00
|
|
|
end
|
2010-11-22 00:32:54 +00:00
|
|
|
|
2010-11-21 00:14:03 +00:00
|
|
|
if res.redirect then
|
|
|
|
redirect = redirect or res.redirect
|
|
|
|
end
|
2010-11-22 00:32:54 +00:00
|
|
|
|
|
|
|
if res.pageaction == false then
|
|
|
|
pageaction = false
|
|
|
|
end
|
2010-11-27 18:17:15 +00:00
|
|
|
|
|
|
|
if res.message then
|
|
|
|
messages = messages or { }
|
|
|
|
messages[#messages+1] = res.message
|
|
|
|
end
|
2008-03-02 21:52:58 +00:00
|
|
|
end
|
2010-11-22 00:32:54 +00:00
|
|
|
|
|
|
|
for i, res in ipairs(maps) do
|
|
|
|
res:render({
|
|
|
|
firstmap = (i == 1),
|
|
|
|
applymap = applymap,
|
|
|
|
redirect = redirect,
|
2010-11-27 18:17:15 +00:00
|
|
|
messages = messages,
|
2010-11-22 00:32:54 +00:00
|
|
|
pageaction = pageaction,
|
|
|
|
parsechain = parsechain
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2009-03-27 00:10:17 +00:00
|
|
|
if not config.nofooter then
|
2010-11-21 00:14:03 +00:00
|
|
|
tpl.render("cbi/footer", {
|
|
|
|
flow = config,
|
|
|
|
pageaction = pageaction,
|
|
|
|
redirect = redirect,
|
|
|
|
state = state,
|
|
|
|
autoapply = config.autoapply
|
|
|
|
})
|
2009-03-27 00:10:17 +00:00
|
|
|
end
|
2008-05-24 22:58:45 +00:00
|
|
|
end
|
2008-08-09 14:14:04 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
function cbi(model, config)
|
2015-10-20 18:58:30 +00:00
|
|
|
return {
|
|
|
|
type = "cbi",
|
|
|
|
post = { ["cbi.submit"] = "1" },
|
|
|
|
config = config,
|
|
|
|
model = model,
|
|
|
|
target = _cbi
|
|
|
|
}
|
2009-01-04 15:45:57 +00:00
|
|
|
end
|
2008-08-29 20:36:45 +00:00
|
|
|
|
2008-08-09 14:14:04 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local function _arcombine(self, ...)
|
|
|
|
local argv = {...}
|
|
|
|
local target = #argv > 0 and self.targets[2] or self.targets[1]
|
|
|
|
setfenv(target.target, self.env)
|
|
|
|
target:target(unpack(argv))
|
|
|
|
end
|
2008-10-20 22:35:11 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
function arcombine(trg1, trg2)
|
|
|
|
return {type = "arcombine", env = getfenv(), target = _arcombine, targets = {trg1, trg2}}
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local function _form(self, ...)
|
|
|
|
local cbi = require "luci.cbi"
|
|
|
|
local tpl = require "luci.template"
|
|
|
|
local http = require "luci.http"
|
2008-08-09 14:14:04 +00:00
|
|
|
|
2009-01-04 15:45:57 +00:00
|
|
|
local maps = luci.cbi.load(self.model, ...)
|
|
|
|
local state = nil
|
|
|
|
|
|
|
|
for i, res in ipairs(maps) do
|
|
|
|
local cstate = res:parse()
|
2009-03-07 16:28:27 +00:00
|
|
|
if cstate and (not state or cstate < state) then
|
2009-01-04 15:45:57 +00:00
|
|
|
state = cstate
|
2008-08-09 14:14:04 +00:00
|
|
|
end
|
|
|
|
end
|
2009-01-04 15:45:57 +00:00
|
|
|
|
|
|
|
http.header("X-CBI-State", state or 0)
|
|
|
|
tpl.render("header")
|
|
|
|
for i, res in ipairs(maps) do
|
|
|
|
res:render()
|
|
|
|
end
|
|
|
|
tpl.render("footer")
|
|
|
|
end
|
|
|
|
|
|
|
|
function form(model)
|
2015-10-20 18:58:30 +00:00
|
|
|
return {
|
|
|
|
type = "cbi",
|
|
|
|
post = { ["cbi.submit"] = "1" },
|
|
|
|
model = model,
|
|
|
|
target = _form
|
|
|
|
}
|
2008-08-09 14:14:04 +00:00
|
|
|
end
|
2011-08-12 11:13:39 +00:00
|
|
|
|
|
|
|
translate = i18n.translate
|
2011-08-12 13:11:29 +00:00
|
|
|
|
|
|
|
-- This function does not actually translate the given argument but
|
|
|
|
-- is used by build/i18n-scan.pl to find translatable entries.
|
|
|
|
function _(text)
|
|
|
|
return text
|
|
|
|
end
|