Merge pull request #4200 from zhanhb/luci-app-acme
[project/luci.git] / libs / luci-lib-base / luasrc / http.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io>
3 -- Licensed to the public under the Apache License 2.0.
4
5 local util = require "luci.util"
6 local coroutine = require "coroutine"
7 local table = require "table"
8 local lhttp = require "lucihttp"
9 local nixio = require "nixio"
10 local ltn12 = require "luci.ltn12"
11
12 local table, ipairs, pairs, type, tostring, tonumber, error =
13 table, ipairs, pairs, type, tostring, tonumber, error
14
15 module "luci.http"
16
17 HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size
18
19 context = util.threadlocal()
20
21 Request = util.class()
22 function Request.__init__(self, env, sourcein, sinkerr)
23 self.input = sourcein
24 self.error = sinkerr
25
26
27 -- File handler nil by default to let .content() work
28 self.filehandler = nil
29
30 -- HTTP-Message table
31 self.message = {
32 env = env,
33 headers = {},
34 params = urldecode_params(env.QUERY_STRING or ""),
35 }
36
37 self.parsed_input = false
38 end
39
40 function Request.formvalue(self, name, noparse)
41 if not noparse and not self.parsed_input then
42 self:_parse_input()
43 end
44
45 if name then
46 return self.message.params[name]
47 else
48 return self.message.params
49 end
50 end
51
52 function Request.formvaluetable(self, prefix)
53 local vals = {}
54 prefix = prefix and prefix .. "." or "."
55
56 if not self.parsed_input then
57 self:_parse_input()
58 end
59
60 local void = self.message.params[nil]
61 for k, v in pairs(self.message.params) do
62 if k:find(prefix, 1, true) == 1 then
63 vals[k:sub(#prefix + 1)] = tostring(v)
64 end
65 end
66
67 return vals
68 end
69
70 function Request.content(self)
71 if not self.parsed_input then
72 self:_parse_input()
73 end
74
75 return self.message.content, self.message.content_length
76 end
77
78 function Request.getcookie(self, name)
79 return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name)
80 end
81
82 function Request.getenv(self, name)
83 if name then
84 return self.message.env[name]
85 else
86 return self.message.env
87 end
88 end
89
90 function Request.setfilehandler(self, callback)
91 self.filehandler = callback
92
93 if not self.parsed_input then
94 return
95 end
96
97 -- If input has already been parsed then uploads are stored as unlinked
98 -- temporary files pointed to by open file handles in the parameter
99 -- value table. Loop all params, and invoke the file callback for any
100 -- param with an open file handle.
101 local name, value
102 for name, value in pairs(self.message.params) do
103 if type(value) == "table" then
104 while value.fd do
105 local data = value.fd:read(1024)
106 local eof = (not data or data == "")
107
108 callback(value, data, eof)
109
110 if eof then
111 value.fd:close()
112 value.fd = nil
113 end
114 end
115 end
116 end
117 end
118
119 function Request._parse_input(self)
120 parse_message_body(
121 self.input,
122 self.message,
123 self.filehandler
124 )
125 self.parsed_input = true
126 end
127
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 function content()
141 return context.request:content()
142 end
143
144 function formvalue(name, noparse)
145 return context.request:formvalue(name, noparse)
146 end
147
148 function formvaluetable(prefix)
149 return context.request:formvaluetable(prefix)
150 end
151
152 function getcookie(name)
153 return context.request:getcookie(name)
154 end
155
156 -- or the environment table itself.
157 function getenv(name)
158 return context.request:getenv(name)
159 end
160
161 function setfilehandler(callback)
162 return context.request:setfilehandler(callback)
163 end
164
165 function header(key, value)
166 if not context.headers then
167 context.headers = {}
168 end
169 context.headers[key:lower()] = value
170 coroutine.yield(2, key, value)
171 end
172
173 function prepare_content(mime)
174 if not context.headers or not context.headers["content-type"] then
175 if mime == "application/xhtml+xml" then
176 if not getenv("HTTP_ACCEPT") or
177 not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
178 mime = "text/html; charset=UTF-8"
179 end
180 header("Vary", "Accept")
181 end
182 header("Content-Type", mime)
183 end
184 end
185
186 function source()
187 return context.request.input
188 end
189
190 function status(code, message)
191 code = code or 200
192 message = message or "OK"
193 context.status = code
194 coroutine.yield(1, code, message)
195 end
196
197 -- This function is as a valid LTN12 sink.
198 -- If the content chunk is nil this function will automatically invoke close.
199 function write(content, src_err)
200 if not content then
201 if src_err then
202 error(src_err)
203 else
204 close()
205 end
206 return true
207 elseif #content == 0 then
208 return true
209 else
210 if not context.eoh then
211 if not context.status then
212 status()
213 end
214 if not context.headers or not context.headers["content-type"] then
215 header("Content-Type", "text/html; charset=utf-8")
216 end
217 if not context.headers["cache-control"] then
218 header("Cache-Control", "no-cache")
219 header("Expires", "0")
220 end
221 if not context.headers["x-frame-options"] then
222 header("X-Frame-Options", "SAMEORIGIN")
223 end
224 if not context.headers["x-xss-protection"] then
225 header("X-XSS-Protection", "1; mode=block")
226 end
227 if not context.headers["x-content-type-options"] then
228 header("X-Content-Type-Options", "nosniff")
229 end
230
231 context.eoh = true
232 coroutine.yield(3)
233 end
234 coroutine.yield(4, content)
235 return true
236 end
237 end
238
239 function splice(fd, size)
240 coroutine.yield(6, fd, size)
241 end
242
243 function redirect(url)
244 if url == "" then url = "/" end
245 status(302, "Found")
246 header("Location", url)
247 close()
248 end
249
250 function build_querystring(q)
251 local s, n, k, v = {}, 1, nil, nil
252
253 for k, v in pairs(q) do
254 s[n+0] = (n == 1) and "?" or "&"
255 s[n+1] = util.urlencode(k)
256 s[n+2] = "="
257 s[n+3] = util.urlencode(v)
258 n = n + 4
259 end
260
261 return table.concat(s, "")
262 end
263
264 urldecode = util.urldecode
265
266 urlencode = util.urlencode
267
268 function write_json(x)
269 util.serialize_json(x, write)
270 end
271
272 -- from given url or string. Returns a table with urldecoded values.
273 -- Simple parameters are stored as string values associated with the parameter
274 -- name within the table. Parameters with multiple values are stored as array
275 -- containing the corresponding values.
276 function urldecode_params(url, tbl)
277 local parser, name
278 local params = tbl or { }
279
280 parser = lhttp.urlencoded_parser(function (what, buffer, length)
281 if what == parser.TUPLE then
282 name, value = nil, nil
283 elseif what == parser.NAME then
284 name = lhttp.urldecode(buffer)
285 elseif what == parser.VALUE and name then
286 params[name] = lhttp.urldecode(buffer) or ""
287 end
288
289 return true
290 end)
291
292 if parser then
293 parser:parse((url or ""):match("[^?]*$"))
294 parser:parse(nil)
295 end
296
297 return params
298 end
299
300 -- separated by "&". Tables are encoded as parameters with multiple values by
301 -- repeating the parameter name with each value.
302 function urlencode_params(tbl)
303 local k, v
304 local n, enc = 1, {}
305 for k, v in pairs(tbl) do
306 if type(v) == "table" then
307 local i, v2
308 for i, v2 in ipairs(v) do
309 if enc[1] then
310 enc[n] = "&"
311 n = n + 1
312 end
313
314 enc[n+0] = lhttp.urlencode(k)
315 enc[n+1] = "="
316 enc[n+2] = lhttp.urlencode(v2)
317 n = n + 3
318 end
319 else
320 if enc[1] then
321 enc[n] = "&"
322 n = n + 1
323 end
324
325 enc[n+0] = lhttp.urlencode(k)
326 enc[n+1] = "="
327 enc[n+2] = lhttp.urlencode(v)
328 n = n + 3
329 end
330 end
331
332 return table.concat(enc, "")
333 end
334
335 -- Content-Type. Stores all extracted data associated with its parameter name
336 -- in the params table within the given message object. Multiple parameter
337 -- values are stored as tables, ordinary ones as strings.
338 -- If an optional file callback function is given then it is fed with the
339 -- file contents chunk by chunk and only the extracted file name is stored
340 -- within the params table. The callback function will be called subsequently
341 -- with three arguments:
342 -- o Table containing decoded (name, file) and raw (headers) mime header data
343 -- o String value containing a chunk of the file data
344 -- o Boolean which indicates whether the current chunk is the last one (eof)
345 function mimedecode_message_body(src, msg, file_cb)
346 local parser, header, field
347 local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
348
349 parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length)
350 if what == parser.PART_INIT then
351 field = { }
352
353 elseif what == parser.HEADER_NAME then
354 header = buffer:lower()
355
356 elseif what == parser.HEADER_VALUE and header then
357 if header:lower() == "content-disposition" and
358 lhttp.header_attribute(buffer, nil) == "form-data"
359 then
360 field.name = lhttp.header_attribute(buffer, "name")
361 field.file = lhttp.header_attribute(buffer, "filename")
362 field[1] = field.file
363 end
364
365 if field.headers then
366 field.headers[header] = buffer
367 else
368 field.headers = { [header] = buffer }
369 end
370
371 elseif what == parser.PART_BEGIN then
372 return not field.file
373
374 elseif what == parser.PART_DATA and field.name and length > 0 then
375 if field.file then
376 if file_cb then
377 file_cb(field, buffer, false)
378 msg.params[field.name] = msg.params[field.name] or field
379 else
380 if not field.fd then
381 field.fd = nixio.mkstemp(field.name)
382 end
383
384 if field.fd then
385 field.fd:write(buffer)
386 msg.params[field.name] = msg.params[field.name] or field
387 end
388 end
389 else
390 field.value = buffer
391 end
392
393 elseif what == parser.PART_END and field.name then
394 if field.file and msg.params[field.name] then
395 if file_cb then
396 file_cb(field, "", true)
397 elseif field.fd then
398 field.fd:seek(0, "set")
399 end
400 else
401 local val = msg.params[field.name]
402
403 if type(val) == "table" then
404 val[#val+1] = field.value or ""
405 elseif val ~= nil then
406 msg.params[field.name] = { val, field.value or "" }
407 else
408 msg.params[field.name] = field.value or ""
409 end
410 end
411
412 field = nil
413
414 elseif what == parser.ERROR then
415 err = buffer
416 end
417
418 return true
419 end, HTTP_MAX_CONTENT)
420
421 return ltn12.pump.all(src, function (chunk)
422 len = len + (chunk and #chunk or 0)
423
424 if maxlen and len > maxlen + 2 then
425 return nil, "Message body size exceeds Content-Length"
426 end
427
428 if not parser or not parser:parse(chunk) then
429 return nil, err
430 end
431
432 return true
433 end)
434 end
435
436 -- Content-Type. Stores all extracted data associated with its parameter name
437 -- in the params table within the given message object. Multiple parameter
438 -- values are stored as tables, ordinary ones as strings.
439 function urldecode_message_body(src, msg)
440 local err, name, value, parser
441 local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
442
443 parser = lhttp.urlencoded_parser(function (what, buffer, length)
444 if what == parser.TUPLE then
445 name, value = nil, nil
446 elseif what == parser.NAME then
447 name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS)
448 elseif what == parser.VALUE and name then
449 local val = msg.params[name]
450
451 if type(val) == "table" then
452 val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
453 elseif val ~= nil then
454 msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" }
455 else
456 msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or ""
457 end
458 elseif what == parser.ERROR then
459 err = buffer
460 end
461
462 return true
463 end, HTTP_MAX_CONTENT)
464
465 return ltn12.pump.all(src, function (chunk)
466 len = len + (chunk and #chunk or 0)
467
468 if maxlen and len > maxlen + 2 then
469 return nil, "Message body size exceeds Content-Length"
470 elseif len > HTTP_MAX_CONTENT then
471 return nil, "Message body size exceeds maximum allowed length"
472 end
473
474 if not parser or not parser:parse(chunk) then
475 return nil, err
476 end
477
478 return true
479 end)
480 end
481
482 -- This function will examine the Content-Type within the given message object
483 -- to select the appropriate content decoder.
484 -- Currently the application/x-www-urlencoded and application/form-data
485 -- mime types are supported. If the encountered content encoding can't be
486 -- handled then the whole message body will be stored unaltered as "content"
487 -- property within the given message object.
488 function parse_message_body(src, msg, filecb)
489 if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then
490 local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil)
491
492 -- Is it multipart/mime ?
493 if ctype == "multipart/form-data" then
494 return mimedecode_message_body(src, msg, filecb)
495
496 -- Is it application/x-www-form-urlencoded ?
497 elseif ctype == "application/x-www-form-urlencoded" then
498 return urldecode_message_body(src, msg)
499
500 end
501
502 -- Unhandled encoding
503 -- If a file callback is given then feed it chunk by chunk, else
504 -- store whole buffer in message.content
505 local sink
506
507 -- If we have a file callback then feed it
508 if type(filecb) == "function" then
509 local meta = {
510 name = "raw",
511 encoding = msg.env.CONTENT_TYPE
512 }
513 sink = function( chunk )
514 if chunk then
515 return filecb(meta, chunk, false)
516 else
517 return filecb(meta, nil, true)
518 end
519 end
520 -- ... else append to .content
521 else
522 msg.content = ""
523 msg.content_length = 0
524
525 sink = function( chunk )
526 if chunk then
527 if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then
528 msg.content = msg.content .. chunk
529 msg.content_length = msg.content_length + #chunk
530 return true
531 else
532 return nil, "POST data exceeds maximum allowed length"
533 end
534 end
535 return true
536 end
537 end
538
539 -- Pump data...
540 while true do
541 local ok, err = ltn12.pump.step( src, sink )
542
543 if not ok and err then
544 return nil, err
545 elseif not ok then -- eof
546 return true
547 end
548 end
549
550 return true
551 end
552
553 return false
554 end