socket.http.request(): simultaneous support for http and https URL schemes, with caller-adjustable scheme-to-transport mappings (default "socket.http" and "ssl.https")
parent
38865fad3a
commit
e587800164
56
src/http.lua
56
src/http.lua
|
@ -26,15 +26,20 @@ _M.TIMEOUT = 60
|
||||||
-- user agent field sent in request
|
-- user agent field sent in request
|
||||||
_M.USERAGENT = socket._VERSION
|
_M.USERAGENT = socket._VERSION
|
||||||
|
|
||||||
-- supported schemes
|
-- supported schemes and their particulars
|
||||||
local SCHEMES = {
|
local SCHEMES = {
|
||||||
http = { port = 80 }
|
http = {
|
||||||
, https = { port = 443 }}
|
port = 80
|
||||||
|
, create = function(t)
|
||||||
|
return socket.tcp end }
|
||||||
|
, https = {
|
||||||
|
port = 443
|
||||||
|
, create = function(t)
|
||||||
|
return require("ssl.https").tcp(t) end }}
|
||||||
|
|
||||||
-- default scheme and port for document retrieval
|
-- default scheme and port for document retrieval
|
||||||
local SCHEME = 'http'
|
local SCHEME = 'http'
|
||||||
local PORT = SCHEMES[SCHEME].port
|
local PORT = SCHEMES[SCHEME].port
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Reads MIME headers from a connection, unfolding where needed
|
-- Reads MIME headers from a connection, unfolding where needed
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
@ -115,13 +120,13 @@ local metat = { __index = {} }
|
||||||
|
|
||||||
function _M.open(host, port, create)
|
function _M.open(host, port, create)
|
||||||
-- create socket with user connect function, or with default
|
-- create socket with user connect function, or with default
|
||||||
local c = socket.try((create or socket.tcp)())
|
local c = socket.try(create())
|
||||||
local h = base.setmetatable({ c = c }, metat)
|
local h = base.setmetatable({ c = c }, metat)
|
||||||
-- create finalized try
|
-- create finalized try
|
||||||
h.try = socket.newtry(function() h:close() end)
|
h.try = socket.newtry(function() h:close() end)
|
||||||
-- set timeout before connecting
|
-- set timeout before connecting
|
||||||
h.try(c:settimeout(_M.TIMEOUT))
|
h.try(c:settimeout(_M.TIMEOUT))
|
||||||
h.try(c:connect(host, port or PORT))
|
h.try(c:connect(host, port))
|
||||||
-- here everything worked
|
-- here everything worked
|
||||||
return h
|
return h
|
||||||
end
|
end
|
||||||
|
@ -221,14 +226,13 @@ end
|
||||||
|
|
||||||
local function adjustheaders(reqt)
|
local function adjustheaders(reqt)
|
||||||
-- default headers
|
-- default headers
|
||||||
local headhost = reqt.host
|
local host = reqt.host
|
||||||
local headport = tostring(reqt.port)
|
local port = tostring(reqt.port)
|
||||||
local schemeport = tostring(SCHEMES[reqt.scheme].port)
|
if port ~= tostring(SCHEMES[reqt.scheme].port) then
|
||||||
if headport ~= schemeport then
|
host = host .. ':' .. port end
|
||||||
headhost = headhost .. ':' .. headport end
|
|
||||||
local lower = {
|
local lower = {
|
||||||
["user-agent"] = _M.USERAGENT,
|
["user-agent"] = _M.USERAGENT,
|
||||||
["host"] = headhost,
|
["host"] = host,
|
||||||
["connection"] = "close, TE",
|
["connection"] = "close, TE",
|
||||||
["te"] = "trailers"
|
["te"] = "trailers"
|
||||||
}
|
}
|
||||||
|
@ -267,8 +271,13 @@ local function adjustrequest(reqt)
|
||||||
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
||||||
-- explicit components override url
|
-- explicit components override url
|
||||||
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
||||||
if nreqt.port == "" then nreqt.port = PORT end
|
-- default to scheme particulars
|
||||||
if not (nreqt.host and nreqt.host ~= "") then
|
local schemedefs, host, port, method
|
||||||
|
= SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method
|
||||||
|
if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end
|
||||||
|
if not (port and port ~= '') then nreqt.port = schemedefs.port end
|
||||||
|
if not (method and method ~= '') then nreqt.method = 'GET' end
|
||||||
|
if not (host and host ~= "") then
|
||||||
socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
|
socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
|
||||||
end
|
end
|
||||||
-- compute uri if user hasn't overriden
|
-- compute uri if user hasn't overriden
|
||||||
|
@ -285,8 +294,10 @@ local function shouldredirect(reqt, code, headers)
|
||||||
if not location then return false end
|
if not location then return false end
|
||||||
location = string.gsub(location, "%s", "")
|
location = string.gsub(location, "%s", "")
|
||||||
if location == "" then return false end
|
if location == "" then return false end
|
||||||
local scheme = string.match(location, "^([%w][%w%+%-%.]*)%:")
|
local scheme = url.parse(location).scheme
|
||||||
if scheme and not SCHEMES[scheme] then return false end
|
if scheme and (not SCHEMES[scheme]) then return false end
|
||||||
|
-- avoid https downgrades
|
||||||
|
if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end
|
||||||
return (reqt.redirect ~= false) and
|
return (reqt.redirect ~= false) and
|
||||||
(code == 301 or code == 302 or code == 303 or code == 307) and
|
(code == 301 or code == 302 or code == 303 or code == 307) and
|
||||||
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
||||||
|
@ -306,10 +317,16 @@ end
|
||||||
local trequest, tredirect
|
local trequest, tredirect
|
||||||
|
|
||||||
--[[local]] function tredirect(reqt, location)
|
--[[local]] function tredirect(reqt, location)
|
||||||
|
-- the RFC says the redirect URL has to be absolute, but some
|
||||||
|
-- servers do not respect that
|
||||||
|
local newurl = url.absolute(reqt.url, location)
|
||||||
|
-- if switching schemes, reset port and create function
|
||||||
|
if url.parse(newurl).scheme ~= reqt.scheme then
|
||||||
|
reqt.port = nil
|
||||||
|
reqt.create = nil end
|
||||||
|
-- make new request
|
||||||
local result, code, headers, status = trequest {
|
local result, code, headers, status = trequest {
|
||||||
-- the RFC says the redirect URL has to be absolute, but some
|
url = newurl,
|
||||||
-- servers do not respect that
|
|
||||||
url = url.absolute(reqt.url, location),
|
|
||||||
source = reqt.source,
|
source = reqt.source,
|
||||||
sink = reqt.sink,
|
sink = reqt.sink,
|
||||||
headers = reqt.headers,
|
headers = reqt.headers,
|
||||||
|
@ -397,4 +414,5 @@ _M.request = socket.protect(function(reqt, body)
|
||||||
else return trequest(reqt) end
|
else return trequest(reqt) end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
_M.schemes = SCHEMES
|
||||||
return _M
|
return _M
|
||||||
|
|
Loading…
Reference in New Issue