luci-0.9: merge r5130-r5143
authorJo-Philipp Wich <jow@openwrt.org>
Sun, 26 Jul 2009 21:28:44 +0000 (21:28 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sun, 26 Jul 2009 21:28:44 +0000 (21:28 +0000)
13 files changed:
libs/core/luasrc/fs.lua
libs/core/luasrc/util.lua
libs/httpclient/luasrc/httpclient/receiver.lua
libs/lmo/src/lmo_lualib.c
libs/lmo/src/lmo_lualib.h
libs/lucid-http/luasrc/lucid/http/handler/luci.lua
libs/lucid-http/luasrc/lucid/http/server.lua
libs/lucid/luasrc/lucid/tcpserver.lua
libs/sgi-cgi/luasrc/sgi/cgi.lua
libs/uvl/luasrc/uvl.lua
libs/web/luasrc/dispatcher.lua
libs/web/luasrc/http.lua
libs/web/root/etc/config/luci

index f98f6e6..a81ff67 100644 (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
index 94b5ce6..a3ba432 100644 (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
index cac96cd..4f08e93 100644 (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
-       
-       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
index 676f788..59d88a1 100644 (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;
index 096fa02..6435117 100644 (file)
 
 #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);
 
index 9fe9a73..c54e393 100644 (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
index 4c3016a..24eb042 100644 (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
index 6c61ff6..2d82246 100644 (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)
index 15363a1..f2c6f69 100644 (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
index 7f149cf..3b5b854 100644 (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.
index 8c3320b..a375eec 100644 (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.
index bac9979..d34e253 100644 (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)
index 7c0ed5b..a42bac3 100644 (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