173 lines
4.7 KiB
Lua
Executable File
173 lines
4.7 KiB
Lua
Executable File
local http = require "luci.http"
|
|
local nixio = require "nixio"
|
|
local ltn12 = require "luci.ltn12"
|
|
local table = require "table"
|
|
local util = require "luci.util"
|
|
|
|
module("luci.controller.istore_backend", package.seeall)
|
|
|
|
local BLOCKSIZE = 2048
|
|
local ISTOREOS_PORT = 3000
|
|
|
|
function index()
|
|
entry({"istore"}, call("istore_backend")).leaf=true
|
|
end
|
|
|
|
function sink_socket(sock, io_err)
|
|
if sock then
|
|
return function(chunk, err)
|
|
if not chunk then
|
|
return 1
|
|
else
|
|
return sock:send(chunk)
|
|
end
|
|
end
|
|
else
|
|
return ltn12.sink.error(io_err or "unable to send socket")
|
|
end
|
|
end
|
|
|
|
local function session_retrieve(sid, allowed_users)
|
|
local sdat = util.ubus("session", "get", { ubus_rpc_session = sid })
|
|
if type(sdat) == "table" and
|
|
type(sdat.values) == "table" and
|
|
type(sdat.values.token) == "string" and
|
|
(not allowed_users or
|
|
util.contains(allowed_users, sdat.values.username))
|
|
then
|
|
return sid, sdat.values
|
|
end
|
|
return nil, nil
|
|
end
|
|
|
|
function istore_backend()
|
|
local sock = nixio.connect("127.0.0.1", ISTOREOS_PORT)
|
|
if not sock then
|
|
http.status(500, "connect failed")
|
|
return
|
|
end
|
|
local input = {}
|
|
input[#input+1] = http.getenv("REQUEST_METHOD") .. " " .. http.getenv("REQUEST_URI") .. " HTTP/1.1"
|
|
local req = http.context.request
|
|
local start = "HTTP_"
|
|
local start_len = string.len(start)
|
|
local ctype = http.getenv("CONTENT_TYPE")
|
|
if ctype then
|
|
input[#input+1] = "Content-Type: " .. ctype
|
|
end
|
|
for k, v in pairs(req.message.env) do
|
|
if string.sub(k, 1, start_len) == start and not string.find(k, "FORWARDED") then
|
|
input[#input+1] = string.sub(k, start_len+1, string.len(k)) .. ": " .. v
|
|
end
|
|
end
|
|
local sid = http.getcookie("sysauth")
|
|
if sid then
|
|
local sid, sdat = session_retrieve(sid, nil)
|
|
if sdat ~= nil then
|
|
input[#input+1] = "X-Forwarded-Sid: " .. sid
|
|
input[#input+1] = "X-Forwarded-Token: " .. sdat.token
|
|
end
|
|
end
|
|
input[#input+1] = "X-Forwarded-For: " .. http.getenv("REMOTE_HOST") ..":".. http.getenv("REMOTE_PORT")
|
|
local num = tonumber(http.getenv("CONTENT_LENGTH")) or 0
|
|
input[#input+1] = "Content-Length: " .. tostring(num)
|
|
input[#input+1] = "\r\n"
|
|
local source = ltn12.source.cat(ltn12.source.string(table.concat(input, "\r\n")), http.source())
|
|
local ret = ltn12.pump.all(source, sink_socket(sock, "write sock error"))
|
|
if ret ~= 1 then
|
|
sock:close()
|
|
http.status(500, "proxy error")
|
|
return
|
|
end
|
|
|
|
local linesrc = sock:linesource()
|
|
local line, code, error = linesrc()
|
|
if not line then
|
|
sock:close()
|
|
http.status(500, "response parse failed")
|
|
return
|
|
end
|
|
|
|
local protocol, status, msg = line:match("^([%w./]+) ([0-9]+) (.*)")
|
|
if not protocol then
|
|
sock:close()
|
|
http.status(500, "response protocol error")
|
|
return
|
|
end
|
|
num = tonumber(status) or 0
|
|
http.status(num, msg)
|
|
|
|
local chunked = 0
|
|
line = linesrc()
|
|
while line and line ~= "" do
|
|
local key, val = line:match("^([%w-]+)%s?:%s?(.*)")
|
|
if key and key ~= "Status" then
|
|
if key == "Transfer-Encoding" and val == "chunked" then
|
|
chunked = 1
|
|
end
|
|
if key ~= "Connection" and key ~= "Transfer-Encoding" then
|
|
http.header(key, val)
|
|
end
|
|
end
|
|
line = linesrc()
|
|
end
|
|
if not line then
|
|
sock:close()
|
|
http.status(500, "parse header failed")
|
|
return
|
|
end
|
|
|
|
local body_buffer = linesrc(true)
|
|
if chunked == 1 then
|
|
ltn12.pump.all(chunksource(sock, body_buffer), http.write)
|
|
else
|
|
local body_source = ltn12.source.cat(ltn12.source.string(body_buffer), sock:blocksource())
|
|
ltn12.pump.all(body_source, http.write)
|
|
end
|
|
|
|
sock:close()
|
|
end
|
|
|
|
function chunksource(sock, buffer)
|
|
buffer = buffer or ""
|
|
return function()
|
|
local output
|
|
local _, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
|
|
while not count and #buffer <= 1024 do
|
|
local newblock, code = sock:recv(1024 - #buffer)
|
|
if not newblock then
|
|
return nil, code
|
|
end
|
|
buffer = buffer .. newblock
|
|
_, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
|
|
end
|
|
count = tonumber(count, 16)
|
|
if not count then
|
|
return nil, -1, "invalid encoding"
|
|
elseif count == 0 then
|
|
return nil
|
|
elseif count + 2 <= #buffer - endp then
|
|
output = buffer:sub(endp+1, endp+count)
|
|
buffer = buffer:sub(endp+count+3)
|
|
return output
|
|
else
|
|
output = buffer:sub(endp+1, endp+count)
|
|
buffer = ""
|
|
if count - #output > 0 then
|
|
local remain, code = sock:recvall(count-#output)
|
|
if not remain then
|
|
return nil, code
|
|
end
|
|
output = output .. remain
|
|
count, code = sock:recvall(2)
|
|
else
|
|
count, code = sock:recvall(count+2-#buffer+endp)
|
|
end
|
|
if not count then
|
|
return nil, code
|
|
end
|
|
return output
|
|
end
|
|
end
|
|
end
|