diff --git a/files/usr/lib/lua/aredn/utils.lua b/files/usr/lib/lua/aredn/utils.lua index 1261478a..a745faf9 100755 --- a/files/usr/lib/lua/aredn/utils.lua +++ b/files/usr/lib/lua/aredn/utils.lua @@ -37,7 +37,7 @@ local nxo = require("nixio") local ipc = require("luci.ip") -require('luci.ohttp') +require('luci.http') require("uci") function round2(num, idp) diff --git a/files/usr/lib/lua/luci/ohttp.lua b/files/usr/lib/lua/luci/ohttp.lua deleted file mode 100755 index 20b55f28..00000000 --- a/files/usr/lib/lua/luci/ohttp.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 diff --git a/files/www/cgi-bin/admin b/files/www/cgi-bin/admin index bc62716a..a0432743 100755 --- a/files/www/cgi-bin/admin +++ b/files/www/cgi-bin/admin @@ -169,7 +169,7 @@ end local parms = {} local firmfile = "" if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancedconfig b/files/www/cgi-bin/advancedconfig index 41c24f20..e6de4ccc 100755 --- a/files/www/cgi-bin/advancedconfig +++ b/files/www/cgi-bin/advancedconfig @@ -665,7 +665,7 @@ end -- read_postdata local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancednetwork b/files/www/cgi-bin/advancednetwork index a13e87ec..def3e0ac 100755 --- a/files/www/cgi-bin/advancednetwork +++ b/files/www/cgi-bin/advancednetwork @@ -329,7 +329,7 @@ local layout = layouts[get_board_type] local configs = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/mesh b/files/www/cgi-bin/mesh index 521ad1a5..18f50e64 100755 --- a/files/www/cgi-bin/mesh +++ b/files/www/cgi-bin/mesh @@ -90,7 +90,7 @@ end -- post data if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/ports b/files/www/cgi-bin/ports index 3f66e8ec..bb6f3fdb 100755 --- a/files/www/cgi-bin/ports +++ b/files/www/cgi-bin/ports @@ -60,7 +60,7 @@ end -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/scan b/files/www/cgi-bin/scan index a97263fd..f1e62e74 100755 --- a/files/www/cgi-bin/scan +++ b/files/www/cgi-bin/scan @@ -149,7 +149,7 @@ end -- scan end if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/setup b/files/www/cgi-bin/setup index f8288509..51106932 100755 --- a/files/www/cgi-bin/setup +++ b/files/www/cgi-bin/setup @@ -41,7 +41,7 @@ require("aredn.http") require("aredn.utils") require("aredn.hardware") require("uci") -require('luci.ohttp') +require('luci.http') local html = require("aredn.html") local aredn_info = require("aredn.info") diff --git a/files/www/cgi-bin/signal b/files/www/cgi-bin/signal index deecbe4b..25c755c8 100755 --- a/files/www/cgi-bin/signal +++ b/files/www/cgi-bin/signal @@ -52,7 +52,7 @@ local dmode = "Realtime" -- query string local query = os.getenv("QUERY_STRING") if query then - require('luci.ohttp') + require('luci.http') local params = luci.http.urldecode_params(query) if params.realtime then dmode = "Realtime" diff --git a/files/www/cgi-bin/status b/files/www/cgi-bin/status index 88cc0b81..92b102a3 100755 --- a/files/www/cgi-bin/status +++ b/files/www/cgi-bin/status @@ -227,7 +227,7 @@ end -- post data if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/vpn b/files/www/cgi-bin/vpn index 34399fab..50cc89dd 100755 --- a/files/www/cgi-bin/vpn +++ b/files/www/cgi-bin/vpn @@ -57,7 +57,7 @@ local VPNVER = "1.1" -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/vpnc b/files/www/cgi-bin/vpnc index 43107358..44835b3b 100755 --- a/files/www/cgi-bin/vpnc +++ b/files/www/cgi-bin/vpnc @@ -61,7 +61,7 @@ local VPNVER = "1.0" -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.ohttp') + require('luci.http') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/patches/780-restore-request-class.patch b/patches/780-restore-request-class.patch new file mode 100755 index 00000000..464f468d --- /dev/null +++ b/patches/780-restore-request-class.patch @@ -0,0 +1,382 @@ +--- a/feeds/luci/libs/luci-lib-base/luasrc/http.lua ++++ b/feeds/luci/libs/luci-lib-base/luasrc/http.lua +@@ -6,13 +6,378 @@ + local coroutine = require "coroutine" + local table = require "table" + local lhttp = require "lucihttp" ++local nixio = require "nixio" ++local ltn12 = require "luci.ltn12" + +-local L, table, ipairs, pairs, type, error = _G.L, table, ipairs, pairs, type, error ++local L, table, ipairs, pairs, type, tostring, tonumber, error = _G.L, table, ipairs, pairs, type, tostring, tonumber, error + + module "luci.http" + + HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size + ++-- ++-- Restore Request functionality ++-- ++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 ++ ++-- 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 ++ ++-- 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 ++ ++-- ++-- END ++-- ++ + function close() + L.http:close() + end diff --git a/patches/series b/patches/series index f79821f6..218dcf6f 100644 --- a/patches/series +++ b/patches/series @@ -39,5 +39,6 @@ 751-x86.patch 752-mikrotik-nand-revert.patch 753-ubiquiti-2ac.patch +780-restore-request-class.patch 800-upgrade-compatibility.patch 801-mikrotik-lhg-variants.patch