diff --git a/modules b/modules index 45e90be959..a1812c678e 100644 --- a/modules +++ b/modules @@ -1,13 +1,13 @@ OPENWRT_REPO=https://git.openwrt.org/openwrt/openwrt.git -OPENWRT_COMMIT=33732f4a9c17921b782167a0dcaba9703d4e6753 +OPENWRT_COMMIT=d5810aa61367a9424599935572f622d27f8303f0 OPENWRT_BRANCH=openwrt-19.07 PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git -PACKAGES_PACKAGES_COMMIT=99efce0cd27adfcc53384fba93f37e5ee2e517de +PACKAGES_PACKAGES_COMMIT=eae1bb397f064befe003b01a36ae318321e81d35 PACKAGES_PACKAGES_BRANCH=openwrt-19.07 PACKAGES_LUCI_REPO=https://github.com/openwrt/luci.git -PACKAGES_LUCI_COMMIT=13dd17fca148965d38f0d4e578b19679a7c4daa2 +PACKAGES_LUCI_COMMIT=0d0ab01a64f25d15325d3c98a7df252085382f1d PACKAGES_LUCI_BRANCH=openwrt-19.07 PACKAGES_FREIFUNK_REPO=https://github.com/freifunk/openwrt-packages.git @@ -15,13 +15,13 @@ PACKAGES_FREIFUNK_COMMIT=73454e6fe1bdc902c69ca0079d979fdb94d6fb1f PACKAGES_FREIFUNK_BRANCH=openwrt-19.07 PACKAGES_ROUTING_REPO=https://github.com/openwrt-routing/packages.git -PACKAGES_ROUTING_COMMIT=efa6e5445adda9c6545f551808829ec927cbade8 +PACKAGES_ROUTING_COMMIT=b77498bd56d5e45ab4577a1f4ad6ffc55b4a86b7 PACKAGES_ROUTING_BRANCH=openwrt-19.07 PACKAGES_PACKAGES_BERLIN_REPO=https://github.com/freifunk-berlin/firmware-packages.git -PACKAGES_PACKAGES_BERLIN_COMMIT=b03e01ed5a3b691a19cf284627aab9820ce6c2b8 +PACKAGES_PACKAGES_BERLIN_COMMIT=7d9cc4f998ce76db71cd2e64acd23d3c5f1af458 PACKAGES_PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git -PACKAGES_PACKAGES_GLUON_COMMIT=033401c18ecbf5073f5330b4462af6e450e358ff +PACKAGES_PACKAGES_GLUON_COMMIT=95c805c863cd0818f0e5196d3b7bde6860fd2861 GLUON_FEEDS='packages luci freifunk routing packages_berlin packages_gluon' diff --git a/patches/openwrt/1600-imagebuilder-custom-postinst-script.patch b/patches/openwrt/1600-imagebuilder-custom-postinst-script.patch index 4a692a8f85..9f6e30ebe1 100644 --- a/patches/openwrt/1600-imagebuilder-custom-postinst-script.patch +++ b/patches/openwrt/1600-imagebuilder-custom-postinst-script.patch @@ -2,14 +2,11 @@ From: template Date: Fri, 6 Sep 2019 08:29:50 +0000 Subject: imagebuilder-custom-postinst-script ---- - - diff --git a/target/imagebuilder/files/Makefile b/target/imagebuilder/files/Makefile -index 95df8bf113..0debd5a882 100644 +index 835dd98ca5fe9f876247d3bf43c02459e640dcd1..59f99d13ab32634ef29591743d1d3b4dc020ee50 100644 --- a/target/imagebuilder/files/Makefile +++ b/target/imagebuilder/files/Makefile -@@ -105,6 +105,9 @@ _call_image: staging_dir/host/.prereq-build +@@ -117,6 +117,9 @@ _call_image: staging_dir/host/.prereq-build $(MAKE) package_reload $(MAKE) package_install $(MAKE) -s prepare_rootfs @@ -17,9 +14,5 @@ index 95df8bf113..0debd5a882 100644 + (cd "$(TARGET_DIR)" ; bash $(CUSTOM_POSTINST_SCRIPT)) +endif $(MAKE) -s build_image + $(MAKE) -s json_overview_image_info $(MAKE) -s checksum - --- -2.20.1 - - diff --git a/patches/packages/luci/0202-split-luci-base_PR2817.patch b/patches/packages/luci/0202-split-luci-base_PR2817.patch index 67c17bcddd..01d5a86100 100644 --- a/patches/packages/luci/0202-split-luci-base_PR2817.patch +++ b/patches/packages/luci/0202-split-luci-base_PR2817.patch @@ -1,12 +1,40 @@ +From 47b14b662412deb55fd089b9677ef8c75bef047c Mon Sep 17 00:00:00 2001 From: template Date: Fri, 6 Sep 2019 08:29:50 +0000 -Subject: split-luci-base_PR2817 +Subject: [PATCH] split-luci-base_PR2817 --- + .../luasrc/model/cbi/upnp/upnp.lua | 2 +- + .../luci-app-wol/luasrc/model/cbi/wol.lua | 3 ++- + libs/luci-lib-base/Makefile | 14 ++++++++++ + .../luci-lib-base}/luasrc/debug.lua | 0 + .../luci-lib-base}/luasrc/http.lua | 0 + .../luci-lib-base}/luasrc/http.luadoc | 0 + .../luci-lib-base}/luasrc/ltn12.lua | 0 + .../luci-lib-base}/luasrc/util.lua | 10 ------- + .../luci-lib-base}/luasrc/util.luadoc | 18 ------------- + libs/luci-lib-httpclient/Makefile | 2 +- + libs/luci-lib-httpprotoutils/Makefile | 2 +- + modules/luci-base/Makefile | 2 +- + modules/luci-base/luasrc/dispatcher.lua | 11 ++++---- + modules/luci-base/luasrc/xml.lua | 26 +++++++++++++++++++ + modules/luci-base/luasrc/xml.luadoc | 23 ++++++++++++++++ + .../model/cbi/admin_system/backupfiles.lua | 2 +- + 16 files changed, 76 insertions(+), 39 deletions(-) + create mode 100644 libs/luci-lib-base/Makefile + rename {modules/luci-base => libs/luci-lib-base}/luasrc/debug.lua (100%) + rename {modules/luci-base => libs/luci-lib-base}/luasrc/http.lua (100%) + rename {modules/luci-base => libs/luci-lib-base}/luasrc/http.luadoc (100%) + rename {modules/luci-base => libs/luci-lib-base}/luasrc/ltn12.lua (100%) + rename {modules/luci-base => libs/luci-lib-base}/luasrc/util.lua (98%) + rename {modules/luci-base => libs/luci-lib-base}/luasrc/util.luadoc (96%) + create mode 100644 modules/luci-base/luasrc/xml.lua + create mode 100644 modules/luci-base/luasrc/xml.luadoc - ---- luci/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua -+++ luci/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua +diff --git a/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua b/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua +index a2023926e..fa823a7a7 100644 +--- a/applications/luci-app-upnp/luasrc/model/cbi/upnp/upnp.lua ++++ b/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. @@ -16,8 +44,10 @@ Subject: split-luci-base_PR2817 translate("UPnP allows clients in the local network to automatically configure the router.")) m:section(SimpleSection).template = "upnp_status" ---- luci/applications/luci-app-wol/luasrc/model/cbi/wol.lua -+++ luci/applications/luci-app-wol/luasrc/model/cbi/wol.lua +diff --git a/applications/luci-app-wol/luasrc/model/cbi/wol.lua b/applications/luci-app-wol/luasrc/model/cbi/wol.lua +index 43b87dda9..f64713693 100644 +--- a/applications/luci-app-wol/luasrc/model/cbi/wol.lua ++++ b/applications/luci-app-wol/luasrc/model/cbi/wol.lua @@ -2,6 +2,7 @@ -- Licensed to the public under the Apache License 2.0. @@ -32,4465 +62,94 @@ Subject: split-luci-base_PR2817 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 -+++ 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 -+++ 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 -+++ 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 -+++ 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 -+++ 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 -+++ 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 -+++ 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 -+]] -+ ---- luci/libs/luci-lib-httpclient/Makefile -+++ 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 - ---- luci/libs/luci-lib-httpprotoutils/Makefile -+++ 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 - ---- luci/modules/luci-base/Makefile -+++ 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 ---- 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 -- ---- luci/modules/luci-base/luasrc/dispatcher.lua -+++ 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; ---- 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 ---- 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 --]] ---- 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 -- ---- 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 + } + + local p = io.popen(cmd .. " 2>&1") +diff --git a/libs/luci-lib-base/Makefile b/libs/luci-lib-base/Makefile +new file mode 100644 +index 000000000..35b1836ec +--- /dev/null ++++ b/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 +diff --git a/modules/luci-base/luasrc/debug.lua b/libs/luci-lib-base/luasrc/debug.lua +similarity index 100% +rename from modules/luci-base/luasrc/debug.lua +rename to libs/luci-lib-base/luasrc/debug.lua +diff --git a/modules/luci-base/luasrc/http.lua b/libs/luci-lib-base/luasrc/http.lua +similarity index 100% +rename from modules/luci-base/luasrc/http.lua +rename to libs/luci-lib-base/luasrc/http.lua +diff --git a/modules/luci-base/luasrc/http.luadoc b/libs/luci-lib-base/luasrc/http.luadoc +similarity index 100% +rename from modules/luci-base/luasrc/http.luadoc +rename to libs/luci-lib-base/luasrc/http.luadoc +diff --git a/modules/luci-base/luasrc/ltn12.lua b/libs/luci-lib-base/luasrc/ltn12.lua +similarity index 100% +rename from modules/luci-base/luasrc/ltn12.lua +rename to libs/luci-lib-base/luasrc/ltn12.lua +diff --git a/modules/luci-base/luasrc/util.lua b/libs/luci-lib-base/luasrc/util.lua +similarity index 98% +rename from modules/luci-base/luasrc/util.lua +rename to libs/luci-lib-base/luasrc/util.lua +index a30e8b72f..f3aa52603 100644 +--- a/modules/luci-base/luasrc/util.lua ++++ b/libs/luci-lib-base/luasrc/util.lua +@@ -159,10 +159,6 @@ end + -- String and data manipulation routines + -- + +-function pcdata(value) +- return value and tparser.pcdata(tostring(value)) -end - --function copcall(f, ...) -- return coxpcall(f, id, ...) + function urlencode(value) + if value ~= nil then + local str = tostring(value) +@@ -182,10 +178,6 @@ function urldecode(value, decode_plus) + return nil + end + +-function striptags(value) +- return value and tparser.striptags(tostring(value)) -end ---- 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 --]] - + function shellquote(value) + return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) + end +@@ -343,8 +335,6 @@ function parse_units(ustr) + 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 +diff --git a/modules/luci-base/luasrc/util.luadoc b/libs/luci-lib-base/luasrc/util.luadoc +similarity index 96% +rename from modules/luci-base/luasrc/util.luadoc +rename to libs/luci-lib-base/luasrc/util.luadoc +index 4ec68dd1e..6ab130008 100644 +--- a/modules/luci-base/luasrc/util.luadoc ++++ b/libs/luci-lib-base/luasrc/util.luadoc +@@ -67,15 +67,6 @@ Recursively dumps a table to stdout, useful for testing and debugging. + @return Always nil + ]] + ----[[ -Create valid XML PCDATA from given string. - @@ -4500,27 +159,13 @@ Subject: split-luci-base_PR2817 -@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 --]] -- + ---[[ + Decode an URL-encoded string - optionally decoding the "+" sign to space. + +@@ -97,15 +88,6 @@ URL-encode given string. + @see urldecode + ]] + ----[[ -Strip HTML tags from given string. - @@ -4530,313 +175,100 @@ Subject: split-luci-base_PR2817 -@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 --]] -- + ---[[ + Safely quote value for use in shell commands. + +diff --git a/libs/luci-lib-httpclient/Makefile b/libs/luci-lib-httpclient/Makefile +index b8bd428b2..9c28c35d8 100644 +--- a/libs/luci-lib-httpclient/Makefile ++++ b/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 + +diff --git a/libs/luci-lib-httpprotoutils/Makefile b/libs/luci-lib-httpprotoutils/Makefile +index 851a362eb..95f45d200 100644 +--- a/libs/luci-lib-httpprotoutils/Makefile ++++ b/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 + +diff --git a/modules/luci-base/Makefile b/modules/luci-base/Makefile +index ea2330910..fde712a50 100644 +--- a/modules/luci-base/Makefile ++++ b/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 +diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua +index d14a86673..050e656b5 100644 +--- a/modules/luci-base/luasrc/dispatcher.lua ++++ b/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" + +@@ -271,12 +272,12 @@ end + + local function tree_to_json(node, json) + local fs = require "nixio.fs" +- local util = require "luci.util" ++ local xml = require "luci.xml" + + if type(node.nodes) == "table" then + for subname, subnode in pairs(node.nodes) do + local spec = { +- title = util.striptags(subnode.title), ++ title = xml.striptags(subnode.title), + order = subnode.order + } + +@@ -741,7 +742,7 @@ local function init_template_engine(ctx) + (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) +@@ -756,8 +757,8 @@ local function init_template_engine(ctx) + 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; +diff --git a/modules/luci-base/luasrc/xml.lua b/modules/luci-base/luasrc/xml.lua +new file mode 100644 +index 000000000..30b37210b --- /dev/null -+++ luci/modules/luci-base/luasrc/xml.lua ++++ b/modules/luci-base/luasrc/xml.lua @@ -0,0 +1,26 @@ +-- Copyright 2008 Steven Barth +-- Licensed to the public under the Apache License 2.0. @@ -4864,8 +296,11 @@ Subject: split-luci-base_PR2817 +-- also register functions above in the central string class for convenience +string.pcdata = pcdata +string.striptags = striptags +diff --git a/modules/luci-base/luasrc/xml.luadoc b/modules/luci-base/luasrc/xml.luadoc +new file mode 100644 +index 000000000..58de53396 --- /dev/null -+++ luci/modules/luci-base/luasrc/xml.luadoc ++++ b/modules/luci-base/luasrc/xml.luadoc @@ -0,0 +1,23 @@ +---[[ +LuCI utility functions. @@ -4890,8 +325,10 @@ Subject: split-luci-base_PR2817 +@return String with HTML tags stripped of +]] + ---- luci/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua -+++ luci/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua +diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua +index c81466c87..91c654916 100644 +--- a/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua ++++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua @@ -68,7 +68,7 @@ else break else @@ -4904,4 +341,3 @@ Subject: split-luci-base_PR2817 -- 2.20.1 -