diff --git a/.rubocop.yml b/.rubocop.yml index aec81d47..e197d7ac 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +AllCops: + DisplayCopNames: true + Metrics/BlockNesting: Max: 2 diff --git a/lib/http/timeout/global.rb b/lib/http/timeout/global.rb index 9b22fcd3..55d7ff5e 100644 --- a/lib/http/timeout/global.rb +++ b/lib/http/timeout/global.rb @@ -104,16 +104,32 @@ def perform_io :eof end - # Wait for a socket to become readable - def wait_readable_or_timeout - IO.select([@socket], nil, nil, time_left) - log_time - end + if RUBY_VERSION < "2.0.0" + # Wait for a socket to become readable + def wait_readable_or_timeout + IO.select([@socket], nil, nil, time_left) + log_time + end - # Wait for a socket to become writable - def wait_writable_or_timeout - IO.select(nil, [@socket], nil, time_left) - log_time + # Wait for a socket to become writable + def wait_writable_or_timeout + IO.select(nil, [@socket], nil, time_left) + log_time + end + else + require "io/wait" + + # Wait for a socket to become readable + def wait_readable_or_timeout + @socket.to_io.wait_readable(time_left) + log_time + end + + # Wait for a socket to become writable + def wait_writable_or_timeout + @socket.to_io.wait_writable(time_left) + log_time + end end # Due to the run/retry nature of nonblocking I/O, it's easier to keep track of time diff --git a/lib/http/timeout/null.rb b/lib/http/timeout/null.rb index c766c658..85d26ba8 100644 --- a/lib/http/timeout/null.rb +++ b/lib/http/timeout/null.rb @@ -50,26 +50,43 @@ def write(data) end alias_method :<<, :write + # These cops can be re-eanbled after we go Ruby 2.0+ only + # rubocop:disable Lint/UselessAccessModifier, Metrics/BlockNesting + private - # Retry reading - def rescue_readable - yield - rescue IO::WaitReadable - if IO.select([socket], nil, nil, read_timeout) - retry - else + if RUBY_VERSION < "2.0.0" + # Retry reading + def rescue_readable + yield + rescue IO::WaitReadable + retry if IO.select([socket], nil, nil, read_timeout) + raise TimeoutError, "Read timed out after #{read_timeout} seconds" + end + + # Retry writing + def rescue_writable + yield + rescue IO::WaitWritable + retry if IO.select(nil, [socket], nil, write_timeout) + raise TimeoutError, "Write timed out after #{write_timeout} seconds" + end + else + require "io/wait" + + # Retry reading + def rescue_readable + yield + rescue IO::WaitReadable + retry if socket.to_io.wait_readable(read_timeout) raise TimeoutError, "Read timed out after #{read_timeout} seconds" end - end - # Retry writing - def rescue_writable - yield - rescue IO::WaitWritable - if IO.select(nil, [socket], nil, write_timeout) - retry - else + # Retry writing + def rescue_writable + yield + rescue IO::WaitWritable + retry if socket.to_io.wait_writable(write_timeout) raise TimeoutError, "Write timed out after #{write_timeout} seconds" end end diff --git a/lib/http/timeout/per_operation.rb b/lib/http/timeout/per_operation.rb index 2746469a..736e4ae7 100644 --- a/lib/http/timeout/per_operation.rb +++ b/lib/http/timeout/per_operation.rb @@ -59,14 +59,17 @@ def write(data) # Read data from the socket def readpartial(size) loop do - result = socket.read_nonblock(size, :exception => false) + result = rescue_readable do + socket.read_nonblock(size, :exception => false) + end + if result.nil? return :eof elsif result != :wait_readable return result end - unless IO.select([socket], nil, nil, read_timeout) + unless socket.to_io.wait_readable(read_timeout) fail TimeoutError, "Read timed out after #{read_timeout} seconds" end end @@ -75,10 +78,13 @@ def readpartial(size) # Write data to the socket def write(data) loop do - result = socket.write_nonblock(data, :exception => false) + result = rescue_writable do + socket.write_nonblock(data, :exception => false) + end + return result unless result == :wait_writable - unless IO.select(nil, [socket], nil, write_timeout) + unless socket.to_io.wait_writable(write_timeout) fail TimeoutError, "Read timed out after #{write_timeout} seconds" end end