Skip to content

Commit

Permalink
handle read_nonblock EOF as nil when exception: false (Ruby 2.3 compa…
Browse files Browse the repository at this point in the history
…tibility)
  • Loading branch information
kares committed Dec 21, 2015
1 parent 9dce852 commit 2ef7b9c
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 11 deletions.
25 changes: 14 additions & 11 deletions src/main/java/org/jruby/ext/openssl/SSLSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -733,19 +733,22 @@ private IRubyObject sysreadImpl(final ThreadContext context,
if ( ex instanceof IRubyObject ) return (IRubyObject) ex; // :wait_readable
}

ByteBuffer dst = ByteBuffer.allocate(length);
int rr = -1;
final ByteBuffer dst = ByteBuffer.allocate(length);
int read = -1;
// ensure >0 bytes read; sysread is blocking read.
while ( rr <= 0 ) {
while ( read <= 0 ) {
if ( engine == null ) {
rr = socketChannelImpl().read(dst);
read = socketChannelImpl().read(dst);
} else {
rr = read(dst, blocking);
read = read(dst, blocking);
}

if ( rr == -1 ) throw runtime.newEOFError();
if ( read == -1 ) {
if ( exception ) throw runtime.newEOFError();
return runtime.getNil();
}

if ( rr == 0 && status == SSLEngineResult.Status.BUFFER_UNDERFLOW ) {
if ( read == 0 && status == SSLEngineResult.Status.BUFFER_UNDERFLOW ) {
// If we didn't get any data back because we only read in a partial TLS record,
// instead of spinning until the rest comes in, call waitSelect to either block
// until the rest is available, or throw a "read would block" error if we are in
Expand All @@ -754,10 +757,10 @@ private IRubyObject sysreadImpl(final ThreadContext context,
if ( ex instanceof IRubyObject ) return (IRubyObject) ex; // :wait_readable
}
}
byte[] bss = new byte[rr];
dst.position(dst.position() - rr);
dst.get(bss);
buffStr.setValue(new ByteList(bss, false));
byte[] bytesRead = new byte[read];
dst.position(dst.position() - read);
dst.get(bytesRead);
buffStr.setValue(new ByteList(bytesRead, false));
return buffStr;
}
catch (IOException ioe) {
Expand Down
64 changes: 64 additions & 0 deletions src/test/ruby/ssl/test_socket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,68 @@ def test_ssl_sysread_blocking_error
end
end if RUBY_VERSION > '2.2'

def test_read_nonblock_no_exception
ssl_pair do |s1, s2|
assert_equal :wait_readable, eval('s2.read_nonblock 10, exception: false')
s1.write "abc\ndef\n"
IO.select [ s2 ]
ret = eval('s2.read_nonblock 2, exception: false')
assert_equal "ab", ret
assert_equal "c\n", s2.gets
ret = eval('s2.read_nonblock 10, exception: false')
assert_equal("def\n", ret)
s1.close
sleep 0.1
opts = { :exception => false }
assert_equal nil, s2.read_nonblock(10, opts)
end
end if RUBY_VERSION > '2.2'

private

def server
require 'socket'
host = "127.0.0.1"; port = 0
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
server = TCPServer.new(host, port)
OpenSSL::SSL::SSLServer.new(server, ctx)
end

def client(port)
require 'socket'
host = "127.0.0.1"
ctx = OpenSSL::SSL::SSLContext.new()
ctx.ciphers = "ADH"
client = TCPSocket.new(host, port)
ssl = OpenSSL::SSL::SSLSocket.new(client, ctx)
ssl.connect
ssl.sync_close = true
ssl
end

def ssl_pair
ssl_server = server
thread = Thread.new do
ssl_server.accept.tap { ssl_server.close }
end
port = ssl_server.to_io.local_address.ip_port
ssl_client = client(port)
ssl_socket = thread.value
if block_given?
begin
yield ssl_client, ssl_socket
ensure
ssl_client.close unless ssl_client.closed?
ssl_socket.close unless ssl_socket.closed?
end
else
return ssl_client, ssl_socket
end
ensure
if thread && thread.alive?
thread.kill; thread.join
end
end

end

0 comments on commit 2ef7b9c

Please sign in to comment.