Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for bind before connect. #140

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 50 additions & 15 deletions src/http.lua
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,43 @@ end
-----------------------------------------------------------------------------
local metat = { __index = {} }

function _M.open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)())
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(_M.TIMEOUT))
h.try(c:connect(host, port or _M.PORT))
-- here everything worked
return h
local function _bindBeforeConnect(host, port, timeout)
-- Keep trying to get an ephemeral port, degrade gracefully.
-- Ports will free up as sockets move out of TIME_WAIT and
-- are released by the kernel (60 seconds or so).
local t = socket.gettime() + timeout
while socket.gettime() < t do
local c = socket.tcp()
c:settimeout(timeout)
c:setoption("reuseaddr", true)
c:bind("*", 0)
if c:connect(host, port) == 1 then
return c
end
c:close()
end
end

function _M.open(host, opt)
local port = opt.port or _M.port
local timeout = opt.timeout or _M.TIMEOUT
if opt.bindBeforeConnect == true then
local c = socket.try(_bindBeforeConnect(host, port, timeout))
local h = base.setmetatable({ c = c }, metat)
h.try = socket.newtry(function() h:close() end)
return h
else
-- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)())
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(timeout))
h.try(c:connect(host, port))
-- here everything worked
return h
end
end

function metat.__index:sendrequestline(method, uri)
Expand Down Expand Up @@ -294,7 +320,7 @@ end
-- we loop until we get what we want, or
-- until we are sure there is no way to get it
local nreqt = adjustrequest(reqt)
local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
local h = _M.open(nreqt.host, nreqt)
-- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers)
Expand Down Expand Up @@ -329,12 +355,21 @@ end
return 1, code, headers, status
end

local function srequest(u, b)
local function srequest(u, b, o)
local t = {}
local reqt = {
url = u,
sink = ltn12.sink.table(t)
}
if base.type(b) == "table" then
o = b
b = nil
end
if o ~= nil then
for k,v in pairs(o) do
reqt[k] = v
end
end
if b then
reqt.source = ltn12.source.string(b)
reqt.headers = {
Expand All @@ -347,8 +382,8 @@ local function srequest(u, b)
return table.concat(t), code, headers, status
end

_M.request = socket.protect(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
_M.request = socket.protect(function(reqt, body, opt)
if base.type(reqt) == "string" then return srequest(reqt, body, opt)
else return trequest(reqt) end
end)

Expand Down