bb05c680b1072c1e23f1ac991373e18e9dacd890
[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