-- @return Number containing the os specific errno on error
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.
-- @class function
-- @name stat
-- @return Table containing file or directory properties or nil on error
-- @return String containing the error description 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.
-- @class function
-- @param value String containing the HTML text
-- @return String with HTML tags stripped of
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
--- Splits given string on a defined separator sequence and return a table
end
-- 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
- return false, err(debug.traceback(co, (...)), ...)
+ return false, err(debug.traceback(co, arg1), arg1, arg2, arg3, arg4, arg5)
end
- if coroutine.status(co) == 'suspended' then
- return performResume(err, co, coroutine.yield(...))
- else
- return true, ...
+
+ if coroutine.status(co) ~= 'suspended' then
+ return true, arg1, arg2, arg3, arg4, arg5
end
+
+ return performResume(err, co, coroutine.yield(arg1, arg2, arg3, arg4, arg5))
end
-- Resume execution of protected function call
-function performResume(err, co, ...)
- if get_memory_limit and get_memory_limit() > 0 and
- collectgarbage("count") > (get_memory_limit() * 0.8)
- then
- collectgarbage("collect")
- end
-
- return handleReturnValue(err, co, coroutine.resume(co, ...))
+function performResume(err, co, arg1, arg2, arg3, arg4, arg5)
+ return handleReturnValue(err, co, coroutine.resume(co, arg1, arg2, arg3, arg4, arg5))
end
cbs = cbs or {}
options.headers = options.headers or {}
local hdr = options.headers
+ local file, code, msg
- local file, code, msg = prepare_fd(target)
- if not file then
- return file, code, msg
- end
-
- local off = file:tell()
+ if target then
+ file, code, msg = prepare_fd(target)
+ if not file then
+ return file, code, msg
+ end
- -- Set content range
- if off > 0 then
- hdr.Range = hdr.Range or ("bytes=" .. off .. "-")
+ local off = file:tell()
+
+ -- Set content range
+ if off > 0 then
+ hdr.Range = hdr.Range or ("bytes=" .. off .. "-")
+ end
end
local code, resp, buffer, sock = httpc.request_raw(uri, options)
if not code then
-- No success
- file:close()
+ if file then
+ file:close()
+ end
return code, resp, buffer
elseif hdr.Range and code ~= 206 then
-- We wanted a part but we got the while file
sock:close()
- file:close()
+ if file then
+ file:close()
+ end
return nil, -4, code, resp
elseif not hdr.Range and code ~= 200 then
-- We encountered an error
sock:close()
- file:close()
+ if file then
+ file:close()
+ end
return nil, -4, code, resp
end
if cbs.on_header then
local stat = {cbs.on_header(file, code, resp)}
if stat[1] == false then
- file:close()
+ if file then
+ file:close()
+ end
sock:close()
return unpack(stat)
+ elseif stat[2] then
+ file = file and stat[2]
end
end
+
+ if not file then
+ return nil, -5, "no target given"
+ end
local chunked = resp.headers["Transfer-Encoding"] == "chunked"
local stat
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) {
lmo_entry_t *e = ar->index;
+ lmo_luaentry_t *le = NULL;
while( e != NULL )
{
if( e->key_id == hash )
{
- lua_pushlstring(L, &ar->mmap[e->offset], e->length);
- return 1;
+ if( (le = _lmo_push_entry(L)) != NULL )
+ {
+ le->archive = ar;
+ le->entry = e;
+ return 1;
+ }
+ else
+ {
+ lua_pushnil(L);
+ lua_pushstring(L, "out of memory");
+ return 2;
+ }
}
e = e->next;
}
-/* 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[] = {
- {"close", lmo_L__gc},
- {"get", lmo_L_get},
- {"lookup", lmo_L_lookup},
- {"foreach", lmo_L_foreach},
+ {"close", lmo_L__gc},
+ {"get", lmo_L_get},
+ {"lookup", lmo_L_lookup},
+ {"foreach", lmo_L_foreach},
{"__tostring", lmo_L__tostring},
- {"__gc", lmo_L__gc},
- {NULL, NULL}
+ {"__gc", lmo_L__gc},
+ {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 */
lua_setfield(L, -2, "__index");
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);
return 1;
#define LMO_LUALIB_META "lmo"
#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);
$Id$
]]--
-local cbi = require "luci.cbi"
local dsp = require "luci.dispatcher"
local util = require "luci.util"
local http = require "luci.http"
function Luci.__init__(self, name, prefix)
srv.Handler.__init__(self, name)
self.prefix = prefix
-
- self.dsp_tree = dsp.createtree()
end
function Luci.handle_HEAD(self, ...)
local x = coroutine.create(dsp.httpdispatch)
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
status = 500
end
if stat then
+ request.env.HTTP_AUTH_USER, request.env.HTTP_AUTH_PASS = user, pass
return
end
end
if not chunk then
return sock:writeall("0\r\n\r\n")
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
headers["Content-Length"] = sourceout.len
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
headers["Transfer-Encoding"] = "chunked"
sinkout = chunksink(client)
if sourceout and stat then
if util.instanceof(sourceout, IOResource) then
- stat, code, msg = sourceout.fd:copyz(client, sourceout.len)
- else
+ if not headers["Transfer-Encoding"] then
+ 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)
end
end
end
local socket, host, port = polle.fd:accept()
if not socket then
- return nixio.syslog("warn", "accept() failed: " .. port)
+ return nixio.syslog("warning", "accept() failed: " .. port)
end
socket:setblocking(true)
]]--
module("luci.sgi.cgi", package.seeall)
local ltn12 = require("luci.ltn12")
+require("nixio.util")
require("luci.http")
require("luci.sys")
require("luci.dispatcher")
io.flush()
io.close()
active = false
+ elseif id == 6 then
+ data1:copyz(nixio.stdout, data2)
end
end
end
local require, pcall, ipairs, pairs = require, pcall, ipairs, pairs
local type, error, tonumber, tostring = type, error, tonumber, tostring
-local unpack, loadfile = unpack, loadfile
+local unpack, loadfile, collectgarbage = unpack, loadfile, collectgarbage
module "luci.uvl"
local TYPE_OPTION = 0x03
local TYPE_ENUM = 0x04
+local PAT_EXPR1 = "^%$?[%w_]+$"
+local PAT_EXPR2 = "^%$?[%w_]+%.%$?[%w_]+$"
+local PAT_EXPR3 = "^%$?[%w_]+%.%$?[%w_]+%.%$?[%w_]+$"
+
--- Boolean; default true;
-- treat sections found in config but not in scheme as error
STRICT_UNKNOWN_SECTIONS = true
if STRICT_UNKNOWN_OPTIONS and not section:scheme('dynamic') then
for k, v in pairs(section:config()) do
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))
end
end
local so = scheme:section(v.name)
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
s.depends = self:_read_dependency( v2, s.depends )
if not s.depends then
local to = so:option(v.name)
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
t.depends = self:_read_dependency( v2, t.depends )
if not t.depends then
local k, e, v = val:match("%s*([%w$_.]+)%s*(=?)%s*(.*)")
if k and (
- k:match("^"..expr.."%."..expr.."%."..expr.."$") or
- k:match("^"..expr.."%."..expr.."$") or
- k:match("^"..expr.."$")
+ k:match(PAT_EXPR1) or k:match(PAT_EXPR2) or k:match(PAT_EXPR3)
) then
condition[k] = (e == '=') and v or true
else
validator = self:_resolve_function( (value:gsub("^lua:","") ) )
elseif value:match("^regexp:") then
local pattern = value:gsub("^regexp:","")
- validator = function( type, dtype, pack, sect, optn, ... )
- local values = { ... }
+ validator = function( type, dtype, pack, sect, optn, arg1, arg2, arg3, arg4, arg5 )
+ local values = { arg1, arg2, arg3, arg4, arg5 }
for _, v in ipairs(values) do
local ok, match =
pcall( string.match, v, pattern )
end
end
-function uvlitem.error(self, ...)
+function uvlitem.error(self, arg1, arg2, arg3, arg4, arg5)
if not self.e then
local errconst = { ERR.CONFIG, ERR.SECTION, ERR.OPTION, ERR.OPTION }
self.e = errconst[#self.cref]( self )
end
- return self.e:child( ... )
+ return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end
function uvlitem.errors(self)
--- Add an error to scheme.
-- @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
- return self.e:child( ... )
+ return self.e:child( arg1, arg2, arg3, arg4, arg5 )
end
--- Get an associated config object.
--- Dispatch an HTTP request.
-- @param request LuCI HTTP Request object
-function httpdispatch(request, prefix, ext_tree)
+function httpdispatch(request, prefix)
luci.http.context.request = request
- context.request = {}
+
+ local r = {}
+ context.request = r
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
- table.insert(context.request, node)
+ r[#r+1] = node
end
local stat, err = util.coxpcall(function()
- dispatch(context.request, ext_tree)
+ dispatch(context.request)
end, error500)
luci.http.close()
--- Dispatches a LuCI virtual path.
-- @param request Virtual path
-function dispatch(request, ext_tree)
+function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace("l")
local ctx = context
ctx.path = request
end
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 stat
+ if not c then
+ c = createtree()
+ end
+
local track = {}
local args = {}
ctx.args = args
end
tpl.context.viewns = setmetatable({
- write = luci.http.write;
- include = function(name) tpl.Template(name):render(getfenv(2)) end;
- translate = function(...) return require("luci.i18n").translate(...) end;
- striptags = util.striptags;
- media = media;
- theme = fs.basename(media);
- resource = luci.config.main.resourcebase
+ write = luci.http.write;
+ include = function(name) tpl.Template(name):render(getfenv(2)) end;
+ translate = function(...) return require("luci.i18n").translate(...) end;
+ striptags = util.striptags;
+ media = media;
+ theme = fs.basename(media);
+ resource = luci.config.main.resourcebase
}, {__index=function(table, key)
if key == "controller" then
return build_url()
local verifytoken = false
if not sess then
sess = luci.http.getcookie("sysauth")
- sess = sess and sess:match("^[a-f0-9]+$")
+ sess = sess and sess:match("^[a-f0-9]*$")
verifytoken = true
end
if not verifytoken or ctx.urltoken.stok == sdat.token then
user = sdat.user
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
if not util.contains(accs, user) then
local suff = { ".lua", ".lua.gz" }
if luci.util.copcall(require, "luci.fastindex") then
- return createindex_fastindex(path, suff)
+ createindex_fastindex(path, suff)
else
- return createindex_plain(path, suff)
+ createindex_plain(path, suff)
end
end
-- @param path Controller base directory
-- @param suffixes Controller file suffixes
function createindex_fastindex(path, suffixes)
- local index = {}
+ index = {}
if not fi then
fi = luci.fastindex.new("index")
for k, v in pairs(fi.indexes) do
index[v[2]] = v[1]
end
-
- return index
end
--- Generate the dispatching index using the native file-cache based strategy.
end
end
- local index = {}
+ index = {}
for i,c in ipairs(controllers) do
local module = "luci.controller." .. c:sub(#path+1, #c):gsub("/", ".")
f:writeall(util.get_bytecode(index))
f:close()
end
-
- return index
end
--- Create the dispatching tree from the index.
-- Build the index before if it does not exist yet.
function createtree()
- local ctx = context
- local tree = {nodes={}}
- local cache = setmetatable({}, {__mode="v"})
- local modi = {}
-
- if not ctx.index then
- ctx.index = createindex()
+ if not index then
+ createindex()
end
- ctx.tree = tree
- ctx.treecache = cache
+ local ctx = context
+ local tree = {nodes={}}
+ local modi = {}
+
+ ctx.treecache = setmetatable({}, {__mode="v"})
+ ctx.tree = tree
ctx.modifiers = modi
-- Load default translation
local scope = setmetatable({}, {__index = luci.dispatcher})
- for k, v in pairs(ctx.index) do
+ for k, v in pairs(index) do
scope._NAME = k
setfenv(v, scope)
- pcall(v)
+ v()
end
local function modisort(a,b)
for _, v in util.spairs(modi, modisort) do
scope._NAME = v.module
setfenv(v.func, scope)
- pcall(v.func)
+ v.func()
end
- return { index, tree, cache, modi }
+ return tree
end
--- Register a tree modifier.
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.
-- @param url Target URL
function redirect(url)
option enable 1
config internal template
- option compiler_mode file
+ option compiler_mode memory
option compiledir "/tmp/luci-templatecache"
config internal themes