From f59e4d40b66b13b1da9422b0dccb8cf2a12930cf Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sat, 3 Oct 2026 03:22:58 +0900 Subject: [PATCH] ssl: update rdoc for SSLSocket#pending and #wait_readable Clarify how they (do not) interact with read buffers. SSLSocket#pending corresponds to SSL_pending(). It reports data that is already processed and is immediately available to read from the OpenSSL library's internal buffer. SSLSocket#wait_readable does not check for buffered data, either in the OpenSSL library or in OpenSSL::Buffering, so it may block even when data is already available to read. This is different from IO#wait_readable. I considered changing SSLSocket#wait_readable to check these buffers, but rejected it because it is also used when the caller specifically needs to wait for new records from the peer, particularly after SSLSocket#write_nonblock returns :wait_readable. --- ext/openssl/ossl_ssl.c | 9 ++++++++- lib/openssl/ssl.rb | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index f551032b2..1e3881ec5 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -2440,7 +2440,14 @@ ossl_ssl_get_state(VALUE self) * call-seq: * ssl.pending => Integer * - * The number of bytes that are immediately available for reading. + * Returns the number of bytes buffered by the OpenSSL library and immediately + * available for reading with #sysread. + * + * This does not include data read ahead and buffered by SSLSocket. It may + * therefore return 0 even when data is available for reading with methods + * that are aware of the SSLSocket buffer, such as #read or #gets. + * + * See also the man page SSL_pending(3). */ static VALUE ossl_ssl_pending(VALUE self) diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb index 486bdf858..9edbcb62e 100644 --- a/lib/openssl/ssl.rb +++ b/lib/openssl/ssl.rb @@ -223,14 +223,23 @@ def close_on_exec? to_io.close_on_exec? end + # Calls IO#wait on the underlying socket. + # + # Note that this method may block even when there is data immediately + # available to read, unlike IO#wait_readable. def wait(*args) to_io.wait(*args) end + # Calls IO#wait_readable on the underlying socket. + # + # Note that this method may block even when there is data immediately + # available to read, unlike IO#wait_readable. def wait_readable(*args) to_io.wait_readable(*args) end + # Calls IO#wait_writable on the underlying socket. def wait_writable(*args) to_io.wait_writable(*args) end