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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
#!Lua-5.0.exe
-- Test of CGI capability.
-- by Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr
-- v. 1.2 -- 2003/07/07 -- Converted to Lua 5.0, improved split and encode entities
-- v. 1.1 -- 2002/05/17 -- Added some other environment variables, encoded output
-- v. 1.0 -- 2001/08/07
-- Maximum length of input (to avoid overflooding)
maxInput = 5 * 1024 -- 5KB
programName = "TestCGI.lua"
programVersion = "1.1"
-- io.write HTML header
io.write[[
Content-Type: text/html
<html>
]]
-- Page to ouput
htmlPageHead = [[
<head>
<title>Lua CGI Test</title>
<meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
<meta name="GENERATOR" content="%s %s">
</head>
<body>
<center><h1>Test of CGI capability using Lua</h1></center>
]]
io.write(format(htmlPageHead, programName, programVersion))
function Split(separator, toSplit)
local splitted = {}
local i = 0
local re = "([^" .. separator .. "]*)" .. separator .. "?"
for part in string.gfind(toSplit .. separator, re) do
i = i + 1
splitted[i] = part
end
splitted[i] = nil
return splitted
end
function OutputError(message)
io.write('<p><font color="red">', message, '</font></p>')
end
function DecodeString(encodedString)
if encodedString == nil or type(encodedString) ~= "string" then
return ''
end
-- Convert plus to space
local decodedString = string.gsub(encodedString, '+', ' ')
-- Convert %XX from hex numbers to alphanumeric
decodedString = string.gsub(decodedString, "%%(%x%x)", function (hexa) return string.char(tonumber(hexa, 16)) end)
return decodedString
end
entities =
{
['&'] = "&",
['<'] = "<",
['>'] = ">",
-- French entities (the most common ones)
['à'] = "à",
['â'] = "â",
['é'] = "é",
['è'] = "è",
['ê'] = "ê",
['ë'] = "ë",
['î'] = "î",
['ï'] = "ï",
['ô'] = "ô",
['ù'] = "ù",
['û'] = "û",
['À'] = "À",
['Â'] = "Â",
['É'] = "É",
['È'] = "È",
['Ê'] = "Ê",
['Ë'] = "Ë",
['Î'] = "Î",
['Ï'] = "Ï",
['Ô'] = "Ô",
['Ù'] = "Ù",
['Û'] = "Û",
['ç'] = "ç",
['Ç'] = "Ç",
['«'] = "«",
['»'] = "»",
['©'] = "©",
['®'] = "®",
[''] = "Œ", -- Not understood by all browsers
[''] = "œ", -- Not understood by all browsers
}
function EncodeEntities(toEncode)
if toEncode == nil or type(toEncode) ~= "string" then
return ''
end
local EncodeToEntities = function (char)
local entity = entities[char]
if entity == nil then
local code = string.byte(char)
if code > 127 then
entity = string.format("&#%d;", code)
end
end
return entity or char
end
encodedString = string.gsub(toEncode, '(.)', EncodeToEntities)
return encodedString
end
-- Discard the input (POST request) in case it is too long, to avoid attacks.
-- Idea and code from CGILua.
function FlushInput(dataLength)
local blockSize = 8192
local dump
while dataLength > 0 do
-- Must avoid to read _STDIN with too much size, as it will lock waiting for more data...
blockSize = math.min(dataLength, blockSize)
dump = io.read(blockSize)
if dump == nil then break end
dataLength = dataLength - string.len(dump)
end
end
function GetFormInput()
local requestMethod = os.getenv("REQUEST_METHOD")
local queryString = ''
local query = {}
local resultQuery = {}
local contentLength
if requestMethod == "GET" then
queryString = os.getenv("QUERY_STRING")
elseif requestMethod == "POST" then
contentLength = tonumber(os.getenv("CONTENT_LENGTH"))
if contentLength > maxInput then
FlushInput(contentLength)
OutputError(string.format("Your request exceeded the allowed maximum length: %s characters!", maxInput))
return nil
end
queryString = io.read(contentLength)
elseif requestMethod == "" then
-- Command line parameters
else
OutputError("Use *only* GET or POST method!")
return nil
end
if queryString and queryString ~= '' then
query = Split('&', queryString)
for i, val in query do
-- Split into name and value: name=value
local pair = Split('=', val)
resultQuery[DecodeString(pair[1])] = DecodeString(pair[2])
end
end
return resultQuery, queryString
end
function DumpInputData()
local DumpVal = function (name, value)
if value == nil or value == '' then
value = " " -- Preserve table cell
end
io.write("<tr><td>", name, "</td><td>", EncodeEntities(value), "</td>\n")
end
local inputData, query = GetFormInput()
if query then
io.write("<p><b>Query String:</b> ", EncodeEntities(query), "</p>\n")
else
io.write("<p>No query string</p>\n")
end
io.write[[
<table border="1">
<tr>
<td colspan="2" align="center"><font size="+2"><b>Input Data</b></font></td>
</tr>
<tr>
<td><b>Name</b></td><td><b>Value</b></td>
</tr>
]]
local itemNb = 0
if inputData then
for i, val in inputData do
DumpVal(i, val)
itemNb = itemNb + 1
end
end
if itemNb == 0 then
io.write[[
<tr>
<td colspan='2'>No data to display</td>
</tr>
]]
end
io.write[[
</table>
]]
end
function DumpCGIVariables()
local DumpVar = function (varName)
local value = os.getenv(varName)
if value == nil then
value = "(not defined)"
end
io.write("<tr><td>", varName, "</td><td>", EncodeEntities(value), "</td>\n")
end
io.write[[
<table border="1">
<tr>
<td colspan="2" align="center"><font size="+2"><b>CGI Variables</b></font></td>
</tr>
]]
io.write[[
<tr>
<td colspan="2"><font size="+1"><b>CGI environment variables:</b></font></td>
</tr><tr>
<td><b>Name</b></td><td><b>Value</b></td>
</tr>
]]
DumpVar("AUTH_TYPE")
DumpVar("CONTENT_LENGTH")
DumpVar("GATEWAY_INTERFACE")
DumpVar("PATH_INFO")
DumpVar("PATH_TRANSLATED")
DumpVar("QUERY_STRING")
DumpVar("REMOTE_ADDR")
DumpVar("REMOTE_HOST")
DumpVar("REMOTE_IDENT")
DumpVar("REMOTE_USER")
DumpVar("REQUEST_METHOD")
DumpVar("SCRIPT_NAME")
DumpVar("SERVER_NAME")
DumpVar("SERVER_PORT")
DumpVar("SERVER_PROTOCOL")
DumpVar("SERVER_SOFTWARE")
io.write[[
<tr>
<td colspan="2"><font size="+1"><b>HTTP environment variables:</b></font></td>
</tr><tr>
<td><b>Name</b></td><td><b>Value</b></td>
</tr>
]]
DumpVar("HTTP_ACCEPT")
DumpVar("HTTP_ACCEPT_ENCODING")
DumpVar("HTTP_ACCEPT_LANGUAGE")
DumpVar("HTTP_CACHE_CONTROL")
DumpVar("HTTP_HOST")
DumpVar("HTTP_REFERER")
DumpVar("HTTP_USER_AGENT")
DumpVar("HTTP_VIA")
DumpVar("HTTP_X_FORWARDED_FOR")
io.write[[
</table>
]]
end
DumpInputData()
DumpCGIVariables()
-- io.write HTML tail
io.write[[
</body>
</html>
]]
|