X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=modules%2Fluci-base%2Fluasrc%2Fdispatcher.lua;h=6d5a8f4d3db655680a626aa44bc0938357e1c624;hb=b9dd1c951c85ada6f9ba9781e1a85e6503b34b26;hp=1b684aa79c93271fca9a0f02511451d6af212d88;hpb=6d9fd0aeb7dd3081ec7c6359c76a896f503113ef;p=oweals%2Fluci.git diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua index 1b684aa79..6d5a8f4d3 100644 --- a/modules/luci-base/luasrc/dispatcher.lua +++ b/modules/luci-base/luasrc/dispatcher.lua @@ -75,11 +75,16 @@ function error404(message) http.status(404, "Not Found") message = message or "Not Found" - require("luci.template") - if not util.copcall(luci.template.render, "error404") then + local function render() + local template = require "luci.template" + template.render("error404") + end + + if not util.copcall(render) then http.prepare_content("text/plain") http.write(message) end + return false end @@ -113,7 +118,8 @@ function httpdispatch(request, prefix) end end - for node in pathinfo:gmatch("[^/]+") do + local node + for node in pathinfo:gmatch("[^/%z]+") do r[#r+1] = node end @@ -136,8 +142,7 @@ local function require_post_security(target) if (type(required_val) == "string" and request_val ~= required_val) or - (required_val == true and - (request_val == nil or request_val == "")) + (required_val == true and request_val == nil) then return false end @@ -177,6 +182,7 @@ local function session_retrieve(sid, allowed_users) (not allowed_users or util.contains(allowed_users, sdat.values.username)) then + uci:set_session_id(sid) return sid, sdat.values end @@ -191,6 +197,9 @@ local function session_setup(user, pass, allowed_users) timeout = tonumber(luci.config.sauth.sessiontime) }) + local rp = context.requestpath + and table.concat(context.requestpath, "/") or "" + if type(login) == "table" and type(login.ubus_rpc_session) == "string" then @@ -199,8 +208,14 @@ local function session_setup(user, pass, allowed_users) values = { token = sys.uniqueid(16) } }) + io.stderr:write("luci: accepted login on /%s for %s from %s\n" + %{ rp, user, http.getenv("REMOTE_ADDR") or "?" }) + return session_retrieve(login.ubus_rpc_session) end + + io.stderr:write("luci: failed login on /%s for %s from %s\n" + %{ rp, user, http.getenv("REMOTE_ADDR") or "?" }) end return nil, nil @@ -219,10 +234,19 @@ function dispatch(request) 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 - lpat = lpat and lpat:gsub("-", "_") - if conf.languages[lpat] then - lang = lpat + for aclang in aclang:gmatch("[%w_-]+") do + local country, culture = aclang:match("^([a-z][a-z])[_-]([a-zA-Z][a-zA-Z])$") + if country and culture then + local cc = "%s_%s" %{ country, culture:lower() } + if conf.languages[cc] then + lang = cc + break + elseif conf.languages[country] then + lang = country + break + end + elseif conf.languages[aclang] then + lang = aclang break end end @@ -328,15 +352,23 @@ function dispatch(request) ifattr = function(...) return _ifattr(...) end; attr = function(...) return _ifattr(true, ...) end; url = build_url; - }, {__index=function(table, key) + }, {__index=function(tbl, key) if key == "controller" then return build_url() elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) + elseif key == "FULL_REQUEST_URI" then + local url = { http.getenv("SCRIPT_NAME") or "", http.getenv("PATH_INFO") } + local query = http.getenv("QUERY_STRING") + if query and #query > 0 then + url[#url+1] = "?" + url[#url+1] = query + end + return table.concat(url, "") elseif key == "token" then return ctx.authtoken else - return rawget(table, key) or _G[key] + return rawget(tbl, key) or _G[key] end end}) end @@ -349,7 +381,7 @@ function dispatch(request) "https://github.com/openwrt/luci/issues" ) - if track.sysauth then + if track.sysauth and not ctx.authsession then local authen = track.sysauth_authenticator local _, sid, sdat, default_user, allowed_users @@ -397,7 +429,9 @@ function dispatch(request) return end - http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() }) + http.header("Set-Cookie", 'sysauth=%s; path=%s; HttpOnly%s' %{ + sid, build_url(), http.getenv("HTTPS") == "on" and "; secure" or "" + }) http.redirect(build_url(unpack(ctx.requestpath))) end @@ -411,6 +445,13 @@ function dispatch(request) ctx.authuser = sdat.username end + if track.cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then + luci.http.status(200, "OK") + luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*") + luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + return + end + if c and require_post_security(c.target) then if not test_post_security(c) then return @@ -466,10 +507,11 @@ function dispatch(request) else ok, err = util.copcall(target, unpack(args)) end - 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)")) + if not ok then + error500("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)")) + end else local root = node() if not root or not root.target then @@ -632,6 +674,23 @@ function node(...) return c end +function lookup(...) + local i, path = nil, {} + for i = 1, select('#', ...) do + local name, arg = nil, tostring(select(i, ...)) + for name in arg:gmatch("[^/]+") do + path[#path+1] = name + end + end + + for i = #path, 1, -1 do + local node = context.treecache[table.concat(path, ".", 1, i)] + if node and (i == #path or node.leaf) then + return node, build_url(unpack(path)) + end + end +end + function _create_node(path) if #path == 0 then return context.tree @@ -644,15 +703,22 @@ function _create_node(path) local last = table.remove(path) local parent = _create_node(path) - c = {nodes={}, auto=true} - -- 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 + c = {nodes={}, auto=true, inreq=true} + + local _, n + for _, n in ipairs(path) do + if context.path[_] ~= n then + c.inreq = false + break + end end + + c.inreq = c.inreq and (context.path[#path + 1] == last) + parent.nodes[last] = c context.treecache[name] = c end + return c end @@ -773,7 +839,16 @@ local function _cbi(self, ...) local state = nil + local i, res for i, res in ipairs(maps) do + if util.instanceof(res, cbi.SimpleForm) then + io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n" + % self.model) + + io.stderr:write("please change %s to use the form() action instead.\n" + % table.concat(context.request, "/")) + end + res.flow = config local cstate = res:parse() if cstate and (not state or cstate < state) then @@ -818,6 +893,8 @@ local function _cbi(self, ...) local pageaction = true local parsechain = { } + local is_rollback, time_remaining = uci:rollback_pending() + for i, res in ipairs(maps) do if res.apply_needed and res.parsechain then local c @@ -845,6 +922,7 @@ local function _cbi(self, ...) res:render({ firstmap = (i == 1), applymap = applymap, + confirmmap = (is_rollback and time_remaining or nil), redirect = redirect, messages = messages, pageaction = pageaction, @@ -866,7 +944,7 @@ end function cbi(model, config) return { type = "cbi", - post = { ["cbi.submit"] = "1" }, + post = { ["cbi.submit"] = true }, config = config, model = model, target = _cbi @@ -894,6 +972,7 @@ local function _form(self, ...) local maps = luci.cbi.load(self.model, ...) local state = nil + local i, res for i, res in ipairs(maps) do local cstate = res:parse() if cstate and (not state or cstate < state) then @@ -912,7 +991,7 @@ end function form(model) return { type = "cbi", - post = { ["cbi.submit"] = "1" }, + post = { ["cbi.submit"] = true }, model = model, target = _form }