luci-0.9: merge r5130-r5143

This commit is contained in:
Jo-Philipp Wich 2009-07-26 21:28:44 +00:00
parent c2eb3ea4a5
commit a545e495ba
13 changed files with 247 additions and 101 deletions

View file

@ -176,6 +176,15 @@ end
-- @return Number containing the os specific errno on error -- @return Number containing the os specific errno on error
rmdir = fs.rmdir rmdir = fs.rmdir
local stat_tr = {
reg = "regular",
dir = "directory",
lnk = "link",
chr = "character device",
blk = "block device",
fifo = "fifo",
sock = "socket"
}
--- Get information about given file or directory. --- Get information about given file or directory.
-- @class function -- @class function
-- @name stat -- @name stat
@ -183,7 +192,14 @@ rmdir = fs.rmdir
-- @return Table containing file or directory properties or nil on error -- @return Table containing file or directory properties or nil on error
-- @return String containing the error description on error -- @return String containing the error description on error
-- @return Number containing the os specific errno on error -- @return Number containing the os specific errno on error
stat = fs.stat function stat(path, key)
local data, code, msg = fs.stat(path)
if data then
data.mode = data.modestr
data.type = stat_tr[data.type] or "?"
end
return key and data and data[key] or data, code, msg
end
--- Set permissions on given file or directory. --- Set permissions on given file or directory.
-- @class function -- @class function

View file

@ -215,7 +215,7 @@ end
-- @param value String containing the HTML text -- @param value String containing the HTML text
-- @return String with HTML tags stripped of -- @return String with HTML tags stripped of
function striptags(s) function striptags(s)
return pcdata(s:gsub("</?[A-Za-z][A-Za-z0-9:_%-]*[^>]*>", " "):gsub("%s+", " ")) return pcdata(tostring(s):gsub("</?[A-Za-z][A-Za-z0-9:_%-]*[^>]*>", " "):gsub("%s+", " "))
end end
--- Splits given string on a defined separator sequence and return a table --- Splits given string on a defined separator sequence and return a table
@ -768,24 +768,19 @@ function copcall(f, ...)
end end
-- Handle return value of protected call -- Handle return value of protected call
function handleReturnValue(err, co, status, ...) function handleReturnValue(err, co, status, arg1, arg2, arg3, arg4, arg5)
if not status then if not status then
return false, err(debug.traceback(co, (...)), ...) return false, err(debug.traceback(co, arg1), arg1, arg2, arg3, arg4, arg5)
end end
if coroutine.status(co) == 'suspended' then
return performResume(err, co, coroutine.yield(...)) if coroutine.status(co) ~= 'suspended' then
else return true, arg1, arg2, arg3, arg4, arg5
return true, ...
end end
return performResume(err, co, coroutine.yield(arg1, arg2, arg3, arg4, arg5))
end end
-- Resume execution of protected function call -- Resume execution of protected function call
function performResume(err, co, ...) function performResume(err, co, arg1, arg2, arg3, arg4, arg5)
if get_memory_limit and get_memory_limit() > 0 and return handleReturnValue(err, co, coroutine.resume(co, arg1, arg2, arg3, arg4, arg5))
collectgarbage("count") > (get_memory_limit() * 0.8)
then
collectgarbage("collect")
end
return handleReturnValue(err, co, coroutine.resume(co, ...))
end end

View file

@ -171,45 +171,62 @@ function request_to_file(uri, target, options, cbs)
cbs = cbs or {} cbs = cbs or {}
options.headers = options.headers or {} options.headers = options.headers or {}
local hdr = options.headers local hdr = options.headers
local file, code, msg
local file, code, msg = prepare_fd(target) if target then
if not file then file, code, msg = prepare_fd(target)
return file, code, msg if not file then
end return file, code, msg
end
local off = file:tell() local off = file:tell()
-- Set content range -- Set content range
if off > 0 then if off > 0 then
hdr.Range = hdr.Range or ("bytes=" .. off .. "-") hdr.Range = hdr.Range or ("bytes=" .. off .. "-")
end
end end
local code, resp, buffer, sock = httpc.request_raw(uri, options) local code, resp, buffer, sock = httpc.request_raw(uri, options)
if not code then if not code then
-- No success -- No success
file:close() if file then
file:close()
end
return code, resp, buffer return code, resp, buffer
elseif hdr.Range and code ~= 206 then elseif hdr.Range and code ~= 206 then
-- We wanted a part but we got the while file -- We wanted a part but we got the while file
sock:close() sock:close()
file:close() if file then
file:close()
end
return nil, -4, code, resp return nil, -4, code, resp
elseif not hdr.Range and code ~= 200 then elseif not hdr.Range and code ~= 200 then
-- We encountered an error -- We encountered an error
sock:close() sock:close()
file:close() if file then
file:close()
end
return nil, -4, code, resp return nil, -4, code, resp
end end
if cbs.on_header then if cbs.on_header then
local stat = {cbs.on_header(file, code, resp)} local stat = {cbs.on_header(file, code, resp)}
if stat[1] == false then if stat[1] == false then
file:close() if file then
file:close()
end
sock:close() sock:close()
return unpack(stat) return unpack(stat)
elseif stat[2] then
file = file and stat[2]
end end
end end
if not file then
return nil, -5, "no target given"
end
local chunked = resp.headers["Transfer-Encoding"] == "chunked" local chunked = resp.headers["Transfer-Encoding"] == "chunked"
local stat local stat

View file

@ -53,15 +53,40 @@ static int lmo_L_hash(lua_State *L) {
return 1; return 1;
} }
static lmo_luaentry_t *_lmo_push_entry(lua_State *L) {
lmo_luaentry_t *le;
if( (le = lua_newuserdata(L, sizeof(lmo_luaentry_t))) != NULL )
{
luaL_getmetatable(L, LMO_ENTRY_META);
lua_setmetatable(L, -2);
return le;
}
return NULL;
}
static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) { static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) {
lmo_entry_t *e = ar->index; lmo_entry_t *e = ar->index;
lmo_luaentry_t *le = NULL;
while( e != NULL ) while( e != NULL )
{ {
if( e->key_id == hash ) if( e->key_id == hash )
{ {
lua_pushlstring(L, &ar->mmap[e->offset], e->length); if( (le = _lmo_push_entry(L)) != NULL )
return 1; {
le->archive = ar;
le->entry = e;
return 1;
}
else
{
lua_pushnil(L);
lua_pushstring(L, "out of memory");
return 2;
}
} }
e = e->next; e = e->next;
@ -121,15 +146,69 @@ static int lmo_L__tostring(lua_State *L) {
} }
/* method table */ static int _lmo_convert_entry(lua_State *L, int idx) {
lmo_luaentry_t *le = luaL_checkudata(L, idx, LMO_ENTRY_META);
lua_pushlstring(L,
&le->archive->mmap[le->entry->offset],
le->entry->length
);
return 1;
}
static int lmo_L_entry__tostring(lua_State *L) {
return _lmo_convert_entry(L, 1);
}
static int lmo_L_entry__concat(lua_State *L) {
if( lua_isuserdata(L, 1) )
_lmo_convert_entry(L, 1);
else
lua_pushstring(L, lua_tostring(L, 1));
if( lua_isuserdata(L, 2) )
_lmo_convert_entry(L, 2);
else
lua_pushstring(L, lua_tostring(L, 2));
lua_concat(L, 2);
return 1;
}
static int lmo_L_entry__len(lua_State *L) {
lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
lua_pushinteger(L, le->entry->length);
return 1;
}
static int lmo_L_entry__gc(lua_State *L) {
lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
le->archive = NULL;
le->entry = NULL;
return 0;
}
/* lmo method table */
static const luaL_reg M[] = { static const luaL_reg M[] = {
{"close", lmo_L__gc}, {"close", lmo_L__gc},
{"get", lmo_L_get}, {"get", lmo_L_get},
{"lookup", lmo_L_lookup}, {"lookup", lmo_L_lookup},
{"foreach", lmo_L_foreach}, {"foreach", lmo_L_foreach},
{"__tostring", lmo_L__tostring}, {"__tostring", lmo_L__tostring},
{"__gc", lmo_L__gc}, {"__gc", lmo_L__gc},
{NULL, NULL} {NULL, NULL}
};
/* lmo.entry method table */
static const luaL_reg E[] = {
{"__tostring", lmo_L_entry__tostring},
{"__concat", lmo_L_entry__concat},
{"__len", lmo_L_entry__len},
{"__gc", lmo_L_entry__gc},
{NULL, NULL}
}; };
/* module table */ /* module table */
@ -146,6 +225,12 @@ LUALIB_API int luaopen_lmo(lua_State *L) {
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_setglobal(L, LMO_ARCHIVE_META); lua_setglobal(L, LMO_ARCHIVE_META);
luaL_newmetatable(L, LMO_ENTRY_META);
luaL_register(L, NULL, E);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_setglobal(L, LMO_ENTRY_META);
luaL_register(L, LMO_LUALIB_META, R); luaL_register(L, LMO_LUALIB_META, R);
return 1; return 1;

View file

@ -27,6 +27,15 @@
#define LMO_LUALIB_META "lmo" #define LMO_LUALIB_META "lmo"
#define LMO_ARCHIVE_META "lmo.archive" #define LMO_ARCHIVE_META "lmo.archive"
#define LMO_ENTRY_META "lmo.entry"
struct lmo_luaentry {
lmo_archive_t *archive;
lmo_entry_t *entry;
};
typedef struct lmo_luaentry lmo_luaentry_t;
LUALIB_API int luaopen_lmo(lua_State *L); LUALIB_API int luaopen_lmo(lua_State *L);

View file

@ -11,7 +11,6 @@ You may obtain a copy of the License at
$Id$ $Id$
]]-- ]]--
local cbi = require "luci.cbi"
local dsp = require "luci.dispatcher" local dsp = require "luci.dispatcher"
local util = require "luci.util" local util = require "luci.util"
local http = require "luci.http" local http = require "luci.http"
@ -27,8 +26,6 @@ Luci = util.class(srv.Handler)
function Luci.__init__(self, name, prefix) function Luci.__init__(self, name, prefix)
srv.Handler.__init__(self, name) srv.Handler.__init__(self, name)
self.prefix = prefix self.prefix = prefix
self.dsp_tree = dsp.createtree()
end end
function Luci.handle_HEAD(self, ...) function Luci.handle_HEAD(self, ...)
@ -53,7 +50,7 @@ function Luci.handle_GET(self, request, sourcein)
local x = coroutine.create(dsp.httpdispatch) local x = coroutine.create(dsp.httpdispatch)
while not id or id < 3 do while not id or id < 3 do
res, id, data1, data2 = coroutine.resume(x, r, self.prefix, self.dsp_tree) res, id, data1, data2 = coroutine.resume(x, r, self.prefix)
if not res then if not res then
status = 500 status = 500

View file

@ -117,6 +117,7 @@ function Handler.checkrestricted(self, request)
end end
if stat then if stat then
request.env.HTTP_AUTH_USER, request.env.HTTP_AUTH_PASS = user, pass
return return
end end
end end
@ -256,7 +257,7 @@ local function chunksink(sock)
if not chunk then if not chunk then
return sock:writeall("0\r\n\r\n") return sock:writeall("0\r\n\r\n")
else else
return sock:writeall(("%X\r\n%s\r\n"):format(#chunk, chunk)) return sock:writeall(("%X\r\n%s\r\n"):format(#chunk, tostring(chunk)))
end end
end end
end end
@ -460,7 +461,7 @@ function Server.process(self, client, env)
headers["Content-Length"] = sourceout.len headers["Content-Length"] = sourceout.len
end end
end end
if not headers["Content-Length"] then if not headers["Content-Length"] and not close then
if message.env.SERVER_PROTOCOL == "HTTP/1.1" then if message.env.SERVER_PROTOCOL == "HTTP/1.1" then
headers["Transfer-Encoding"] = "chunked" headers["Transfer-Encoding"] = "chunked"
sinkout = chunksink(client) sinkout = chunksink(client)
@ -504,8 +505,15 @@ function Server.process(self, client, env)
if sourceout and stat then if sourceout and stat then
if util.instanceof(sourceout, IOResource) then if util.instanceof(sourceout, IOResource) then
stat, code, msg = sourceout.fd:copyz(client, sourceout.len) if not headers["Transfer-Encoding"] then
else stat, code, msg = sourceout.fd:copyz(client, sourceout.len)
sourceout = nil
else
sourceout = sourceout.fd:blocksource(nil, sourceout.len)
end
end
if sourceout then
stat, msg = ltn12.pump.all(sourceout, sinkout) stat, msg = ltn12.pump.all(sourceout, sinkout)
end end
end end

View file

@ -110,7 +110,7 @@ function accept(polle)
end end
local socket, host, port = polle.fd:accept() local socket, host, port = polle.fd:accept()
if not socket then if not socket then
return nixio.syslog("warn", "accept() failed: " .. port) return nixio.syslog("warning", "accept() failed: " .. port)
end end
socket:setblocking(true) socket:setblocking(true)

View file

@ -25,6 +25,7 @@ limitations under the License.
]]-- ]]--
module("luci.sgi.cgi", package.seeall) module("luci.sgi.cgi", package.seeall)
local ltn12 = require("luci.ltn12") local ltn12 = require("luci.ltn12")
require("nixio.util")
require("luci.http") require("luci.http")
require("luci.sys") require("luci.sys")
require("luci.dispatcher") require("luci.dispatcher")
@ -84,6 +85,8 @@ function run()
io.flush() io.flush()
io.close() io.close()
active = false active = false
elseif id == 6 then
data1:copyz(nixio.stdout, data2)
end end
end end
end end

View file

@ -28,7 +28,7 @@ local string = require "string"
local require, pcall, ipairs, pairs = require, pcall, ipairs, pairs local require, pcall, ipairs, pairs = require, pcall, ipairs, pairs
local type, error, tonumber, tostring = type, error, tonumber, tostring local type, error, tonumber, tostring = type, error, tonumber, tostring
local unpack, loadfile = unpack, loadfile local unpack, loadfile, collectgarbage = unpack, loadfile, collectgarbage
module "luci.uvl" module "luci.uvl"
@ -43,6 +43,10 @@ local TYPE_SECTION = 0x02
local TYPE_OPTION = 0x03 local TYPE_OPTION = 0x03
local TYPE_ENUM = 0x04 local TYPE_ENUM = 0x04
local PAT_EXPR1 = "^%$?[%w_]+$"
local PAT_EXPR2 = "^%$?[%w_]+%.%$?[%w_]+$"
local PAT_EXPR3 = "^%$?[%w_]+%.%$?[%w_]+%.%$?[%w_]+$"
--- Boolean; default true; --- Boolean; default true;
-- treat sections found in config but not in scheme as error -- treat sections found in config but not in scheme as error
STRICT_UNKNOWN_SECTIONS = true STRICT_UNKNOWN_SECTIONS = true
@ -274,7 +278,7 @@ function UVL._validate_section( self, section )
if STRICT_UNKNOWN_OPTIONS and not section:scheme('dynamic') then if STRICT_UNKNOWN_OPTIONS and not section:scheme('dynamic') then
for k, v in pairs(section:config()) do for k, v in pairs(section:config()) do
local oo = section:option(k) local oo = section:option(k)
if k:sub(1,1) ~= "." and not self.beenthere[oo:cid()] then if k:byte(1) == 46 and not self.beenthere[oo:cid()] then
section:error(ERR.OPT_UNKNOWN(oo)) section:error(ERR.OPT_UNKNOWN(oo))
end end
end end
@ -542,7 +546,7 @@ function UVL._parse_section(self, scheme, k, v)
local so = scheme:section(v.name) local so = scheme:section(v.name)
for k, v2 in pairs(v) do for k, v2 in pairs(v) do
if k ~= "name" and k ~= "package" and k:sub(1,1) ~= "." then if k ~= "name" and k ~= "package" and k:byte(1) == 46 then
if k == "depends" then if k == "depends" then
s.depends = self:_read_dependency( v2, s.depends ) s.depends = self:_read_dependency( v2, s.depends )
if not s.depends then if not s.depends then
@ -595,7 +599,7 @@ function UVL._parse_var(self, scheme, k, v)
local to = so:option(v.name) local to = so:option(v.name)
for k, v2 in pairs(v) do for k, v2 in pairs(v) do
if k ~= "name" and k ~= "section" and k:sub(1,1) ~= "." then if k ~= "name" and k ~= "section" and k:byte(1) == 46 then
if k == "depends" then if k == "depends" then
t.depends = self:_read_dependency( v2, t.depends ) t.depends = self:_read_dependency( v2, t.depends )
if not t.depends then if not t.depends then
@ -718,9 +722,7 @@ function UVL._read_dependency( self, values, deps )
local k, e, v = val:match("%s*([%w$_.]+)%s*(=?)%s*(.*)") local k, e, v = val:match("%s*([%w$_.]+)%s*(=?)%s*(.*)")
if k and ( if k and (
k:match("^"..expr.."%."..expr.."%."..expr.."$") or k:match(PAT_EXPR1) or k:match(PAT_EXPR2) or k:match(PAT_EXPR3)
k:match("^"..expr.."%."..expr.."$") or
k:match("^"..expr.."$")
) then ) then
condition[k] = (e == '=') and v or true condition[k] = (e == '=') and v or true
else else
@ -752,8 +754,8 @@ function UVL._read_validator( self, values, validators )
validator = self:_resolve_function( (value:gsub("^lua:","") ) ) validator = self:_resolve_function( (value:gsub("^lua:","") ) )
elseif value:match("^regexp:") then elseif value:match("^regexp:") then
local pattern = value:gsub("^regexp:","") local pattern = value:gsub("^regexp:","")
validator = function( type, dtype, pack, sect, optn, ... ) validator = function( type, dtype, pack, sect, optn, arg1, arg2, arg3, arg4, arg5 )
local values = { ... } local values = { arg1, arg2, arg3, arg4, arg5 }
for _, v in ipairs(values) do for _, v in ipairs(values) do
local ok, match = local ok, match =
pcall( string.match, v, pattern ) pcall( string.match, v, pattern )
@ -920,13 +922,13 @@ function uvlitem.type(self)
end end
end end
function uvlitem.error(self, ...) function uvlitem.error(self, arg1, arg2, arg3, arg4, arg5)
if not self.e then if not self.e then
local errconst = { ERR.CONFIG, ERR.SECTION, ERR.OPTION, ERR.OPTION } local errconst = { ERR.CONFIG, ERR.SECTION, ERR.OPTION, ERR.OPTION }
self.e = errconst[#self.cref]( self ) self.e = errconst[#self.cref]( self )
end end
return self.e:child( ... ) return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end end
function uvlitem.errors(self) function uvlitem.errors(self)
@ -993,9 +995,9 @@ end
--- Add an error to scheme. --- Add an error to scheme.
-- @return Scheme error context -- @return Scheme error context
function scheme.error(self, ...) function scheme.error(self, arg1, arg2, arg3, arg4, arg5)
if not self.e then self.e = ERR.SCHEME( self ) end if not self.e then self.e = ERR.SCHEME( self ) end
return self.e:child( ... ) return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end end
--- Get an associated config object. --- Get an associated config object.

View file

@ -108,17 +108,25 @@ end
--- Dispatch an HTTP request. --- Dispatch an HTTP request.
-- @param request LuCI HTTP Request object -- @param request LuCI HTTP Request object
function httpdispatch(request, prefix, ext_tree) function httpdispatch(request, prefix)
luci.http.context.request = request luci.http.context.request = request
context.request = {}
local r = {}
context.request = r
local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true)
if prefix then
for _, node in ipairs(prefix) do
r[#r+1] = node
end
end
for node in pathinfo:gmatch("[^/]+") do for node in pathinfo:gmatch("[^/]+") do
table.insert(context.request, node) r[#r+1] = node
end end
local stat, err = util.coxpcall(function() local stat, err = util.coxpcall(function()
dispatch(context.request, ext_tree) dispatch(context.request)
end, error500) end, error500)
luci.http.close() luci.http.close()
@ -128,7 +136,7 @@ end
--- Dispatches a LuCI virtual path. --- Dispatches a LuCI virtual path.
-- @param request Virtual path -- @param request Virtual path
function dispatch(request, ext_tree) function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace("l") --context._disable_memtrace = require "luci.debug".trap_memtrace("l")
local ctx = context local ctx = context
ctx.path = request ctx.path = request
@ -151,14 +159,12 @@ function dispatch(request, ext_tree)
end end
require "luci.i18n".setlanguage(lang) require "luci.i18n".setlanguage(lang)
if ext_tree then
ctx.index, ctx.tree, ctx.treecache, ctx.modifiers = unpack(ext_tree)
elseif not ctx.tree then
createtree()
end
local c = ctx.tree local c = ctx.tree
local stat local stat
if not c then
c = createtree()
end
local track = {} local track = {}
local args = {} local args = {}
ctx.args = args ctx.args = args
@ -226,13 +232,13 @@ function dispatch(request, ext_tree)
end end
tpl.context.viewns = setmetatable({ tpl.context.viewns = setmetatable({
write = luci.http.write; write = luci.http.write;
include = function(name) tpl.Template(name):render(getfenv(2)) end; include = function(name) tpl.Template(name):render(getfenv(2)) end;
translate = function(...) return require("luci.i18n").translate(...) end; translate = function(...) return require("luci.i18n").translate(...) end;
striptags = util.striptags; striptags = util.striptags;
media = media; media = media;
theme = fs.basename(media); theme = fs.basename(media);
resource = luci.config.main.resourcebase resource = luci.config.main.resourcebase
}, {__index=function(table, key) }, {__index=function(table, key)
if key == "controller" then if key == "controller" then
return build_url() return build_url()
@ -260,7 +266,7 @@ function dispatch(request, ext_tree)
local verifytoken = false local verifytoken = false
if not sess then if not sess then
sess = luci.http.getcookie("sysauth") sess = luci.http.getcookie("sysauth")
sess = sess and sess:match("^[a-f0-9]+$") sess = sess and sess:match("^[a-f0-9]*$")
verifytoken = true verifytoken = true
end end
@ -274,6 +280,12 @@ function dispatch(request, ext_tree)
if not verifytoken or ctx.urltoken.stok == sdat.token then if not verifytoken or ctx.urltoken.stok == sdat.token then
user = sdat.user user = sdat.user
end end
else
local eu = http.getenv("HTTP_AUTH_USER")
local ep = http.getenv("HTTP_AUTH_PASS")
if eu and ep and luci.sys.user.checkpasswd(eu, ep) then
authen = function() return eu end
end
end end
if not util.contains(accs, user) then if not util.contains(accs, user) then
@ -364,9 +376,9 @@ function createindex()
local suff = { ".lua", ".lua.gz" } local suff = { ".lua", ".lua.gz" }
if luci.util.copcall(require, "luci.fastindex") then if luci.util.copcall(require, "luci.fastindex") then
return createindex_fastindex(path, suff) createindex_fastindex(path, suff)
else else
return createindex_plain(path, suff) createindex_plain(path, suff)
end end
end end
@ -374,7 +386,7 @@ end
-- @param path Controller base directory -- @param path Controller base directory
-- @param suffixes Controller file suffixes -- @param suffixes Controller file suffixes
function createindex_fastindex(path, suffixes) function createindex_fastindex(path, suffixes)
local index = {} index = {}
if not fi then if not fi then
fi = luci.fastindex.new("index") fi = luci.fastindex.new("index")
@ -388,8 +400,6 @@ function createindex_fastindex(path, suffixes)
for k, v in pairs(fi.indexes) do for k, v in pairs(fi.indexes) do
index[v[2]] = v[1] index[v[2]] = v[1]
end end
return index
end end
--- Generate the dispatching index using the native file-cache based strategy. --- Generate the dispatching index using the native file-cache based strategy.
@ -424,7 +434,7 @@ function createindex_plain(path, suffixes)
end end
end end
local index = {} index = {}
for i,c in ipairs(controllers) do for i,c in ipairs(controllers) do
local module = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".") local module = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".")
@ -445,24 +455,21 @@ function createindex_plain(path, suffixes)
f:writeall(util.get_bytecode(index)) f:writeall(util.get_bytecode(index))
f:close() f:close()
end end
return index
end end
--- Create the dispatching tree from the index. --- Create the dispatching tree from the index.
-- Build the index before if it does not exist yet. -- Build the index before if it does not exist yet.
function createtree() function createtree()
local ctx = context if not index then
local tree = {nodes={}} createindex()
local cache = setmetatable({}, {__mode="v"})
local modi = {}
if not ctx.index then
ctx.index = createindex()
end end
ctx.tree = tree local ctx = context
ctx.treecache = cache local tree = {nodes={}}
local modi = {}
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
ctx.modifiers = modi ctx.modifiers = modi
-- Load default translation -- Load default translation
@ -470,10 +477,10 @@ function createtree()
local scope = setmetatable({}, {__index = luci.dispatcher}) local scope = setmetatable({}, {__index = luci.dispatcher})
for k, v in pairs(ctx.index) do for k, v in pairs(index) do
scope._NAME = k scope._NAME = k
setfenv(v, scope) setfenv(v, scope)
pcall(v) v()
end end
local function modisort(a,b) local function modisort(a,b)
@ -483,10 +490,10 @@ function createtree()
for _, v in util.spairs(modi, modisort) do for _, v in util.spairs(modi, modisort) do
scope._NAME = v.module scope._NAME = v.module
setfenv(v.func, scope) setfenv(v.func, scope)
pcall(v.func) v.func()
end end
return { index, tree, cache, modi } return tree
end end
--- Register a tree modifier. --- Register a tree modifier.

View file

@ -258,6 +258,13 @@ function write(content, src_err)
end end
end end
--- Splice data from a filedescriptor to the client.
-- @param fp File descriptor
-- @param size Bytes to splice (optional)
function splice(fd, size)
coroutine.yield(6, fd, size)
end
--- Redirects the client to a new URL and closes the connection. --- Redirects the client to a new URL and closes the connection.
-- @param url Target URL -- @param url Target URL
function redirect(url) function redirect(url)

View file

@ -22,7 +22,7 @@ config internal ccache
option enable 1 option enable 1
config internal template config internal template
option compiler_mode file option compiler_mode memory
option compiledir "/tmp/luci-templatecache" option compiledir "/tmp/luci-templatecache"
config internal themes config internal themes