Skip to content

Commit f7fd8a7

Browse files
committed
[fix] read_nonblock(exception: false) raising SSLErrorWaitReadable
`readAndUnwrap()` called doHandshake(blocking) assuming `exception = true` When a post-handshake TLS event (e.g. TLS 1.3 NewSessionTicket) triggered handshake during a non-blocking read, waitSelect raised SSLErrorWaitReadable instead of returning :wait_readable.
1 parent cfcc6d1 commit f7fd8a7

File tree

2 files changed

+11
-12
lines changed

2 files changed

+11
-12
lines changed

src/main/java/org/jruby/ext/openssl/SSLSocket.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -553,10 +553,6 @@ private static void writeWouldBlock(final Ruby runtime, final boolean exception,
553553
result[0] = WRITE_WOULD_BLOCK_RESULT;
554554
}
555555

556-
private void doHandshake(final boolean blocking) throws IOException {
557-
doHandshake(blocking, true);
558-
}
559-
560556
// might return :wait_readable | :wait_writable in case (true, false)
561557
private IRubyObject doHandshake(final boolean blocking, final boolean exception) throws IOException {
562558
while (true) {
@@ -706,11 +702,15 @@ public int write(ByteBuffer src, boolean blocking) throws SSLException, IOExcept
706702
}
707703

708704
public int read(final ByteBuffer dst, final boolean blocking) throws IOException {
705+
return read(dst, blocking, true);
706+
}
707+
708+
private int read(final ByteBuffer dst, final boolean blocking, final boolean exception) throws IOException {
709709
if ( initialHandshake ) return 0;
710710
if ( engine.isInboundDone() ) return -1;
711711

712712
if ( ! appReadData.hasRemaining() ) {
713-
int appBytesProduced = readAndUnwrap(blocking);
713+
int appBytesProduced = readAndUnwrap(blocking, exception);
714714
if (appBytesProduced == -1 || appBytesProduced == 0) {
715715
return appBytesProduced;
716716
}
@@ -722,6 +722,10 @@ public int read(final ByteBuffer dst, final boolean blocking) throws IOException
722722
}
723723

724724
private int readAndUnwrap(final boolean blocking) throws IOException {
725+
return readAndUnwrap(blocking, true);
726+
}
727+
728+
private int readAndUnwrap(final boolean blocking, final boolean exception) throws IOException {
725729
final int bytesRead = socketChannelImpl().read(netReadData);
726730
if ( bytesRead == -1 ) {
727731
if ( ! netReadData.hasRemaining() ||
@@ -769,7 +773,7 @@ private int readAndUnwrap(final boolean blocking) throws IOException {
769773
handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_TASK ||
770774
handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP ||
771775
handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED ) ) {
772-
doHandshake(blocking);
776+
doHandshake(blocking, exception);
773777
}
774778
return appReadData.remaining();
775779
}
@@ -852,7 +856,7 @@ private IRubyObject sysreadImpl(final ThreadContext context, final IRubyObject l
852856
if ( engine == null ) {
853857
read = socketChannelImpl().read(dst);
854858
} else {
855-
read = read(dst, blocking);
859+
read = read(dst, blocking, exception);
856860
}
857861

858862
if ( read == -1 ) {

src/test/ruby/ssl/test_write_flush.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,6 @@ def read_with_timeout(ssl, timeout_sec)
138138
# we've received a plausible amount we can stop.
139139
break if response.include?("OK:") && response.bytesize >= 67
140140
end
141-
rescue IO::WaitReadable
142-
# Can occur despite exception: false and IO.select — TLS protocol
143-
# data (e.g. post-handshake messages) made the socket look readable
144-
# but no application data is available yet.
145-
next
146141
rescue EOFError
147142
break
148143
end

0 commit comments

Comments
 (0)