123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- local internal = require "http.internal"
- local string = string
- local type = type
- local httpd = {}
- local http_status_msg = {
- [100] = "Continue",
- [101] = "Switching Protocols",
- [200] = "OK",
- [201] = "Created",
- [202] = "Accepted",
- [203] = "Non-Authoritative Information",
- [204] = "No Content",
- [205] = "Reset Content",
- [206] = "Partial Content",
- [300] = "Multiple Choices",
- [301] = "Moved Permanently",
- [302] = "Found",
- [303] = "See Other",
- [304] = "Not Modified",
- [305] = "Use Proxy",
- [307] = "Temporary Redirect",
- [400] = "Bad Request",
- [401] = "Unauthorized",
- [402] = "Payment Required",
- [403] = "Forbidden",
- [404] = "Not Found",
- [405] = "Method Not Allowed",
- [406] = "Not Acceptable",
- [407] = "Proxy Authentication Required",
- [408] = "Request Time-out",
- [409] = "Conflict",
- [410] = "Gone",
- [411] = "Length Required",
- [412] = "Precondition Failed",
- [413] = "Request Entity Too Large",
- [414] = "Request-URI Too Large",
- [415] = "Unsupported Media Type",
- [416] = "Requested range not satisfiable",
- [417] = "Expectation Failed",
- [500] = "Internal Server Error",
- [501] = "Not Implemented",
- [502] = "Bad Gateway",
- [503] = "Service Unavailable",
- [504] = "Gateway Time-out",
- [505] = "HTTP Version not supported",
- }
- local function readall(readbytes, bodylimit)
- local tmpline = {}
- local body = internal.recvheader(readbytes, tmpline, "")
- if not body then
- return 413 -- Request Entity Too Large
- end
- local request = assert(tmpline[1])
- local method, url, httpver = request:match "^(%a+)%s+(.-)%s+HTTP/([%d%.]+)$"
- assert(method and url and httpver)
- httpver = assert(tonumber(httpver))
- if httpver < 1.0 or httpver > 1.1 then
- return 505 -- HTTP Version not supported
- end
- local header = internal.parseheader(tmpline,2,{})
- if not header then
- return 400 -- Bad request
- end
- local length = header["content-length"]
- if length then
- length = tonumber(length)
- end
- local mode = header["transfer-encoding"]
- if mode then
- if mode ~= "identity" and mode ~= "chunked" then
- return 501 -- Not Implemented
- end
- end
- if mode == "chunked" then
- body, header = internal.recvchunkedbody(readbytes, bodylimit, header, body)
- if not body then
- return 413
- end
- else
- -- identity mode
- if length then
- if bodylimit and length > bodylimit then
- return 413
- end
- if #body >= length then
- body = body:sub(1,length)
- else
- local padding = readbytes(length - #body)
- body = body .. padding
- end
- end
- end
- return 200, url, method, header, body
- end
- function httpd.read_request(...)
- local ok, code, url, method, header, body = pcall(readall, ...)
- if ok then
- return code, url, method, header, body
- else
- return nil, code
- end
- end
- local function writeall(writefunc, statuscode, bodyfunc, header)
- local statusline = string.format("HTTP/1.1 %03d %s\r\n", statuscode, http_status_msg[statuscode] or "")
- writefunc(statusline)
- if header then
- for k,v in pairs(header) do
- if type(v) == "table" then
- for _,v in ipairs(v) do
- writefunc(string.format("%s: %s\r\n", k,v))
- end
- else
- writefunc(string.format("%s: %s\r\n", k,v))
- end
- end
- end
- local t = type(bodyfunc)
- if t == "string" then
- writefunc(string.format("content-length: %d\r\n\r\n", #bodyfunc))
- writefunc(bodyfunc)
- elseif t == "function" then
- writefunc("transfer-encoding: chunked\r\n")
- while true do
- local s = bodyfunc()
- if s then
- if s ~= "" then
- writefunc(string.format("\r\n%x\r\n", #s))
- writefunc(s)
- end
- else
- writefunc("\r\n0\r\n\r\n")
- break
- end
- end
- else
- assert(t == "nil")
- writefunc("\r\n")
- end
- end
- function httpd.write_response(...)
- return pcall(writeall, ...)
- end
- return httpd
|