http.lua 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
  3. -- Licensed to the public under the Apache License 2.0.
  4. local string = string
  5. local table = table
  6. local nixio = require "nixio"
  7. local protocol = require "gluon.web.http.protocol"
  8. local util = require "gluon.web.util"
  9. local ipairs, pairs, tostring = ipairs, pairs, tostring
  10. module "gluon.web.http"
  11. Http = util.class()
  12. function Http:__init__(env, input, output)
  13. self.input = input
  14. self.output = output
  15. self.request = {
  16. env = env,
  17. headers = {},
  18. params = protocol.urldecode_params(env.QUERY_STRING or ""),
  19. }
  20. self.headers = {}
  21. end
  22. local function push_headers(self)
  23. if self.eoh then return end
  24. for _, header in pairs(self.headers) do
  25. self.output:write(string.format("%s: %s\r\n", header[1], header[2]))
  26. end
  27. self.output:write("\r\n")
  28. self.eoh = true
  29. end
  30. function Http:parse_input(filehandler)
  31. protocol.parse_message_body(
  32. self.input,
  33. self.request,
  34. filehandler
  35. )
  36. end
  37. function Http:formvalue(name)
  38. return self:formvaluetable(name)[1]
  39. end
  40. function Http:formvaluetable(name)
  41. return self.request.params[name] or {}
  42. end
  43. function Http:getcookie(name)
  44. local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";")
  45. local p = ";" .. name .. "=(.-);"
  46. local i, j, value = c:find(p)
  47. return value and urldecode(value)
  48. end
  49. function Http:getenv(name)
  50. return self.request.env[name]
  51. end
  52. function Http:close()
  53. if not self.output then return end
  54. push_headers(self)
  55. self.output:flush()
  56. self.output:close()
  57. self.output = nil
  58. end
  59. function Http:header(key, value)
  60. self.headers[key:lower()] = {key, value}
  61. end
  62. function Http:prepare_content(mime)
  63. if self.headers["content-type"] then return end
  64. if mime == "application/xhtml+xml" then
  65. local accept = self:getenv("HTTP_ACCEPT")
  66. if not accept or not accept:find("application/xhtml+xml", nil, true) then
  67. mime = "text/html; charset=UTF-8"
  68. end
  69. self:header("Vary", "Accept")
  70. end
  71. self:header("Content-Type", mime)
  72. end
  73. function Http:status(code, request)
  74. if not self.output or self.code then return end
  75. code = code or 200
  76. request = request or "OK"
  77. self.code = code
  78. self.output:write(string.format("Status: %i %s\r\n", code, request))
  79. end
  80. function Http:write(content)
  81. if not self.output then return end
  82. self:status()
  83. self:prepare_content("text/html; charset=utf-8")
  84. if not self.headers["cache-control"] then
  85. self:header("Cache-Control", "no-cache")
  86. self:header("Expires", "0")
  87. end
  88. push_headers(self)
  89. self.output:write(content)
  90. end
  91. function Http:redirect(url)
  92. self:status(302, "Found")
  93. self:header("Location", url)
  94. self:close()
  95. end