2540d08a312a187c62a0c7ef088f3d6689befab5
[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 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24
25 ]]--
26
27 module("luci.http", package.seeall)
28 local ltn12 = require("luci.ltn12")
29 require("luci.http.protocol")
30 require("luci.util")
31
32 context = luci.util.threadlocal()
33
34
35 Request = luci.util.class()
36 function Request.__init__(self, env, sourcein, sinkerr)
37 self.input = sourcein
38 self.error = sinkerr
39
40
41 -- File handler
42 self.filehandler = function() end
43
44 -- HTTP-Message table
45 self.message = {
46 env = env,
47 headers = {},
48 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
49 }
50
51 self.parsed_input = false
52 end
53
54 function Request.formvalue(self, name, noparse)
55 if not noparse and not self.parsed_input then
56 self:_parse_input()
57 end
58
59 if name then
60 return self.message.params[name]
61 else
62 return self.message.params
63 end
64 end
65
66 function Request.formvaluetable(self, prefix)
67 local vals = {}
68 prefix = prefix and prefix .. "." or "."
69
70 if not self.parsed_input then
71 self:_parse_input()
72 end
73
74 local void = self.message.params[nil]
75 for k, v in pairs(self.message.params) do
76 if k:find(prefix, 1, true) == 1 then
77 vals[k:sub(#prefix + 1)] = tostring(v)
78 end
79 end
80
81 return vals
82 end
83
84 function Request.getcookie(self, name)
85 local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
86 local p = ";" .. name .. "=(.-);"
87 local i, j, value = c:find(p)
88 return value and urldecode(value)
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 function Request._parse_input(self)
104 luci.http.protocol.parse_message_body(
105 self.input,
106 self.message,
107 self.filehandler
108 )
109 self.parsed_input = true
110 end
111
112
113 function close()
114 if not context.eoh then
115 context.eoh = true
116 coroutine.yield(3)
117 end
118
119 if not context.closed then
120 context.closed = true
121 coroutine.yield(5)
122 end
123 end
124
125 function formvalue(...)
126 return context.request:formvalue(...)
127 end
128
129 function formvaluetable(...)
130 return context.request:formvaluetable(...)
131 end
132
133 function getcookie(...)
134 return context.request:getcookie(...)
135 end
136
137 function getvalue(...)
138 return context.request:getvalue(...)
139 end
140
141 function postvalue(...)
142 return context.request:postvalue(...)
143 end
144
145 function getenv(...)
146 return context.request:getenv(...)
147 end
148
149 function setfilehandler(...)
150 return context.request:setfilehandler(...)
151 end
152
153 function header(key, value)
154 if not context.headers then
155 context.headers = {}
156 end
157 context.headers[key:lower()] = value
158 coroutine.yield(2, key, value)
159 end
160
161 function prepare_content(mime)
162 header("Content-Type", mime)
163 end
164
165 function status(code, message)
166 code = code or 200
167 message = message or "OK"
168 context.status = code
169 coroutine.yield(1, code, message)
170 end
171
172 function write(content, src_err)
173 if not content then
174 if src_err then
175 error(src_err)
176 else
177 close()
178 end
179 return true
180 elseif #content == 0 then
181 return true
182 else
183 if not context.eoh then
184 if not context.status then
185 status()
186 end
187 if not context.headers or not context.headers["content-type"] then
188 header("Content-Type", "text/html; charset=utf-8")
189 end
190 if not context.headers["cache-control"] then
191 header("Cache-Control", "no-cache")
192 end
193
194
195 context.eoh = true
196 coroutine.yield(3)
197 end
198 coroutine.yield(4, content)
199 return true
200 end
201 end
202
203 function redirect(url)
204 status(302, "Found")
205 header("Location", url)
206 close()
207 end
208
209 function build_querystring(table)
210 local s="?"
211
212 for k, v in pairs(table) do
213 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
214 end
215
216 return s
217 end
218
219 urldecode = luci.http.protocol.urldecode
220 urlencode = luci.http.protocol.urlencode