2023-08-15 19:37:07 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
accept response object are callback return value this will allow more flexibility, like adding headers
diff --git a/README.md b/README.md index 1c50a73..07a2ad6 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ which looks like this: = responses +== simple responses + As can be seen in the hello world example above, most callbacks will return just one value: the payload string, which typically contains some HTML in web apps or some JSON in APIs. However, callbacks can return up to four values: @@ -80,6 +82,15 @@ local function private_page(req) end ``` +== advanced response + +If the first value returned by a callback is a table (instead of string), +then all response parameters are read from this table, the response object. + +In addition to "data" (i.e. payload), "status", "reason" and "cookies", +the response object can also optionally include the "headers" value. +This should be a table with additional response headers. + = templates ``` diff --git a/lib/ludweb/http.lua b/lib/ludweb/http.lua index caa15aa..e267921 100644 --- a/lib/ludweb/http.lua +++ b/lib/ludweb/http.lua @@ -92,28 +92,41 @@ local function build_cookie_data(cookies) return data end -local function build_response(data, status, reason, cookies, keep_alive) +local function build_header(headers) local header = "" - if status == nil then - status = 200 - reason = "OK" - elseif status == 303 then - reason = reason or "See Other" - header = "Location: " .. data .. "\r\n" + for key, val in pairs(headers) do + header = header .. key .. ": " .. val .. "\r\n" + end + return header +end + +local function build_response(resp, keep_alive) + local headers = {} + if resp.status == nil then + resp.status = 200 + resp.reason = "OK" + elseif resp.status == 303 then + resp.reason = resp.reason or "See Other" + headers["Location"] = resp.data end -- it's nice to provide a minimal error message by default - if status ~= 200 and data == "" then - data = status.." "..reason.."\n" + if resp.status ~= 200 and resp.data == "" then + resp.data = resp.status.." "..resp.reason.."\n" end if keep_alive then - header = header .. "Connection: keep-alive\r\n" + headers["Connection"] = "keep-alive" else - header = header .. "Connection: close\r\n" + headers["Connection"] = "close" + end + headers["Content-Length"] = #resp.data + resp.headers = resp.headers or {} + if resp.headers["Content-Type"] == nil then + headers["Content-Type"] = "text/html; charset=utf-8" end - header = header .. "Content-Length: " .. #data .. "\r\n" - header = header .. build_cookie_data(cookies) + local header = build_header(headers) .. build_header(resp.headers) + header = header .. build_cookie_data(resp.cookies) local fmt = "HTTP/1.1 %03d %s\r\n%s\r\n%s" - return fmt:format(status, reason, header, data) + return fmt:format(resp.status, resp.reason, header, resp.data) end local HTTP = {} @@ -144,17 +157,18 @@ local function new_http() return "", true end local req = parse_request(datain) - local dataout, status, reason, cookies = obj:process(req) - if dataout == nil then - return nil + local resp, status, reason, cookies = obj:process(req) + if resp == nil then return nil end + if type(resp) == "string" then + resp = {data=resp, status=status, reason=reason, cookies=cookies} end local keep_alive = req.headers.connection ~= "close" -- randomly close some connections to save resources if keep_alive and math.random(32) == 1 then keep_alive = false end - local resp = build_response(dataout, status, reason, cookies, keep_alive) - return resp, keep_alive + local dataout = build_response(resp, keep_alive) + return dataout, keep_alive end return obj end