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