summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/luasrc
diff options
context:
space:
mode:
authorDaniel Dickinson <openwrt@daniel.thecshore.com>2015-12-15 11:37:33 -0500
committerDaniel Dickinson <openwrt@daniel.thecshore.com>2015-12-15 13:12:29 -0500
commitb130ca554f13e17c787a1c6fd09e67dd7727a4d3 (patch)
tree1be82d3ec849d76104228c1b263a547b334077f8 /modules/luci-base/luasrc
parent0ec3f91a0c7a8c71980f5e70f3322397e496a8d6 (diff)
lib-nixio / luci-base: Fix for reading csrf token prevents file upload
The call to http.formvalue in order to read the csrf token causes _parse_input to be triggered *before* controllers and cbi maps have been built. This results in the failure of file uploads because the file handler is not yet in place when _parse_input gets called, and it is in _parse_input that POST data is parsed (including files). To fix this we add the ability to write file fields to temporary files (using mkstemp and unlink in nixio.file) and use this to store file data until the filehandler is registered, with a fallback to reading the file data into memory. Once the filehandler callback gets registered we iterate though all previously parsed (saved) files and copy the data to the file handler, and then close the temporary file (which finally removes because we unlinked after creating the file, but didn't close the file so unlink was deferred). Signed-off-by: Daniel Dickinson <openwrt@daniel.thecshore.com>
Diffstat (limited to 'modules/luci-base/luasrc')
-rw-r--r--modules/luci-base/luasrc/http.lua31
-rw-r--r--modules/luci-base/luasrc/http/protocol.lua26
2 files changed, 57 insertions, 0 deletions
diff --git a/modules/luci-base/luasrc/http.lua b/modules/luci-base/luasrc/http.lua
index 4b3573172..8795dfc4b 100644
--- a/modules/luci-base/luasrc/http.lua
+++ b/modules/luci-base/luasrc/http.lua
@@ -89,6 +89,37 @@ end
function Request.setfilehandler(self, callback)
self.filehandler = callback
+
+ -- If input has already been parsed then any files are either in temporary files
+ -- or are in self.message.params[key]
+ if self.parsed_input then
+ for param, value in pairs(self.message.params) do
+ repeat
+ -- We're only interested in files
+ if (not value["file"]) then break end
+ -- If we were able to write to temporary file
+ if (value["fd"]) then
+ fd = value["fd"]
+ local eof = false
+ repeat
+ filedata = fd:read(1024)
+ if (filedata:len() < 1024) then
+ eof = true
+ end
+ callback({ name=value["name"], file=value["file"] }, filedata, eof)
+ until (eof)
+ fd:close()
+ value["fd"] = nil
+ -- We had to read into memory
+ else
+ -- There should only be one numbered value in table - the data
+ for k, v in ipairs(value) do
+ callback({ name=value["name"], file=value["file"] }, v, true)
+ end
+ end
+ until true
+ end
+ end
end
function Request._parse_input(self)
diff --git a/modules/luci-base/luasrc/http/protocol.lua b/modules/luci-base/luasrc/http/protocol.lua
index 0cb62aeec..061c6ad54 100644
--- a/modules/luci-base/luasrc/http/protocol.lua
+++ b/modules/luci-base/luasrc/http/protocol.lua
@@ -114,6 +114,16 @@ local function __initval( tbl, key )
end
-- (Internal function)
+-- Initialize given file parameter.
+local function __initfileval( tbl, key, filename, fd )
+ if tbl[key] == nil then
+ tbl[key] = { file=filename, fd=fd, name=key, "" }
+ else
+ table.insert( tbl[key], "" )
+ end
+end
+
+-- (Internal function)
-- Append given data to given parameter, either by extending the string value
-- or by appending it to the last string in the parameter's value table.
local function __appendval( tbl, key, chunk )
@@ -313,6 +323,22 @@ function mimedecode_message_body( src, msg, filecb )
__appendval( msg.params, field.name, field.file )
store = filecb
+ elseif field.name and field.file then
+ local nxf = require "nixio"
+ local fd = nxf.mkstemp(field.name)
+ __initfileval ( msg.params, field.name, field.file, fd )
+ if fd then
+ store = function(hdr, buf, eof)
+ fd:write(buf)
+ if (eof) then
+ fd:seek(0, "set")
+ end
+ end
+ else
+ store = function( hdr, buf, eof )
+ __appendval( msg.params, field.name, buf )
+ end
+ end
elseif field.name then
__initval( msg.params, field.name )