Skip to content

Instantly share code, notes, and snippets.

@suzumura-ss
Last active December 22, 2015 05:17
Show Gist options
  • Save suzumura-ss/1dc0860820c975e859a2 to your computer and use it in GitHub Desktop.
Save suzumura-ss/1dc0860820c975e859a2 to your computer and use it in GitHub Desktop.
nginx-lua: upload request-body to other service without LuaSocket
local function header_join_with_crlf(header)
local str = "", k, v
for k,v in pairs(header) do
str = str .. v .. "\r\n"
end
return str
end
-- @return client, err
local function connect(ngxctx, host, port, path)
local ok, err
local obj = {}
obj.clientsock, err = ngxctx.req.socket()
if err then
return nil, 'failed to get sock - ' .. err
end
obj.serversock = ngxctx.socket.tcp()
ok, err = obj.serversock:connect(host, port)
if not ok then
return nil, 'failed to connect: ' .. host .. ':' .. port .. ' - ' .. err
end
obj.path = path
obj.send_header = function(self, m)
local method = m or ngxctx.req.get_method()
local headers = ngxctx.req.get_headers()
local reqtype = headers['content-type'] or 'application/json'
local reqsize = headers['content-length'] or '0'
local header = {method.." "..path.." HTTP/1.0", "Content-Type: "..reqtype, "Content-Length: "..reqsize, ""}
local bytes, err = self.serversock:send(header_join_with_crlf(header))
if err then
self.err = 'failed to send header - ' .. err
return nil
end
self.reqsize = reqsize
return true
end
obj.send_body = function(self)
local size = tonumber(self.reqsize)
while size>0 do
local rsize = 2048
if size<rsize then rsize=size end
local data, err, partial = self.clientsock:receive(rsize)
if err then
self.err = 'failed to receive request body - ' .. err
return nil
end
if not chunk then chunk = partial end
local bytes, err = self.serversock:send(data)
if err then
self.err = 'failed to send request body - ' .. err
return nil
end
size = size - rsize
end
return true
end
obj.recv_header = function(self)
self.content_length = nil
while true do
local data, err, partial = self.serversock:receive()
if err then
self.err = 'failed to receive response - ' .. err
return nil
end
if not data then data = partial end
local m, err = ngxctx.re.match(data, "HTTP/1.[01] ([0-9]+)", "i")
if m then ngxctx.status = tonumber(m[1]) end
m, err = ngxctx.re.match(data, "content-type: (.+)", "i")
if m then ngxctx.header.content_type = m[1] end
m, err = ngxctx.re.match(data, "content-length: ([0-9]+)", "i")
if m then self.content_length = tonumber(m[1]) end
if data=="" then break end
end
return true
end
obj.recv_body = function(self)
if self.content_length then
local data, err, partial = self.serversock:receive(self.content_length)
if err then
self.err = 'failed to receive response - ' .. err
return nil
end
if not data then data = partial end
ngxctx.header.content_length = #data
ngxctx.say(data)
end
return true
end
obj.request = function(self, m)
local ok = self:send_header(m) and self:send_body() and self:recv_header() and self:recv_body()
self.serversock:close()
return ok
end
return obj
end
-- upload
local client, err = connect(ngx, '127.0.0.1', 80, '/teapot')
if err then
ngx.log(ngx.ERR, err)
return ngx.exit(500)
end
if not client:request('PUT') then
ngx.log(ngx.ERR, client.err)
return ngx.exit(500)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment