+local function splice_async(sock, pipeout, pipein, file, cb)
+ local ssize = 65536
+ local smode = nixio.splice_flags("move", "more", "nonblock")
+
+ -- Set pipe non-blocking otherwise we might end in a deadlock
+ local stat, code, msg = pipein:setblocking(false)
+ if stat then
+ stat, code, msg = pipeout:setblocking(false)
+ end
+ if not stat then
+ return stat, code, msg
+ end
+
+
+ local pollsock = {
+ {fd=sock, events=nixio.poll_flags("in")}
+ }
+
+ local pollfile = {
+ {fd=file, events=nixio.poll_flags("out")}
+ }
+
+ local done
+ local active -- Older splice implementations sometimes don't detect EOS
+
+ repeat
+ active = false
+
+ -- Socket -> Pipe
+ repeat
+ nixio.poll(pollsock, 15000)
+
+ stat, code, msg = nixio.splice(sock, pipeout, ssize, smode)
+ if stat == nil then
+ return stat, code, msg
+ elseif stat == 0 then
+ done = true
+ break
+ elseif stat then
+ active = true
+ end
+ until stat == false
+
+ -- Pipe -> File
+ repeat
+ nixio.poll(pollfile, 15000)
+
+ stat, code, msg = nixio.splice(pipein, file, ssize, smode)
+ if stat == nil then
+ return stat, code, msg
+ elseif stat then
+ active = true
+ end
+ until stat == false
+
+ if cb then
+ cb(file)
+ end
+
+ if not active then
+ -- We did not splice any data, maybe EOS, fallback to default
+ return false
+ end
+ until done
+
+ pipein:close()
+ pipeout:close()
+ sock:close()
+ file:close()
+ return true
+end
+
+local function splice_sync(sock, pipeout, pipein, file, cb)
+ local os = require "os"
+ local posix = require "posix"
+ local ssize = 65536
+ local smode = nixio.splice_flags("move", "more")
+ local stat
+
+ -- This is probably the only forking http-client ;-)
+ local pid, code, msg = posix.fork()
+ if not pid then
+ return pid, code, msg
+ elseif pid == 0 then
+ pipein:close()
+ file:close()
+
+ repeat
+ stat, code = nixio.splice(sock, pipeout, ssize, smode)
+ until not stat or stat == 0
+
+ pipeout:close()
+ sock:close()
+ os.exit(stat or code)
+ else
+ pipeout:close()
+ sock:close()
+
+ repeat
+ stat, code, msg = nixio.splice(pipein, file, ssize, smode)
+ if cb then
+ cb(file)
+ end
+ until not stat or stat == 0
+
+ pipein:close()
+ file:close()
+
+ if not stat then
+ posix.kill(pid)
+ posix.wait(pid)
+ return stat, code, msg
+ else
+ pid, msg, code = posix.wait(pid)
+ if msg == "exited" then
+ if code == 0 then
+ return true
+ else
+ return nil, code, nixio.strerror(code)
+ end
+ else
+ return nil, -0x11, "broken pump"
+ end
+ end
+ end
+end