lib/httpx/connection.rb in httpx-0.17.0 vs lib/httpx/connection.rb in httpx-0.18.0
- old
+ new
@@ -68,11 +68,11 @@
transition(:idle)
end
@inflight = 0
@keep_alive_timeout = @options.timeout[:keep_alive_timeout]
- @keep_alive_timer = nil
+ @total_timeout = @options.timeout[:total_timeout]
self.addresses = @options.addresses if @options.addresses
end
# this is a semi-private method, to be used by the resolver
@@ -198,15 +198,13 @@
end
nil
end
def close
- @parser.close if @parser
- return unless @keep_alive_timer
+ transition(:active) if @state == :inactive
- @keep_alive_timer.cancel
- remove_instance_variable(:@keep_alive_timer)
+ @parser.close if @parser
end
def reset
transition(:closing)
transition(:closed)
@@ -214,37 +212,59 @@
end
def send(request)
if @parser && !@write_buffer.full?
request.headers["alt-used"] = @origin.authority if match_altsvcs?(request.uri)
- if @keep_alive_timer
+
+ if @response_received_at && @keep_alive_timeout &&
+ Utils.elapsed_time(@response_received_at) > @keep_alive_timeout
# when pushing a request into an existing connection, we have to check whether there
# is the possibility that the connection might have extended the keep alive timeout.
# for such cases, we want to ping for availability before deciding to shovel requests.
- if @keep_alive_timer.fires_in.negative?
- @pending << request
- parser.ping
- return
- end
-
- @keep_alive_timer.pause
+ @pending << request
+ parser.ping
+ transition(:active) if @state == :inactive
+ return
end
- @inflight += 1
- parser.send(request)
+
+ send_request_to_parser(request)
else
@pending << request
end
end
def timeout
+ if @total_timeout
+ return @total_timeout unless @connected_at
+
+ elapsed_time = @total_timeout - Utils.elapsed_time(@connected_at)
+
+ if elapsed_time.negative?
+ ex = TotalTimeoutError.new(@total_timeout, "Timed out after #{@total_timeout} seconds")
+ ex.set_backtrace(caller)
+ on_error(@total_timeout)
+ return
+ end
+
+ return elapsed_time
+ end
+
return @timeout if defined?(@timeout)
return @options.timeout[:connect_timeout] if @state == :idle
@options.timeout[:operation_timeout]
end
+ def deactivate
+ transition(:inactive)
+ end
+
+ def open?
+ @state == :open || @state == :inactive
+ end
+
private
def connect
transition(:open)
end
@@ -377,20 +397,27 @@
end
end
def send_pending
while !@write_buffer.full? && (request = @pending.shift)
- @inflight += 1
- @keep_alive_timer.pause if @keep_alive_timer
- parser.send(request)
+ send_request_to_parser(request)
end
end
def parser
@parser ||= build_parser
end
+ def send_request_to_parser(request)
+ @inflight += 1
+ parser.send(request)
+
+ return unless @state == :inactive
+
+ transition(:active)
+ end
+
def build_parser(protocol = @io.protocol)
parser = registry(protocol).new(@write_buffer, @options)
set_parser_callbacks(parser)
parser
end
@@ -398,11 +425,12 @@
def set_parser_callbacks(parser)
parser.on(:response) do |request, response|
AltSvc.emit(request, response) do |alt_origin, origin, alt_params|
emit(:altsvc, alt_origin, origin, alt_params)
end
- handle_response
+ @response_received_at = Utils.now
+ @inflight -= 1
request.emit(:response, response)
end
parser.on(:altsvc) do |alt_origin, origin, alt_params|
emit(:altsvc, alt_origin, origin, alt_params)
end
@@ -418,11 +446,11 @@
parser.on(:origin) do |origin|
@origins |= [origin]
end
parser.on(:close) do |force|
transition(:closing)
- if force
+ if force || @state == :idle
transition(:closed)
emit(:close)
end
end
parser.on(:close_handshake) do
@@ -464,35 +492,37 @@
@timeout = @current_timeout = @options.timeout[:connect_timeout]
when :open
return if @state == :closed
- total_timeout
-
@io.connect
return unless @io.connected?
+ @connected_at = Utils.now
+
send_pending
@timeout = @current_timeout = parser.timeout
emit(:open)
+ when :inactive
+ return unless @state == :open
when :closing
return unless @state == :open
when :closed
return unless @state == :closing
return unless @write_buffer.empty?
- if @total_timeout
- @total_timeout.cancel
- remove_instance_variable(:@total_timeout)
- end
-
purge_after_closed
when :already_open
nextstate = :open
send_pending
+ when :active
+ return unless @state == :inactive
+
+ nextstate = :open
+ emit(:activate)
end
@state = nextstate
rescue Errno::ECONNREFUSED,
Errno::EADDRNOTAVAIL,
Errno::EHOSTUNREACH,
@@ -504,48 +534,28 @@
end
def purge_after_closed
@io.close if @io
@read_buffer.clear
- if @keep_alive_timer
- @keep_alive_timer.cancel
- remove_instance_variable(:@keep_alive_timer)
- end
-
remove_instance_variable(:@timeout) if defined?(@timeout)
end
- def handle_response
- @inflight -= 1
- return unless @inflight.zero?
-
- if @keep_alive_timer
- @keep_alive_timer.resume
- @keep_alive_timer.reset
- else
- @keep_alive_timer = @timers.after(@keep_alive_timeout) do
- unless @inflight.zero?
- log { "(#{@origin}): keep alive timeout expired" }
- parser.ping
- end
- end
- end
- end
-
def on_error(error)
if error.instance_of?(TimeoutError)
- if @timeout
- @timeout -= error.timeout
- return unless @timeout <= 0
- end
- if @total_timeout && @total_timeout.fires_in.negative?
- ex = TotalTimeoutError.new(@total_timeout.interval, "Timed out after #{@total_timeout.interval} seconds")
+ if @total_timeout && @connected_at &&
+ Utils.elapsed_time(@connected_at) > @total_timeout
+ ex = TotalTimeoutError.new(@total_timeout, "Timed out after #{@total_timeout} seconds")
ex.set_backtrace(error.backtrace)
error = ex
- elsif connecting?
- error = error.to_connection_error
+ else
+ if @timeout
+ @timeout -= error.timeout
+ return unless @timeout <= 0
+ end
+
+ error = error.to_connection_error if connecting?
end
end
handle_error(error)
reset
end
@@ -554,22 +564,9 @@
parser.handle_error(error) if @parser && parser.respond_to?(:handle_error)
while (request = @pending.shift)
response = ErrorResponse.new(request, error, @options)
request.response = response
request.emit(:response, response)
- end
- end
-
- def total_timeout
- total = @options.timeout[:total_timeout]
-
- return unless total
-
- @total_timeout ||= @timers.after(total) do
- ex = TotalTimeoutError.new(total, "Timed out after #{total} seconds")
- ex.set_backtrace(caller)
- on_error(ex)
- @parser.close if @parser
end
end
end
end