1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
Luacurl = {}
Luacurl.__index = Luacurl
setmetatable(Luacurl, {
__call = function (cls, ...)
return cls.new(...)
end,
})
function Luacurl.new(server, port, ssl)
local self = setmetatable({}, Luacurl)
self.sockconnected = false
self.server = server
self.port = port
self.ssl = ssl
self.cookies = {}
return self
end
function Luacurl:get(method,url,headers,data)
core.Info("MAKING SOCKET")
if self.sockconnected == false then
self.sock = core.tcp()
if self.ssl then
local r = self.sock:connect_ssl(self.server,self.port)
else
local r = self.sock:connect(self.server,self.port)
end
self.sockconnected = true
end
core.Info("SOCKET MADE")
local request = method.." "..url.." HTTP/1.1"
if data ~= nil then
request = request .. "\r\nContent-Length: "..string.len(data)
end
if headers ~= null then
for h,v in pairs(headers) do
request = request .. "\r\n"..h..": "..v
end
end
cookstring = ""
for cook,cookval in pairs(self.cookies) do
cookstring = cookstring .. cook.."="..cookval.."; "
end
if string.len(cookstring) > 0 then
request = request .. "\r\nCookie: "..cookstring
end
request = request .. "\r\n\r\n"
if data and string.len(data) > 0 then
request = request .. data
end
--print(request)
core.Info("SENDING REQUEST")
self.sock:send(request)
-- core.Info("PROCESSING RESPONSE")
return processhttpresponse(self.sock)
end
function processhttpresponse(socket)
local res = {}
core.Info("1")
res.status = socket:receive("*l")
core.Info("2")
if res.status == nil then
core.Info(" processhttpresponse RECEIVING status: NIL")
return res
end
core.Info(" processhttpresponse RECEIVING status:"..res.status)
res.headers = {}
res.headerslist = {}
repeat
core.Info("3")
local header = socket:receive("*l")
if header == nil then
return "error"
end
local valuestart = header:find(":")
if valuestart ~= nil then
local head = header:sub(1,valuestart-1)
local value = header:sub(valuestart+2)
table.insert(res.headerslist, {head,value})
res.headers[head] = value
end
until header == ""
local bodydone = false
if res.headers["Connection"] ~= nil and res.headers["Connection"] == "close" then
-- core.Info("luacurl processresponse with connection:close")
res.body = ""
repeat
core.Info("4")
local d = socket:receive("*a")
if d ~= nil then
res.body = res.body .. d
end
until d == nil or d == 0
bodydone = true
end
if bodydone == false and res.headers["Content-Length"] ~= nil then
res.contentlength = tonumber(res.headers["Content-Length"])
if res.contentlength == nil then
core.Warning("res.contentlength ~NIL = "..res.headers["Content-Length"])
end
-- core.Info("luacur, contentlength="..res.contentlength)
res.body = ""
repeat
local d = socket:receive(res.contentlength)
if d == nil then
-- core.Info("luacurl, ERROR?: received NIL, expecting "..res.contentlength.." bytes only got "..string.len(res.body).." sofar")
return
else
res.body = res.body..d
-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body))
if string.len(res.body) >= res.contentlength then
-- core.Info("luacurl, COMPLETE?: expecting "..res.contentlength.." bytes, got "..string.len(res.body))
break
end
end
-- core.Info("processhttpresponse, Loopy, get more body data! to receive complete contentlenght")
until false
end
if res.headers["Transfer-Encoding"] ~= nil and res.headers["Transfer-Encoding"] == "chunked" then
local chunksize = 0
res.contentlength = 0
res.body = ""
repeat
core.Info("5")
local chunksizestr = socket:receive("*l")
if chunksizestr == nil then
break
end
chunksize = tonumber("0x"..chunksizestr)
if chunksize ~= nil then
res.contentlength = res.contentlength + chunksize
if chunksize ~= 0 then
local chunk = socket:receive(chunksize)
res.body = res.body .. chunk
chunksizestr = socket:receive("*l")
if chunksizestr ~= "" then
return "ERROR Chunk-end expected."
end
end
else
break
end
until false
end
core.Info("6")
return res
end
function Luacurl:close()
if self.sockconnected == true then
self.sock:close()
self.sockconnected = false
end
end
function print_r_string(object)
local res = ""
print_r(object,false,function(x) res = res .. x end)
return res
end
core.register_service("fakeserv", "http", function(applet)
core.Info("APPLET START")
local mc = Luacurl("127.0.0.1",8443, true)
local headers = {}
local body = ""
core.Info("APPLET GET")
local res = mc:get("GET", "/", headers, body)
core.Info("APPLET GET done")
local response = print_r_string(res)
applet:add_header("Server", "haproxy/webstats")
applet:add_header("Content-Length", string.len(response))
applet:add_header("Content-Type", "text/html")
applet:start_response()
applet:send(response)
core.Info("APPLET DONE")
end)
|