154f51ac403a368dd1af22b42f0e56812c504494
[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 Request = luci.util.class()
35 function Request.__init__(self, env, sourcein, sinkerr)
36 self.input = sourcein
37 self.error = sinkerr
38
39
40 -- File handler
41 self.filehandler = function() end
42
43 -- HTTP-Message table
44 self.message = {
45 env = env,
46 headers = {},
47 params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""),
48 }
49
50 self.parsed_input = false
51 end
52
53 function Request.formvalue(self, name, noparse)
54 if not noparse and not self.parsed_input then
55 self:_parse_input()
56 end
57
58 if name then
59 return self.message.params[name]
60 else
61 return self.message.params
62 end
63 end
64
65 function Request.formvaluetable(self, prefix)
66 local vals = {}
67 prefix = prefix and prefix .. "." or "."
68
69 if not self.parsed_input then
70 self:_parse_input()
71 end
72
73 local void = self.message.params[nil]
74 for k, v in pairs(self.message.params) do
75 if k:find(prefix, 1, true) == 1 then
76 vals[k:sub(#prefix + 1)] = tostring(v)
77 end
78 end
79
80 return vals
81 end
82
83 function Request.getcookie(self, name)
84 local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
85 local p = ";" .. name .. "=(.-);"
86 local i, j, value = c:find(p)
87 return value and urldecode(value)
88 end
89
90 function Request.getenv(self, name)
91 if name then
92 return self.message.env[name]
93 else
94 return self.message.env
95 end
96 end
97
98 function Request.setfilehandler(self, callback)
99 self.filehandler = callback
100 end
101
102 function Request._parse_input(self)
103 luci.http.protocol.parse_message_body(
104 self.input,
105 self.message,
106 self.filehandler
107 )
108 self.parsed_input = true
109 end
110
111 --- Close the HTTP-Connection.
112 function close()
113 if not context.eoh then
114 context.eoh = true
115 coroutine.yield(3)
116 end
117
118 if not context.closed then
119 context.closed = true
120 coroutine.yield(5)
121 end
122 end
123
124 --- Get a certain HTTP input value or a table of all input values.
125 -- @param name Name of the GET or POST variable to fetch
126 -- @param noparse Don't parse POST data before getting the value
127 -- @return HTTP input value or table of all input value
128 function formvalue(name, noparse)
129 return context.request:formvalue(name, noparse)
130 end
131
132 --- Get a table of all HTTP input values with a certain prefix.
133 -- @param prefix Prefix
134 -- @return Table of all HTTP input values with given prefix
135 function formvaluetable(prefix)
136 return context.request:formvaluetable(prefix)
137 end
138
139 --- Get the value of a certain HTTP-Cookie.
140 -- @param name Cookie Name
141 -- @return String containing cookie data
142 function getcookie(name)
143 return context.request:getcookie(name)
144 end
145
146 --- Get the value of a certain HTTP environment variable
147 -- or the environment table itself.
148 -- @param name Environment variable
149 -- @return HTTP environment value or environment table
150 function getenv(name)
151 return context.request:getenv(name)
152 end
153
154 --- Set a handler function for incoming user file uploads.
155 -- @param callback Handler function
156 function setfilehandler(callback)
157 return context.request:setfilehandler(callback)
158 end
159
160 --- Send a HTTP-Header.
161 -- @param key Header key
162 -- @param value Header value
163 function header(key, value)
164 if not context.headers then
165 context.headers = {}
166 end
167 context.headers[key:lower()] = value
168 coroutine.yield(2, key, value)
169 end
170
171 --- Set the mime type of following content data.
172 -- @param mime Mimetype of following content
173 function prepare_content(mime)
174 header("Content-Type", mime)
175 end
176
177 --- Set the HTTP status code and status message.
178 -- @param code Status code
179 -- @param message Status message
180 function status(code, message)
181 code = code or 200
182 message = message or "OK"
183 context.status = code
184 coroutine.yield(1, code, message)
185 end
186
187 --- Send a chunk of content data to the client.
188 -- This function is as a valid LTN12 sink.
189 -- If the content chunk is nil this function will automatically invoke close.
190 -- @param content Content chunk
191 -- @param src_err Error object from source (optional)
192 -- @see close
193 function write(content, src_err)
194 if not content then
195 if src_err then
196 error(src_err)
197 else
198 close()
199 end
200 return true
201 elseif #content == 0 then
202 return true
203 else
204 if not context.eoh then
205 if not context.status then
206 status()
207 end
208 if not context.headers or not context.headers["content-type"] then
209 header("Content-Type", "text/html; charset=utf-8")
210 end
211 if not context.headers["cache-control"] then
212 header("Cache-Control", "no-cache")
213 end
214
215
216 context.eoh = true
217 coroutine.yield(3)
218 end
219 coroutine.yield(4, content)
220 return true
221 end
222 end
223
224 --- Redirects the client to a new URL and closes the connection.
225 -- @param url Target URL
226 function redirect(url)
227 status(302, "Found")
228 header("Location", url)
229 close()
230 end
231
232 --- Create a querystring out of a table of key - value pairs.
233 -- @param table Query string source table
234 -- @return Encoded HTTP query string
235 function build_querystring(table)
236 local s="?"
237
238 for k, v in pairs(table) do
239 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
240 end
241
242 return s
243 end
244
245 --- Return the URL-decoded equivalent of a string.
246 -- @param str URL-encoded string
247 -- @param no_plus Don't decode + to " "
248 -- @return URL-decoded string
249 -- @see urlencode
250 urldecode = luci.http.protocol.urldecode
251
252 --- Return the URL-encoded equivalent of a string.
253 -- @param str Source string
254 -- @return URL-encoded string
255 -- @see urldecode
256 urlencode = luci.http.protocol.urlencode