libs/json: Completed JSON library
[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 --- LuCI Web Framework high-level HTTP functions.
28 module("luci.http", package.seeall)
29 local ltn12 = require("luci.ltn12")
30 require("luci.http.protocol")
31 require("luci.util")
32
33 context = luci.util.threadlocal()
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.content(self)
85 if not self.parsed_input then
86 self:_parse_input()
87 end
88
89 return self.message.content, self.message.content_length
90 end
91
92 function Request.getcookie(self, name)
93 local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
94 local p = ";" .. name .. "=(.-);"
95 local i, j, value = c:find(p)
96 return value and urldecode(value)
97 end
98
99 function Request.getenv(self, name)
100 if name then
101 return self.message.env[name]
102 else
103 return self.message.env
104 end
105 end
106
107 function Request.setfilehandler(self, callback)
108 self.filehandler = callback
109 end
110
111 function Request._parse_input(self)
112 luci.http.protocol.parse_message_body(
113 self.input,
114 self.message,
115 self.filehandler
116 )
117 self.parsed_input = true
118 end
119
120 --- Close the HTTP-Connection.
121 function close()
122 if not context.eoh then
123 context.eoh = true
124 coroutine.yield(3)
125 end
126
127 if not context.closed then
128 context.closed = true
129 coroutine.yield(5)
130 end
131 end
132
133 --- Return the request content if the request was of unknown type.
134 -- @return HTTP request body
135 -- @return HTTP request body length
136 function content()
137 return context.request:content()
138 end
139
140 --- Get a certain HTTP input value or a table of all input values.
141 -- @param name Name of the GET or POST variable to fetch
142 -- @param noparse Don't parse POST data before getting the value
143 -- @return HTTP input value or table of all input value
144 function formvalue(name, noparse)
145 return context.request:formvalue(name, noparse)
146 end
147
148 --- Get a table of all HTTP input values with a certain prefix.
149 -- @param prefix Prefix
150 -- @return Table of all HTTP input values with given prefix
151 function formvaluetable(prefix)
152 return context.request:formvaluetable(prefix)
153 end
154
155 --- Get the value of a certain HTTP-Cookie.
156 -- @param name Cookie Name
157 -- @return String containing cookie data
158 function getcookie(name)
159 return context.request:getcookie(name)
160 end
161
162 --- Get the value of a certain HTTP environment variable
163 -- or the environment table itself.
164 -- @param name Environment variable
165 -- @return HTTP environment value or environment table
166 function getenv(name)
167 return context.request:getenv(name)
168 end
169
170 --- Set a handler function for incoming user file uploads.
171 -- @param callback Handler function
172 function setfilehandler(callback)
173 return context.request:setfilehandler(callback)
174 end
175
176 --- Send a HTTP-Header.
177 -- @param key Header key
178 -- @param value Header value
179 function header(key, value)
180 if not context.headers then
181 context.headers = {}
182 end
183 context.headers[key:lower()] = value
184 coroutine.yield(2, key, value)
185 end
186
187 --- Set the mime type of following content data.
188 -- @param mime Mimetype of following content
189 function prepare_content(mime)
190 if mime == "application/xhtml+xml" then
191 if not getenv("HTTP_ACCEPT") or
192 not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
193 mime = "text/html; charset=UTF-8"
194 end
195 header("Vary", "Accept")
196 end
197 header("Content-Type", mime)
198 end
199
200 --- Get the RAW HTTP input source
201 -- @return HTTP LTN12 source
202 function source()
203 return context.request.input
204 end
205
206 --- Set the HTTP status code and status message.
207 -- @param code Status code
208 -- @param message Status message
209 function status(code, message)
210 code = code or 200
211 message = message or "OK"
212 context.status = code
213 coroutine.yield(1, code, message)
214 end
215
216 --- Send a chunk of content data to the client.
217 -- This function is as a valid LTN12 sink.
218 -- If the content chunk is nil this function will automatically invoke close.
219 -- @param content Content chunk
220 -- @param src_err Error object from source (optional)
221 -- @see close
222 function write(content, src_err)
223 if not content then
224 if src_err then
225 error(src_err)
226 else
227 close()
228 end
229 return true
230 elseif #content == 0 then
231 return true
232 else
233 if not context.eoh then
234 if not context.status then
235 status()
236 end
237 if not context.headers or not context.headers["content-type"] then
238 header("Content-Type", "text/html; charset=utf-8")
239 end
240 if not context.headers["cache-control"] then
241 header("Cache-Control", "no-cache")
242 header("Expires", "0")
243 end
244
245
246 context.eoh = true
247 coroutine.yield(3)
248 end
249 coroutine.yield(4, content)
250 return true
251 end
252 end
253
254 --- Redirects the client to a new URL and closes the connection.
255 -- @param url Target URL
256 function redirect(url)
257 status(302, "Found")
258 header("Location", url)
259 close()
260 end
261
262 --- Create a querystring out of a table of key - value pairs.
263 -- @param table Query string source table
264 -- @return Encoded HTTP query string
265 function build_querystring(table)
266 local s="?"
267
268 for k, v in pairs(table) do
269 s = s .. urlencode(k) .. "=" .. urlencode(v) .. "&"
270 end
271
272 return s
273 end
274
275 --- Return the URL-decoded equivalent of a string.
276 -- @param str URL-encoded string
277 -- @param no_plus Don't decode + to " "
278 -- @return URL-decoded string
279 -- @see urlencode
280 urldecode = luci.http.protocol.urldecode
281
282 --- Return the URL-encoded equivalent of a string.
283 -- @param str Source string
284 -- @return URL-encoded string
285 -- @see urldecode
286 urlencode = luci.http.protocol.urlencode