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)
|