Skip to content

Commit a77ed4b

Browse files
committed
ssl: deprecate OpenSSL::SSL::SSLServer
Although OpenSSL::SSL::SSLServer presents itself as a TCPServer-like wrapper, its design has flaws. Document OpenSSL::SSL::SSLServer as deprecated and recommend using OpenSSL::SSL::SSLSocket directly. SSLServer#accept calls #accept on the underlying listening socket and then performs the TLS handshake synchronously. This is an obvious problem for programs that expect more than one client to connect. Fixing this would require keeping a backlog of accepted TCP connections in SSLServer while their TLS handshakes complete, which would be too significant a change. This is also why SSLServer#accept_nonblock was never implemented. The blocking behavior of #accept can be worked around by setting SSLServer#start_immediately to false, which skips the handshake. However, at that point SSLServer provides little value over using TCPServer directly and wrapping each accepted socket with SSLSocket.
1 parent 2c109b2 commit a77ed4b

2 files changed

Lines changed: 21 additions & 5 deletions

File tree

ext/openssl/ossl.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -944,16 +944,20 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
944944
* context.cert = cert
945945
* context.key = key
946946
*
947-
* Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the
948-
* context. Use the SSLServer like an ordinary TCP server.
947+
* After establishing a TCP connection, the socket is wrapped in an
948+
* OpenSSL::SSL::SSLSocket with the context. OpenSSL::SSL::SSLSocket#accept
949+
* is called to perform the TLS handshake.
949950
*
950951
* require 'socket'
951952
*
952953
* tcp_server = TCPServer.new 5000
953-
* ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context
954954
*
955955
* loop do
956-
* ssl_connection = ssl_server.accept
956+
* tcp_connection = tcp_server.accept
957+
* ssl_connection = OpenSSL::SSL::SSLSocket.new tcp_connection, context
958+
* # Or you can close tcp_connection manually after ssl_connection.close
959+
* ssl_connection.sync_close = true
960+
* ssl_connection.accept
957961
*
958962
* data = ssl_connection.gets
959963
*

lib/openssl/ssl.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,19 @@ def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)
475475

476476
##
477477
# SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
478+
#
479+
# *Deprecated.* Use TCPServer or Socket to accept a TCP connection, and
480+
# then wrap it with OpenSSL::SSL::SSLSocket.
481+
# See also OpenSSL::SSL::SSLSocket#accept.
478482
class SSLServer
479483
include SocketForwarder
480-
# When true then #accept works exactly the same as TCPServer#accept
484+
485+
# When set to +true+, #accept will immediately perform the SSL/TLS
486+
# handshake after accepting a TCP connection. Defaults to +true+.
487+
#
488+
# *NOTE*: #accept performs the SSL/TLS handshake synchronously. A slow
489+
# client can therefore prevent the server from accepting new connections
490+
# indefinitely. For this reason, SSLServer is deprecated.
481491
attr_accessor :start_immediately
482492

483493
# Creates a new instance of SSLServer.
@@ -511,6 +521,8 @@ def shutdown(how=Socket::SHUT_RDWR)
511521
end
512522

513523
# Works similar to TCPServer#accept.
524+
#
525+
# *NOTE*: SSLServer is deprecated. See #start_immediately for details.
514526
def accept
515527
# Socket#accept returns [socket, addrinfo].
516528
# TCPServer#accept returns a socket.

0 commit comments

Comments
 (0)