fixed another loop caused by certain connection goaway frames from

server not being processed

While introducing yet another test to catch frame processing errors, in
this case with the SETTINGS_TIMEOUT error, another loop was found. It
was caused by two reasons:

* connection was signaling it was "closing" on such an error, which is
  not really true (server already closed the stream, so no need to
  close it again); it should be marked as closed instead.
* write buffer was still full (with the handshake in this case), so the
  connection was still trying to write;
This commit is contained in:
HoneyryderChuck 2020-11-27 12:42:41 +00:00
parent e6c9bb4714
commit 035eda1f95
4 changed files with 30 additions and 7 deletions

View File

@ -269,16 +269,16 @@ module HTTPX
end
def on_close(_last_frame, error, _payload)
is_connection_closed = @connection.state == :closed
if error && error != :no_error
@buffer.clear if is_connection_closed
ex = Error.new(0, error)
ex.set_backtrace(caller)
@streams.each_key do |request|
emit(:error, request, ex)
end
handle_error(ex)
end
return unless @connection.state == :closed && @streams.size.zero?
return unless is_connection_closed && @streams.size.zero?
emit(:close)
emit(:close, is_connection_closed)
end
def on_frame_sent(frame)

View File

@ -98,6 +98,16 @@ class HTTPSTest < Minitest::Test
assert response.version == "1.1", "request should have been retried with HTTP/1.1"
end
end
def test_http2_settings_timeout
uri = build_uri("/get")
HTTPX.plugin(SessionWithPool).plugin(SessionWithFrameDelay).wrap do |http|
response = http.get(uri)
assert response.is_a?(HTTPX::ErrorResponse), "expected to fail for settings timeout"
assert response.status =~ /settings_timeout/,
"connection should have terminated due to HTTP/2 settings timeout"
end
end
end
private

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
#
# This module is used only to test frame errors for HTTP/2. It targets the settings timeout of
# nghttp2.org, which is known as being 10 seconnds.
#
module SessionWithFrameDelay
module ConnectionMethods
def send_pending
sleep(11)
super
end
end
end

View File

@ -12,8 +12,7 @@ module SessionWithSingleStream
@connection.active_stream_count.positive?
end
parser.instance_variable_set(:@max_requests, 10)
connection = parser.instance_variable_get(:@connection)
connection.max_streams = 1
parser.max_streams = 1
parser
end
end