* Introducing LuCI HTTPD as testing environment
[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 return name and self.message.env[name] or self.message.env
93 end
94
95 function Request.setfilehandler(self, callback)
96 self.filehandler = callback
97 end
98
99
100 function close()
101 if not context.eoh then
102 context.eoh = true
103 coroutine.yield(3)
104 end
105
106 if not context.closed then
107 context.closed = true
108 coroutine.yield(5)
109 end
110 end
111
112 function formvalue(...)
113 return context.request:formvalue(...)
114 end
115
116 function formvaluetable(...)
117 return context.request:formvaluetable(...)
118 end
119
120 function getvalue(...)
121 return context.request:getvalue(...)
122 end
123
124 function postvalue(...)
125 return context.request:postvalue(...)
126 end
127
128 function getenv(...)
129 return context.request:getenv(...)
130 end
131
132 function setfilehandler(...)
133 return context.request:setfilehandler(...)
134 end
135
136 function header(key, value)
137 if not context.status then
138 status()
139 end
140 if not context.headers then
141 context.headers = {}
142 end
143 context.headers[key:lower()] = value
144 coroutine.yield(2, key, value)
145 end
146
147 function prepare_content(mime)
148 header("Content-Type", mime)
149 end
150
151 function status(code, message)
152 code = code or 200
153 message = message or "OK"
154 context.status = code
155 coroutine.yield(1, code, message)
156 end
157
158 function write(content)
159 if not content or #content == 0 then
160 return
161 end
162 if not context.eoh then
163 if not context.status then
164 status()
165 end
166 if not context.headers or not context.headers["content-type"] then
167 header("Content-Type", "text/html; charset=utf-8")
168 end
169
170 context.eoh = true
171 coroutine.yield(3)
172 end
173 coroutine.yield(4, content)
174 end
175
176
177 function basic_auth(realm, errorpage)
178 header("Status", "401 Unauthorized")
179 header("WWW-Authenticate", string.format('Basic realm="%s"', realm or ""))
180
181 if errorpage then
182 errorpage()
183 end
184
185 close()
186 end
187
188 function redirect(url)
189 header("Status", "302 Found")
190 header("Location", url)
191 close()
192 end
193
194 function build_querystring(table)
195 local s="?"
196
197 for k, v in pairs(table) do
198 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
199 end
200
201 return s
202 end
203
204 urldecode = luci.http.protocol.urldecode
205 urlencode = luci.http.protocol.urlencode