Fix JSON NaN
[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 local ltn12 = require "luci.ltn12"
28 local protocol = require "luci.http.protocol"
29 local util = require "luci.util"
30 local string = require "string"
31 local coroutine = require "coroutine"
32 local table = require "table"
33
34 local ipairs, pairs, next, type, tostring, error =
35 ipairs, pairs, next, type, tostring, error
36
37 --- LuCI Web Framework high-level HTTP functions.
38 module "luci.http"
39
40 context = util.threadlocal()
41
42 Request = util.class()
43 function Request.__init__(self, env, sourcein, sinkerr)
44 self.input = sourcein
45 self.error = sinkerr
46
47
48 -- File handler
49 self.filehandler = function() end
50
51 -- HTTP-Message table
52 self.message = {
53 env = env,
54 headers = {},
55 params = protocol.urldecode_params(env.QUERY_STRING or ""),
56 }
57
58 self.parsed_input = false
59 end
60
61 function Request.formvalue(self, name, noparse)
62 if not noparse and not self.parsed_input then
63 self:_parse_input()
64 end
65
66 if name then
67 return self.message.params[name]
68 else
69 return self.message.params
70 end
71 end
72
73 function Request.formvaluetable(self, prefix)
74 local vals = {}
75 prefix = prefix and prefix .. "." or "."
76
77 if not self.parsed_input then
78 self:_parse_input()
79 end
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.content(self)
92 if not self.parsed_input then
93 self:_parse_input()
94 end
95
96 return self.message.content, self.message.content_length
97 end
98
99 function Request.getcookie(self, name)
100 local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
101 local p = ";" .. name .. "=(.-);"
102 local i, j, value = c:find(p)
103 return value and urldecode(value)
104 end
105
106 function Request.getenv(self, name)
107 if name then
108 return self.message.env[name]
109 else
110 return self.message.env
111 end
112 end
113
114 function Request.setfilehandler(self, callback)
115 self.filehandler = callback
116 end
117
118 function Request._parse_input(self)
119 protocol.parse_message_body(
120 self.input,
121 self.message,
122 self.filehandler
123 )
124 self.parsed_input = true
125 end
126
127 --- Close the HTTP-Connection.
128 function close()
129 if not context.eoh then
130 context.eoh = true
131 coroutine.yield(3)
132 end
133
134 if not context.closed then
135 context.closed = true
136 coroutine.yield(5)
137 end
138 end
139
140 --- Return the request content if the request was of unknown type.
141 -- @return HTTP request body
142 -- @return HTTP request body length
143 function content()
144 return context.request:content()
145 end
146
147 --- Get a certain HTTP input value or a table of all input values.
148 -- @param name Name of the GET or POST variable to fetch
149 -- @param noparse Don't parse POST data before getting the value
150 -- @return HTTP input value or table of all input value
151 function formvalue(name, noparse)
152 return context.request:formvalue(name, noparse)
153 end
154
155 --- Get a table of all HTTP input values with a certain prefix.
156 -- @param prefix Prefix
157 -- @return Table of all HTTP input values with given prefix
158 function formvaluetable(prefix)
159 return context.request:formvaluetable(prefix)
160 end
161
162 --- Get the value of a certain HTTP-Cookie.
163 -- @param name Cookie Name
164 -- @return String containing cookie data
165 function getcookie(name)
166 return context.request:getcookie(name)
167 end
168
169 --- Get the value of a certain HTTP environment variable
170 -- or the environment table itself.
171 -- @param name Environment variable
172 -- @return HTTP environment value or environment table
173 function getenv(name)
174 return context.request:getenv(name)
175 end
176
177 --- Set a handler function for incoming user file uploads.
178 -- @param callback Handler function
179 function setfilehandler(callback)
180 return context.request:setfilehandler(callback)
181 end
182
183 --- Send a HTTP-Header.
184 -- @param key Header key
185 -- @param value Header value
186 function header(key, value)
187 if not context.headers then
188 context.headers = {}
189 end
190 context.headers[key:lower()] = value
191 coroutine.yield(2, key, value)
192 end
193
194 --- Set the mime type of following content data.
195 -- @param mime Mimetype of following content
196 function prepare_content(mime)
197 if not context.headers or not context.headers["content-type"] then
198 if mime == "application/xhtml+xml" then
199 if not getenv("HTTP_ACCEPT") or
200 not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
201 mime = "text/html; charset=UTF-8"
202 end
203 header("Vary", "Accept")
204 end
205 header("Content-Type", mime)
206 end
207 end
208
209 --- Get the RAW HTTP input source
210 -- @return HTTP LTN12 source
211 function source()
212 return context.request.input
213 end
214
215 --- Set the HTTP status code and status message.
216 -- @param code Status code
217 -- @param message Status message
218 function status(code, message)
219 code = code or 200
220 message = message or "OK"
221 context.status = code
222 coroutine.yield(1, code, message)
223 end
224
225 --- Send a chunk of content data to the client.
226 -- This function is as a valid LTN12 sink.
227 -- If the content chunk is nil this function will automatically invoke close.
228 -- @param content Content chunk
229 -- @param src_err Error object from source (optional)
230 -- @see close
231 function write(content, src_err)
232 if not content then
233 if src_err then
234 error(src_err)
235 else
236 close()
237 end
238 return true
239 elseif #content == 0 then
240 return true
241 else
242 if not context.eoh then
243 if not context.status then
244 status()
245 end
246 if not context.headers or not context.headers["content-type"] then
247 header("Content-Type", "text/html; charset=utf-8")
248 end
249 if not context.headers["cache-control"] then
250 header("Cache-Control", "no-cache")
251 header("Expires", "0")
252 end
253
254
255 context.eoh = true
256 coroutine.yield(3)
257 end
258 coroutine.yield(4, content)
259 return true
260 end
261 end
262
263 --- Splice data from a filedescriptor to the client.
264 -- @param fp File descriptor
265 -- @param size Bytes to splice (optional)
266 function splice(fd, size)
267 coroutine.yield(6, fd, size)
268 end
269
270 --- Redirects the client to a new URL and closes the connection.
271 -- @param url Target URL
272 function redirect(url)
273 status(302, "Found")
274 header("Location", url)
275 close()
276 end
277
278 --- Create a querystring out of a table of key - value pairs.
279 -- @param table Query string source table
280 -- @return Encoded HTTP query string
281 function build_querystring(q)
282 local s = { "?" }
283
284 for k, v in pairs(q) do
285 if #s > 1 then s[#s+1] = "&" end
286
287 s[#s+1] = urldecode(k)
288 s[#s+1] = "="
289 s[#s+1] = urldecode(v)
290 end
291
292 return table.concat(s, "")
293 end
294
295 --- Return the URL-decoded equivalent of a string.
296 -- @param str URL-encoded string
297 -- @param no_plus Don't decode + to " "
298 -- @return URL-decoded string
299 -- @see urlencode
300 urldecode = protocol.urldecode
301
302 --- Return the URL-encoded equivalent of a string.
303 -- @param str Source string
304 -- @return URL-encoded string
305 -- @see urldecode
306 urlencode = protocol.urlencode
307
308 --- Send the given data as JSON encoded string.
309 -- @param data Data to send
310 function write_json(x)
311 if x == nil then
312 write("null")
313 elseif type(x) == "table" then
314 local k, v
315 if type(next(x)) == "number" then
316 write("[ ")
317 for k, v in ipairs(x) do
318 write_json(v)
319 if next(x, k) then
320 write(", ")
321 end
322 end
323 write(" ]")
324 else
325 write("{ ")
326 for k, v in pairs(x) do
327 write("%q: " % k)
328 write_json(v)
329 if next(x, k) then
330 write(", ")
331 end
332 end
333 write(" }")
334 end
335 elseif type(x) == "number" or type(x) == "boolean" then
336 if (x ~= x) then
337 -- NaN is the only value that doesn't equal to itself.
338 write("Number.NaN")
339 else
340 write(tostring(x))
341 end
342 elseif type(x) == "string" then
343 write("%q" % tostring(x))
344 end
345 end