@@ -12,48 +12,64 @@ module Socket
1212 # Common methods for all socket implementations.
1313 ##
1414 module InstanceMethods
15- def readfull ( count )
16- value = String . new ( capacity : count + 1 )
17- loop do
18- result = read_nonblock ( count - value . bytesize , exception : false )
19- value << result if append_to_buffer? ( result )
20- break if value . bytesize == count
15+ def read_available ( reusable_buffer = nil )
16+ if reusable_buffer
17+ value = read_nonblock ( 8196 , reusable_buffer , exception : false )
18+ case value
19+ when :wait_writable , :wait_readable
20+ return reusable_buffer . clear
21+ when nil
22+ raise Errno ::ECONNRESET , "Connection reset: #{ logged_options . inspect } "
23+ end
24+ else
25+ value = '' . b
2126 end
22- value
23- end
2427
25- def read_available
26- value = +''
28+ buffer = '' . b
2729 loop do
28- result = read_nonblock ( 8196 , exception : false )
29- break if WAIT_RCS . include? ( result )
30- raise Errno ::ECONNRESET , "Connection reset: #{ logged_options . inspect } " unless result
31-
32- value << result
30+ result = read_nonblock ( 8196 , buffer , exception : false )
31+ case result
32+ when :wait_writable , :wait_readable
33+ buffer . clear
34+ return value
35+ when nil
36+ raise Errno ::ECONNRESET , "Connection reset: #{ logged_options . inspect } "
37+ else
38+ value << result
39+ end
3340 end
34- value
35- end
36-
37- WAIT_RCS = %i[ wait_writable wait_readable ] . freeze
38-
39- def append_to_buffer? ( result )
40- raise Timeout ::Error , "IO timeout: #{ logged_options . inspect } " if nonblock_timed_out? ( result )
41- raise Errno ::ECONNRESET , "Connection reset: #{ logged_options . inspect } " unless result
42-
43- !WAIT_RCS . include? ( result )
44- end
45-
46- def nonblock_timed_out? ( result )
47- return true if result == :wait_readable && !wait_readable ( options [ :socket_timeout ] )
48-
49- # TODO: Do we actually need this? Looks to be only used in read_nonblock
50- result == :wait_writable && !wait_writable ( options [ :socket_timeout ] )
5141 end
5242
5343 FILTERED_OUT_OPTIONS = %i[ username password ] . freeze
5444 def logged_options
5545 options . except ( *FILTERED_OUT_OPTIONS )
5646 end
47+
48+ # JRuby doesn't support IO#timeout=, so use custom readfull implementation
49+ # CRuby 3.3+ has IO#timeout= which makes IO#read work with timeouts
50+ if RUBY_ENGINE == 'jruby'
51+ # rubocop:disable Metrics/AbcSize
52+ def readfull ( count )
53+ value = String . new ( capacity : count + 1 )
54+
55+ until value . bytesize == count
56+ result = read_nonblock ( count - value . bytesize , exception : false )
57+ case result
58+ when :wait_readable
59+ wait_readable ( options [ :socket_timeout ] ) or raise Timeout ::Error , "IO timeout: #{ logged_options . inspect } "
60+ when :wait_writable
61+ wait_writable ( options [ :socket_timeout ] ) or raise Timeout ::Error , "IO timeout: #{ logged_options . inspect } "
62+ when nil
63+ raise Errno ::ECONNRESET , "Connection reset: #{ logged_options . inspect } "
64+ else
65+ value << result
66+ end
67+ end
68+
69+ value
70+ end
71+ # rubocop:enable Metrics/AbcSize
72+ end
5773 end
5874
5975 ##
0 commit comments