summaryrefslogtreecommitdiffhomepage
path: root/core/src/dispatcher.lua
diff options
context:
space:
mode:
authorSteven Barth <steven@midlink.org>2008-05-22 14:04:03 +0000
committerSteven Barth <steven@midlink.org>2008-05-22 14:04:03 +0000
commit6604399aa8f35d33c53a5e5a1fea765f401aef5e (patch)
treeed818d630634a98a8996a1ba6d10e63bbea17c39 /core/src/dispatcher.lua
parentf738eb786e3d30028310c7bcc447e7e7b63767e0 (diff)
Merge branch 'menu'
Diffstat (limited to 'core/src/dispatcher.lua')
-rw-r--r--core/src/dispatcher.lua309
1 files changed, 100 insertions, 209 deletions
diff --git a/core/src/dispatcher.lua b/core/src/dispatcher.lua
index 0a66ccd3ad..84c665edab 100644
--- a/core/src/dispatcher.lua
+++ b/core/src/dispatcher.lua
@@ -4,63 +4,6 @@ FFLuCI - Dispatcher
Description:
The request dispatcher and module dispatcher generators
-
-The dispatching process:
- For a detailed explanation of the dispatching process we assume:
- You have installed the FFLuCI CGI-Dispatcher in /cgi-bin/ffluci
-
- To enforce a higher level of security only the CGI-Dispatcher
- resides inside the web server's document root, everything else
- stays inside an external directory, we assume this is /lua/ffluci
- for this explanation.
-
- All controllers and action are reachable as sub-objects of /cgi-bin/ffluci
- as if they were virtual folders and files
- e.g.: /cgi-bin/ffluci/public/info/about
- /cgi-bin/ffluci/admin/network/interfaces
- and so on.
-
- The PATH_INFO variable holds the dispatch path and
- will be split into three parts: /category/module/action
-
- Category: This is the category in which modules are stored in
- By default there are two categories:
- "public" - which is the default public category
- "admin" - which is the default protected category
-
- As FFLuCI itself does not implement authentication
- you should make sure that "admin" and other sensitive
- categories are protected by the webserver.
-
- E.g. for busybox add a line like:
- /cgi-bin/ffluci/admin:root:$p$root
- to /etc/httpd.conf to protect the "admin" category
-
-
- Module: This is the controller which will handle the request further
- It is always a submodule of ffluci.controller, so a module
- called "helloworld" will be stored in
- /lua/ffluci/controller/helloworld.lua
- You are free to submodule your controllers any further.
-
- Action: This is action that will be invoked after loading the module.
- The kind of how the action will be dispatched depends on
- the module dispatcher that is defined in the controller.
- See the description of the default module dispatcher down
- on this page for some examples.
-
-
- The main dispatcher at first searches for the module by trying to
- include ffluci.controller.category.module
- (where "category" is the category name and "module" is the module name)
- If this fails a 404 status code will be send to the client and FFLuCI exits
-
- Then the main dispatcher calls the module dispatcher
- ffluci.controller.category.module.dispatcher with the request object
- as the only argument. The module dispatcher is then responsible
- for the further dispatching process.
-
-
FileId:
$Id$
@@ -80,48 +23,24 @@ See the License for the specific language governing permissions and
limitations under the License.
]]--
-
module("ffluci.dispatcher", package.seeall)
require("ffluci.http")
-require("ffluci.template")
-require("ffluci.config")
require("ffluci.sys")
+require("ffluci.fs")
--- Sets privilege for given category
-function assign_privileges(category)
- local cp = ffluci.config.category_privileges
- if cp and cp[category] then
- local u, g = cp[category]:match("([^:]+):([^:]+)")
- ffluci.sys.process.setuser(u)
- ffluci.sys.process.setgroup(g)
- end
-end
+-- Local dispatch database
+local tree = {nodes={}}
+-- Global request object
+request = {}
--- Builds a URL from a triple of category, module and action
-function build_url(category, module, action)
- category = category or "public"
- module = module or "index"
- action = action or "index"
-
- local pattern = ffluci.http.dispatcher() .. "/%s/%s/%s"
- return pattern:format(category, module, action)
-end
+-- Active dispatched node
+dispatched = nil
--- Dispatches the "request"
-function dispatch(req)
- request = req
- local m = "ffluci.controller." .. request.category .. "." .. request.module
- local stat, module = pcall(require, m)
- if not stat then
- return error404()
- else
- module.request = request
- module.dispatcher = module.dispatcher or dynamic
- setfenv(module.dispatcher, module)
- return module.dispatcher(request)
- end
+-- Builds a URL
+function build_url(...)
+ return ffluci.http.dispatcher() .. "/" .. table.concat(arg, "/")
end
-- Sends a 404 error code and renders the "error404" template if available
@@ -129,6 +48,7 @@ function error404(message)
ffluci.http.status(404, "Not Found")
message = message or "Not Found"
+ require("ffluci.template")
if not pcall(ffluci.template.render, "error404") then
ffluci.http.prepare_content("text/plain")
print(message)
@@ -140,6 +60,7 @@ end
function error500(message)
ffluci.http.status(500, "Internal Server Error")
+ require("ffluci.template")
if not pcall(ffluci.template.render, "error500", {message=message}) then
ffluci.http.prepare_content("text/plain")
print(message)
@@ -147,154 +68,124 @@ function error500(message)
return false
end
-
-- Dispatches a request depending on the PATH_INFO variable
function httpdispatch()
local pathinfo = ffluci.http.env.PATH_INFO or ""
- local parts = pathinfo:gmatch("/[%w-]+")
+ local c = tree
- local sanitize = function(s, default)
- return s and s:sub(2) or default
+ for s in pathinfo:gmatch("/([%w-]+)") do
+ table.insert(request, s)
end
- local cat = sanitize(parts(), "public")
- local mod = sanitize(parts(), "index")
- local act = sanitize(parts(), "index")
-
- assign_privileges(cat)
- dispatch({category=cat, module=mod, action=act})
-end
-
-
--- Dispatchers --
-
-
--- The Action Dispatcher searches the module for any function called
--- action_"request.action" and calls it
-function action(...)
- local disp = require("ffluci.dispatcher")
- if not disp._action(...) then
- disp.error404()
- end
+ dispatch()
end
--- The CBI dispatcher directly parses and renders the CBI map which is
--- placed in ffluci/modles/cbi/"request.module"/"request.action"
-function cbi(...)
- local disp = require("ffluci.dispatcher")
- if not disp._cbi(...) then
- disp.error404()
+function dispatch()
+ local c = tree
+ local track = {}
+
+ for i, s in ipairs(request) do
+ c = c.nodes[s]
+ if not c then
+ break
+ end
+
+ for k, v in pairs(c) do
+ track[k] = v
+ end
end
-end
-
--- The dynamic dispatcher chains the action, submodule, simpleview and CBI dispatcher
--- in this particular order. It is the default dispatcher.
-function dynamic(...)
- local disp = require("ffluci.dispatcher")
- if not disp._action(...)
- and not disp._submodule(...)
- and not disp._simpleview(...)
- and not disp._cbi(...) then
- disp.error404()
+
+
+ if track.i18n then
+ require("ffluci.i18n").loadc(track.i18n)
end
-end
-
--- The Simple View Dispatcher directly renders the template
--- which is placed in ffluci/views/"request.module"/"request.action"
-function simpleview(...)
- local disp = require("ffluci.dispatcher")
- if not disp._simpleview(...) then
- disp.error404()
+
+ if track.setuser then
+ ffluci.sys.process.setuser(track.setuser)
end
-end
-
-
--- The submodule dispatcher tries to load a submodule of the controller
--- and calls its "action"-function
-function submodule(...)
- local disp = require("ffluci.dispatcher")
- if not disp._submodule(...) then
- disp.error404()
+
+ if track.setgroup then
+ ffluci.sys.process.setgroup(track.setgroup)
end
-end
-
-
--- Internal Dispatcher Functions --
-
-function _action(request)
- local action = getfenv(2)["action_" .. request.action:gsub("-", "_")]
- local i18n = require("ffluci.i18n")
- if action then
- i18n.loadc(request.category .. "_" .. request.module)
- i18n.loadc(request.category .. "_" .. request.module .. "_" .. request.action)
- action()
- return true
+
+ if c and type(c.target) == "function" then
+ dispatched = c
+
+ stat, err = pcall(c.target)
+ if not stat then
+ error500(err)
+ end
else
- return false
+ error404()
end
end
-function _cbi(request)
- local disp = require("ffluci.dispatcher")
- local tmpl = require("ffluci.template")
- local cbi = require("ffluci.cbi")
- local i18n = require("ffluci.i18n")
-
- local path = request.category.."_"..request.module.."/"..request.action
+-- Calls the index function of all available controllers
+function createindex()
+ local root = ffluci.sys.libpath() .. "/controller/"
+ local suff = ".lua"
+ for i,c in ipairs(ffluci.fs.glob(root .. "*/*" .. suff)) do
+ c = "ffluci.controller." .. c:sub(#root+1, #c-#suff):gsub("/", ".", 1)
+ stat, mod = pcall(require, c)
- local stat, map = pcall(cbi.load, path)
- if stat and map then
- local stat, err = pcall(map.parse, map)
- if not stat then
- disp.error500(err)
- return true
+ if stat and mod and type(mod.index) == "function" then
+ ffluci.util.updfenv(mod.index, ffluci.dispatcher)
+ pcall(mod.index)
end
- i18n.loadc(request.category .. "_" .. request.module)
- i18n.loadc(request.category .. "_" .. request.module .. "_" .. request.action)
- tmpl.render("cbi/header")
- map:render()
- tmpl.render("cbi/footer")
- return true
- elseif not stat then
- disp.error500(map)
- return true
- else
- return false
end
end
-function _simpleview(request)
- local i18n = require("ffluci.i18n")
- local tmpl = require("ffluci.template")
+-- Fetch a dispatching node
+function node(...)
+ local c = tree
- local path = request.category.."_"..request.module.."/"..request.action
+ for k,v in ipairs(arg) do
+ if not c.nodes[v] then
+ c.nodes[v] = {nodes={}}
+ end
+
+ c = c.nodes[v]
+ end
- local stat, t = pcall(tmpl.Template, path)
- if stat then
- i18n.loadc(request.category .. "_" .. request.module)
- i18n.loadc(request.category .. "_" .. request.module .. "_" .. request.action)
- t:render()
- return true
- else
- return false
+ return c
+end
+
+-- Subdispatchers --
+function alias(...)
+ local req = arg
+ return function()
+ request = req
+ dispatch()
end
end
+function template(name)
+ require("ffluci.template")
+ return function() ffluci.template.render(name) end
+end
-function _submodule(request)
- local i18n = require("ffluci.i18n")
- local m = "ffluci.controller." .. request.category .. "." ..
- request.module .. "." .. request.action
- local stat, module = pcall(require, m)
+function cbi(model)
+ require("ffluci.cbi")
+ require("ffluci.template")
- if stat and module.action then
- i18n.loadc(request.category .. "_" .. request.module)
- i18n.loadc(request.category .. "_" .. request.module .. "_" .. request.action)
- return pcall(module.action)
+ return function()
+ local stat, res = pcall(ffluci.cbi.load, model)
+ if not stat then
+ error500(res)
+ return true
+ end
+
+ local stat, err = pcall(res.parse, res)
+ if not stat then
+ error500(err)
+ return true
+ end
+
+ ffluci.template.render("cbi/header")
+ res:render()
+ ffluci.template.render("cbi/footer")
end
-
- return false
end \ No newline at end of file