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
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
@ -183,7 +192,14 @@ rmdir = fs.rmdir
-- @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

View file

@ -215,7 +215,7 @@ end
-- @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
@ -768,24 +768,19 @@ function copcall(f, ...)
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

View file

@ -171,44 +171,61 @@ function request_to_file(uri, target, options, cbs)
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
if target then
file, code, msg = prepare_fd(target)
if not file then
return file, code, msg
end
local off = file:tell()
-- 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

View file

@ -53,15 +53,40 @@ static int lmo_L_hash(lua_State *L) {
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;
@ -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[] = {
{"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 */
@ -146,6 +225,12 @@ LUALIB_API int luaopen_lmo(lua_State *L) {
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;

View file

@ -27,6 +27,15 @@
#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);

View file

@ -11,7 +11,6 @@ You may obtain a copy of the License at
$Id$
]]--
local cbi = require "luci.cbi"
local dsp = require "luci.dispatcher"
local util = require "luci.util"
local http = require "luci.http"
@ -27,8 +26,6 @@ Luci = util.class(srv.Handler)
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, ...)
@ -53,7 +50,7 @@ function Luci.handle_GET(self, request, sourcein)
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

View file

@ -117,6 +117,7 @@ function Handler.checkrestricted(self, request)
end
if stat then
request.env.HTTP_AUTH_USER, request.env.HTTP_AUTH_PASS = user, pass
return
end
end
@ -256,7 +257,7 @@ local function chunksink(sock)
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
@ -460,7 +461,7 @@ function Server.process(self, client, env)
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)
@ -504,8 +505,15 @@ function Server.process(self, client, env)
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

View file

@ -110,7 +110,7 @@ function accept(polle)
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)

View file

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

View file

@ -28,7 +28,7 @@ local string = require "string"
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"
@ -43,6 +43,10 @@ local TYPE_SECTION = 0x02
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
@ -274,7 +278,7 @@ function UVL._validate_section( self, section )
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
@ -542,7 +546,7 @@ function UVL._parse_section(self, scheme, k, v)
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
@ -595,7 +599,7 @@ function UVL._parse_var(self, scheme, k, v)
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
@ -718,9 +722,7 @@ function UVL._read_dependency( self, values, deps )
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
@ -752,8 +754,8 @@ function UVL._read_validator( self, values, validators )
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 )
@ -920,13 +922,13 @@ function uvlitem.type(self)
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)
@ -993,9 +995,9 @@ end
--- 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.

View file

@ -108,17 +108,25 @@ end
--- 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()
@ -128,7 +136,7 @@ end
--- 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
@ -151,14 +159,12 @@ function dispatch(request, ext_tree)
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
@ -226,13 +232,13 @@ function dispatch(request, ext_tree)
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()
@ -260,7 +266,7 @@ function dispatch(request, ext_tree)
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
@ -274,6 +280,12 @@ function dispatch(request, ext_tree)
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
@ -364,9 +376,9 @@ function createindex()
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
@ -374,7 +386,7 @@ 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")
@ -388,8 +400,6 @@ function createindex_fastindex(path, suffixes)
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.
@ -424,7 +434,7 @@ function createindex_plain(path, suffixes)
end
end
local index = {}
index = {}
for i,c in ipairs(controllers) do
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: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
@ -470,10 +477,10 @@ function createtree()
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)
@ -483,10 +490,10 @@ function createtree()
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.

View file

@ -258,6 +258,13 @@ function write(content, src_err)
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)

View file

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