From: k@... Date: 2017-09-22T18:31:02+00:00 Subject: [ruby-core:82939] [Ruby trunk Bug#13921] buffered read_nonblock doesn't work as expected using SSLSocket Issue #13921 has been updated by rhenium (Kazuki Yamaguchi). chucke (Tiago Cardoso) wrote: > I have something similar to the following code that handles both tcp as well as ssl sockets. The idea is to use the #read_nonblock API which uses a buffer when passed in the argument (instead of creating a string every time). > > ``` > class A > def initialize > @buffer = String.new("", encoding: Encoding::BINARY) > end > > def read(io) > io.read_nonblock(16_384, @buffer, exception: false) > # do stuff... > @buffer.clear > end > ``` > > For plain tcp sockets, it works as expected (buffers payload). However, when passed an ssl socket, it buffers the whole SSL payload, which SSLSocket's usually handle transparently. Of course, my logic fails after that. chucke (Tiago Cardoso) wrote: > Just confirmed that the problem only happens because I pass `exception: false`. I don't understand what you mean by "it buffers the whole SSL payload". Passing exception:false to SSLSocket#read_nonblock makes it not raise IO::Wait{Readable,Writable} or EOFError and instead return a symbol or nil, but does nothing else. But I can see the code snippet isn't checking the return value of SSLSocket#read_nonblock. While reviewing the implementation of SSLSocket#sysread{,_nonblock}, I discovered that they leave uninitialized data in the destination buffer String (which may be provided by the caller, as the argument, as in your code) on error paths. Are you referring to this? https://github.com/ruby/openssl/pull/153 ---------------------------------------- Bug #13921: buffered read_nonblock doesn't work as expected using SSLSocket https://bugs.ruby-lang.org/issues/13921#change-66843 * Author: chucke (Tiago Cardoso) * Status: Open * Priority: Normal * Assignee: * Target version: * ruby -v: 2.4.2 * Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN ---------------------------------------- I have something similar to the following code that handles both tcp as well as ssl sockets. The idea is to use the #read_nonblock API which uses a buffer when passed in the argument (instead of creating a string every time). ``` class A def initialize @buffer = String.new("", encoding: Encoding::BINARY) end def read(io) io.read_nonblock(16_384, @buffer, exception: false) # do stuff... @buffer.clear end ``` For plain tcp sockets, it works as expected (buffers payload). However, when passed an ssl socket, it buffers the whole SSL payload, which SSLSocket's usually handle transparently. Of course, my logic fails after that. My current workaround is to resort to the unbuffered API: ``` buffer = io.read_nonblock(16_384, exception: false) ``` however, the call mentioned above should have worked transparently. -- https://bugs.ruby-lang.org/ Unsubscribe: