mirror of
				https://git.haproxy.org/git/haproxy.git/
				synced 2025-10-31 00:21:00 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			181 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| 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)
 |