Migrating from luasocket to lua-http

I saw https://github.com/brunoos/luasec/issues/72#issuecomment-205328635 and couldn’t resist writing the linked code to use lua-http instead.

As the code was originally using luasocket’s http interface, it was straightforward to convert it to lua-http’s http.compat.socket module. This compatability interface provides the same API as luasocket’s socket.http and luasec’s ssl.https modules.

local http = require "http.compat.socket" -- require "socket.http" local https = http -- require "ssl.https" local ltn12 = require "ltn12" local string_sub = string.sub local table_concat = table.concat local function make_request(url, timeout) http.TIMEOUT = timeout http.USERAGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36" local b, c, h, s local tbody = {} local https_opt = { url = url, protocol = "tlsv1", verify = "none", headers = { ["Accept"] = "*/*", ["Accept-Language"] = "sk;q=0.8,en-US,en;q=0.6,cs;q=0.4", ["Accept-Charset"] = "UTF-8;q=0.8,*;q=0.7", }, sink = ltn12.sink.table(tbody), redirect = false, } local http_opt = { url = url, headers = { ["Accept"] = "*/*", ["Accept-Language"] = "sk;q=0.8,en-US,en;q=0.6,cs;q=0.4", ["Accept-Charset"] = "UTF-8;q=0.8,*;q=0.7", }, sink = ltn12.sink.table(tbody), redirect = false, } if string_sub(url, 1, 5) ~= "https" then _, c, h, s = http.request(http_opt) else _, c, h, s = https.request(https_opt) end -- make headers keys lowercase if h ~= nil then local h_tmp = {} for k, v in pairs(h) do h_tmp[k:lower()] = v end h = h_tmp end -- concat body parts b = table_concat(tbody) return {body = b, code = c, headers = h, status = s} end

However, this function can be rewritten much more nicely using the http.request module.

local http_req = require "http.request" local h1_reason_phrases = require "http.h1_reason_phrases" local function make_request(url, timeout) local r = http_req.new_from_uri(url) r.headers:upsert("useragent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36") r.headers:upsert("accept", "*/*") r.headers:upsert("accept-language", "sk;q=0.8,en-US,en;q=0.6,cs;q=0.4") r.headers:upsert("accept-charset", "UTF-8;q=0.8,*;q=0.7") r.follow_redirects = false local headers, stream = r:go(timeout) if headers == nil then return nil, stream end local b, err = stream:get_body_as_string(timeout) -- XXX: use a deadline instead of a timeout? stream:shutdown() -- shutdown ASAP to free resources if b == nil then return nil, err end local c = headers:get(":status") local s = h1_reason_phrases[c] -- look up reason phrase for code c = tonumber(c, 10) or c -- the code might not be numeric -- convert from headers object to unordered table of key/value pairs local h = {} for name in headers:each() do if name ~= ":status" and h[name] == nil then h[name] = headers:get_comma_separated(name) end end return {body = b, code = c, headers = h, status = s} end