Skip to content

Commit 57fd8ad

Browse files
committed
fix: preventing hang when TCPSocket readable, but no app-data available
1 parent d7103a1 commit 57fd8ad

1 file changed

Lines changed: 26 additions & 4 deletions

File tree

lib/net/http.rb

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,10 +2495,17 @@ def begin_transport(req)
24952495
debug 'Conn close because of keep_alive_timeout'
24962496
@socket.close
24972497
connect
2498-
elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
2499-
debug "Conn close because of EOF"
2500-
@socket.close
2501-
connect
2498+
elsif @socket.io.to_io.wait_readable(0)
2499+
# Check for EOF without blocking.
2500+
# With TLS 1.3, servers may send NewSessionTicket after responses,
2501+
# making the socket appear readable when only handshake data is
2502+
# pending. Using eof? here would block waiting for app data.
2503+
# See: https://bugs.ruby-lang.org/issues/19017
2504+
if eof_without_blocking?
2505+
debug "Conn close because of EOF"
2506+
@socket.close
2507+
connect
2508+
end
25022509
end
25032510
end
25042511

@@ -2527,6 +2534,21 @@ def end_transport(req, res)
25272534
end
25282535
end
25292536

2537+
def eof_without_blocking?
2538+
result = @socket.io.read_nonblock(1, exception: false)
2539+
case result
2540+
when nil
2541+
true
2542+
when :wait_readable, :wait_writable
2543+
false
2544+
when String
2545+
@socket.io.ungetc(result)
2546+
false
2547+
end
2548+
rescue EOFError
2549+
true
2550+
end
2551+
25302552
def keep_alive?(req, res)
25312553
return false if req.connection_close?
25322554
if @curr_http_version <= '1.0'

0 commit comments

Comments
 (0)