ssl: allowing non-blocking connects, finally

This commit is contained in:
HoneyryderChuck 2018-03-26 10:04:19 +01:00
parent 7b8d0d89f7
commit 4c9b16740f
6 changed files with 60 additions and 23 deletions

View File

@ -127,12 +127,8 @@ module HTTPX
dwrite
transition(:closed)
emit(:close)
else
catch(:called) do
dread
dwrite
parser.consume
end
when :open
consume
end
nil
end
@ -144,6 +140,14 @@ module HTTPX
private
def consume
catch(:called) do
dread
dwrite
parser.consume
end
end
def dread(wsize = @window_size)
loop do
siz = @io.read(wsize, @read_buffer)
@ -202,7 +206,7 @@ module HTTPX
when :open
return if @state == :closed
@io.connect
return if @io.closed?
return unless @io.connected?
send_pending
when :closing
return unless @state == :open

View File

@ -175,6 +175,10 @@ module HTTPX
@negotiated = false
end
def connected?
@state == :negotiated
end
def connect
super
if @keep_open
@ -183,11 +187,16 @@ module HTTPX
end
return if @state == :negotiated ||
@state != :connected
@io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
@io.hostname = @hostname
@io.sync_close = true
@io.connect
unless @io.is_a?(OpenSSL::SSL::SSLSocket)
@io = OpenSSL::SSL::SSLSocket.new(@io, @ctx)
@io.hostname = @hostname
@io.sync_close = true
end
# TODO: this might block it all
@io.connect_nonblock
transition(:negotiated)
rescue ::IO::WaitReadable,
::IO::WaitWritable
end
if RUBY_VERSION < "2.3"

View File

@ -92,9 +92,22 @@ module HTTPX
end
def to_io
transition(:connecting) if @state == :idle
case @state
when :idle
transition(:connecting)
when :connected
transition(:open)
end
@io.to_io
end
def call
super
case @state
when :connecting
consume
end
end
end
class ProxySSL < SSL

View File

@ -22,7 +22,7 @@ module HTTPX
end
parser.send(connect_request)
else
transition(:open)
transition(:connected)
end
end
@ -31,13 +31,14 @@ module HTTPX
when :connecting
return unless @state == :idle
@io.connect
return if @io.closed?
return unless @io.connected?
@parser = ConnectProxyParser.new(@write_buffer, @options.merge(max_concurrent_requests: 1))
@parser.once(:response, &method(:on_connect))
@parser.on(:close) { transition(:closing) }
proxy_connect
return if @state == :open
when :open
return if @state == :connected
when :connected
return unless @state == :idle || @state == :connecting
case @state
when :connecting
@parser.close
@ -56,7 +57,7 @@ module HTTPX
req, _ = @pending.first
request_uri = req.uri
@io = ProxySSL.new(@io, request_uri, @options)
transition(:open)
transition(:connected)
throw(:called)
else
pending = @pending.map(&:first) + @parser.pending

View File

@ -27,7 +27,7 @@ module HTTPX
req, _ = @pending.first
request_uri = req.uri
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
transition(:open)
transition(:connected)
throw(:called)
else
response = ErrorResponse.new(Error.new("socks error: #{status}"), 0, @options)
@ -43,13 +43,13 @@ module HTTPX
when :connecting
return unless @state == :idle
@io.connect
return if @io.closed?
return unless @io.connected?
req, _ = @pending.first
return unless req
request_uri = req.uri
@write_buffer << Packet.connect(@parameters, request_uri)
proxy_connect
when :open
when :connected
return unless @state == :connecting
@parser = nil
end

View File

@ -17,6 +17,16 @@ module HTTPX
Error = Class.new(Error)
class Socks5ProxyChannel < ProxyChannel
def call
super
case @state
when :connecting,
:negotiating,
:authenticating
consume
end
end
private
def proxy_connect
@ -51,7 +61,7 @@ module HTTPX
req, _ = @pending.first
request_uri = req.uri
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
transition(:open)
transition(:connected)
throw(:called)
end
end
@ -61,7 +71,7 @@ module HTTPX
when :connecting
return unless @state == :idle
@io.connect
return if @io.closed?
return unless @io.connected?
@write_buffer << Packet.negotiate(@parameters)
proxy_connect
when :authenticating
@ -72,7 +82,7 @@ module HTTPX
req, _ = @pending.first
request_uri = req.uri
@write_buffer << Packet.connect(request_uri)
when :open
when :connected
return unless @state == :negotiating
@parser = nil
end