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