http.lua 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Licensed to the public under the Apache License 2.0.
  3. local ltn12 = require "luci.ltn12"
  4. local protocol = require "luci.http.protocol"
  5. local util = require "luci.util"
  6. local string = require "string"
  7. local coroutine = require "coroutine"
  8. local table = require "table"
  9. local ipairs, pairs, next, type, tostring, error =
  10. ipairs, pairs, next, type, tostring, error
  11. module "luci.http"
  12. context = util.threadlocal()
  13. Request = util.class()
  14. function Request.__init__(self, env, sourcein, sinkerr)
  15. self.input = sourcein
  16. self.error = sinkerr
  17. -- File handler nil by default to let .content() work
  18. self.filehandler = nil
  19. -- HTTP-Message table
  20. self.message = {
  21. env = env,
  22. headers = {},
  23. params = protocol.urldecode_params(env.QUERY_STRING or ""),
  24. }
  25. self.parsed_input = false
  26. end
  27. function Request.formvalue(self, name, noparse)
  28. if not noparse and not self.parsed_input then
  29. self:_parse_input()
  30. end
  31. if name then
  32. return self.message.params[name]
  33. else
  34. return self.message.params
  35. end
  36. end
  37. function Request.formvaluetable(self, prefix)
  38. local vals = {}
  39. prefix = prefix and prefix .. "." or "."
  40. if not self.parsed_input then
  41. self:_parse_input()
  42. end
  43. local void = self.message.params[nil]
  44. for k, v in pairs(self.message.params) do
  45. if k:find(prefix, 1, true) == 1 then
  46. vals[k:sub(#prefix + 1)] = tostring(v)
  47. end
  48. end
  49. return vals
  50. end
  51. function Request.content(self)
  52. if not self.parsed_input then
  53. self:_parse_input()
  54. end
  55. return self.message.content, self.message.content_length
  56. end
  57. function Request.getcookie(self, name)
  58. local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
  59. local p = ";" .. name .. "=(.-);"
  60. local i, j, value = c:find(p)
  61. return value and urldecode(value)
  62. end
  63. function Request.getenv(self, name)
  64. if name then
  65. return self.message.env[name]
  66. else
  67. return self.message.env
  68. end
  69. end
  70. function Request.setfilehandler(self, callback)
  71. self.filehandler = callback
  72. end
  73. function Request._parse_input(self)
  74. protocol.parse_message_body(
  75. self.input,
  76. self.message,
  77. self.filehandler
  78. )
  79. self.parsed_input = true
  80. end
  81. function close()
  82. if not context.eoh then
  83. context.eoh = true
  84. coroutine.yield(3)
  85. end
  86. if not context.closed then
  87. context.closed = true
  88. coroutine.yield(5)
  89. end
  90. end
  91. function content()
  92. return context.request:content()
  93. end
  94. function formvalue(name, noparse)
  95. return context.request:formvalue(name, noparse)
  96. end
  97. function formvaluetable(prefix)
  98. return context.request:formvaluetable(prefix)
  99. end
  100. function getcookie(name)
  101. return context.request:getcookie(name)
  102. end
  103. -- or the environment table itself.
  104. function getenv(name)
  105. return context.request:getenv(name)
  106. end
  107. function setfilehandler(callback)
  108. return context.request:setfilehandler(callback)
  109. end
  110. function header(key, value)
  111. if not context.headers then
  112. context.headers = {}
  113. end
  114. context.headers[key:lower()] = value
  115. coroutine.yield(2, key, value)
  116. end
  117. function prepare_content(mime)
  118. if not context.headers or not context.headers["content-type"] then
  119. if mime == "application/xhtml+xml" then
  120. if not getenv("HTTP_ACCEPT") or
  121. not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then
  122. mime = "text/html; charset=UTF-8"
  123. end
  124. header("Vary", "Accept")
  125. end
  126. header("Content-Type", mime)
  127. end
  128. end
  129. function source()
  130. return context.request.input
  131. end
  132. function status(code, message)
  133. code = code or 200
  134. message = message or "OK"
  135. context.status = code
  136. coroutine.yield(1, code, message)
  137. end
  138. -- This function is as a valid LTN12 sink.
  139. -- If the content chunk is nil this function will automatically invoke close.
  140. function write(content, src_err)
  141. if not content then
  142. if src_err then
  143. error(src_err)
  144. else
  145. close()
  146. end
  147. return true
  148. elseif #content == 0 then
  149. return true
  150. else
  151. if not context.eoh then
  152. if not context.status then
  153. status()
  154. end
  155. if not context.headers or not context.headers["content-type"] then
  156. header("Content-Type", "text/html; charset=utf-8")
  157. end
  158. if not context.headers["cache-control"] then
  159. header("Cache-Control", "no-cache")
  160. header("Expires", "0")
  161. end
  162. context.eoh = true
  163. coroutine.yield(3)
  164. end
  165. coroutine.yield(4, content)
  166. return true
  167. end
  168. end
  169. function splice(fd, size)
  170. coroutine.yield(6, fd, size)
  171. end
  172. function redirect(url)
  173. status(302, "Found")
  174. header("Location", url)
  175. close()
  176. end
  177. function build_querystring(q)
  178. local s = { "?" }
  179. for k, v in pairs(q) do
  180. if #s > 1 then s[#s+1] = "&" end
  181. s[#s+1] = urldecode(k)
  182. s[#s+1] = "="
  183. s[#s+1] = urldecode(v)
  184. end
  185. return table.concat(s, "")
  186. end
  187. urldecode = protocol.urldecode
  188. urlencode = protocol.urlencode
  189. function write_json(x)
  190. util.serialize_json(x, write)
  191. end