-- Copyright 2008 Steven Barth -- Copyright 2017 Matthias Schiffer -- Licensed to the public under the Apache License 2.0. local protocol = require "gluon.web.http.protocol" local util = require "gluon.web.util" local M = {} local Http = util.class() M.Http = Http function Http:__init__(env, input, output) self.input = input self.output = output self.request = { env = env, headers = {}, params = protocol.urldecode_params(env.QUERY_STRING or ""), } self.headers = {} end local function push_headers(self) if self.eoh then return end for _, header in pairs(self.headers) do self.output:write(string.format("%s: %s\r\n", header[1], header[2])) end self.output:write("\r\n") self.eoh = true end function Http:parse_input(filehandler) protocol.parse_message_body( self.input, self.request, filehandler ) end function Http:formvalue(name) return self:formvaluetable(name)[1] end function Http:formvaluetable(name) return self.request.params[name] or {} end function Http:getcookie(name) local c = string.gsub(";" .. (self:getenv("HTTP_COOKIE") or "") .. ";", "%s*;%s*", ";") local p = ";" .. name .. "=(.-);" local _, _, value = c:find(p) return value and protocol.urldecode(value) end function Http:getenv(name) return self.request.env[name] end function Http:close() if not self.output then return end push_headers(self) self.output:flush() self.output:close() self.output = nil end function Http:header(key, value) self.headers[key:lower()] = {key, value} end function Http:prepare_content(mime) if self.headers["content-type"] then return end if mime == "application/xhtml+xml" then local accept = self:getenv("HTTP_ACCEPT") if not accept or not accept:find("application/xhtml+xml", nil, true) then mime = "text/html; charset=UTF-8" end self:header("Vary", "Accept") end self:header("Content-Type", mime) end function Http:status(code, request) if not self.output or self.code then return end code = code or 200 request = request or "OK" self.code = code self.output:write(string.format("Status: %i %s\r\n", code, request)) end function Http:write(content) if not self.output then return end self:status() self:prepare_content("text/html; charset=utf-8") if not self.headers["cache-control"] then self:header("Cache-Control", "no-cache") self:header("Expires", "0") end push_headers(self) self.output:write(content) end function Http:redirect(url) self:status(302, "Found") self:header("Location", url) self:close() end return M