diff options
author | Steven Barth <steven@midlink.org> | 2008-06-14 14:12:12 +0000 |
---|---|---|
committer | Steven Barth <steven@midlink.org> | 2008-06-14 14:12:12 +0000 |
commit | 855b7582d3576f45693e3a48fdb253c813cf4dce (patch) | |
tree | b912f63dc43f3b696385083542c801dba8c53976 /libs/web | |
parent | 50fd29841540bb8b1735291b72853454679e9e62 (diff) |
* Rewrote Luci to be coroutine-safe allowing the use of non-forking webservers
* Setting base version to 0.7
Diffstat (limited to 'libs/web')
-rw-r--r-- | libs/web/luasrc/dispatcher.lua | 116 | ||||
-rw-r--r-- | libs/web/luasrc/http.lua | 136 | ||||
-rw-r--r-- | libs/web/luasrc/i18n.lua | 29 | ||||
-rw-r--r-- | libs/web/luasrc/template.lua | 14 |
4 files changed, 217 insertions, 78 deletions
diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua index 64355439b..8516c6f1b 100644 --- a/libs/web/luasrc/dispatcher.lua +++ b/libs/web/luasrc/dispatcher.lua @@ -34,21 +34,10 @@ if (os.time() < 1000000000) then os.execute('date -s '..os.date('%m%d%H%M%Y', luci.fs.mtime(luci.sys.libpath() .. "/dispatcher.lua"))..' > /dev/null 2>&1') end --- Local dispatch database -local tree = {nodes={}} +context = luci.util.threadlocal() -- Index table -local index = {} - --- Global request object -request = {} - --- Active dispatched node -dispatched = nil - --- Status fields -built_index = false -built_tree = false +local index = nil -- Fastindex local fi @@ -64,9 +53,9 @@ function error401(message) message = message or "Unauthorized" require("luci.template") - if not pcall(luci.template.render, "error401") then + if not luci.util.copcall(luci.template.render, "error401") then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end @@ -77,9 +66,9 @@ function error404(message) message = message or "Not Found" require("luci.template") - if not pcall(luci.template.render, "error404") then + if not luci.util.copcall(luci.template.render, "error404") then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end @@ -89,31 +78,39 @@ function error500(message) luci.http.status(500, "Internal Server Error") require("luci.template") - if not pcall(luci.template.render, "error500", {message=message}) then + if not luci.util.copcall(luci.template.render, "error500", {message=message}) then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end -- Creates a request object for dispatching -function httpdispatch() - local pathinfo = luci.http.env.PATH_INFO or "" +function httpdispatch(request) + luci.http.context.request = request + context.request = {} + local pathinfo = request.env.PATH_INFO or "" for node in pathinfo:gmatch("[^/]+") do - table.insert(request, node) + table.insert(context.request, node) end - dispatch() + dispatch(context.request) + luci.http.close() end -- Dispatches a request -function dispatch() - if not built_tree then +function dispatch(request) + context.path = request + + require("luci.i18n") + luci.i18n.setlanguage(require("luci.config").main.lang) + + if not context.tree then createtree() end - - local c = tree + + local c = context.tree local track = {} for i, s in ipairs(request) do @@ -131,6 +128,7 @@ function dispatch() local accs = track.sysauth accs = (type(accs) == "string") and {accs} or accs + --[[ local function sysauth(user, password) return (luci.util.contains(accs, user) and luci.sys.user.checkpasswd(user, password)) @@ -140,6 +138,7 @@ function dispatch() error401() return end + ]]-- end if track.i18n then @@ -156,22 +155,24 @@ function dispatch() -- Init template engine local tpl = require("luci.template") - tpl.viewns.translate = function(...) return require("luci.i18n").translate(...) end - tpl.viewns.controller = luci.http.dispatcher() - tpl.viewns.uploadctrl = luci.http.dispatcher_upload() -- DEPRECATED - tpl.viewns.media = luci.config.main.mediaurlbase - tpl.viewns.resource = luci.config.main.resourcebase - tpl.viewns.REQUEST_URI = luci.http.env.SCRIPT_NAME .. (luci.http.env.PATH_INFO or "") + local viewns = {} + tpl.context.viewns = viewns + viewns.write = luci.http.write + viewns.translate = function(...) return require("luci.i18n").translate(...) end + viewns.controller = luci.http.getenv("SCRIPT_NAME") + viewns.media = luci.config.main.mediaurlbase + viewns.resource = luci.config.main.resourcebase + viewns.REQUEST_URI = luci.http.getenv("SCRIPT_NAME") .. (luci.http.getenv("PATH_INFO") or "") if c and type(c.target) == "function" then - dispatched = c - stat, mod = pcall(require, c.module) + context.dispatched = c + stat, mod = luci.util.copcall(require, c.module) if stat then luci.util.updfenv(c.target, mod) end - stat, err = pcall(c.target) + stat, err = luci.util.copcall(c.target) if not stat then error500(err) end @@ -182,21 +183,20 @@ end -- Generates the dispatching tree function createindex() - index = {} local path = luci.sys.libpath() .. "/controller/" local suff = ".lua" - if pcall(require, "luci.fastindex") then + if luci.util.copcall(require, "luci.fastindex") then createindex_fastindex(path, suff) else createindex_plain(path, suff) end - - built_index = true end -- Uses fastindex to create the dispatching tree -function createindex_fastindex(path, suffix) +function createindex_fastindex(path, suffix) + index = {} + if not fi then fi = luci.fastindex.new("index") fi.add(path .. "*" .. suffix) @@ -212,9 +212,7 @@ end -- Calls the index function of all available controllers -- Fallback for transition purposes / Leave it in as long as it works otherwise throw it away function createindex_plain(path, suffix) - if built_index then - return - end + index = {} local cache = nil @@ -246,7 +244,7 @@ function createindex_plain(path, suffix) end if not cache or stime > ctime then - stat, mod = pcall(require, module) + stat, mod = luci.util.copcall(require, module) if stat and mod and type(mod.index) == "function" then index[module] = mod.index @@ -263,10 +261,11 @@ end -- Creates the dispatching tree from the index function createtree() - if not built_index then + if not index then createindex() end + context.tree = {nodes={}} require("luci.i18n") -- Load default translation @@ -283,14 +282,12 @@ function createtree() scope._NAME = k setfenv(v, scope) - local stat, err = pcall(v) + local stat, err = luci.util.copcall(v) if not stat then error500(err) os.exit(1) end end - - built_tree = true end -- Reassigns a node to another position @@ -302,7 +299,7 @@ function assign(path, clone, title, order) obj.title = title obj.order = order - local c = tree + local c = context.tree for k, v in ipairs(clone) do if not c.nodes[v] then c.nodes[v] = {nodes={}} @@ -330,8 +327,7 @@ end -- Fetch a dispatching node function node(...) - local c = tree - + local c = context.tree arg.n = nil if arg[1] then if type(arg[1]) == "table" then @@ -357,8 +353,7 @@ end function alias(...) local req = arg return function() - request = req - dispatch() + dispatch(req) end end @@ -366,19 +361,20 @@ function rewrite(n, ...) local req = arg return function() for i=1,n do - table.remove(request, 1) + table.remove(context.path, 1) end for i,r in ipairs(req) do - table.insert(request, i, r) + table.insert(context.path, i, r) end dispatch() end end -function call(name) - return function() getfenv()[name]() end +function call(name, ...) + local argv = {...} + return function() return getfenv()[name](unpack(argv)) end end function template(name) @@ -391,13 +387,13 @@ function cbi(model) require("luci.template") return function() - local stat, res = pcall(luci.cbi.load, model) + local stat, res = luci.util.copcall(luci.cbi.load, model) if not stat then error500(res) return true end - local stat, err = pcall(res.parse, res) + local stat, err = luci.util.copcall(res.parse, res) if not stat then error500(err) return true diff --git a/libs/web/luasrc/http.lua b/libs/web/luasrc/http.lua index 3bff28add..8ee864ac7 100644 --- a/libs/web/luasrc/http.lua +++ b/libs/web/luasrc/http.lua @@ -28,13 +28,141 @@ limitations under the License. ]]-- module("luci.http", package.seeall) +require("luci.util") +context = luci.util.threadlocal() -if ENV and ENV.HASERLVER then - require("luci.sgi.haserl") -elseif webuci then - require("luci.sgi.webuci") + +Request = luci.util.class() +function Request.__init__(self) + self.headers = {} + self.request = {} + self.uploads = {} + self.env = {} + self.data = "" +end + +function Request.formvalue(self, name, default) + return self.request[name] or default +end + +function Request.formvalues(self) + return self.request +end + +function Request.formvaluetable(self, prefix) + local vals = {} + prefix = prefix and prefix .. "." or "." + + for k, v in pairs(self.request) do + if k:find(prefix, 1, true) == 1 then + vals[k:sub(#prefix + 1)] = v + end + end + + return vals +end + +function Request.getenv(self, name) + return self.env[name] +end + +function Request.upload(self, name) + return self.uploads[name] +end + + +function close() + if not context.eoh then + context.eoh = true + coroutine.yield(3) + end + + if not context.closed then + context.closed = true + coroutine.yield(5) + end +end + +function formvalue(...) + return context.request:formvalue(...) +end + +function formvalues(...) + return context.request:formvalues(...) +end + +function formvaluetable(...) + return context.request:formvaluetable(...) end +function getenv(...) + return context.request:getenv(...) +end + +function header(key, value) + if not context.status then + status() + end + if not context.headers then + context.headers = {} + end + context.headers[key:lower()] = value + coroutine.yield(2, key, value) +end + +function prepare_content(mime) + header("Content-Type", mime) +end + +function status(code, message) + code = code or 200 + message = message or "OK" + context.status = code + coroutine.yield(1, code, message) +end + +function write(content) + if not content or #content == 0 then + return + end + if not context.eoh then + if not context.status then + status() + end + if not context.headers or not context.headers["content-type"] then + header("Content-Type", "text/html; charset=utf-8") + end + + context.eoh = true + coroutine.yield(3) + end + coroutine.yield(4, content) +end + + +function basic_auth(realm, errorpage) + header("Status", "401 Unauthorized") + header("WWW-Authenticate", string.format('Basic realm="%s"', realm or "")) + + if errorpage then + errorpage() + end + + close() +end + +function redirect(url) + header("Status", "302 Found") + header("Location", url) + close() +end + +function upload(...) + return context.request:upload(...) +end + + + function build_querystring(table) local s="?" diff --git a/libs/web/luasrc/i18n.lua b/libs/web/luasrc/i18n.lua index 3ed1ce017..35ad0965d 100644 --- a/libs/web/luasrc/i18n.lua +++ b/libs/web/luasrc/i18n.lua @@ -30,6 +30,8 @@ require("luci.sys") table = {} i18ndir = luci.sys.libpath() .. "/i18n/" loaded = {} +context = luci.util.threadlocal() +default = "en" -- Clears the translation table function clear() @@ -37,13 +39,17 @@ function clear() end -- Loads a translation and copies its data into the global translation table -function load(file, force) - if force or not loaded[file] then - local f = loadfile(i18ndir..file..".lua") or loadfile(i18ndir..file) +function load(file, lang, force) + lang = lang or "" + if force or not loaded[lang] or not loaded[lang][file] then + local f = loadfile(i18ndir .. file .. "." .. lang .. ".lua") + or loadfile(i18ndir .. file .. "." .. lang) if f then - setfenv(f, table) + table[lang] = table[lang] or {} + setfenv(f, table[lang]) f() - loaded[file] = true + loaded[lang] = loaded[lang] or {} + loaded[lang][file] = true return true else return false @@ -55,13 +61,20 @@ end -- Same as load but autocompletes the filename with .LANG from config.lang function loadc(file, force) - load(file .. ".en", force) - return load(file .. "." .. require("luci.config").main.lang, force) + load(file, default, force) + return load(file, context.lang, force) +end + +-- Sets the context language +function setlanguage(lang) + context.lang = lang end -- Returns the i18n-value defined by "key" or if there is no such: "default" function translate(key, default) - return table[key] or default + return (table[context.lang] and table[context.lang][key]) + or (table[default] and table[default][key]) + or default end -- Translate shourtcut with sprintf/string.format inclusion diff --git a/libs/web/luasrc/template.lua b/libs/web/luasrc/template.lua index 61e4e39ec..29aedcdad 100644 --- a/libs/web/luasrc/template.lua +++ b/libs/web/luasrc/template.lua @@ -44,9 +44,10 @@ compiler_mode = luci.config.template.compiler_mode or "memory" -- Define the namespace for template modules +context = luci.util.threadlocal() + viewns = { - write = io.write, - include = function(name) Template(name):render(getfenv(2)) end, + include = function(name) Template(name):render(getfenv(2)) end, } -- Compiles a given template into an executable Lua module @@ -113,7 +114,7 @@ end -- Oldstyle render shortcut function render(name, scope, ...) scope = scope or getfenv(2) - local s, t = pcall(Template, name) + local s, t = luci.util.copcall(Template, name) if not s then error(t) else @@ -141,9 +142,10 @@ function Template.__init__(self, name) self.viewns = {} -- Copy over from general namespace - for k, v in pairs(viewns) do - self.viewns[k] = v - end + luci.util.update(self.viewns, viewns) + if context.viewns then + luci.util.update(self.viewns, context.viewns) + end -- If we have a cached template, skip compiling and loading if self.template then |