~philho/+junk/Lua

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 =
{
	['&'] = "&amp;",
	['<'] = "&lt;",
	['>'] = "&gt;",
	-- French entities (the most common ones)
	['à'] = "&agrave;",
	['â'] = "&acirc;",
	['é'] = "&eacute;",
	['è'] = "&egrave;",
	['ê'] = "&ecirc;",
	['ë'] = "&euml;",
	['î'] = "&icirc;",
	['ï'] = "&iuml;",
	['ô'] = "&ocirc;",
	['ù'] = "&ugrave;",
	['û'] = "&ucirc;",
	['À'] = "&Agrave;",
	['Â'] = "&Acirc;",
	['É'] = "&Eacute;",
	['È'] = "&Egrave;",
	['Ê'] = "&Ecirc;",
	['Ë'] = "&Euml;",
	['Î'] = "&Icirc;",
	['Ï'] = "&Iuml;",
	['Ô'] = "&Ocirc;",
	['Ù'] = "&Ugrave;",
	['Û'] = "&Ucirc;",
	['ç'] = "&ccedil;",
	['Ç'] = "&Ccedil;",
	['«'] = "&laquo;",
	['»'] = "&raquo;",
	['©'] = "&copy;",
	['®'] = "&reg;",
	['Œ'] = "&OElig;", -- Not understood by all browsers
	['œ'] = "&oelig;", -- 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 = "&nbsp;"	-- 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>
]]