diff options
Diffstat (limited to 'lem/http/response.lua')
-rw-r--r-- | lem/http/response.lua | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/lem/http/response.lua b/lem/http/response.lua new file mode 100644 index 0000000..460c09e --- /dev/null +++ b/lem/http/response.lua @@ -0,0 +1,211 @@ +-- +-- This file is part of LEM, a Lua Event Machine. +-- Copyright 2011-2013 Emil Renner Berthing +-- Copyright 2013 Halfdan Mouritzen +-- +-- LEM is free software: you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as +-- published by the Free Software Foundation, either version 3 of +-- the License, or (at your option) any later version. +-- +-- LEM is distributed in the hope that it will be useful, but +-- WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with LEM. If not, see <http://www.gnu.org/licenses/>. +-- + +local setmetatable = setmetatable +local tostring = tostring +local tonumber = tonumber +local pairs = pairs +local type = type +local date = os.date +local format = string.format +local concat = table.concat +local remove = table.remove + +local M = {} + +local status_string = { + -- 1xx Informational + [100] = '100 Continue', + [101] = '101 Switching Protocols', + [102] = '102 Processing', -- WebDAV + + -- 2xx Success + [200] = '200 OK', + [201] = '201 Created', + [202] = '202 Accepted', + [203] = '203 Non-Authoritative Information', + [204] = '204 No Content', + [205] = '205 Reset Content', + [206] = '206 Partial Content', + [207] = '207 Multi-Status', -- WebDAV + [208] = '208 Already Reported', -- WebDAV + [226] = '226 IM Used', + [230] = '230 Authentication Successfull', + + -- 3xx Redirection + [300] = '300 Multiple Choices', + [301] = '301 Moved Permanently', + [302] = '302 Found', + [303] = '303 See Other', + [304] = '304 Not Modified', + [305] = '305 Use Proxy', + [306] = '306 Switch Proxy', + [307] = '307 Temporary Redirect', + [308] = '308 Permanent Redirect', + + -- 4xx Client Error + [400] = '400 Bad Request', + [401] = '401 Unauthorized', + [402] = '402 Payment Required', + [403] = '403 Forbidden', + [404] = '404 Not Found', + [405] = '405 Method Not Allowed', + [406] = '406 Not Acceptable', + [407] = '407 Proxy Authentication Required', + [408] = '408 Request Timeout', + [409] = '409 Conflict', + [410] = '410 Gone', + [411] = '411 Length Required', + [412] = '412 Precondition Failed', + [413] = '413 Request Entity Too Large', + [414] = '414 Request-URI Too Long', + [415] = '415 Unsupported Media Type', + [416] = '416 Requested Range Not Satisfiable', + [417] = '417 Expectation Failed', + -- ... + [422] = '422 Unprocessable Entity', -- WebDAV + [423] = '423 Locked', -- WebDAV + [424] = '424 Failed Dependency', -- WebDAV + -- ... + [426] = '426 Upgrade Required', + [428] = '428 Precondition Required', + [429] = '429 Too Many Requests', + [431] = '431 Request Header Fields Too Large', + + -- 5xx Server Error + [500] = '500 Internal Server Error', + [501] = '501 Not Implemented', + [502] = '502 Bad Gateway', + [503] = '503 Service Unavailable', + [504] = '504 Gateway Timeout', + [505] = '505 HTTP Version Not Supported', + [506] = '506 Variant Also Negotiates', + [507] = '507 Insufficient Storage', -- WebDAV + [508] = '508 Loop Detected', -- WebDAV + -- ... + [510] = '510 Not Extended', + [511] = '511 Network Authentication Required', + [531] = '531 Access Denied', +} + +M.status_string = status_string + +function M.not_found(req, res) + if req.headers['expect'] ~= '100-continue' then + req:body() + end + + res.status = 404 + res.headers['Content-Type'] = 'text/html; charset=UTF-8' + res:add([[ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<title>Not Found</title> +</head> +<body> +<h1>Not found</h1> +</body> +</html> +]]) +end + +function M.htmlerror(num, text) + local str = format([[ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<title>%s</title> +</head> +<body> +<h1>%s</h1> +</body> +</html> +]], text, text) + return function(req, res) + res.status = num + res.headers['Content-Type'] = 'text/html; charset=UTF-8' + res.headers['Connection'] = 'close' + res:add(str) + end +end + +M.method_not_allowed = M.htmlerror(405, 'Method Not Allowed') +M.expectation_failed = M.htmlerror(417, 'Expectation Failed') +M.version_not_supported = M.htmlerror(505, 'HTTP Version Not Supported') +M.bad_request = M.htmlerror(400, 'Bad Request') + +local Response = {} +Response.__index = Response +M.Response = Response + +function Response:contentlength() + local len = 0 + for i = 1, #self do + len = len + #self[i] + end + return len +end + +function Response:appendheader(rope, i, size) + if not size then size = 0 end + local line + for k, v in pairs(self.headers) do + line = format('%s: %s\r\n', k, tostring(v)) + i = i + 1 + rope[i] = line + size = size + #line + end + i = i + 1 + rope[i] = '\r\n' + size = size + 2 + return i, size +end + +function Response:appendbody(rope, i, size) + if not size then size = 0 end + local chunk + for j = 1, #self do + chunk = self[j] + i = i + 1 + rope[i] = chunk + size = size + #chunk + end + return i, size +end + +function M.new(req) + local n = 0 + return setmetatable({ + headers = {}, + version = req and req.version or nil, + add = function(self, fmt, first, ...) + n = n + 1 + if first then + self[n] = format(fmt, first, ...) + else + self[n] = fmt + end + end + }, Response) +end + +return M + +-- vim: ts=2 sw=2 noet: |