From bfc8f48cf017a96266e3b4d4ad7c4e246a1a1a5f Mon Sep 17 00:00:00 2001 From: Sven Roederer Date: Tue, 19 Nov 2019 21:35:41 +0100 Subject: [PATCH] patches: add Luci PR2817 This splits some commonly used files from luci-base into a separate package. So the non LuCI-web parts can be used without bloat added. --- patches/202-split-luci-base_PR2817.patch | 4896 ++++++++++++++++++++++ patches/series | 1 + 2 files changed, 4897 insertions(+) create mode 100644 patches/202-split-luci-base_PR2817.patch diff --git a/patches/202-split-luci-base_PR2817.patch b/patches/202-split-luci-base_PR2817.patch new file mode 100644 index 0000000000..d0014dd30c --- /dev/null +++ b/patches/202-split-luci-base_PR2817.patch @@ -0,0 +1,4896 @@ +--- a/feeds/luci/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua ++++ b/feeds/luci/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua +@@ -2,7 +2,7 @@ + -- Copyright 2008-2011 Jo-Philipp Wich + -- Licensed to the public under the Apache License 2.0. + +-m = Map("upnpd", luci.util.pcdata(translate("Universal Plug & Play")), ++m = Map("upnpd", luci.xml.pcdata(translate("Universal Plug & Play")), + translate("UPnP allows clients in the local network to automatically configure the router.")) + + m:section(SimpleSection).template = "upnp_status" +--- a/feeds/luci/applications/luci-app-wol/luasrc/model/cbi/wol.lua ++++ b/feeds/luci/applications/luci-app-wol/luasrc/model/cbi/wol.lua +@@ -2,6 +2,7 @@ + -- Licensed to the public under the Apache License 2.0. + + local utl = require "luci.util" ++local xml = require "luci.xml" + local sys = require "luci.sys" + local ipc = require "luci.ip" + local fs = require "nixio.fs" +@@ -79,7 +80,7 @@ function host.write(self, s, val) + end + + local msg = "

%s

%s

" %{ +- translate("Starting WoL utility:"), utl.pcdata(cmd) ++ translate("Starting WoL utility:"), xml.pcdata(cmd) + } + + local p = io.popen(cmd .. " 2>&1") +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/Makefile +@@ -0,0 +1,14 @@ ++# ++# Copyright (C) 2008-2014 The LuCI Team ++# ++# This is free software, licensed under the Apache License, Version 2.0 . ++# ++ ++include $(TOPDIR)/rules.mk ++ ++LUCI_TITLE:=basic libraries for luci ++LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +luci-lib-jsonc +liblucihttp-lua ++ ++include ../../luci.mk ++ ++# call BuildPackage - OpenWrt buildroot signature +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/debug.lua +@@ -0,0 +1,37 @@ ++local debug = require "debug" ++local io = require "io" ++local collectgarbage, floor = collectgarbage, math.floor ++ ++module "luci.debug" ++__file__ = debug.getinfo(1, 'S').source:sub(2) ++ ++-- Enables the memory tracer with given flags and returns a function to disable the tracer again ++function trap_memtrace(flags, dest) ++ flags = flags or "clr" ++ local tracefile = io.open(dest or "/tmp/memtrace", "w") ++ local peak = 0 ++ ++ local function trap(what, line) ++ local info = debug.getinfo(2, "Sn") ++ local size = floor(collectgarbage("count")) ++ if size > peak then ++ peak = size ++ end ++ if tracefile then ++ tracefile:write( ++ "[", what, "] ", info.source, ":", (line or "?"), "\t", ++ (info.namewhat or ""), "\t", ++ (info.name or ""), "\t", ++ size, " (", peak, ")\n" ++ ) ++ end ++ end ++ ++ debug.sethook(trap, flags) ++ ++ return function() ++ debug.sethook() ++ tracefile:close() ++ end ++end ++ +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/http.lua +@@ -0,0 +1,554 @@ ++-- Copyright 2008 Steven Barth ++-- Copyright 2010-2018 Jo-Philipp Wich ++-- Licensed to the public under the Apache License 2.0. ++ ++local util = require "luci.util" ++local coroutine = require "coroutine" ++local table = require "table" ++local lhttp = require "lucihttp" ++local nixio = require "nixio" ++local ltn12 = require "luci.ltn12" ++ ++local table, ipairs, pairs, type, tostring, tonumber, error = ++ table, ipairs, pairs, type, tostring, tonumber, error ++ ++module "luci.http" ++ ++HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size ++ ++context = util.threadlocal() ++ ++Request = util.class() ++function Request.__init__(self, env, sourcein, sinkerr) ++ self.input = sourcein ++ self.error = sinkerr ++ ++ ++ -- File handler nil by default to let .content() work ++ self.filehandler = nil ++ ++ -- HTTP-Message table ++ self.message = { ++ env = env, ++ headers = {}, ++ params = urldecode_params(env.QUERY_STRING or ""), ++ } ++ ++ self.parsed_input = false ++end ++ ++function Request.formvalue(self, name, noparse) ++ if not noparse and not self.parsed_input then ++ self:_parse_input() ++ end ++ ++ if name then ++ return self.message.params[name] ++ else ++ return self.message.params ++ end ++end ++ ++function Request.formvaluetable(self, prefix) ++ local vals = {} ++ prefix = prefix and prefix .. "." or "." ++ ++ if not self.parsed_input then ++ self:_parse_input() ++ end ++ ++ local void = self.message.params[nil] ++ for k, v in pairs(self.message.params) do ++ if k:find(prefix, 1, true) == 1 then ++ vals[k:sub(#prefix + 1)] = tostring(v) ++ end ++ end ++ ++ return vals ++end ++ ++function Request.content(self) ++ if not self.parsed_input then ++ self:_parse_input() ++ end ++ ++ return self.message.content, self.message.content_length ++end ++ ++function Request.getcookie(self, name) ++ return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) ++end ++ ++function Request.getenv(self, name) ++ if name then ++ return self.message.env[name] ++ else ++ return self.message.env ++ end ++end ++ ++function Request.setfilehandler(self, callback) ++ self.filehandler = callback ++ ++ if not self.parsed_input then ++ return ++ end ++ ++ -- If input has already been parsed then uploads are stored as unlinked ++ -- temporary files pointed to by open file handles in the parameter ++ -- value table. Loop all params, and invoke the file callback for any ++ -- param with an open file handle. ++ local name, value ++ for name, value in pairs(self.message.params) do ++ if type(value) == "table" then ++ while value.fd do ++ local data = value.fd:read(1024) ++ local eof = (not data or data == "") ++ ++ callback(value, data, eof) ++ ++ if eof then ++ value.fd:close() ++ value.fd = nil ++ end ++ end ++ end ++ end ++end ++ ++function Request._parse_input(self) ++ parse_message_body( ++ self.input, ++ self.message, ++ self.filehandler ++ ) ++ self.parsed_input = true ++end ++ ++function close() ++ if not context.eoh then ++ context.eoh = true ++ coroutine.yield(3) ++ end ++ ++ if not context.closed then ++ context.closed = true ++ coroutine.yield(5) ++ end ++end ++ ++function content() ++ return context.request:content() ++end ++ ++function formvalue(name, noparse) ++ return context.request:formvalue(name, noparse) ++end ++ ++function formvaluetable(prefix) ++ return context.request:formvaluetable(prefix) ++end ++ ++function getcookie(name) ++ return context.request:getcookie(name) ++end ++ ++-- or the environment table itself. ++function getenv(name) ++ return context.request:getenv(name) ++end ++ ++function setfilehandler(callback) ++ return context.request:setfilehandler(callback) ++end ++ ++function header(key, value) ++ if not context.headers then ++ context.headers = {} ++ end ++ context.headers[key:lower()] = value ++ coroutine.yield(2, key, value) ++end ++ ++function prepare_content(mime) ++ if not context.headers or not context.headers["content-type"] then ++ if mime == "application/xhtml+xml" then ++ if not getenv("HTTP_ACCEPT") or ++ not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then ++ mime = "text/html; charset=UTF-8" ++ end ++ header("Vary", "Accept") ++ end ++ header("Content-Type", mime) ++ end ++end ++ ++function source() ++ return context.request.input ++end ++ ++function status(code, message) ++ code = code or 200 ++ message = message or "OK" ++ context.status = code ++ coroutine.yield(1, code, message) ++end ++ ++-- This function is as a valid LTN12 sink. ++-- If the content chunk is nil this function will automatically invoke close. ++function write(content, src_err) ++ if not content then ++ if src_err then ++ error(src_err) ++ else ++ close() ++ end ++ return true ++ elseif #content == 0 then ++ return true ++ else ++ if not context.eoh then ++ if not context.status then ++ status() ++ end ++ if not context.headers or not context.headers["content-type"] then ++ header("Content-Type", "text/html; charset=utf-8") ++ end ++ if not context.headers["cache-control"] then ++ header("Cache-Control", "no-cache") ++ header("Expires", "0") ++ end ++ if not context.headers["x-frame-options"] then ++ header("X-Frame-Options", "SAMEORIGIN") ++ end ++ if not context.headers["x-xss-protection"] then ++ header("X-XSS-Protection", "1; mode=block") ++ end ++ if not context.headers["x-content-type-options"] then ++ header("X-Content-Type-Options", "nosniff") ++ end ++ ++ context.eoh = true ++ coroutine.yield(3) ++ end ++ coroutine.yield(4, content) ++ return true ++ end ++end ++ ++function splice(fd, size) ++ coroutine.yield(6, fd, size) ++end ++ ++function redirect(url) ++ if url == "" then url = "/" end ++ status(302, "Found") ++ header("Location", url) ++ close() ++end ++ ++function build_querystring(q) ++ local s, n, k, v = {}, 1, nil, nil ++ ++ for k, v in pairs(q) do ++ s[n+0] = (n == 1) and "?" or "&" ++ s[n+1] = util.urlencode(k) ++ s[n+2] = "=" ++ s[n+3] = util.urlencode(v) ++ n = n + 4 ++ end ++ ++ return table.concat(s, "") ++end ++ ++urldecode = util.urldecode ++ ++urlencode = util.urlencode ++ ++function write_json(x) ++ util.serialize_json(x, write) ++end ++ ++-- from given url or string. Returns a table with urldecoded values. ++-- Simple parameters are stored as string values associated with the parameter ++-- name within the table. Parameters with multiple values are stored as array ++-- containing the corresponding values. ++function urldecode_params(url, tbl) ++ local parser, name ++ local params = tbl or { } ++ ++ parser = lhttp.urlencoded_parser(function (what, buffer, length) ++ if what == parser.TUPLE then ++ name, value = nil, nil ++ elseif what == parser.NAME then ++ name = lhttp.urldecode(buffer) ++ elseif what == parser.VALUE and name then ++ params[name] = lhttp.urldecode(buffer) or "" ++ end ++ ++ return true ++ end) ++ ++ if parser then ++ parser:parse((url or ""):match("[^?]*$")) ++ parser:parse(nil) ++ end ++ ++ return params ++end ++ ++-- separated by "&". Tables are encoded as parameters with multiple values by ++-- repeating the parameter name with each value. ++function urlencode_params(tbl) ++ local k, v ++ local n, enc = 1, {} ++ for k, v in pairs(tbl) do ++ if type(v) == "table" then ++ local i, v2 ++ for i, v2 in ipairs(v) do ++ if enc[1] then ++ enc[n] = "&" ++ n = n + 1 ++ end ++ ++ enc[n+0] = lhttp.urlencode(k) ++ enc[n+1] = "=" ++ enc[n+2] = lhttp.urlencode(v2) ++ n = n + 3 ++ end ++ else ++ if enc[1] then ++ enc[n] = "&" ++ n = n + 1 ++ end ++ ++ enc[n+0] = lhttp.urlencode(k) ++ enc[n+1] = "=" ++ enc[n+2] = lhttp.urlencode(v) ++ n = n + 3 ++ end ++ end ++ ++ return table.concat(enc, "") ++end ++ ++-- Content-Type. Stores all extracted data associated with its parameter name ++-- in the params table within the given message object. Multiple parameter ++-- values are stored as tables, ordinary ones as strings. ++-- If an optional file callback function is given then it is fed with the ++-- file contents chunk by chunk and only the extracted file name is stored ++-- within the params table. The callback function will be called subsequently ++-- with three arguments: ++-- o Table containing decoded (name, file) and raw (headers) mime header data ++-- o String value containing a chunk of the file data ++-- o Boolean which indicates whether the current chunk is the last one (eof) ++function mimedecode_message_body(src, msg, file_cb) ++ local parser, header, field ++ local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) ++ ++ parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) ++ if what == parser.PART_INIT then ++ field = { } ++ ++ elseif what == parser.HEADER_NAME then ++ header = buffer:lower() ++ ++ elseif what == parser.HEADER_VALUE and header then ++ if header:lower() == "content-disposition" and ++ lhttp.header_attribute(buffer, nil) == "form-data" ++ then ++ field.name = lhttp.header_attribute(buffer, "name") ++ field.file = lhttp.header_attribute(buffer, "filename") ++ field[1] = field.file ++ end ++ ++ if field.headers then ++ field.headers[header] = buffer ++ else ++ field.headers = { [header] = buffer } ++ end ++ ++ elseif what == parser.PART_BEGIN then ++ return not field.file ++ ++ elseif what == parser.PART_DATA and field.name and length > 0 then ++ if field.file then ++ if file_cb then ++ file_cb(field, buffer, false) ++ msg.params[field.name] = msg.params[field.name] or field ++ else ++ if not field.fd then ++ field.fd = nixio.mkstemp(field.name) ++ end ++ ++ if field.fd then ++ field.fd:write(buffer) ++ msg.params[field.name] = msg.params[field.name] or field ++ end ++ end ++ else ++ field.value = buffer ++ end ++ ++ elseif what == parser.PART_END and field.name then ++ if field.file and msg.params[field.name] then ++ if file_cb then ++ file_cb(field, "", true) ++ elseif field.fd then ++ field.fd:seek(0, "set") ++ end ++ else ++ local val = msg.params[field.name] ++ ++ if type(val) == "table" then ++ val[#val+1] = field.value or "" ++ elseif val ~= nil then ++ msg.params[field.name] = { val, field.value or "" } ++ else ++ msg.params[field.name] = field.value or "" ++ end ++ end ++ ++ field = nil ++ ++ elseif what == parser.ERROR then ++ err = buffer ++ end ++ ++ return true ++ end, HTTP_MAX_CONTENT) ++ ++ return ltn12.pump.all(src, function (chunk) ++ len = len + (chunk and #chunk or 0) ++ ++ if maxlen and len > maxlen + 2 then ++ return nil, "Message body size exceeds Content-Length" ++ end ++ ++ if not parser or not parser:parse(chunk) then ++ return nil, err ++ end ++ ++ return true ++ end) ++end ++ ++-- Content-Type. Stores all extracted data associated with its parameter name ++-- in the params table within the given message object. Multiple parameter ++-- values are stored as tables, ordinary ones as strings. ++function urldecode_message_body(src, msg) ++ local err, name, value, parser ++ local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) ++ ++ parser = lhttp.urlencoded_parser(function (what, buffer, length) ++ if what == parser.TUPLE then ++ name, value = nil, nil ++ elseif what == parser.NAME then ++ name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) ++ elseif what == parser.VALUE and name then ++ local val = msg.params[name] ++ ++ if type(val) == "table" then ++ val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" ++ elseif val ~= nil then ++ msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } ++ else ++ msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" ++ end ++ elseif what == parser.ERROR then ++ err = buffer ++ end ++ ++ return true ++ end, HTTP_MAX_CONTENT) ++ ++ return ltn12.pump.all(src, function (chunk) ++ len = len + (chunk and #chunk or 0) ++ ++ if maxlen and len > maxlen + 2 then ++ return nil, "Message body size exceeds Content-Length" ++ elseif len > HTTP_MAX_CONTENT then ++ return nil, "Message body size exceeds maximum allowed length" ++ end ++ ++ if not parser or not parser:parse(chunk) then ++ return nil, err ++ end ++ ++ return true ++ end) ++end ++ ++-- This function will examine the Content-Type within the given message object ++-- to select the appropriate content decoder. ++-- Currently the application/x-www-urlencoded and application/form-data ++-- mime types are supported. If the encountered content encoding can't be ++-- handled then the whole message body will be stored unaltered as "content" ++-- property within the given message object. ++function parse_message_body(src, msg, filecb) ++ if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then ++ local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) ++ ++ -- Is it multipart/mime ? ++ if ctype == "multipart/form-data" then ++ return mimedecode_message_body(src, msg, filecb) ++ ++ -- Is it application/x-www-form-urlencoded ? ++ elseif ctype == "application/x-www-form-urlencoded" then ++ return urldecode_message_body(src, msg) ++ ++ end ++ ++ -- Unhandled encoding ++ -- If a file callback is given then feed it chunk by chunk, else ++ -- store whole buffer in message.content ++ local sink ++ ++ -- If we have a file callback then feed it ++ if type(filecb) == "function" then ++ local meta = { ++ name = "raw", ++ encoding = msg.env.CONTENT_TYPE ++ } ++ sink = function( chunk ) ++ if chunk then ++ return filecb(meta, chunk, false) ++ else ++ return filecb(meta, nil, true) ++ end ++ end ++ -- ... else append to .content ++ else ++ msg.content = "" ++ msg.content_length = 0 ++ ++ sink = function( chunk ) ++ if chunk then ++ if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then ++ msg.content = msg.content .. chunk ++ msg.content_length = msg.content_length + #chunk ++ return true ++ else ++ return nil, "POST data exceeds maximum allowed length" ++ end ++ end ++ return true ++ end ++ end ++ ++ -- Pump data... ++ while true do ++ local ok, err = ltn12.pump.step( src, sink ) ++ ++ if not ok and err then ++ return nil, err ++ elseif not ok then -- eof ++ return true ++ end ++ end ++ ++ return true ++ end ++ ++ return false ++end +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/http.luadoc +@@ -0,0 +1,260 @@ ++---[[ ++LuCI Web Framework high-level HTTP functions. ++]] ++module "luci.http" ++ ++---[[ ++Close the HTTP-Connection. ++ ++@class function ++@name close ++]] ++ ++---[[ ++Return the request content if the request was of unknown type. ++ ++@class function ++@name content ++@return HTTP request body ++@return HTTP request body length ++]] ++ ++---[[ ++Get a certain HTTP input value or a table of all input values. ++ ++@class function ++@name formvalue ++@param name Name of the GET or POST variable to fetch ++@param noparse Don't parse POST data before getting the value ++@return HTTP input value or table of all input value ++]] ++ ++---[[ ++Get a table of all HTTP input values with a certain prefix. ++ ++@class function ++@name formvaluetable ++@param prefix Prefix ++@return Table of all HTTP input values with given prefix ++]] ++ ++---[[ ++Get the value of a certain HTTP-Cookie. ++ ++@class function ++@name getcookie ++@param name Cookie Name ++@return String containing cookie data ++]] ++ ++---[[ ++Get the value of a certain HTTP environment variable ++or the environment table itself. ++ ++@class function ++@name getenv ++@param name Environment variable ++@return HTTP environment value or environment table ++]] ++ ++---[[ ++Set a handler function for incoming user file uploads. ++ ++@class function ++@name setfilehandler ++@param callback Handler function ++]] ++ ++---[[ ++Send a HTTP-Header. ++ ++@class function ++@name header ++@param key Header key ++@param value Header value ++]] ++ ++---[[ ++Set the mime type of following content data. ++ ++@class function ++@name prepare_content ++@param mime Mimetype of following content ++]] ++ ++---[[ ++Get the RAW HTTP input source ++ ++@class function ++@name source ++@return HTTP LTN12 source ++]] ++ ++---[[ ++Set the HTTP status code and status message. ++ ++@class function ++@name status ++@param code Status code ++@param message Status message ++]] ++ ++---[[ ++Send a chunk of content data to the client. ++ ++This function is as a valid LTN12 sink. ++If the content chunk is nil this function will automatically invoke close. ++ ++@class function ++@name write ++@param content Content chunk ++@param src_err Error object from source (optional) ++@see close ++]] ++ ++---[[ ++Splice data from a filedescriptor to the client. ++ ++@class function ++@name splice ++@param fp File descriptor ++@param size Bytes to splice (optional) ++]] ++ ++---[[ ++Redirects the client to a new URL and closes the connection. ++ ++@class function ++@name redirect ++@param url Target URL ++]] ++ ++---[[ ++Create a querystring out of a table of key - value pairs. ++ ++@class function ++@name build_querystring ++@param table Query string source table ++@return Encoded HTTP query string ++]] ++ ++---[[ ++Return the URL-decoded equivalent of a string. ++ ++@class function ++@name urldecode ++@param str URL-encoded string ++@param no_plus Don't decode + to " " ++@return URL-decoded string ++@see urlencode ++]] ++ ++---[[ ++Return the URL-encoded equivalent of a string. ++ ++@class function ++@name urlencode ++@param str Source string ++@return URL-encoded string ++@see urldecode ++]] ++ ++---[[ ++Send the given data as JSON encoded string. ++ ++@class function ++@name write_json ++@param data Data to send ++]] ++ ++---[[ ++Extract and split urlencoded data pairs, separated bei either "&" or ";" ++from given url or string. Returns a table with urldecoded values. ++ ++Simple parameters are stored as string values associated with the parameter ++name within the table. Parameters with multiple values are stored as array ++containing the corresponding values. ++ ++@class function ++@name urldecode_params ++@param url The url or string which contains x-www-urlencoded form data ++@param tbl Use the given table for storing values (optional) ++@return Table containing the urldecoded parameters ++@see urlencode_params ++]] ++ ++---[[ ++Encode each key-value-pair in given table to x-www-urlencoded format, ++separated by "&". ++ ++Tables are encoded as parameters with multiple values by repeating the ++parameter name with each value. ++ ++@class function ++@name urlencode_params ++@param tbl Table with the values ++@return String containing encoded values ++@see urldecode_params ++]] ++ ++---[[ ++Decode a mime encoded http message body with multipart/form-data Content-Type. ++ ++Stores all extracted data associated with its parameter name ++in the params table within the given message object. Multiple parameter ++values are stored as tables, ordinary ones as strings. ++ ++If an optional file callback function is given then it is fed with the ++file contents chunk by chunk and only the extracted file name is stored ++within the params table. The callback function will be called subsequently ++with three arguments: ++ o Table containing decoded (name, file) and raw (headers) mime header data ++ o String value containing a chunk of the file data ++ o Boolean which indicates whether the current chunk is the last one (eof) ++ ++@class function ++@name mimedecode_message_body ++@param src Ltn12 source function ++@param msg HTTP message object ++@param filecb File callback function (optional) ++@return Value indicating successful operation (not nil means "ok") ++@return String containing the error if unsuccessful ++@see parse_message_header ++]] ++ ++---[[ ++Decode an urlencoded http message body with application/x-www-urlencoded ++Content-Type. ++ ++Stores all extracted data associated with its parameter name in the params ++table within the given message object. Multiple parameter values are stored ++as tables, ordinary ones as strings. ++ ++@class function ++@name urldecode_message_body ++@param src Ltn12 source function ++@param msg HTTP message object ++@return Value indicating successful operation (not nil means "ok") ++@return String containing the error if unsuccessful ++@see parse_message_header ++]] ++ ++---[[ ++Try to extract and decode a http message body from the given ltn12 source. ++This function will examine the Content-Type within the given message object ++to select the appropriate content decoder. ++ ++Currently the application/x-www-urlencoded and application/form-data ++mime types are supported. If the encountered content encoding can't be ++handled then the whole message body will be stored unaltered as "content" ++property within the given message object. ++ ++@class function ++@name parse_message_body ++@param src Ltn12 source function ++@param msg HTTP message object ++@param filecb File data callback (optional, see mimedecode_message_body()) ++@return Value indicating successful operation (not nil means "ok") ++@return String containing the error if unsuccessful ++@see parse_message_header ++]] +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/ltn12.lua +@@ -0,0 +1,316 @@ ++--[[ ++LuaSocket 2.0.2 license ++Copyright � 2004-2007 Diego Nehab ++ ++Permission is hereby granted, free of charge, to any person obtaining a ++copy of this software and associated documentation files (the "Software"), ++to deal in the Software without restriction, including without limitation ++the rights to use, copy, modify, merge, publish, distribute, sublicense, ++and/or sell copies of the Software, and to permit persons to whom the ++Software is furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++DEALINGS IN THE SOFTWARE. ++]]-- ++--[[ ++ Changes made by LuCI project: ++ * Renamed to luci.ltn12 to avoid collisions with luasocket ++ * Added inline documentation ++]]-- ++----------------------------------------------------------------------------- ++-- LTN12 - Filters, sources, sinks and pumps. ++-- LuaSocket toolkit. ++-- Author: Diego Nehab ++-- RCS ID: $Id$ ++----------------------------------------------------------------------------- ++ ++----------------------------------------------------------------------------- ++-- Declare module ++----------------------------------------------------------------------------- ++local string = require("string") ++local table = require("table") ++local base = _G ++ ++-- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts ++module("luci.ltn12") ++ ++filter = {} ++source = {} ++sink = {} ++pump = {} ++ ++-- 2048 seems to be better in windows... ++BLOCKSIZE = 2048 ++_VERSION = "LTN12 1.0.1" ++ ++----------------------------------------------------------------------------- ++-- Filter stuff ++----------------------------------------------------------------------------- ++ ++ ++-- by passing it each chunk and updating a context between calls. ++function filter.cycle(low, ctx, extra) ++ base.assert(low) ++ return function(chunk) ++ local ret ++ ret, ctx = low(ctx, chunk, extra) ++ return ret ++ end ++end ++ ++-- (thanks to Wim Couwenberg) ++function filter.chain(...) ++ local n = table.getn(arg) ++ local top, index = 1, 1 ++ local retry = "" ++ return function(chunk) ++ retry = chunk and retry ++ while true do ++ if index == top then ++ chunk = arg[index](chunk) ++ if chunk == "" or top == n then return chunk ++ elseif chunk then index = index + 1 ++ else ++ top = top+1 ++ index = top ++ end ++ else ++ chunk = arg[index](chunk or "") ++ if chunk == "" then ++ index = index - 1 ++ chunk = retry ++ elseif chunk then ++ if index == n then return chunk ++ else index = index + 1 end ++ else base.error("filter returned inappropriate nil") end ++ end ++ end ++ end ++end ++ ++----------------------------------------------------------------------------- ++-- Source stuff ++----------------------------------------------------------------------------- ++ ++ ++-- create an empty source ++local function empty() ++ return nil ++end ++ ++function source.empty() ++ return empty ++end ++ ++function source.error(err) ++ return function() ++ return nil, err ++ end ++end ++ ++function source.file(handle, io_err) ++ if handle then ++ return function() ++ local chunk = handle:read(BLOCKSIZE) ++ if chunk and chunk:len() == 0 then chunk = nil end ++ if not chunk then handle:close() end ++ return chunk ++ end ++ else return source.error(io_err or "unable to open file") end ++end ++ ++function source.simplify(src) ++ base.assert(src) ++ return function() ++ local chunk, err_or_new = src() ++ src = err_or_new or src ++ if not chunk then return nil, err_or_new ++ else return chunk end ++ end ++end ++ ++function source.string(s) ++ if s then ++ local i = 1 ++ return function() ++ local chunk = string.sub(s, i, i+BLOCKSIZE-1) ++ i = i + BLOCKSIZE ++ if chunk ~= "" then return chunk ++ else return nil end ++ end ++ else return source.empty() end ++end ++ ++function source.rewind(src) ++ base.assert(src) ++ local t = {} ++ return function(chunk) ++ if not chunk then ++ chunk = table.remove(t) ++ if not chunk then return src() ++ else return chunk end ++ else ++ t[#t+1] = chunk ++ end ++ end ++end ++ ++function source.chain(src, f) ++ base.assert(src and f) ++ local last_in, last_out = "", "" ++ local state = "feeding" ++ local err ++ return function() ++ if not last_out then ++ base.error('source is empty!', 2) ++ end ++ while true do ++ if state == "feeding" then ++ last_in, err = src() ++ if err then return nil, err end ++ last_out = f(last_in) ++ if not last_out then ++ if last_in then ++ base.error('filter returned inappropriate nil') ++ else ++ return nil ++ end ++ elseif last_out ~= "" then ++ state = "eating" ++ if last_in then last_in = "" end ++ return last_out ++ end ++ else ++ last_out = f(last_in) ++ if last_out == "" then ++ if last_in == "" then ++ state = "feeding" ++ else ++ base.error('filter returned ""') ++ end ++ elseif not last_out then ++ if last_in then ++ base.error('filter returned inappropriate nil') ++ else ++ return nil ++ end ++ else ++ return last_out ++ end ++ end ++ end ++ end ++end ++ ++-- Sources will be used one after the other, as if they were concatenated ++-- (thanks to Wim Couwenberg) ++function source.cat(...) ++ local src = table.remove(arg, 1) ++ return function() ++ while src do ++ local chunk, err = src() ++ if chunk then return chunk end ++ if err then return nil, err end ++ src = table.remove(arg, 1) ++ end ++ end ++end ++ ++----------------------------------------------------------------------------- ++-- Sink stuff ++----------------------------------------------------------------------------- ++ ++ ++function sink.table(t) ++ t = t or {} ++ local f = function(chunk, err) ++ if chunk then t[#t+1] = chunk end ++ return 1 ++ end ++ return f, t ++end ++ ++function sink.simplify(snk) ++ base.assert(snk) ++ return function(chunk, err) ++ local ret, err_or_new = snk(chunk, err) ++ if not ret then return nil, err_or_new end ++ snk = err_or_new or snk ++ return 1 ++ end ++end ++ ++function sink.file(handle, io_err) ++ if handle then ++ return function(chunk, err) ++ if not chunk then ++ handle:close() ++ return 1 ++ else return handle:write(chunk) end ++ end ++ else return sink.error(io_err or "unable to open file") end ++end ++ ++-- creates a sink that discards data ++local function null() ++ return 1 ++end ++ ++function sink.null() ++ return null ++end ++ ++function sink.error(err) ++ return function() ++ return nil, err ++ end ++end ++ ++function sink.chain(f, snk) ++ base.assert(f and snk) ++ return function(chunk, err) ++ if chunk ~= "" then ++ local filtered = f(chunk) ++ local done = chunk and "" ++ while true do ++ local ret, snkerr = snk(filtered, err) ++ if not ret then return nil, snkerr end ++ if filtered == done then return 1 end ++ filtered = f(done) ++ end ++ else return 1 end ++ end ++end ++ ++----------------------------------------------------------------------------- ++-- Pump stuff ++----------------------------------------------------------------------------- ++ ++ ++function pump.step(src, snk) ++ local chunk, src_err = src() ++ local ret, snk_err = snk(chunk, src_err) ++ if chunk and ret then return 1 ++ else return nil, src_err or snk_err end ++end ++ ++function pump.all(src, snk, step) ++ base.assert(src and snk) ++ step = step or pump.step ++ while true do ++ local ret, err = step(src, snk) ++ if not ret then ++ if err then return nil, err ++ else return 1 end ++ end ++ end ++end ++ +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/util.lua +@@ -0,0 +1,766 @@ ++-- Copyright 2008 Steven Barth ++-- Licensed to the public under the Apache License 2.0. ++ ++local io = require "io" ++local math = require "math" ++local table = require "table" ++local debug = require "debug" ++local ldebug = require "luci.debug" ++local string = require "string" ++local coroutine = require "coroutine" ++local tparser = require "luci.template.parser" ++local json = require "luci.jsonc" ++local lhttp = require "lucihttp" ++ ++local _ubus = require "ubus" ++local _ubus_connection = nil ++ ++local getmetatable, setmetatable = getmetatable, setmetatable ++local rawget, rawset, unpack, select = rawget, rawset, unpack, select ++local tostring, type, assert, error = tostring, type, assert, error ++local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring ++local require, pcall, xpcall = require, pcall, xpcall ++local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit ++ ++module "luci.util" ++ ++-- ++-- Pythonic string formatting extension ++-- ++getmetatable("").__mod = function(a, b) ++ local ok, res ++ ++ if not b then ++ return a ++ elseif type(b) == "table" then ++ local k, _ ++ for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end ++ ++ ok, res = pcall(a.format, a, unpack(b)) ++ if not ok then ++ error(res, 2) ++ end ++ return res ++ else ++ if type(b) == "userdata" then b = tostring(b) end ++ ++ ok, res = pcall(a.format, a, b) ++ if not ok then ++ error(res, 2) ++ end ++ return res ++ end ++end ++ ++ ++-- ++-- Class helper routines ++-- ++ ++-- Instantiates a class ++local function _instantiate(class, ...) ++ local inst = setmetatable({}, {__index = class}) ++ ++ if inst.__init__ then ++ inst:__init__(...) ++ end ++ ++ return inst ++end ++ ++-- The class object can be instantiated by calling itself. ++-- Any class functions or shared parameters can be attached to this object. ++-- Attaching a table to the class object makes this table shared between ++-- all instances of this class. For object parameters use the __init__ function. ++-- Classes can inherit member functions and values from a base class. ++-- Class can be instantiated by calling them. All parameters will be passed ++-- to the __init__ function of this class - if such a function exists. ++-- The __init__ function must be used to set any object parameters that are not shared ++-- with other objects of this class. Any return values will be ignored. ++function class(base) ++ return setmetatable({}, { ++ __call = _instantiate, ++ __index = base ++ }) ++end ++ ++function instanceof(object, class) ++ local meta = getmetatable(object) ++ while meta and meta.__index do ++ if meta.__index == class then ++ return true ++ end ++ meta = getmetatable(meta.__index) ++ end ++ return false ++end ++ ++ ++-- ++-- Scope manipulation routines ++-- ++ ++coxpt = setmetatable({}, { __mode = "kv" }) ++ ++local tl_meta = { ++ __mode = "k", ++ ++ __index = function(self, key) ++ local t = rawget(self, coxpt[coroutine.running()] ++ or coroutine.running() or 0) ++ return t and t[key] ++ end, ++ ++ __newindex = function(self, key, value) ++ local c = coxpt[coroutine.running()] or coroutine.running() or 0 ++ local r = rawget(self, c) ++ if not r then ++ rawset(self, c, { [key] = value }) ++ else ++ r[key] = value ++ end ++ end ++} ++ ++-- the current active coroutine. A thread local store is private a table object ++-- whose values can't be accessed from outside of the running coroutine. ++function threadlocal(tbl) ++ return setmetatable(tbl or {}, tl_meta) ++end ++ ++ ++-- ++-- Debugging routines ++-- ++ ++function perror(obj) ++ return io.stderr:write(tostring(obj) .. "\n") ++end ++ ++function dumptable(t, maxdepth, i, seen) ++ i = i or 0 ++ seen = seen or setmetatable({}, {__mode="k"}) ++ ++ for k,v in pairs(t) do ++ perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v)) ++ if type(v) == "table" and (not maxdepth or i < maxdepth) then ++ if not seen[v] then ++ seen[v] = true ++ dumptable(v, maxdepth, i+1, seen) ++ else ++ perror(string.rep("\t", i) .. "*** RECURSION ***") ++ end ++ end ++ end ++end ++ ++ ++-- ++-- String and data manipulation routines ++-- ++ ++function urlencode(value) ++ if value ~= nil then ++ local str = tostring(value) ++ return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL) ++ or str ++ end ++ return nil ++end ++ ++function urldecode(value, decode_plus) ++ if value ~= nil then ++ local flag = decode_plus and lhttp.DECODE_PLUS or 0 ++ local str = tostring(value) ++ return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag) ++ or str ++ end ++ return nil ++end ++ ++function shellquote(value) ++ return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) ++end ++ ++-- for bash, ash and similar shells single-quoted strings are taken ++-- literally except for single quotes (which terminate the string) ++-- (and the exception noted below for dash (-) at the start of a ++-- command line parameter). ++function shellsqescape(value) ++ local res ++ res, _ = string.gsub(value, "'", "'\\''") ++ return res ++end ++ ++-- bash, ash and other similar shells interpret a dash (-) at the start ++-- of a command-line parameters as an option indicator regardless of ++-- whether it is inside a single-quoted string. It must be backlash ++-- escaped to resolve this. This requires in some funky special-case ++-- handling. It may actually be a property of the getopt function ++-- rather than the shell proper. ++function shellstartsqescape(value) ++ res, _ = string.gsub(value, "^%-", "\\-") ++ return shellsqescape(res) ++end ++ ++-- containing the resulting substrings. The optional max parameter specifies ++-- the number of bytes to process, regardless of the actual length of the given ++-- string. The optional last parameter, regex, specifies whether the separator ++-- sequence is interpreted as regular expression. ++-- pattern as regular expression (optional, default is false) ++function split(str, pat, max, regex) ++ pat = pat or "\n" ++ max = max or #str ++ ++ local t = {} ++ local c = 1 ++ ++ if #str == 0 then ++ return {""} ++ end ++ ++ if #pat == 0 then ++ return nil ++ end ++ ++ if max == 0 then ++ return str ++ end ++ ++ repeat ++ local s, e = str:find(pat, c, not regex) ++ max = max - 1 ++ if s and max < 0 then ++ t[#t+1] = str:sub(c) ++ else ++ t[#t+1] = str:sub(c, s and s - 1) ++ end ++ c = e and e + 1 or #str + 1 ++ until not s or max < 0 ++ ++ return t ++end ++ ++function trim(str) ++ return (str:gsub("^%s*(.-)%s*$", "%1")) ++end ++ ++function cmatch(str, pat) ++ local count = 0 ++ for _ in str:gmatch(pat) do count = count + 1 end ++ return count ++end ++ ++-- one token per invocation, the tokens are separated by whitespace. If the ++-- input value is a table, it is transformed into a string first. A nil value ++-- will result in a valid iterator which aborts with the first invocation. ++function imatch(v) ++ if type(v) == "table" then ++ local k = nil ++ return function() ++ k = next(v, k) ++ return v[k] ++ end ++ ++ elseif type(v) == "number" or type(v) == "boolean" then ++ local x = true ++ return function() ++ if x then ++ x = false ++ return tostring(v) ++ end ++ end ++ ++ elseif type(v) == "userdata" or type(v) == "string" then ++ return tostring(v):gmatch("%S+") ++ end ++ ++ return function() end ++end ++ ++-- value or 0 if the unit is unknown. Upper- or lower case is irrelevant. ++-- Recognized units are: ++-- o "y" - one year (60*60*24*366) ++-- o "m" - one month (60*60*24*31) ++-- o "w" - one week (60*60*24*7) ++-- o "d" - one day (60*60*24) ++-- o "h" - one hour (60*60) ++-- o "min" - one minute (60) ++-- o "kb" - one kilobyte (1024) ++-- o "mb" - one megabyte (1024*1024) ++-- o "gb" - one gigabyte (1024*1024*1024) ++-- o "kib" - one si kilobyte (1000) ++-- o "mib" - one si megabyte (1000*1000) ++-- o "gib" - one si gigabyte (1000*1000*1000) ++function parse_units(ustr) ++ ++ local val = 0 ++ ++ -- unit map ++ local map = { ++ -- date stuff ++ y = 60 * 60 * 24 * 366, ++ m = 60 * 60 * 24 * 31, ++ w = 60 * 60 * 24 * 7, ++ d = 60 * 60 * 24, ++ h = 60 * 60, ++ min = 60, ++ ++ -- storage sizes ++ kb = 1024, ++ mb = 1024 * 1024, ++ gb = 1024 * 1024 * 1024, ++ ++ -- storage sizes (si) ++ kib = 1000, ++ mib = 1000 * 1000, ++ gib = 1000 * 1000 * 1000 ++ } ++ ++ -- parse input string ++ for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do ++ ++ local num = spec:gsub("[^0-9%.]+$","") ++ local spn = spec:gsub("^[0-9%.]+", "") ++ ++ if map[spn] or map[spn:sub(1,1)] then ++ val = val + num * ( map[spn] or map[spn:sub(1,1)] ) ++ else ++ val = val + num ++ end ++ end ++ ++ ++ return val ++end ++ ++-- also register functions above in the central string class for convenience ++string.split = split ++string.trim = trim ++string.cmatch = cmatch ++string.parse_units = parse_units ++ ++ ++function append(src, ...) ++ for i, a in ipairs({...}) do ++ if type(a) == "table" then ++ for j, v in ipairs(a) do ++ src[#src+1] = v ++ end ++ else ++ src[#src+1] = a ++ end ++ end ++ return src ++end ++ ++function combine(...) ++ return append({}, ...) ++end ++ ++function contains(table, value) ++ for k, v in pairs(table) do ++ if value == v then ++ return k ++ end ++ end ++ return false ++end ++ ++-- Both table are - in fact - merged together. ++function update(t, updates) ++ for k, v in pairs(updates) do ++ t[k] = v ++ end ++end ++ ++function keys(t) ++ local keys = { } ++ if t then ++ for k, _ in kspairs(t) do ++ keys[#keys+1] = k ++ end ++ end ++ return keys ++end ++ ++function clone(object, deep) ++ local copy = {} ++ ++ for k, v in pairs(object) do ++ if deep and type(v) == "table" then ++ v = clone(v, deep) ++ end ++ copy[k] = v ++ end ++ ++ return setmetatable(copy, getmetatable(object)) ++end ++ ++ ++-- Serialize the contents of a table value. ++function _serialize_table(t, seen) ++ assert(not seen[t], "Recursion detected.") ++ seen[t] = true ++ ++ local data = "" ++ local idata = "" ++ local ilen = 0 ++ ++ for k, v in pairs(t) do ++ if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then ++ k = serialize_data(k, seen) ++ v = serialize_data(v, seen) ++ data = data .. ( #data > 0 and ", " or "" ) .. ++ '[' .. k .. '] = ' .. v ++ elseif k > ilen then ++ ilen = k ++ end ++ end ++ ++ for i = 1, ilen do ++ local v = serialize_data(t[i], seen) ++ idata = idata .. ( #idata > 0 and ", " or "" ) .. v ++ end ++ ++ return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data ++end ++ ++-- with loadstring(). ++function serialize_data(val, seen) ++ seen = seen or setmetatable({}, {__mode="k"}) ++ ++ if val == nil then ++ return "nil" ++ elseif type(val) == "number" then ++ return val ++ elseif type(val) == "string" then ++ return "%q" % val ++ elseif type(val) == "boolean" then ++ return val and "true" or "false" ++ elseif type(val) == "function" then ++ return "loadstring(%q)" % get_bytecode(val) ++ elseif type(val) == "table" then ++ return "{ " .. _serialize_table(val, seen) .. " }" ++ else ++ return '"[unhandled data type:' .. type(val) .. ']"' ++ end ++end ++ ++function restore_data(str) ++ return loadstring("return " .. str)() ++end ++ ++ ++-- ++-- Byte code manipulation routines ++-- ++ ++-- will be stripped before it is returned. ++function get_bytecode(val) ++ local code ++ ++ if type(val) == "function" then ++ code = string.dump(val) ++ else ++ code = string.dump( loadstring( "return " .. serialize_data(val) ) ) ++ end ++ ++ return code -- and strip_bytecode(code) ++end ++ ++-- numbers and debugging numbers will be discarded. Original version by ++-- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) ++function strip_bytecode(code) ++ local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12) ++ local subint ++ if endian == 1 then ++ subint = function(code, i, l) ++ local val = 0 ++ for n = l, 1, -1 do ++ val = val * 256 + code:byte(i + n - 1) ++ end ++ return val, i + l ++ end ++ else ++ subint = function(code, i, l) ++ local val = 0 ++ for n = 1, l, 1 do ++ val = val * 256 + code:byte(i + n - 1) ++ end ++ return val, i + l ++ end ++ end ++ ++ local function strip_function(code) ++ local count, offset = subint(code, 1, size) ++ local stripped = { string.rep("\0", size) } ++ local dirty = offset + count ++ offset = offset + count + int * 2 + 4 ++ offset = offset + int + subint(code, offset, int) * ins ++ count, offset = subint(code, offset, int) ++ for n = 1, count do ++ local t ++ t, offset = subint(code, offset, 1) ++ if t == 1 then ++ offset = offset + 1 ++ elseif t == 4 then ++ offset = offset + size + subint(code, offset, size) ++ elseif t == 3 then ++ offset = offset + num ++ elseif t == 254 or t == 9 then ++ offset = offset + lnum ++ end ++ end ++ count, offset = subint(code, offset, int) ++ stripped[#stripped+1] = code:sub(dirty, offset - 1) ++ for n = 1, count do ++ local proto, off = strip_function(code:sub(offset, -1)) ++ stripped[#stripped+1] = proto ++ offset = offset + off - 1 ++ end ++ offset = offset + subint(code, offset, int) * int + int ++ count, offset = subint(code, offset, int) ++ for n = 1, count do ++ offset = offset + subint(code, offset, size) + size + int * 2 ++ end ++ count, offset = subint(code, offset, int) ++ for n = 1, count do ++ offset = offset + subint(code, offset, size) + size ++ end ++ stripped[#stripped+1] = string.rep("\0", int * 3) ++ return table.concat(stripped), offset ++ end ++ ++ return code:sub(1,12) .. strip_function(code:sub(13,-1)) ++end ++ ++ ++-- ++-- Sorting iterator functions ++-- ++ ++function _sortiter( t, f ) ++ local keys = { } ++ ++ local k, v ++ for k, v in pairs(t) do ++ keys[#keys+1] = k ++ end ++ ++ local _pos = 0 ++ ++ table.sort( keys, f ) ++ ++ return function() ++ _pos = _pos + 1 ++ if _pos <= #keys then ++ return keys[_pos], t[keys[_pos]], _pos ++ end ++ end ++end ++ ++-- the provided callback function. ++function spairs(t,f) ++ return _sortiter( t, f ) ++end ++ ++-- The table pairs are sorted by key. ++function kspairs(t) ++ return _sortiter( t ) ++end ++ ++-- The table pairs are sorted by value. ++function vspairs(t) ++ return _sortiter( t, function (a,b) return t[a] < t[b] end ) ++end ++ ++ ++-- ++-- System utility functions ++-- ++ ++function bigendian() ++ return string.byte(string.dump(function() end), 7) == 0 ++end ++ ++function exec(command) ++ local pp = io.popen(command) ++ local data = pp:read("*a") ++ pp:close() ++ ++ return data ++end ++ ++function execi(command) ++ local pp = io.popen(command) ++ ++ return pp and function() ++ local line = pp:read() ++ ++ if not line then ++ pp:close() ++ end ++ ++ return line ++ end ++end ++ ++-- Deprecated ++function execl(command) ++ local pp = io.popen(command) ++ local line = "" ++ local data = {} ++ ++ while true do ++ line = pp:read() ++ if (line == nil) then break end ++ data[#data+1] = line ++ end ++ pp:close() ++ ++ return data ++end ++ ++ ++local ubus_codes = { ++ "INVALID_COMMAND", ++ "INVALID_ARGUMENT", ++ "METHOD_NOT_FOUND", ++ "NOT_FOUND", ++ "NO_DATA", ++ "PERMISSION_DENIED", ++ "TIMEOUT", ++ "NOT_SUPPORTED", ++ "UNKNOWN_ERROR", ++ "CONNECTION_FAILED" ++} ++ ++local function ubus_return(...) ++ if select('#', ...) == 2 then ++ local rv, err = select(1, ...), select(2, ...) ++ if rv == nil and type(err) == "number" then ++ return nil, err, ubus_codes[err] ++ end ++ end ++ ++ return ... ++end ++ ++function ubus(object, method, data) ++ if not _ubus_connection then ++ _ubus_connection = _ubus.connect() ++ assert(_ubus_connection, "Unable to establish ubus connection") ++ end ++ ++ if object and method then ++ if type(data) ~= "table" then ++ data = { } ++ end ++ return ubus_return(_ubus_connection:call(object, method, data)) ++ elseif object then ++ return _ubus_connection:signatures(object) ++ else ++ return _ubus_connection:objects() ++ end ++end ++ ++function serialize_json(x, cb) ++ local js = json.stringify(x) ++ if type(cb) == "function" then ++ cb(js) ++ else ++ return js ++ end ++end ++ ++ ++function libpath() ++ return require "nixio.fs".dirname(ldebug.__file__) ++end ++ ++function checklib(fullpathexe, wantedlib) ++ local fs = require "nixio.fs" ++ local haveldd = fs.access('/usr/bin/ldd') ++ local haveexe = fs.access(fullpathexe) ++ if not haveldd or not haveexe then ++ return false ++ end ++ local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe))) ++ if not libs then ++ return false ++ end ++ for k, v in ipairs(split(libs)) do ++ if v:find(wantedlib) then ++ return true ++ end ++ end ++ return false ++end ++ ++------------------------------------------------------------------------------- ++-- Coroutine safe xpcall and pcall versions ++-- ++-- Encapsulates the protected calls with a coroutine based loop, so errors can ++-- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines ++-- yielding inside the call to pcall or xpcall. ++-- ++-- Authors: Roberto Ierusalimschy and Andre Carregal ++-- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas ++-- ++-- Copyright 2005 - Kepler Project ++-- ++-- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $ ++------------------------------------------------------------------------------- ++ ++------------------------------------------------------------------------------- ++-- Implements xpcall with coroutines ++------------------------------------------------------------------------------- ++local coromap = setmetatable({}, { __mode = "k" }) ++ ++local function handleReturnValue(err, co, status, ...) ++ if not status then ++ return false, err(debug.traceback(co, (...)), ...) ++ end ++ if coroutine.status(co) == 'suspended' then ++ return performResume(err, co, coroutine.yield(...)) ++ else ++ return true, ... ++ end ++end ++ ++function performResume(err, co, ...) ++ return handleReturnValue(err, co, coroutine.resume(co, ...)) ++end ++ ++local function id(trace, ...) ++ return trace ++end ++ ++function coxpcall(f, err, ...) ++ local current = coroutine.running() ++ if not current then ++ if err == id then ++ return pcall(f, ...) ++ else ++ if select("#", ...) > 0 then ++ local oldf, params = f, { ... } ++ f = function() return oldf(unpack(params)) end ++ end ++ return xpcall(f, err) ++ end ++ else ++ local res, co = pcall(coroutine.create, f) ++ if not res then ++ local newf = function(...) return f(...) end ++ co = coroutine.create(newf) ++ end ++ coromap[co] = current ++ coxpt[co] = coxpt[current] or current or 0 ++ return performResume(err, co, ...) ++ end ++end ++ ++function copcall(f, ...) ++ return coxpcall(f, id, ...) ++end +--- /dev/null ++++ b/feeds/luci/libs/luci-lib-base/luasrc/util.luadoc +@@ -0,0 +1,395 @@ ++---[[ ++LuCI utility functions. ++]] ++module "luci.util" ++ ++---[[ ++Create a Class object (Python-style object model). ++ ++The class object can be instantiated by calling itself. ++Any class functions or shared parameters can be attached to this object. ++Attaching a table to the class object makes this table shared between ++all instances of this class. For object parameters use the __init__ function. ++Classes can inherit member functions and values from a base class. ++Class can be instantiated by calling them. All parameters will be passed ++to the __init__ function of this class - if such a function exists. ++The __init__ function must be used to set any object parameters that are not shared ++with other objects of this class. Any return values will be ignored. ++ ++@class function ++@name class ++@param base The base class to inherit from (optional) ++@return A class object ++@see instanceof ++@see clone ++]] ++ ++---[[ ++Test whether the given object is an instance of the given class. ++ ++@class function ++@name instanceof ++@param object Object instance ++@param class Class object to test against ++@return Boolean indicating whether the object is an instance ++@see class ++@see clone ++]] ++ ++---[[ ++Create a new or get an already existing thread local store associated with ++the current active coroutine. ++ ++A thread local store is private a table object ++whose values can't be accessed from outside of the running coroutine. ++ ++@class function ++@name threadlocal ++@return Table value representing the corresponding thread local store ++]] ++ ++---[[ ++Write given object to stderr. ++ ++@class function ++@name perror ++@param obj Value to write to stderr ++@return Boolean indicating whether the write operation was successful ++]] ++ ++---[[ ++Recursively dumps a table to stdout, useful for testing and debugging. ++ ++@class function ++@name dumptable ++@param t Table value to dump ++@param maxdepth Maximum depth ++@return Always nil ++]] ++ ++---[[ ++Decode an URL-encoded string - optionally decoding the "+" sign to space. ++ ++@class function ++@name urldecode ++@param str Input string in x-www-urlencoded format ++@param decode_plus Decode "+" signs to spaces if true (optional) ++@return The decoded string ++@see urlencode ++]] ++ ++---[[ ++URL-encode given string. ++ ++@class function ++@name urlencode ++@param str String to encode ++@return String containing the encoded data ++@see urldecode ++]] ++ ++---[[ ++Safely quote value for use in shell commands. ++ ++@class function ++@name shellquote ++@param value String containing the value to quote ++@return Single-quote enclosed string with embedded quotes escaped ++]] ++ ++---[[ ++Splits given string on a defined separator sequence and return a table ++containing the resulting substrings. ++ ++The optional max parameter specifies the number of bytes to process, ++regardless of the actual length of the given string. The optional last ++parameter, regex, specifies whether the separator sequence is ++nterpreted as regular expression. ++ ++@class function ++@name split ++@param str String value containing the data to split up ++@param pat String with separator pattern (optional, defaults to "\n") ++@param max Maximum times to split (optional) ++@param regex Boolean indicating whether to interpret the separator ++-- pattern as regular expression (optional, default is false) ++@return Table containing the resulting substrings ++]] ++ ++---[[ ++Remove leading and trailing whitespace from given string value. ++ ++@class function ++@name trim ++@param str String value containing whitespace padded data ++@return String value with leading and trailing space removed ++]] ++ ++---[[ ++Count the occurrences of given substring in given string. ++ ++@class function ++@name cmatch ++@param str String to search in ++@param pattern String containing pattern to find ++@return Number of found occurrences ++]] ++ ++---[[ ++Return a matching iterator for the given value. ++ ++The iterator will return one token per invocation, the tokens are separated by ++whitespace. If the input value is a table, it is transformed into a string first. ++A nil value will result in a valid iterator which aborts with the first invocation. ++ ++@class function ++@name imatch ++@param val The value to scan (table, string or nil) ++@return Iterator which returns one token per call ++]] ++ ++---[[ ++Parse certain units from the given string and return the canonical integer ++value or 0 if the unit is unknown. ++ ++Upper- or lower case is irrelevant. ++Recognized units are: ++ ++-- o "y" - one year (60*60*24*366) ++ o "m" - one month (60*60*24*31) ++ o "w" - one week (60*60*24*7) ++ o "d" - one day (60*60*24) ++ o "h" - one hour (60*60) ++ o "min" - one minute (60) ++ o "kb" - one kilobyte (1024) ++ o "mb" - one megabyte (1024*1024) ++ o "gb" - one gigabyte (1024*1024*1024) ++ o "kib" - one si kilobyte (1000) ++ o "mib" - one si megabyte (1000*1000) ++ o "gib" - one si gigabyte (1000*1000*1000) ++ ++@class function ++@name parse_units ++@param ustr String containing a numerical value with trailing unit ++@return Number containing the canonical value ++]] ++ ++---[[ ++Appends numerically indexed tables or single objects to a given table. ++ ++@class function ++@name append ++@param src Target table ++@param ... Objects to insert ++@return Target table ++]] ++ ++---[[ ++Combines two or more numerically indexed tables and single objects into one table. ++ ++@class function ++@name combine ++@param tbl1 Table value to combine ++@param tbl2 Table value to combine ++@param ... More tables to combine ++@return Table value containing all values of given tables ++]] ++ ++---[[ ++Checks whether the given table contains the given value. ++ ++@class function ++@name contains ++@param table Table value ++@param value Value to search within the given table ++@return Number indicating the first index at which the given value occurs ++-- within table or false. ++]] ++ ++---[[ ++Update values in given table with the values from the second given table. ++ ++Both table are - in fact - merged together. ++ ++@class function ++@name update ++@param t Table which should be updated ++@param updates Table containing the values to update ++@return Always nil ++]] ++ ++---[[ ++Retrieve all keys of given associative table. ++ ++@class function ++@name keys ++@param t Table to extract keys from ++@return Sorted table containing the keys ++]] ++ ++---[[ ++Clones the given object and return it's copy. ++ ++@class function ++@name clone ++@param object Table value to clone ++@param deep Boolean indicating whether to do recursive cloning ++@return Cloned table value ++]] ++ ++---[[ ++Recursively serialize given data to lua code, suitable for restoring ++with loadstring(). ++ ++@class function ++@name serialize_data ++@param val Value containing the data to serialize ++@return String value containing the serialized code ++@see restore_data ++@see get_bytecode ++]] ++ ++---[[ ++Restore data previously serialized with serialize_data(). ++ ++@class function ++@name restore_data ++@param str String containing the data to restore ++@return Value containing the restored data structure ++@see serialize_data ++@see get_bytecode ++]] ++ ++---[[ ++Return the current runtime bytecode of the given data. The byte code ++will be stripped before it is returned. ++ ++@class function ++@name get_bytecode ++@param val Value to return as bytecode ++@return String value containing the bytecode of the given data ++]] ++ ++---[[ ++Strips unnecessary lua bytecode from given string. ++ ++Information like line numbers and debugging numbers will be discarded. ++Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) ++ ++@class function ++@name strip_bytecode ++@param code String value containing the original lua byte code ++@return String value containing the stripped lua byte code ++]] ++ ++---[[ ++Return a key, value iterator which returns the values sorted according to ++the provided callback function. ++ ++@class function ++@name spairs ++@param t The table to iterate ++@param f A callback function to decide the order of elements ++@return Function value containing the corresponding iterator ++]] ++ ++---[[ ++Return a key, value iterator for the given table. ++ ++The table pairs are sorted by key. ++ ++@class function ++@name kspairs ++@param t The table to iterate ++@return Function value containing the corresponding iterator ++]] ++ ++---[[ ++Return a key, value iterator for the given table. ++ ++The table pairs are sorted by value. ++ ++@class function ++@name vspairs ++@param t The table to iterate ++@return Function value containing the corresponding iterator ++]] ++ ++---[[ ++Test whether the current system is operating in big endian mode. ++ ++@class function ++@name bigendian ++@return Boolean value indicating whether system is big endian ++]] ++ ++---[[ ++Execute given commandline and gather stdout. ++ ++@class function ++@name exec ++@param command String containing command to execute ++@return String containing the command's stdout ++]] ++ ++---[[ ++Return a line-buffered iterator over the output of given command. ++ ++@class function ++@name execi ++@param command String containing the command to execute ++@return Iterator ++]] ++ ++---[[ ++Issue an ubus call. ++ ++@class function ++@name ubus ++@param object String containing the ubus object to call ++@param method String containing the ubus method to call ++@param values Table containing the values to pass ++@return Table containin the ubus result ++]] ++ ++---[[ ++Convert data structure to JSON ++ ++@class function ++@name serialize_json ++@param data The data to serialize ++@param writer A function to write a chunk of JSON data (optional) ++@return String containing the JSON if called without write callback ++]] ++ ++---[[ ++Returns the absolute path to LuCI base directory. ++ ++@class function ++@name libpath ++@return String containing the directory path ++]] ++ ++---[[ ++This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function ++ ++@class function ++@name coxpcall ++@param f Lua function to be called protected ++@param err Custom error handler ++@param ... Parameters passed to the function ++@return A boolean whether the function call succeeded and the return ++-- values of either the function or the error handler ++]] ++ ++---[[ ++This is a coroutine-safe drop-in replacement for Lua's "pcall"-function ++ ++@class function ++@name copcall ++@param f Lua function to be called protected ++@param ... Parameters passed to the function ++@return A boolean whether the function call succeeded and the returns ++-- values of the function or the error object ++]] ++ +--- a/feeds/luci/libs/luci-lib-httpclient/Makefile ++++ b/feeds/luci/libs/luci-lib-httpclient/Makefile +@@ -7,7 +7,7 @@ + include $(TOPDIR)/rules.mk + + LUCI_TITLE:=HTTP(S) client library +-LUCI_DEPENDS:=+luci-base +luci-lib-nixio +luci-lib-httpprotoutils ++LUCI_DEPENDS:=+luci-lib-base +luci-lib-nixio +luci-lib-httpprotoutils + + include ../../luci.mk + +--- a/feeds/luci/libs/luci-lib-httpprotoutils/Makefile ++++ b/feeds/luci/libs/luci-lib-httpprotoutils/Makefile +@@ -7,7 +7,7 @@ + include $(TOPDIR)/rules.mk + + LUCI_TITLE:=HTTP protocol utility functions +-LUCI_DEPENDS:=+luci-base ++LUCI_DEPENDS:=+luci-lib-base + + include ../../luci.mk + +--- a/feeds/luci/modules/luci-base/Makefile ++++ b/feeds/luci/modules/luci-base/Makefile +@@ -12,7 +12,7 @@ LUCI_TYPE:=mod + LUCI_BASENAME:=base + + LUCI_TITLE:=LuCI core libraries +-LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua +rpcd-mod-file +rpcd-mod-luci +cgi-io ++LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua +luci-lib-base +rpcd-mod-file +rpcd-mod-luci +cgi-io + + + PKG_SOURCE:=v1.0.0.tar.gz +--- a/feeds/luci/modules/luci-base/luasrc/debug.lua ++++ /dev/null +@@ -1,37 +0,0 @@ +-local debug = require "debug" +-local io = require "io" +-local collectgarbage, floor = collectgarbage, math.floor +- +-module "luci.debug" +-__file__ = debug.getinfo(1, 'S').source:sub(2) +- +--- Enables the memory tracer with given flags and returns a function to disable the tracer again +-function trap_memtrace(flags, dest) +- flags = flags or "clr" +- local tracefile = io.open(dest or "/tmp/memtrace", "w") +- local peak = 0 +- +- local function trap(what, line) +- local info = debug.getinfo(2, "Sn") +- local size = floor(collectgarbage("count")) +- if size > peak then +- peak = size +- end +- if tracefile then +- tracefile:write( +- "[", what, "] ", info.source, ":", (line or "?"), "\t", +- (info.namewhat or ""), "\t", +- (info.name or ""), "\t", +- size, " (", peak, ")\n" +- ) +- end +- end +- +- debug.sethook(trap, flags) +- +- return function() +- debug.sethook() +- tracefile:close() +- end +-end +- +--- a/feeds/luci/modules/luci-base/luasrc/dispatcher.lua ++++ b/feeds/luci/modules/luci-base/luasrc/dispatcher.lua +@@ -5,6 +5,7 @@ + local fs = require "nixio.fs" + local sys = require "luci.sys" + local util = require "luci.util" ++local xml = require "luci.xml" + local http = require "luci.http" + local nixio = require "nixio", require "nixio.util" + +@@ -413,7 +414,7 @@ function dispatch(request) + (scope and type(scope[key]) ~= "function" and scope[key]) or "") + + if noescape ~= true then +- val = util.pcdata(val) ++ val = xml.pcdata(val) + end + + return string.format(' %s="%s"', tostring(key), val) +@@ -428,8 +429,8 @@ function dispatch(request) + translate = i18n.translate; + translatef = i18n.translatef; + export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; +- striptags = util.striptags; +- pcdata = util.pcdata; ++ striptags = xml.striptags; ++ pcdata = xml.pcdata; + media = media; + theme = fs.basename(media); + resource = luci.config.main.resourcebase; +--- a/feeds/luci/modules/luci-base/luasrc/http.lua ++++ /dev/null +@@ -1,554 +0,0 @@ +--- Copyright 2008 Steven Barth +--- Copyright 2010-2018 Jo-Philipp Wich +--- Licensed to the public under the Apache License 2.0. +- +-local util = require "luci.util" +-local coroutine = require "coroutine" +-local table = require "table" +-local lhttp = require "lucihttp" +-local nixio = require "nixio" +-local ltn12 = require "luci.ltn12" +- +-local table, ipairs, pairs, type, tostring, tonumber, error = +- table, ipairs, pairs, type, tostring, tonumber, error +- +-module "luci.http" +- +-HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size +- +-context = util.threadlocal() +- +-Request = util.class() +-function Request.__init__(self, env, sourcein, sinkerr) +- self.input = sourcein +- self.error = sinkerr +- +- +- -- File handler nil by default to let .content() work +- self.filehandler = nil +- +- -- HTTP-Message table +- self.message = { +- env = env, +- headers = {}, +- params = urldecode_params(env.QUERY_STRING or ""), +- } +- +- self.parsed_input = false +-end +- +-function Request.formvalue(self, name, noparse) +- if not noparse and not self.parsed_input then +- self:_parse_input() +- end +- +- if name then +- return self.message.params[name] +- else +- return self.message.params +- end +-end +- +-function Request.formvaluetable(self, prefix) +- local vals = {} +- prefix = prefix and prefix .. "." or "." +- +- if not self.parsed_input then +- self:_parse_input() +- end +- +- local void = self.message.params[nil] +- for k, v in pairs(self.message.params) do +- if k:find(prefix, 1, true) == 1 then +- vals[k:sub(#prefix + 1)] = tostring(v) +- end +- end +- +- return vals +-end +- +-function Request.content(self) +- if not self.parsed_input then +- self:_parse_input() +- end +- +- return self.message.content, self.message.content_length +-end +- +-function Request.getcookie(self, name) +- return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) +-end +- +-function Request.getenv(self, name) +- if name then +- return self.message.env[name] +- else +- return self.message.env +- end +-end +- +-function Request.setfilehandler(self, callback) +- self.filehandler = callback +- +- if not self.parsed_input then +- return +- end +- +- -- If input has already been parsed then uploads are stored as unlinked +- -- temporary files pointed to by open file handles in the parameter +- -- value table. Loop all params, and invoke the file callback for any +- -- param with an open file handle. +- local name, value +- for name, value in pairs(self.message.params) do +- if type(value) == "table" then +- while value.fd do +- local data = value.fd:read(1024) +- local eof = (not data or data == "") +- +- callback(value, data, eof) +- +- if eof then +- value.fd:close() +- value.fd = nil +- end +- end +- end +- end +-end +- +-function Request._parse_input(self) +- parse_message_body( +- self.input, +- self.message, +- self.filehandler +- ) +- self.parsed_input = true +-end +- +-function close() +- if not context.eoh then +- context.eoh = true +- coroutine.yield(3) +- end +- +- if not context.closed then +- context.closed = true +- coroutine.yield(5) +- end +-end +- +-function content() +- return context.request:content() +-end +- +-function formvalue(name, noparse) +- return context.request:formvalue(name, noparse) +-end +- +-function formvaluetable(prefix) +- return context.request:formvaluetable(prefix) +-end +- +-function getcookie(name) +- return context.request:getcookie(name) +-end +- +--- or the environment table itself. +-function getenv(name) +- return context.request:getenv(name) +-end +- +-function setfilehandler(callback) +- return context.request:setfilehandler(callback) +-end +- +-function header(key, value) +- if not context.headers then +- context.headers = {} +- end +- context.headers[key:lower()] = value +- coroutine.yield(2, key, value) +-end +- +-function prepare_content(mime) +- if not context.headers or not context.headers["content-type"] then +- if mime == "application/xhtml+xml" then +- if not getenv("HTTP_ACCEPT") or +- not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then +- mime = "text/html; charset=UTF-8" +- end +- header("Vary", "Accept") +- end +- header("Content-Type", mime) +- end +-end +- +-function source() +- return context.request.input +-end +- +-function status(code, message) +- code = code or 200 +- message = message or "OK" +- context.status = code +- coroutine.yield(1, code, message) +-end +- +--- This function is as a valid LTN12 sink. +--- If the content chunk is nil this function will automatically invoke close. +-function write(content, src_err) +- if not content then +- if src_err then +- error(src_err) +- else +- close() +- end +- return true +- elseif #content == 0 then +- return true +- else +- if not context.eoh then +- if not context.status then +- status() +- end +- if not context.headers or not context.headers["content-type"] then +- header("Content-Type", "text/html; charset=utf-8") +- end +- if not context.headers["cache-control"] then +- header("Cache-Control", "no-cache") +- header("Expires", "0") +- end +- if not context.headers["x-frame-options"] then +- header("X-Frame-Options", "SAMEORIGIN") +- end +- if not context.headers["x-xss-protection"] then +- header("X-XSS-Protection", "1; mode=block") +- end +- if not context.headers["x-content-type-options"] then +- header("X-Content-Type-Options", "nosniff") +- end +- +- context.eoh = true +- coroutine.yield(3) +- end +- coroutine.yield(4, content) +- return true +- end +-end +- +-function splice(fd, size) +- coroutine.yield(6, fd, size) +-end +- +-function redirect(url) +- if url == "" then url = "/" end +- status(302, "Found") +- header("Location", url) +- close() +-end +- +-function build_querystring(q) +- local s, n, k, v = {}, 1, nil, nil +- +- for k, v in pairs(q) do +- s[n+0] = (n == 1) and "?" or "&" +- s[n+1] = util.urlencode(k) +- s[n+2] = "=" +- s[n+3] = util.urlencode(v) +- n = n + 4 +- end +- +- return table.concat(s, "") +-end +- +-urldecode = util.urldecode +- +-urlencode = util.urlencode +- +-function write_json(x) +- util.serialize_json(x, write) +-end +- +--- from given url or string. Returns a table with urldecoded values. +--- Simple parameters are stored as string values associated with the parameter +--- name within the table. Parameters with multiple values are stored as array +--- containing the corresponding values. +-function urldecode_params(url, tbl) +- local parser, name +- local params = tbl or { } +- +- parser = lhttp.urlencoded_parser(function (what, buffer, length) +- if what == parser.TUPLE then +- name, value = nil, nil +- elseif what == parser.NAME then +- name = lhttp.urldecode(buffer) +- elseif what == parser.VALUE and name then +- params[name] = lhttp.urldecode(buffer) or "" +- end +- +- return true +- end) +- +- if parser then +- parser:parse((url or ""):match("[^?]*$")) +- parser:parse(nil) +- end +- +- return params +-end +- +--- separated by "&". Tables are encoded as parameters with multiple values by +--- repeating the parameter name with each value. +-function urlencode_params(tbl) +- local k, v +- local n, enc = 1, {} +- for k, v in pairs(tbl) do +- if type(v) == "table" then +- local i, v2 +- for i, v2 in ipairs(v) do +- if enc[1] then +- enc[n] = "&" +- n = n + 1 +- end +- +- enc[n+0] = lhttp.urlencode(k) +- enc[n+1] = "=" +- enc[n+2] = lhttp.urlencode(v2) +- n = n + 3 +- end +- else +- if enc[1] then +- enc[n] = "&" +- n = n + 1 +- end +- +- enc[n+0] = lhttp.urlencode(k) +- enc[n+1] = "=" +- enc[n+2] = lhttp.urlencode(v) +- n = n + 3 +- end +- end +- +- return table.concat(enc, "") +-end +- +--- Content-Type. Stores all extracted data associated with its parameter name +--- in the params table within the given message object. Multiple parameter +--- values are stored as tables, ordinary ones as strings. +--- If an optional file callback function is given then it is fed with the +--- file contents chunk by chunk and only the extracted file name is stored +--- within the params table. The callback function will be called subsequently +--- with three arguments: +--- o Table containing decoded (name, file) and raw (headers) mime header data +--- o String value containing a chunk of the file data +--- o Boolean which indicates whether the current chunk is the last one (eof) +-function mimedecode_message_body(src, msg, file_cb) +- local parser, header, field +- local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) +- +- parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) +- if what == parser.PART_INIT then +- field = { } +- +- elseif what == parser.HEADER_NAME then +- header = buffer:lower() +- +- elseif what == parser.HEADER_VALUE and header then +- if header:lower() == "content-disposition" and +- lhttp.header_attribute(buffer, nil) == "form-data" +- then +- field.name = lhttp.header_attribute(buffer, "name") +- field.file = lhttp.header_attribute(buffer, "filename") +- field[1] = field.file +- end +- +- if field.headers then +- field.headers[header] = buffer +- else +- field.headers = { [header] = buffer } +- end +- +- elseif what == parser.PART_BEGIN then +- return not field.file +- +- elseif what == parser.PART_DATA and field.name and length > 0 then +- if field.file then +- if file_cb then +- file_cb(field, buffer, false) +- msg.params[field.name] = msg.params[field.name] or field +- else +- if not field.fd then +- field.fd = nixio.mkstemp(field.name) +- end +- +- if field.fd then +- field.fd:write(buffer) +- msg.params[field.name] = msg.params[field.name] or field +- end +- end +- else +- field.value = buffer +- end +- +- elseif what == parser.PART_END and field.name then +- if field.file and msg.params[field.name] then +- if file_cb then +- file_cb(field, "", true) +- elseif field.fd then +- field.fd:seek(0, "set") +- end +- else +- local val = msg.params[field.name] +- +- if type(val) == "table" then +- val[#val+1] = field.value or "" +- elseif val ~= nil then +- msg.params[field.name] = { val, field.value or "" } +- else +- msg.params[field.name] = field.value or "" +- end +- end +- +- field = nil +- +- elseif what == parser.ERROR then +- err = buffer +- end +- +- return true +- end, HTTP_MAX_CONTENT) +- +- return ltn12.pump.all(src, function (chunk) +- len = len + (chunk and #chunk or 0) +- +- if maxlen and len > maxlen + 2 then +- return nil, "Message body size exceeds Content-Length" +- end +- +- if not parser or not parser:parse(chunk) then +- return nil, err +- end +- +- return true +- end) +-end +- +--- Content-Type. Stores all extracted data associated with its parameter name +--- in the params table within the given message object. Multiple parameter +--- values are stored as tables, ordinary ones as strings. +-function urldecode_message_body(src, msg) +- local err, name, value, parser +- local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) +- +- parser = lhttp.urlencoded_parser(function (what, buffer, length) +- if what == parser.TUPLE then +- name, value = nil, nil +- elseif what == parser.NAME then +- name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) +- elseif what == parser.VALUE and name then +- local val = msg.params[name] +- +- if type(val) == "table" then +- val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" +- elseif val ~= nil then +- msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } +- else +- msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" +- end +- elseif what == parser.ERROR then +- err = buffer +- end +- +- return true +- end, HTTP_MAX_CONTENT) +- +- return ltn12.pump.all(src, function (chunk) +- len = len + (chunk and #chunk or 0) +- +- if maxlen and len > maxlen + 2 then +- return nil, "Message body size exceeds Content-Length" +- elseif len > HTTP_MAX_CONTENT then +- return nil, "Message body size exceeds maximum allowed length" +- end +- +- if not parser or not parser:parse(chunk) then +- return nil, err +- end +- +- return true +- end) +-end +- +--- This function will examine the Content-Type within the given message object +--- to select the appropriate content decoder. +--- Currently the application/x-www-urlencoded and application/form-data +--- mime types are supported. If the encountered content encoding can't be +--- handled then the whole message body will be stored unaltered as "content" +--- property within the given message object. +-function parse_message_body(src, msg, filecb) +- if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then +- local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) +- +- -- Is it multipart/mime ? +- if ctype == "multipart/form-data" then +- return mimedecode_message_body(src, msg, filecb) +- +- -- Is it application/x-www-form-urlencoded ? +- elseif ctype == "application/x-www-form-urlencoded" then +- return urldecode_message_body(src, msg) +- +- end +- +- -- Unhandled encoding +- -- If a file callback is given then feed it chunk by chunk, else +- -- store whole buffer in message.content +- local sink +- +- -- If we have a file callback then feed it +- if type(filecb) == "function" then +- local meta = { +- name = "raw", +- encoding = msg.env.CONTENT_TYPE +- } +- sink = function( chunk ) +- if chunk then +- return filecb(meta, chunk, false) +- else +- return filecb(meta, nil, true) +- end +- end +- -- ... else append to .content +- else +- msg.content = "" +- msg.content_length = 0 +- +- sink = function( chunk ) +- if chunk then +- if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then +- msg.content = msg.content .. chunk +- msg.content_length = msg.content_length + #chunk +- return true +- else +- return nil, "POST data exceeds maximum allowed length" +- end +- end +- return true +- end +- end +- +- -- Pump data... +- while true do +- local ok, err = ltn12.pump.step( src, sink ) +- +- if not ok and err then +- return nil, err +- elseif not ok then -- eof +- return true +- end +- end +- +- return true +- end +- +- return false +-end +--- a/feeds/luci/modules/luci-base/luasrc/http.luadoc ++++ /dev/null +@@ -1,260 +0,0 @@ +----[[ +-LuCI Web Framework high-level HTTP functions. +-]] +-module "luci.http" +- +----[[ +-Close the HTTP-Connection. +- +-@class function +-@name close +-]] +- +----[[ +-Return the request content if the request was of unknown type. +- +-@class function +-@name content +-@return HTTP request body +-@return HTTP request body length +-]] +- +----[[ +-Get a certain HTTP input value or a table of all input values. +- +-@class function +-@name formvalue +-@param name Name of the GET or POST variable to fetch +-@param noparse Don't parse POST data before getting the value +-@return HTTP input value or table of all input value +-]] +- +----[[ +-Get a table of all HTTP input values with a certain prefix. +- +-@class function +-@name formvaluetable +-@param prefix Prefix +-@return Table of all HTTP input values with given prefix +-]] +- +----[[ +-Get the value of a certain HTTP-Cookie. +- +-@class function +-@name getcookie +-@param name Cookie Name +-@return String containing cookie data +-]] +- +----[[ +-Get the value of a certain HTTP environment variable +-or the environment table itself. +- +-@class function +-@name getenv +-@param name Environment variable +-@return HTTP environment value or environment table +-]] +- +----[[ +-Set a handler function for incoming user file uploads. +- +-@class function +-@name setfilehandler +-@param callback Handler function +-]] +- +----[[ +-Send a HTTP-Header. +- +-@class function +-@name header +-@param key Header key +-@param value Header value +-]] +- +----[[ +-Set the mime type of following content data. +- +-@class function +-@name prepare_content +-@param mime Mimetype of following content +-]] +- +----[[ +-Get the RAW HTTP input source +- +-@class function +-@name source +-@return HTTP LTN12 source +-]] +- +----[[ +-Set the HTTP status code and status message. +- +-@class function +-@name status +-@param code Status code +-@param message Status message +-]] +- +----[[ +-Send a chunk of content data to the client. +- +-This function is as a valid LTN12 sink. +-If the content chunk is nil this function will automatically invoke close. +- +-@class function +-@name write +-@param content Content chunk +-@param src_err Error object from source (optional) +-@see close +-]] +- +----[[ +-Splice data from a filedescriptor to the client. +- +-@class function +-@name splice +-@param fp File descriptor +-@param size Bytes to splice (optional) +-]] +- +----[[ +-Redirects the client to a new URL and closes the connection. +- +-@class function +-@name redirect +-@param url Target URL +-]] +- +----[[ +-Create a querystring out of a table of key - value pairs. +- +-@class function +-@name build_querystring +-@param table Query string source table +-@return Encoded HTTP query string +-]] +- +----[[ +-Return the URL-decoded equivalent of a string. +- +-@class function +-@name urldecode +-@param str URL-encoded string +-@param no_plus Don't decode + to " " +-@return URL-decoded string +-@see urlencode +-]] +- +----[[ +-Return the URL-encoded equivalent of a string. +- +-@class function +-@name urlencode +-@param str Source string +-@return URL-encoded string +-@see urldecode +-]] +- +----[[ +-Send the given data as JSON encoded string. +- +-@class function +-@name write_json +-@param data Data to send +-]] +- +----[[ +-Extract and split urlencoded data pairs, separated bei either "&" or ";" +-from given url or string. Returns a table with urldecoded values. +- +-Simple parameters are stored as string values associated with the parameter +-name within the table. Parameters with multiple values are stored as array +-containing the corresponding values. +- +-@class function +-@name urldecode_params +-@param url The url or string which contains x-www-urlencoded form data +-@param tbl Use the given table for storing values (optional) +-@return Table containing the urldecoded parameters +-@see urlencode_params +-]] +- +----[[ +-Encode each key-value-pair in given table to x-www-urlencoded format, +-separated by "&". +- +-Tables are encoded as parameters with multiple values by repeating the +-parameter name with each value. +- +-@class function +-@name urlencode_params +-@param tbl Table with the values +-@return String containing encoded values +-@see urldecode_params +-]] +- +----[[ +-Decode a mime encoded http message body with multipart/form-data Content-Type. +- +-Stores all extracted data associated with its parameter name +-in the params table within the given message object. Multiple parameter +-values are stored as tables, ordinary ones as strings. +- +-If an optional file callback function is given then it is fed with the +-file contents chunk by chunk and only the extracted file name is stored +-within the params table. The callback function will be called subsequently +-with three arguments: +- o Table containing decoded (name, file) and raw (headers) mime header data +- o String value containing a chunk of the file data +- o Boolean which indicates whether the current chunk is the last one (eof) +- +-@class function +-@name mimedecode_message_body +-@param src Ltn12 source function +-@param msg HTTP message object +-@param filecb File callback function (optional) +-@return Value indicating successful operation (not nil means "ok") +-@return String containing the error if unsuccessful +-@see parse_message_header +-]] +- +----[[ +-Decode an urlencoded http message body with application/x-www-urlencoded +-Content-Type. +- +-Stores all extracted data associated with its parameter name in the params +-table within the given message object. Multiple parameter values are stored +-as tables, ordinary ones as strings. +- +-@class function +-@name urldecode_message_body +-@param src Ltn12 source function +-@param msg HTTP message object +-@return Value indicating successful operation (not nil means "ok") +-@return String containing the error if unsuccessful +-@see parse_message_header +-]] +- +----[[ +-Try to extract and decode a http message body from the given ltn12 source. +-This function will examine the Content-Type within the given message object +-to select the appropriate content decoder. +- +-Currently the application/x-www-urlencoded and application/form-data +-mime types are supported. If the encountered content encoding can't be +-handled then the whole message body will be stored unaltered as "content" +-property within the given message object. +- +-@class function +-@name parse_message_body +-@param src Ltn12 source function +-@param msg HTTP message object +-@param filecb File data callback (optional, see mimedecode_message_body()) +-@return Value indicating successful operation (not nil means "ok") +-@return String containing the error if unsuccessful +-@see parse_message_header +-]] +--- a/feeds/luci/modules/luci-base/luasrc/ltn12.lua ++++ /dev/null +@@ -1,316 +0,0 @@ +---[[ +-LuaSocket 2.0.2 license +-Copyright � 2004-2007 Diego Nehab +- +-Permission is hereby granted, free of charge, to any person obtaining a +-copy of this software and associated documentation files (the "Software"), +-to deal in the Software without restriction, including without limitation +-the rights to use, copy, modify, merge, publish, distribute, sublicense, +-and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions: +- +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software. +- +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE. +-]]-- +---[[ +- Changes made by LuCI project: +- * Renamed to luci.ltn12 to avoid collisions with luasocket +- * Added inline documentation +-]]-- +------------------------------------------------------------------------------ +--- LTN12 - Filters, sources, sinks and pumps. +--- LuaSocket toolkit. +--- Author: Diego Nehab +--- RCS ID: $Id$ +------------------------------------------------------------------------------ +- +------------------------------------------------------------------------------ +--- Declare module +------------------------------------------------------------------------------ +-local string = require("string") +-local table = require("table") +-local base = _G +- +--- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts +-module("luci.ltn12") +- +-filter = {} +-source = {} +-sink = {} +-pump = {} +- +--- 2048 seems to be better in windows... +-BLOCKSIZE = 2048 +-_VERSION = "LTN12 1.0.1" +- +------------------------------------------------------------------------------ +--- Filter stuff +------------------------------------------------------------------------------ +- +- +--- by passing it each chunk and updating a context between calls. +-function filter.cycle(low, ctx, extra) +- base.assert(low) +- return function(chunk) +- local ret +- ret, ctx = low(ctx, chunk, extra) +- return ret +- end +-end +- +--- (thanks to Wim Couwenberg) +-function filter.chain(...) +- local n = table.getn(arg) +- local top, index = 1, 1 +- local retry = "" +- return function(chunk) +- retry = chunk and retry +- while true do +- if index == top then +- chunk = arg[index](chunk) +- if chunk == "" or top == n then return chunk +- elseif chunk then index = index + 1 +- else +- top = top+1 +- index = top +- end +- else +- chunk = arg[index](chunk or "") +- if chunk == "" then +- index = index - 1 +- chunk = retry +- elseif chunk then +- if index == n then return chunk +- else index = index + 1 end +- else base.error("filter returned inappropriate nil") end +- end +- end +- end +-end +- +------------------------------------------------------------------------------ +--- Source stuff +------------------------------------------------------------------------------ +- +- +--- create an empty source +-local function empty() +- return nil +-end +- +-function source.empty() +- return empty +-end +- +-function source.error(err) +- return function() +- return nil, err +- end +-end +- +-function source.file(handle, io_err) +- if handle then +- return function() +- local chunk = handle:read(BLOCKSIZE) +- if chunk and chunk:len() == 0 then chunk = nil end +- if not chunk then handle:close() end +- return chunk +- end +- else return source.error(io_err or "unable to open file") end +-end +- +-function source.simplify(src) +- base.assert(src) +- return function() +- local chunk, err_or_new = src() +- src = err_or_new or src +- if not chunk then return nil, err_or_new +- else return chunk end +- end +-end +- +-function source.string(s) +- if s then +- local i = 1 +- return function() +- local chunk = string.sub(s, i, i+BLOCKSIZE-1) +- i = i + BLOCKSIZE +- if chunk ~= "" then return chunk +- else return nil end +- end +- else return source.empty() end +-end +- +-function source.rewind(src) +- base.assert(src) +- local t = {} +- return function(chunk) +- if not chunk then +- chunk = table.remove(t) +- if not chunk then return src() +- else return chunk end +- else +- t[#t+1] = chunk +- end +- end +-end +- +-function source.chain(src, f) +- base.assert(src and f) +- local last_in, last_out = "", "" +- local state = "feeding" +- local err +- return function() +- if not last_out then +- base.error('source is empty!', 2) +- end +- while true do +- if state == "feeding" then +- last_in, err = src() +- if err then return nil, err end +- last_out = f(last_in) +- if not last_out then +- if last_in then +- base.error('filter returned inappropriate nil') +- else +- return nil +- end +- elseif last_out ~= "" then +- state = "eating" +- if last_in then last_in = "" end +- return last_out +- end +- else +- last_out = f(last_in) +- if last_out == "" then +- if last_in == "" then +- state = "feeding" +- else +- base.error('filter returned ""') +- end +- elseif not last_out then +- if last_in then +- base.error('filter returned inappropriate nil') +- else +- return nil +- end +- else +- return last_out +- end +- end +- end +- end +-end +- +--- Sources will be used one after the other, as if they were concatenated +--- (thanks to Wim Couwenberg) +-function source.cat(...) +- local src = table.remove(arg, 1) +- return function() +- while src do +- local chunk, err = src() +- if chunk then return chunk end +- if err then return nil, err end +- src = table.remove(arg, 1) +- end +- end +-end +- +------------------------------------------------------------------------------ +--- Sink stuff +------------------------------------------------------------------------------ +- +- +-function sink.table(t) +- t = t or {} +- local f = function(chunk, err) +- if chunk then t[#t+1] = chunk end +- return 1 +- end +- return f, t +-end +- +-function sink.simplify(snk) +- base.assert(snk) +- return function(chunk, err) +- local ret, err_or_new = snk(chunk, err) +- if not ret then return nil, err_or_new end +- snk = err_or_new or snk +- return 1 +- end +-end +- +-function sink.file(handle, io_err) +- if handle then +- return function(chunk, err) +- if not chunk then +- handle:close() +- return 1 +- else return handle:write(chunk) end +- end +- else return sink.error(io_err or "unable to open file") end +-end +- +--- creates a sink that discards data +-local function null() +- return 1 +-end +- +-function sink.null() +- return null +-end +- +-function sink.error(err) +- return function() +- return nil, err +- end +-end +- +-function sink.chain(f, snk) +- base.assert(f and snk) +- return function(chunk, err) +- if chunk ~= "" then +- local filtered = f(chunk) +- local done = chunk and "" +- while true do +- local ret, snkerr = snk(filtered, err) +- if not ret then return nil, snkerr end +- if filtered == done then return 1 end +- filtered = f(done) +- end +- else return 1 end +- end +-end +- +------------------------------------------------------------------------------ +--- Pump stuff +------------------------------------------------------------------------------ +- +- +-function pump.step(src, snk) +- local chunk, src_err = src() +- local ret, snk_err = snk(chunk, src_err) +- if chunk and ret then return 1 +- else return nil, src_err or snk_err end +-end +- +-function pump.all(src, snk, step) +- base.assert(src and snk) +- step = step or pump.step +- while true do +- local ret, err = step(src, snk) +- if not ret then +- if err then return nil, err +- else return 1 end +- end +- end +-end +- +--- a/feeds/luci/modules/luci-base/luasrc/util.lua ++++ /dev/null +@@ -1,776 +0,0 @@ +--- Copyright 2008 Steven Barth +--- Licensed to the public under the Apache License 2.0. +- +-local io = require "io" +-local math = require "math" +-local table = require "table" +-local debug = require "debug" +-local ldebug = require "luci.debug" +-local string = require "string" +-local coroutine = require "coroutine" +-local tparser = require "luci.template.parser" +-local json = require "luci.jsonc" +-local lhttp = require "lucihttp" +- +-local _ubus = require "ubus" +-local _ubus_connection = nil +- +-local getmetatable, setmetatable = getmetatable, setmetatable +-local rawget, rawset, unpack, select = rawget, rawset, unpack, select +-local tostring, type, assert, error = tostring, type, assert, error +-local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring +-local require, pcall, xpcall = require, pcall, xpcall +-local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit +- +-module "luci.util" +- +--- +--- Pythonic string formatting extension +--- +-getmetatable("").__mod = function(a, b) +- local ok, res +- +- if not b then +- return a +- elseif type(b) == "table" then +- local k, _ +- for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end +- +- ok, res = pcall(a.format, a, unpack(b)) +- if not ok then +- error(res, 2) +- end +- return res +- else +- if type(b) == "userdata" then b = tostring(b) end +- +- ok, res = pcall(a.format, a, b) +- if not ok then +- error(res, 2) +- end +- return res +- end +-end +- +- +--- +--- Class helper routines +--- +- +--- Instantiates a class +-local function _instantiate(class, ...) +- local inst = setmetatable({}, {__index = class}) +- +- if inst.__init__ then +- inst:__init__(...) +- end +- +- return inst +-end +- +--- The class object can be instantiated by calling itself. +--- Any class functions or shared parameters can be attached to this object. +--- Attaching a table to the class object makes this table shared between +--- all instances of this class. For object parameters use the __init__ function. +--- Classes can inherit member functions and values from a base class. +--- Class can be instantiated by calling them. All parameters will be passed +--- to the __init__ function of this class - if such a function exists. +--- The __init__ function must be used to set any object parameters that are not shared +--- with other objects of this class. Any return values will be ignored. +-function class(base) +- return setmetatable({}, { +- __call = _instantiate, +- __index = base +- }) +-end +- +-function instanceof(object, class) +- local meta = getmetatable(object) +- while meta and meta.__index do +- if meta.__index == class then +- return true +- end +- meta = getmetatable(meta.__index) +- end +- return false +-end +- +- +--- +--- Scope manipulation routines +--- +- +-coxpt = setmetatable({}, { __mode = "kv" }) +- +-local tl_meta = { +- __mode = "k", +- +- __index = function(self, key) +- local t = rawget(self, coxpt[coroutine.running()] +- or coroutine.running() or 0) +- return t and t[key] +- end, +- +- __newindex = function(self, key, value) +- local c = coxpt[coroutine.running()] or coroutine.running() or 0 +- local r = rawget(self, c) +- if not r then +- rawset(self, c, { [key] = value }) +- else +- r[key] = value +- end +- end +-} +- +--- the current active coroutine. A thread local store is private a table object +--- whose values can't be accessed from outside of the running coroutine. +-function threadlocal(tbl) +- return setmetatable(tbl or {}, tl_meta) +-end +- +- +--- +--- Debugging routines +--- +- +-function perror(obj) +- return io.stderr:write(tostring(obj) .. "\n") +-end +- +-function dumptable(t, maxdepth, i, seen) +- i = i or 0 +- seen = seen or setmetatable({}, {__mode="k"}) +- +- for k,v in pairs(t) do +- perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v)) +- if type(v) == "table" and (not maxdepth or i < maxdepth) then +- if not seen[v] then +- seen[v] = true +- dumptable(v, maxdepth, i+1, seen) +- else +- perror(string.rep("\t", i) .. "*** RECURSION ***") +- end +- end +- end +-end +- +- +--- +--- String and data manipulation routines +--- +- +-function pcdata(value) +- return value and tparser.pcdata(tostring(value)) +-end +- +-function urlencode(value) +- if value ~= nil then +- local str = tostring(value) +- return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL) +- or str +- end +- return nil +-end +- +-function urldecode(value, decode_plus) +- if value ~= nil then +- local flag = decode_plus and lhttp.DECODE_PLUS or 0 +- local str = tostring(value) +- return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag) +- or str +- end +- return nil +-end +- +-function striptags(value) +- return value and tparser.striptags(tostring(value)) +-end +- +-function shellquote(value) +- return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) +-end +- +--- for bash, ash and similar shells single-quoted strings are taken +--- literally except for single quotes (which terminate the string) +--- (and the exception noted below for dash (-) at the start of a +--- command line parameter). +-function shellsqescape(value) +- local res +- res, _ = string.gsub(value, "'", "'\\''") +- return res +-end +- +--- bash, ash and other similar shells interpret a dash (-) at the start +--- of a command-line parameters as an option indicator regardless of +--- whether it is inside a single-quoted string. It must be backlash +--- escaped to resolve this. This requires in some funky special-case +--- handling. It may actually be a property of the getopt function +--- rather than the shell proper. +-function shellstartsqescape(value) +- res, _ = string.gsub(value, "^%-", "\\-") +- return shellsqescape(res) +-end +- +--- containing the resulting substrings. The optional max parameter specifies +--- the number of bytes to process, regardless of the actual length of the given +--- string. The optional last parameter, regex, specifies whether the separator +--- sequence is interpreted as regular expression. +--- pattern as regular expression (optional, default is false) +-function split(str, pat, max, regex) +- pat = pat or "\n" +- max = max or #str +- +- local t = {} +- local c = 1 +- +- if #str == 0 then +- return {""} +- end +- +- if #pat == 0 then +- return nil +- end +- +- if max == 0 then +- return str +- end +- +- repeat +- local s, e = str:find(pat, c, not regex) +- max = max - 1 +- if s and max < 0 then +- t[#t+1] = str:sub(c) +- else +- t[#t+1] = str:sub(c, s and s - 1) +- end +- c = e and e + 1 or #str + 1 +- until not s or max < 0 +- +- return t +-end +- +-function trim(str) +- return (str:gsub("^%s*(.-)%s*$", "%1")) +-end +- +-function cmatch(str, pat) +- local count = 0 +- for _ in str:gmatch(pat) do count = count + 1 end +- return count +-end +- +--- one token per invocation, the tokens are separated by whitespace. If the +--- input value is a table, it is transformed into a string first. A nil value +--- will result in a valid iterator which aborts with the first invocation. +-function imatch(v) +- if type(v) == "table" then +- local k = nil +- return function() +- k = next(v, k) +- return v[k] +- end +- +- elseif type(v) == "number" or type(v) == "boolean" then +- local x = true +- return function() +- if x then +- x = false +- return tostring(v) +- end +- end +- +- elseif type(v) == "userdata" or type(v) == "string" then +- return tostring(v):gmatch("%S+") +- end +- +- return function() end +-end +- +--- value or 0 if the unit is unknown. Upper- or lower case is irrelevant. +--- Recognized units are: +--- o "y" - one year (60*60*24*366) +--- o "m" - one month (60*60*24*31) +--- o "w" - one week (60*60*24*7) +--- o "d" - one day (60*60*24) +--- o "h" - one hour (60*60) +--- o "min" - one minute (60) +--- o "kb" - one kilobyte (1024) +--- o "mb" - one megabyte (1024*1024) +--- o "gb" - one gigabyte (1024*1024*1024) +--- o "kib" - one si kilobyte (1000) +--- o "mib" - one si megabyte (1000*1000) +--- o "gib" - one si gigabyte (1000*1000*1000) +-function parse_units(ustr) +- +- local val = 0 +- +- -- unit map +- local map = { +- -- date stuff +- y = 60 * 60 * 24 * 366, +- m = 60 * 60 * 24 * 31, +- w = 60 * 60 * 24 * 7, +- d = 60 * 60 * 24, +- h = 60 * 60, +- min = 60, +- +- -- storage sizes +- kb = 1024, +- mb = 1024 * 1024, +- gb = 1024 * 1024 * 1024, +- +- -- storage sizes (si) +- kib = 1000, +- mib = 1000 * 1000, +- gib = 1000 * 1000 * 1000 +- } +- +- -- parse input string +- for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do +- +- local num = spec:gsub("[^0-9%.]+$","") +- local spn = spec:gsub("^[0-9%.]+", "") +- +- if map[spn] or map[spn:sub(1,1)] then +- val = val + num * ( map[spn] or map[spn:sub(1,1)] ) +- else +- val = val + num +- end +- end +- +- +- return val +-end +- +--- also register functions above in the central string class for convenience +-string.pcdata = pcdata +-string.striptags = striptags +-string.split = split +-string.trim = trim +-string.cmatch = cmatch +-string.parse_units = parse_units +- +- +-function append(src, ...) +- for i, a in ipairs({...}) do +- if type(a) == "table" then +- for j, v in ipairs(a) do +- src[#src+1] = v +- end +- else +- src[#src+1] = a +- end +- end +- return src +-end +- +-function combine(...) +- return append({}, ...) +-end +- +-function contains(table, value) +- for k, v in pairs(table) do +- if value == v then +- return k +- end +- end +- return false +-end +- +--- Both table are - in fact - merged together. +-function update(t, updates) +- for k, v in pairs(updates) do +- t[k] = v +- end +-end +- +-function keys(t) +- local keys = { } +- if t then +- for k, _ in kspairs(t) do +- keys[#keys+1] = k +- end +- end +- return keys +-end +- +-function clone(object, deep) +- local copy = {} +- +- for k, v in pairs(object) do +- if deep and type(v) == "table" then +- v = clone(v, deep) +- end +- copy[k] = v +- end +- +- return setmetatable(copy, getmetatable(object)) +-end +- +- +--- Serialize the contents of a table value. +-function _serialize_table(t, seen) +- assert(not seen[t], "Recursion detected.") +- seen[t] = true +- +- local data = "" +- local idata = "" +- local ilen = 0 +- +- for k, v in pairs(t) do +- if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then +- k = serialize_data(k, seen) +- v = serialize_data(v, seen) +- data = data .. ( #data > 0 and ", " or "" ) .. +- '[' .. k .. '] = ' .. v +- elseif k > ilen then +- ilen = k +- end +- end +- +- for i = 1, ilen do +- local v = serialize_data(t[i], seen) +- idata = idata .. ( #idata > 0 and ", " or "" ) .. v +- end +- +- return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data +-end +- +--- with loadstring(). +-function serialize_data(val, seen) +- seen = seen or setmetatable({}, {__mode="k"}) +- +- if val == nil then +- return "nil" +- elseif type(val) == "number" then +- return val +- elseif type(val) == "string" then +- return "%q" % val +- elseif type(val) == "boolean" then +- return val and "true" or "false" +- elseif type(val) == "function" then +- return "loadstring(%q)" % get_bytecode(val) +- elseif type(val) == "table" then +- return "{ " .. _serialize_table(val, seen) .. " }" +- else +- return '"[unhandled data type:' .. type(val) .. ']"' +- end +-end +- +-function restore_data(str) +- return loadstring("return " .. str)() +-end +- +- +--- +--- Byte code manipulation routines +--- +- +--- will be stripped before it is returned. +-function get_bytecode(val) +- local code +- +- if type(val) == "function" then +- code = string.dump(val) +- else +- code = string.dump( loadstring( "return " .. serialize_data(val) ) ) +- end +- +- return code -- and strip_bytecode(code) +-end +- +--- numbers and debugging numbers will be discarded. Original version by +--- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) +-function strip_bytecode(code) +- local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12) +- local subint +- if endian == 1 then +- subint = function(code, i, l) +- local val = 0 +- for n = l, 1, -1 do +- val = val * 256 + code:byte(i + n - 1) +- end +- return val, i + l +- end +- else +- subint = function(code, i, l) +- local val = 0 +- for n = 1, l, 1 do +- val = val * 256 + code:byte(i + n - 1) +- end +- return val, i + l +- end +- end +- +- local function strip_function(code) +- local count, offset = subint(code, 1, size) +- local stripped = { string.rep("\0", size) } +- local dirty = offset + count +- offset = offset + count + int * 2 + 4 +- offset = offset + int + subint(code, offset, int) * ins +- count, offset = subint(code, offset, int) +- for n = 1, count do +- local t +- t, offset = subint(code, offset, 1) +- if t == 1 then +- offset = offset + 1 +- elseif t == 4 then +- offset = offset + size + subint(code, offset, size) +- elseif t == 3 then +- offset = offset + num +- elseif t == 254 or t == 9 then +- offset = offset + lnum +- end +- end +- count, offset = subint(code, offset, int) +- stripped[#stripped+1] = code:sub(dirty, offset - 1) +- for n = 1, count do +- local proto, off = strip_function(code:sub(offset, -1)) +- stripped[#stripped+1] = proto +- offset = offset + off - 1 +- end +- offset = offset + subint(code, offset, int) * int + int +- count, offset = subint(code, offset, int) +- for n = 1, count do +- offset = offset + subint(code, offset, size) + size + int * 2 +- end +- count, offset = subint(code, offset, int) +- for n = 1, count do +- offset = offset + subint(code, offset, size) + size +- end +- stripped[#stripped+1] = string.rep("\0", int * 3) +- return table.concat(stripped), offset +- end +- +- return code:sub(1,12) .. strip_function(code:sub(13,-1)) +-end +- +- +--- +--- Sorting iterator functions +--- +- +-function _sortiter( t, f ) +- local keys = { } +- +- local k, v +- for k, v in pairs(t) do +- keys[#keys+1] = k +- end +- +- local _pos = 0 +- +- table.sort( keys, f ) +- +- return function() +- _pos = _pos + 1 +- if _pos <= #keys then +- return keys[_pos], t[keys[_pos]], _pos +- end +- end +-end +- +--- the provided callback function. +-function spairs(t,f) +- return _sortiter( t, f ) +-end +- +--- The table pairs are sorted by key. +-function kspairs(t) +- return _sortiter( t ) +-end +- +--- The table pairs are sorted by value. +-function vspairs(t) +- return _sortiter( t, function (a,b) return t[a] < t[b] end ) +-end +- +- +--- +--- System utility functions +--- +- +-function bigendian() +- return string.byte(string.dump(function() end), 7) == 0 +-end +- +-function exec(command) +- local pp = io.popen(command) +- local data = pp:read("*a") +- pp:close() +- +- return data +-end +- +-function execi(command) +- local pp = io.popen(command) +- +- return pp and function() +- local line = pp:read() +- +- if not line then +- pp:close() +- end +- +- return line +- end +-end +- +--- Deprecated +-function execl(command) +- local pp = io.popen(command) +- local line = "" +- local data = {} +- +- while true do +- line = pp:read() +- if (line == nil) then break end +- data[#data+1] = line +- end +- pp:close() +- +- return data +-end +- +- +-local ubus_codes = { +- "INVALID_COMMAND", +- "INVALID_ARGUMENT", +- "METHOD_NOT_FOUND", +- "NOT_FOUND", +- "NO_DATA", +- "PERMISSION_DENIED", +- "TIMEOUT", +- "NOT_SUPPORTED", +- "UNKNOWN_ERROR", +- "CONNECTION_FAILED" +-} +- +-local function ubus_return(...) +- if select('#', ...) == 2 then +- local rv, err = select(1, ...), select(2, ...) +- if rv == nil and type(err) == "number" then +- return nil, err, ubus_codes[err] +- end +- end +- +- return ... +-end +- +-function ubus(object, method, data) +- if not _ubus_connection then +- _ubus_connection = _ubus.connect() +- assert(_ubus_connection, "Unable to establish ubus connection") +- end +- +- if object and method then +- if type(data) ~= "table" then +- data = { } +- end +- return ubus_return(_ubus_connection:call(object, method, data)) +- elseif object then +- return _ubus_connection:signatures(object) +- else +- return _ubus_connection:objects() +- end +-end +- +-function serialize_json(x, cb) +- local js = json.stringify(x) +- if type(cb) == "function" then +- cb(js) +- else +- return js +- end +-end +- +- +-function libpath() +- return require "nixio.fs".dirname(ldebug.__file__) +-end +- +-function checklib(fullpathexe, wantedlib) +- local fs = require "nixio.fs" +- local haveldd = fs.access('/usr/bin/ldd') +- local haveexe = fs.access(fullpathexe) +- if not haveldd or not haveexe then +- return false +- end +- local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe))) +- if not libs then +- return false +- end +- for k, v in ipairs(split(libs)) do +- if v:find(wantedlib) then +- return true +- end +- end +- return false +-end +- +-------------------------------------------------------------------------------- +--- Coroutine safe xpcall and pcall versions +--- +--- Encapsulates the protected calls with a coroutine based loop, so errors can +--- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines +--- yielding inside the call to pcall or xpcall. +--- +--- Authors: Roberto Ierusalimschy and Andre Carregal +--- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas +--- +--- Copyright 2005 - Kepler Project +--- +--- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $ +-------------------------------------------------------------------------------- +- +-------------------------------------------------------------------------------- +--- Implements xpcall with coroutines +-------------------------------------------------------------------------------- +-local coromap = setmetatable({}, { __mode = "k" }) +- +-local function handleReturnValue(err, co, status, ...) +- if not status then +- return false, err(debug.traceback(co, (...)), ...) +- end +- if coroutine.status(co) == 'suspended' then +- return performResume(err, co, coroutine.yield(...)) +- else +- return true, ... +- end +-end +- +-function performResume(err, co, ...) +- return handleReturnValue(err, co, coroutine.resume(co, ...)) +-end +- +-local function id(trace, ...) +- return trace +-end +- +-function coxpcall(f, err, ...) +- local current = coroutine.running() +- if not current then +- if err == id then +- return pcall(f, ...) +- else +- if select("#", ...) > 0 then +- local oldf, params = f, { ... } +- f = function() return oldf(unpack(params)) end +- end +- return xpcall(f, err) +- end +- else +- local res, co = pcall(coroutine.create, f) +- if not res then +- local newf = function(...) return f(...) end +- co = coroutine.create(newf) +- end +- coromap[co] = current +- coxpt[co] = coxpt[current] or current or 0 +- return performResume(err, co, ...) +- end +-end +- +-function copcall(f, ...) +- return coxpcall(f, id, ...) +-end +--- a/feeds/luci/modules/luci-base/luasrc/util.luadoc ++++ /dev/null +@@ -1,413 +0,0 @@ +----[[ +-LuCI utility functions. +-]] +-module "luci.util" +- +----[[ +-Create a Class object (Python-style object model). +- +-The class object can be instantiated by calling itself. +-Any class functions or shared parameters can be attached to this object. +-Attaching a table to the class object makes this table shared between +-all instances of this class. For object parameters use the __init__ function. +-Classes can inherit member functions and values from a base class. +-Class can be instantiated by calling them. All parameters will be passed +-to the __init__ function of this class - if such a function exists. +-The __init__ function must be used to set any object parameters that are not shared +-with other objects of this class. Any return values will be ignored. +- +-@class function +-@name class +-@param base The base class to inherit from (optional) +-@return A class object +-@see instanceof +-@see clone +-]] +- +----[[ +-Test whether the given object is an instance of the given class. +- +-@class function +-@name instanceof +-@param object Object instance +-@param class Class object to test against +-@return Boolean indicating whether the object is an instance +-@see class +-@see clone +-]] +- +----[[ +-Create a new or get an already existing thread local store associated with +-the current active coroutine. +- +-A thread local store is private a table object +-whose values can't be accessed from outside of the running coroutine. +- +-@class function +-@name threadlocal +-@return Table value representing the corresponding thread local store +-]] +- +----[[ +-Write given object to stderr. +- +-@class function +-@name perror +-@param obj Value to write to stderr +-@return Boolean indicating whether the write operation was successful +-]] +- +----[[ +-Recursively dumps a table to stdout, useful for testing and debugging. +- +-@class function +-@name dumptable +-@param t Table value to dump +-@param maxdepth Maximum depth +-@return Always nil +-]] +- +----[[ +-Create valid XML PCDATA from given string. +- +-@class function +-@name pcdata +-@param value String value containing the data to escape +-@return String value containing the escaped data +-]] +- +----[[ +-Decode an URL-encoded string - optionally decoding the "+" sign to space. +- +-@class function +-@name urldecode +-@param str Input string in x-www-urlencoded format +-@param decode_plus Decode "+" signs to spaces if true (optional) +-@return The decoded string +-@see urlencode +-]] +- +----[[ +-URL-encode given string. +- +-@class function +-@name urlencode +-@param str String to encode +-@return String containing the encoded data +-@see urldecode +-]] +- +----[[ +-Strip HTML tags from given string. +- +-@class function +-@name striptags +-@param value String containing the HTML text +-@return String with HTML tags stripped of +-]] +- +----[[ +-Safely quote value for use in shell commands. +- +-@class function +-@name shellquote +-@param value String containing the value to quote +-@return Single-quote enclosed string with embedded quotes escaped +-]] +- +----[[ +-Splits given string on a defined separator sequence and return a table +-containing the resulting substrings. +- +-The optional max parameter specifies the number of bytes to process, +-regardless of the actual length of the given string. The optional last +-parameter, regex, specifies whether the separator sequence is +-nterpreted as regular expression. +- +-@class function +-@name split +-@param str String value containing the data to split up +-@param pat String with separator pattern (optional, defaults to "\n") +-@param max Maximum times to split (optional) +-@param regex Boolean indicating whether to interpret the separator +--- pattern as regular expression (optional, default is false) +-@return Table containing the resulting substrings +-]] +- +----[[ +-Remove leading and trailing whitespace from given string value. +- +-@class function +-@name trim +-@param str String value containing whitespace padded data +-@return String value with leading and trailing space removed +-]] +- +----[[ +-Count the occurrences of given substring in given string. +- +-@class function +-@name cmatch +-@param str String to search in +-@param pattern String containing pattern to find +-@return Number of found occurrences +-]] +- +----[[ +-Return a matching iterator for the given value. +- +-The iterator will return one token per invocation, the tokens are separated by +-whitespace. If the input value is a table, it is transformed into a string first. +-A nil value will result in a valid iterator which aborts with the first invocation. +- +-@class function +-@name imatch +-@param val The value to scan (table, string or nil) +-@return Iterator which returns one token per call +-]] +- +----[[ +-Parse certain units from the given string and return the canonical integer +-value or 0 if the unit is unknown. +- +-Upper- or lower case is irrelevant. +-Recognized units are: +- +--- o "y" - one year (60*60*24*366) +- o "m" - one month (60*60*24*31) +- o "w" - one week (60*60*24*7) +- o "d" - one day (60*60*24) +- o "h" - one hour (60*60) +- o "min" - one minute (60) +- o "kb" - one kilobyte (1024) +- o "mb" - one megabyte (1024*1024) +- o "gb" - one gigabyte (1024*1024*1024) +- o "kib" - one si kilobyte (1000) +- o "mib" - one si megabyte (1000*1000) +- o "gib" - one si gigabyte (1000*1000*1000) +- +-@class function +-@name parse_units +-@param ustr String containing a numerical value with trailing unit +-@return Number containing the canonical value +-]] +- +----[[ +-Appends numerically indexed tables or single objects to a given table. +- +-@class function +-@name append +-@param src Target table +-@param ... Objects to insert +-@return Target table +-]] +- +----[[ +-Combines two or more numerically indexed tables and single objects into one table. +- +-@class function +-@name combine +-@param tbl1 Table value to combine +-@param tbl2 Table value to combine +-@param ... More tables to combine +-@return Table value containing all values of given tables +-]] +- +----[[ +-Checks whether the given table contains the given value. +- +-@class function +-@name contains +-@param table Table value +-@param value Value to search within the given table +-@return Number indicating the first index at which the given value occurs +--- within table or false. +-]] +- +----[[ +-Update values in given table with the values from the second given table. +- +-Both table are - in fact - merged together. +- +-@class function +-@name update +-@param t Table which should be updated +-@param updates Table containing the values to update +-@return Always nil +-]] +- +----[[ +-Retrieve all keys of given associative table. +- +-@class function +-@name keys +-@param t Table to extract keys from +-@return Sorted table containing the keys +-]] +- +----[[ +-Clones the given object and return it's copy. +- +-@class function +-@name clone +-@param object Table value to clone +-@param deep Boolean indicating whether to do recursive cloning +-@return Cloned table value +-]] +- +----[[ +-Recursively serialize given data to lua code, suitable for restoring +-with loadstring(). +- +-@class function +-@name serialize_data +-@param val Value containing the data to serialize +-@return String value containing the serialized code +-@see restore_data +-@see get_bytecode +-]] +- +----[[ +-Restore data previously serialized with serialize_data(). +- +-@class function +-@name restore_data +-@param str String containing the data to restore +-@return Value containing the restored data structure +-@see serialize_data +-@see get_bytecode +-]] +- +----[[ +-Return the current runtime bytecode of the given data. The byte code +-will be stripped before it is returned. +- +-@class function +-@name get_bytecode +-@param val Value to return as bytecode +-@return String value containing the bytecode of the given data +-]] +- +----[[ +-Strips unnecessary lua bytecode from given string. +- +-Information like line numbers and debugging numbers will be discarded. +-Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) +- +-@class function +-@name strip_bytecode +-@param code String value containing the original lua byte code +-@return String value containing the stripped lua byte code +-]] +- +----[[ +-Return a key, value iterator which returns the values sorted according to +-the provided callback function. +- +-@class function +-@name spairs +-@param t The table to iterate +-@param f A callback function to decide the order of elements +-@return Function value containing the corresponding iterator +-]] +- +----[[ +-Return a key, value iterator for the given table. +- +-The table pairs are sorted by key. +- +-@class function +-@name kspairs +-@param t The table to iterate +-@return Function value containing the corresponding iterator +-]] +- +----[[ +-Return a key, value iterator for the given table. +- +-The table pairs are sorted by value. +- +-@class function +-@name vspairs +-@param t The table to iterate +-@return Function value containing the corresponding iterator +-]] +- +----[[ +-Test whether the current system is operating in big endian mode. +- +-@class function +-@name bigendian +-@return Boolean value indicating whether system is big endian +-]] +- +----[[ +-Execute given commandline and gather stdout. +- +-@class function +-@name exec +-@param command String containing command to execute +-@return String containing the command's stdout +-]] +- +----[[ +-Return a line-buffered iterator over the output of given command. +- +-@class function +-@name execi +-@param command String containing the command to execute +-@return Iterator +-]] +- +----[[ +-Issue an ubus call. +- +-@class function +-@name ubus +-@param object String containing the ubus object to call +-@param method String containing the ubus method to call +-@param values Table containing the values to pass +-@return Table containin the ubus result +-]] +- +----[[ +-Convert data structure to JSON +- +-@class function +-@name serialize_json +-@param data The data to serialize +-@param writer A function to write a chunk of JSON data (optional) +-@return String containing the JSON if called without write callback +-]] +- +----[[ +-Returns the absolute path to LuCI base directory. +- +-@class function +-@name libpath +-@return String containing the directory path +-]] +- +----[[ +-This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function +- +-@class function +-@name coxpcall +-@param f Lua function to be called protected +-@param err Custom error handler +-@param ... Parameters passed to the function +-@return A boolean whether the function call succeeded and the return +--- values of either the function or the error handler +-]] +- +----[[ +-This is a coroutine-safe drop-in replacement for Lua's "pcall"-function +- +-@class function +-@name copcall +-@param f Lua function to be called protected +-@param ... Parameters passed to the function +-@return A boolean whether the function call succeeded and the returns +--- values of the function or the error object +-]] +- +--- /dev/null ++++ b/feeds/luci/modules/luci-base/luasrc/xml.lua +@@ -0,0 +1,26 @@ ++-- Copyright 2008 Steven Barth ++-- Licensed to the public under the Apache License 2.0. ++ ++local tparser = require "luci.template.parser" ++local string = require "string" ++ ++local tostring = tostring ++ ++module "luci.xml" ++ ++-- ++-- String and data manipulation routines ++-- ++ ++function pcdata(value) ++ return value and tparser.pcdata(tostring(value)) ++end ++ ++function striptags(value) ++ return value and tparser.striptags(tostring(value)) ++end ++ ++ ++-- also register functions above in the central string class for convenience ++string.pcdata = pcdata ++string.striptags = striptags +--- /dev/null ++++ b/feeds/luci/modules/luci-base/luasrc/xml.luadoc +@@ -0,0 +1,23 @@ ++---[[ ++LuCI utility functions. ++]] ++module "luci.xml" ++ ++---[[ ++Create valid XML PCDATA from given string. ++ ++@class function ++@name pcdata ++@param value String value containing the data to escape ++@return String value containing the escaped data ++]] ++ ++---[[ ++Strip HTML tags from given string. ++ ++@class function ++@name striptags ++@param value String containing the HTML text ++@return String with HTML tags stripped of ++]] ++ +--- a/feeds/luci/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua ++++ b/feeds/luci/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua +@@ -68,7 +68,7 @@ else + break + else + files[#files+1] = "

  • " +- files[#files+1] = luci.util.pcdata(ln) ++ files[#files+1] = luci.xml.pcdata(ln) + files[#files+1] = "
  • " + end + end diff --git a/patches/series b/patches/series index 30ce363edc..556af70bf8 100644 --- a/patches/series +++ b/patches/series @@ -12,3 +12,4 @@ 800-mbedtls-accept-rsa-1024.patch 0001-tools-mkimake-fix-handling-of-long-pathnames.patch 0002-tools-u-boot-enlage-max-pathlength-for-mkimage.patch +202-split-luci-base_PR2817.patch