webmcp
view libraries/rocketcgi/rocketcgi.lua @ 2:72860d232f32
Version 1.0.2
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
author | jbe/bsw |
---|---|
date | Thu Dec 10 12:00:00 2009 +0100 (2009-12-10) |
parents | 9fdfb27f8e67 |
children | d76a8857ba62 |
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 function add_header(...)
36 if data_sent then
37 error("Can not add header after data has been sent.", 2)
38 end
39 io.stdout:write(...)
40 io.stdout:write("\r\n")
41 end
43 function send_data(...)
44 if not data_sent then
45 io.stdout:write("\r\n")
46 data_sent = true
47 end
48 io.stdout:write(...)
49 end
51 function set_status(status)
52 add_header("Status: ", status)
53 end
55 function redirect(location)
56 set_status("303 See Other")
57 add_header("Location: ", location)
58 end
60 function set_content_type(content_type)
61 add_header("Content-Type: ", content_type)
62 end
64 method = os.getenv("REQUEST_METHOD") or false
65 query = os.getenv("QUERY_STRING") or false
66 cookie_data = os.getenv("HTTP_COOKIE") or false
67 post_data = io.stdin:read("*a") or false
68 post_contenttype = os.getenv("CONTENT_TYPE") or false
69 params = {}
70 get_params = {}
71 cookies = {}
72 post_params = {}
73 post_filenames = {}
74 post_types = {}
76 local urldecode
77 do
78 local b0 = string.byte("0")
79 local b9 = string.byte("9")
80 local bA = string.byte("A")
81 local bF = string.byte("F")
82 local ba = string.byte("a")
83 local bf = string.byte("f")
84 function urldecode(str)
85 return (
86 string.gsub(
87 string.gsub(str, "%+", " "),
88 "%%([0-9A-Fa-f][0-9A-Fa-f])",
89 function(hex)
90 local n1, n2 = string.byte(hex, 1, 2)
91 if n1 >= b0 and n1 <= b9 then n1 = n1 - b0
92 elseif n1 >= bA and n1 <= bF then n1 = n1 - bA + 10
93 elseif n1 >= ba and n1 <= bf then n1 = n1 - ba + 10
94 else return end
95 if n2 >= b0 and n2 <= b9 then n2 = n2 - b0
96 elseif n2 >= bA and n2 <= bF then n2 = n2 - bA + 10
97 elseif n2 >= ba and n2 <= bf then n2 = n2 - ba + 10
98 else return end
99 return string.char(n1 * 16 + n2)
100 end
101 )
102 )
103 end
104 end
106 local function proc_param(tbl, key, value)
107 if string.find(key, "%[%]$") then
108 if tbl[key] then
109 table.insert(tbl[key], value)
110 else
111 local list = { value }
112 params[key] = list
113 tbl[key] = list
114 end
115 else
116 params[key] = value
117 tbl[key] = value
118 end
119 end
121 local function read_urlencoded_form(tbl, data)
122 for rawkey, rawvalue in string.gmatch(data, "([^=&]*)=([^=&]*)") do
123 proc_param(tbl, urldecode(rawkey), urldecode(rawvalue))
124 end
125 end
127 if query then
128 read_urlencoded_form(get_params, query)
129 end
131 if cookie_data then
132 for rawkey, rawvalue in string.gmatch(cookie_data, "([^=; ]*)=([^=; ]*)") do
133 cookies[urldecode(rawkey)] = urldecode(rawvalue)
134 end
135 end
137 if post_contenttype == "application/x-www-form-urlencoded" then
138 read_urlencoded_form(post_params, post_data)
139 elseif post_contenttype then
140 local boundary = string.match(
141 post_contenttype,
142 '^multipart/form%-data[ \t]*;[ \t]*boundary="([^"]+)"'
143 ) or string.match(
144 post_contenttype,
145 '^multipart/form%-data[ \t]*;[ \t]*boundary=([^"; \t]+)'
146 )
147 if boundary then
148 local parts = {}
149 do
150 local boundary = "\r\n--" .. boundary
151 local post_data = "\r\n" .. post_data
152 local pos1, pos2 = string.find(post_data, boundary, 1, true)
153 while true do
154 local ind = string.sub(post_data, pos2 + 1, pos2 + 2)
155 if ind == "\r\n" then
156 local pos3, pos4 = string.find(post_data, boundary, pos2 + 1, true)
157 if pos3 then
158 parts[#parts + 1] = string.sub(post_data, pos2 + 3, pos3 - 1)
159 else
160 error("Illegal POST data.")
161 end
162 pos1, pos2 = pos3, pos4
163 elseif ind == "--" then
164 break
165 else
166 error("Illegal POST data.")
167 end
168 end
169 end
170 for i, part in ipairs(parts) do
171 local pos = 1
172 local name, filename, contenttype
173 while true do
174 local header
175 do
176 local oldpos = pos
177 pos = string.find(part, "\r\n", oldpos, true)
178 if not pos then
179 error("Illegal POST data.")
180 end
181 if pos == oldpos then break end
182 header = string.sub(part, oldpos, pos - 1)
183 pos = pos + 2
184 end
185 if string.find(
186 string.lower(header),
187 "^content%-disposition:[ \t]*form%-data[ \t]*;"
188 ) then
189 -- TODO: handle all cases correctly
190 name = string.match(header, ';[ \t]*name="([^"]*)"') or
191 string.match(header, ';[ \t]*name=([^"; \t]+)')
192 filename = string.match(header, ';[ \t]*filename="([^"]*)"') or
193 string.match(header, ';[ \t]*filename=([^"; \t]+)')
194 else
195 local dummy, subpos = string.find(
196 string.lower(header),
197 "^content%-type:[ \t]*"
198 )
199 if subpos then
200 contenttype = string.sub(header, subpos + 1, #header)
201 end
202 end
203 end
204 local content = string.sub(part, pos + 2, #part)
205 if not name then
206 error("Illegal POST data.")
207 end
208 proc_param(post_params, name, content)
209 post_filenames[name] = filename
210 post_types[name] = contenttype
211 end
212 end
213 end
215 if post_data and #post_data > 262144 then
216 post_data = nil
217 collectgarbage("collect")
218 else
219 post_data = nil
220 end