* Added support for CGI SGI
[project/luci.git] / libs / web / luasrc / http.lua
1 --[[
2 LuCI - HTTP-Interaction
3
4 Description:
5 HTTP-Header manipulator and form variable preprocessor
6
7 FileId:
8 $Id$
9
10 ToDo:
11 - Cookie handling
12
13 License:
14 Copyright 2008 Steven Barth <steven@midlink.org>
15
16 Licensed under the Apache License, Version 2.0 (the "License");
17 you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at
19
20 http://www.apache.org/licenses/LICENSE-2.0
21
22 Unless required by applicable law or agreed to in writing, software
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27
28 ]]--
29
30 module("luci.http", package.seeall)
31 require("luci.http.protocol")
32 require("luci.util")
33
34 context = luci.util.threadlocal()
35
36
37 Request = luci.util.class()
38 function Request.__init__(self, env, instream, errstream)
39 self.input = instream
40 self.error = errstream
41
42 -- Provide readline function
43 self.inputreader = self.input.readline
44 or self.input.read and function() return self.input:read() end
45 or self.input.receive and function() return self.input:receive() end
46 or function() return nil end
47
48 -- File handler
49 self.filehandler = function() end
50
51 -- HTTP-Message table
52 self.message = {
53 env = env,
54 headers = {},
55 params = luci.http.protocol.urldecode_params("?"..env.QUERY_STRING),
56 }
57
58 setmetatable(self.message.params, {__index =
59 function(tbl, key)
60 luci.http.protocol.parse_message_body(
61 self.inputreader,
62 self.message,
63 self.filehandler
64 )
65
66 setmetatable(tbl, nil)
67 return rawget(tbl, key)
68 end
69 })
70 end
71
72 function Request.formvalue(self, name, default)
73 if name then
74 return self.message.params[name] and tostring(self.message.params[name]) or default
75 else
76 return self.message.params
77 end
78 end
79
80 function Request.formvaluetable(self, prefix)
81 local vals = {}
82 prefix = prefix and prefix .. "." or "."
83
84 local void = self.message.params[nil]
85 for k, v in pairs(self.message.params) do
86 if k:find(prefix, 1, true) == 1 then
87 vals[k:sub(#prefix + 1)] = tostring(v)
88 end
89 end
90
91 return vals
92 end
93
94 function Request.getenv(self, name)
95 return name and self.message.env[name] or self.message.env
96 end
97
98 function Request.setfilehandler(self, callback)
99 self.filehandler = callback
100 end
101
102
103 function close()
104 if not context.eoh then
105 context.eoh = true
106 coroutine.yield(3)
107 end
108
109 if not context.closed then
110 context.closed = true
111 coroutine.yield(5)
112 end
113 end
114
115 function formvalue(...)
116 return context.request:formvalue(...)
117 end
118
119 function formvaluetable(...)
120 return context.request:formvaluetable(...)
121 end
122
123 function getvalue(...)
124 return context.request:getvalue(...)
125 end
126
127 function postvalue(...)
128 return context.request:postvalue(...)
129 end
130
131 function getenv(...)
132 return context.request:getenv(...)
133 end
134
135 function setfilehandler(...)
136 return context.request:setfilehandler(...)
137 end
138
139 function header(key, value)
140 if not context.status then
141 status()
142 end
143 if not context.headers then
144 context.headers = {}
145 end
146 context.headers[key:lower()] = value
147 coroutine.yield(2, key, value)
148 end
149
150 function prepare_content(mime)
151 header("Content-Type", mime)
152 end
153
154 function status(code, message)
155 code = code or 200
156 message = message or "OK"
157 context.status = code
158 coroutine.yield(1, code, message)
159 end
160
161 function write(content)
162 if not content or #content == 0 then
163 return
164 end
165 if not context.eoh then
166 if not context.status then
167 status()
168 end
169 if not context.headers or not context.headers["content-type"] then
170 header("Content-Type", "text/html; charset=utf-8")
171 end
172
173 context.eoh = true
174 coroutine.yield(3)
175 end
176 coroutine.yield(4, content)
177 end
178
179
180 function basic_auth(realm, errorpage)
181 header("Status", "401 Unauthorized")
182 header("WWW-Authenticate", string.format('Basic realm="%s"', realm or ""))
183
184 if errorpage then
185 errorpage()
186 end
187
188 close()
189 end
190
191 function redirect(url)
192 header("Status", "302 Found")
193 header("Location", url)
194 close()
195 end
196
197 function build_querystring(table)
198 local s="?"
199
200 for k, v in pairs(table) do
201 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
202 end
203
204 return s
205 end
206
207 urldecode = luci.http.protocol.urldecode
208 urlencode = luci.http.protocol.urlencode