libs/web: Fixed bug where the environment table gets returned in case of an undefined...
[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("ltn12")
32 require("luci.http.protocol")
33 require("luci.util")
34
35 context = luci.util.threadlocal()
36
37
38 Request = luci.util.class()
39 function Request.__init__(self, env, sourcein, sinkerr)
40 self.input = sourcein
41 self.error = sinkerr
42
43
44 -- File handler
45 self.filehandler = function() end
46
47 -- HTTP-Message table
48 self.message = {
49 env = env,
50 headers = {},
51 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
52 }
53
54 setmetatable(self.message.params, {__index =
55 function(tbl, key)
56 setmetatable(tbl, nil)
57
58 luci.http.protocol.parse_message_body(
59 self.input,
60 self.message,
61 self.filehandler
62 )
63
64 return rawget(tbl, key)
65 end
66 })
67 end
68
69 function Request.formvalue(self, name, default)
70 if name then
71 return self.message.params[name] and tostring(self.message.params[name]) or default
72 else
73 return self.message.params
74 end
75 end
76
77 function Request.formvaluetable(self, prefix)
78 local vals = {}
79 prefix = prefix and prefix .. "." or "."
80
81 local void = self.message.params[nil]
82 for k, v in pairs(self.message.params) do
83 if k:find(prefix, 1, true) == 1 then
84 vals[k:sub(#prefix + 1)] = tostring(v)
85 end
86 end
87
88 return vals
89 end
90
91 function Request.getenv(self, name)
92 if name then
93 return self.message.env[name]
94 else
95 return self.message.env
96 end
97 end
98
99 function Request.setfilehandler(self, callback)
100 self.filehandler = callback
101 end
102
103
104 function close()
105 if not context.eoh then
106 context.eoh = true
107 coroutine.yield(3)
108 end
109
110 if not context.closed then
111 context.closed = true
112 coroutine.yield(5)
113 end
114 end
115
116 function formvalue(...)
117 return context.request:formvalue(...)
118 end
119
120 function formvaluetable(...)
121 return context.request:formvaluetable(...)
122 end
123
124 function getvalue(...)
125 return context.request:getvalue(...)
126 end
127
128 function postvalue(...)
129 return context.request:postvalue(...)
130 end
131
132 function getenv(...)
133 return context.request:getenv(...)
134 end
135
136 function setfilehandler(...)
137 return context.request:setfilehandler(...)
138 end
139
140 function header(key, value)
141 if not context.status then
142 status()
143 end
144 if not context.headers then
145 context.headers = {}
146 end
147 context.headers[key:lower()] = value
148 coroutine.yield(2, key, value)
149 end
150
151 function prepare_content(mime)
152 header("Content-Type", mime)
153 end
154
155 function status(code, message)
156 code = code or 200
157 message = message or "OK"
158 context.status = code
159 coroutine.yield(1, code, message)
160 end
161
162 function write(content)
163 if not content or #content == 0 then
164 return
165 end
166 if not context.eoh then
167 if not context.status then
168 status()
169 end
170 if not context.headers or not context.headers["content-type"] then
171 header("Content-Type", "text/html; charset=utf-8")
172 end
173
174 context.eoh = true
175 coroutine.yield(3)
176 end
177 coroutine.yield(4, content)
178 end
179
180
181 function basic_auth(realm, errorpage)
182 header("Status", "401 Unauthorized")
183 header("WWW-Authenticate", string.format('Basic realm="%s"', realm or ""))
184
185 if errorpage then
186 errorpage()
187 end
188
189 close()
190 end
191
192 function redirect(url)
193 header("Status", "302 Found")
194 header("Location", url)
195 close()
196 end
197
198 function build_querystring(table)
199 local s="?"
200
201 for k, v in pairs(table) do
202 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
203 end
204
205 return s
206 end
207
208 urldecode = luci.http.protocol.urldecode
209 urlencode = luci.http.protocol.urlencode