webmcp

view libraries/rocketcgi/rocketcgi.lua @ 18:486ad118c277

Fixed wrong/duplicate autodoc entry in rocketcgi.lua
author bsw
date Thu Mar 25 20:33:00 2010 +0100 (2010-03-25)
parents 944642a3e488
children 3d43a5cf17c1
line source
1 #!/usr/bin/env lua
3 local assert = assert
4 local collectgarbage = collectgarbage
5 local error = error
6 local getfenv = getfenv
7 local getmetatable = getmetatable
8 local ipairs = ipairs
9 local next = next
10 local pairs = pairs
11 local pcall = pcall
12 local print = print
13 local rawequal = rawequal
14 local rawget = rawget
15 local rawset = rawset
16 local select = select
17 local setfenv = setfenv
18 local setmetatable = setmetatable
19 local tonumber = tonumber
20 local tostring = tostring
21 local type = type
22 local unpack = unpack
23 local xpcall = xpcall
25 local io = io
26 local math = math
27 local os = os
28 local string = string
29 local table = table
31 module(...)
33 data_sent = false
35 --[[--
36 rocketcgi.add_header(
37 string_part1, -- string
38 string_part2, -- optional second part of string to be concatted
39 ...
40 )
42 Sends a header line to the browser. Multiple arguments are concatted to form a single string.
44 --]]--
45 function add_header(...)
46 if data_sent then
47 error("Can not add header after data has been sent.", 2)
48 end
49 io.stdout:write(...)
50 io.stdout:write("\r\n")
51 end
52 --//--
54 --[[--
55 rocketcgi.send_data(
56 string_part1, -- string
57 string_part2, -- optional second part of string to be concatted
58 ...
59 )
61 Sends document data to the browser. Multiple arguments are concatted to form a single string.
63 --]]--
64 function send_data(...)
65 if not data_sent then
66 io.stdout:write("\r\n")
67 data_sent = true
68 end
69 io.stdout:write(...)
70 end
71 --//--
73 --[[--
74 rocketcgi.set_status(
75 status -- Status code and description, e.g. "404 Not Found"
76 )
78 Sends a header line to the browser, indicating a given HTTP status.
80 --]]--
81 function set_status(status)
82 add_header("Status: ", status)
83 end
84 --//--
86 --[[--
87 rocketcgi.redirect(
88 status -- Absolute URL to redirect the browser to
89 )
91 Redirects the browser to the given absolute URL, using a 303 Redirect.
93 --]]--
94 function redirect(location)
95 set_status("303 See Other")
96 add_header("Location: ", location)
97 end
98 --//--
100 --[[--
101 rocketcgi.set_content_type(
102 content_type -- MIME content type
103 )
105 Sends a header line specifying the content-type to the browser.
107 --]]--
108 function set_content_type(content_type)
109 add_header("Content-Type: ", content_type)
110 end
111 --//--
113 --[[--
114 rocketcgi.set_cookie{
115 name = name, -- name of cookie
116 value = value, -- value of cookie
117 domain = domain, -- domain where cookie is transmitted
118 path = path, -- path where cookie is transmitted
119 secure = secure -- boolean, indicating if cookie should only be transmitted over HTTPS
120 }
122 Sends a header line setting a cookie. NOTE: Currently only session cookies are supported.
124 --]]--
125 function set_cookie(args)
126 assert(string.find(args.name, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie name")
127 assert(string.find(args.value, "^[0-9A-Za-z%%._~-]+$"), "Illegal cookie value")
128 local parts = {"Set-Cookie: " .. args.name .. "=" .. args.value}
129 if args.domain then
130 assert(
131 string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"),
132 "Illegal cookie domain"
133 )
134 parts[#parts+1] = "domain=" .. args.domain
135 end
136 if args.path then
137 assert(
138 string.find(args.path, "^[0-9A-Za-z%%/._~-]+$"),
139 "Illegal cookie path"
140 )
141 parts[#parts+1] = "path=" .. args.path
142 end
143 if args.secure then
144 parts[#parts+1] = "secure"
145 end
146 add_header(table.concat(parts, "; "))
147 end
148 --//--
150 method = os.getenv("REQUEST_METHOD") or false
151 query = os.getenv("QUERY_STRING") or false
152 cookie_data = os.getenv("HTTP_COOKIE") or false
153 post_data = io.stdin:read("*a") or false
154 post_contenttype = os.getenv("CONTENT_TYPE") or false
155 params = {}
156 get_params = {}
157 cookies = {}
158 post_params = {}
159 post_filenames = {}
160 post_types = {}
162 local urldecode
163 do
164 local b0 = string.byte("0")
165 local b9 = string.byte("9")
166 local bA = string.byte("A")
167 local bF = string.byte("F")
168 local ba = string.byte("a")
169 local bf = string.byte("f")
170 function urldecode(str)
171 return (
172 string.gsub(
173 string.gsub(str, "%+", " "),
174 "%%([0-9A-Fa-f][0-9A-Fa-f])",
175 function(hex)
176 local n1, n2 = string.byte(hex, 1, 2)
177 if n1 >= b0 and n1 <= b9 then n1 = n1 - b0
178 elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10
179 elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10
180 else return end
181 if n2 >= b0 and n2 <= b9 then n2 = n2 - b0
182 elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10
183 elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10
184 else return end
185 return string.char(n1 * 16 + n2)
186 end
187 )
188 )
189 end
190 end
192 local function proc_param(tbl, key, value)
193 if string.find(key, "%[%]$") then
194 if tbl[key] then
195 table.insert(tbl[key], value)
196 else
197 local list = { value }
198 params[key] = list
199 tbl[key] = list
200 end
201 else
202 params[key] = value
203 tbl[key] = value
204 end
205 end
207 local function read_urlencoded_form(tbl, data)
208 for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do
209 proc_param(tbl, urldecode(rawkey), urldecode(rawvalue))
210 end
211 end
213 if query then
214 read_urlencoded_form(get_params, query)
215 end
217 if cookie_data then
218 for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do
219 cookies[urldecode(rawkey)] = urldecode(rawvalue)
220 end
221 end
223 if post_contenttype and (
224 post_contenttype == "application/x-www-form-urlencoded" or
225 string.match(post_contenttype, "^application/x%-www%-form%-urlencoded[ ;]")
226 ) then
227 read_urlencoded_form(post_params, post_data)
228 elseif post_contenttype then
229 local boundary = string.match(
230 post_contenttype,
231 '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"'
232 ) or string.match(
233 post_contenttype,
234 '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)'
235 )
236 if boundary then
237 local parts = {}
238 do
239 local boundary = "\r\n--" .. boundary
240 local post_data = "\r\n" .. post_data
241 local pos1, pos2 = string.find(post_data, boundary, 1, true)
242 while true do
243 local ind = string.sub(post_data, pos2 + 1, pos2 + 2)
244 if ind == "\r\n" then
245 local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true)
246 if pos3 then
247 parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1)
248 else
249 error("Illegal POST data.")
250 end
251 pos1, pos2 = pos3, pos4
252 elseif ind == "--" then
253 break
254 else
255 error("Illegal POST data.")
256 end
257 end
258 end
259 for i, part in ipairs(parts) do
260 local pos = 1
261 local name, filename, contenttype
262 while true do
263 local header
264 do
265 local oldpos = pos
266 pos = string.find(part, "\r\n", oldpos, true)
267 if not pos then
268 error("Illegal POST data.")
269 end
270 if pos == oldpos then break end
271 header = string.sub(part, oldpos, pos - 1)
272 pos = pos + 2
273 end
274 if string.find(
275 string.lower(header),
276 "^content%-disposition:[ \t]*form%-data[ \t]*;"
277 ) then
278 -- TODO: handle all cases correctly
279 name = string.match(header, ';[ \t]*name="([^"]*)"') or
280 string.match(header, ';[ \t]*name=([^"; \t]+)')
281 filename = string.match(header, ';[ \t]*filename="([^"]*)"') or
282 string.match(header, ';[ \t]*filename=([^"; \t]+)')
283 else
284 local dummy, subpos = string.find(
285 string.lower(header),
286 "^content%-type:[ \t]*"
287 )
288 if subpos then
289 contenttype = string.sub(header, subpos + 1, #header)
290 end
291 end
292 end
293 local content = string.sub(part, pos + 2, #part)
294 if not name then
295 error("Illegal POST data.")
296 end
297 proc_param(post_params, name, content)
298 post_filenames[name] = filename
299 post_types[name] = contenttype
300 end
301 end
302 end
304 if post_data and #post_data > 262144 then
305 post_data = nil
306 collectgarbage("collect")
307 else
308 post_data = nil
309 end

Impressum / About Us