ssl: support session resumption on reconnections with same session

when connections get reset due to max number of requests being reached,
the same TLS session is going to be reused, as long as it's valid.

This change is ported from the same feature in net-http, including [the
tls 1.3
improvements](ddf5c52b5f)
This commit is contained in:
HoneyryderChuck 2023-09-03 00:50:28 +01:00
parent f03d9bb648
commit ef2f0cc998
3 changed files with 41 additions and 8 deletions

View File

@ -42,7 +42,7 @@ module HTTPX
def_delegator :@write_buffer, :empty?
attr_reader :type, :io, :origin, :origins, :state, :pending, :options
attr_reader :type, :io, :origin, :origins, :state, :pending, :options, :ssl_session
attr_writer :timers
@ -138,6 +138,12 @@ module HTTPX
def merge(connection)
@origins |= connection.instance_variable_get(:@origins)
if connection.ssl_session
@ssl_session = connection.ssl_session
@io.session_new_cb do |sess|
@ssl_session = sess
end if @io
end
connection.purge_pending do |req|
send(req)
end
@ -594,14 +600,21 @@ module HTTPX
end
def build_socket(addrs = nil)
transport_type = case @type
when "tcp" then TCP
when "ssl" then SSL
when "unix" then UNIX
else
raise Error, "unsupported transport (#{@type})"
case @type
when "tcp"
TCP.new(@origin, addrs, @options)
when "ssl"
sock = SSL.new(@origin, addrs, @options)
sock.ssl_session = @ssl_session
sock.session_new_cb do |sess|
@ssl_session = sess
end
sock
when "unix"
UNIX.new(@origin, addrs, @options)
else
raise Error, "unsupported transport (#{@type})"
end
transport_type.new(@origin, addrs, @options)
end
def on_error(error)

View File

@ -15,6 +15,8 @@ module HTTPX
{}.freeze
end
attr_writer :ssl_session
def initialize(_, _, options)
super
@ -39,6 +41,15 @@ module HTTPX
@verify_hostname = @ctx.verify_hostname
end
if OpenSSL::SSL::SSLContext.method_defined?(:session_new_cb=)
def session_new_cb(&pr)
@ctx.session_new_cb = proc { |_, sess| pr.call(sess) }
end
else
# session_new_cb not implemented under JRuby
def session_new_cb; end
end
def protocol
@io.alpn_protocol || super
rescue StandardError
@ -81,6 +92,11 @@ module HTTPX
else
@io.hostname = @sni_hostname
end
if @ssl_session &&
Process.clock_gettime(Process::CLOCK_REALTIME) < (@ssl_session.time.to_f + @ssl_session.timeout)
puts "reusing session y'all: #{@ssl_session}"
@io.session = @ssl_session
end
@io.sync_close = true
end
try_ssl_connect

View File

@ -93,6 +93,10 @@ class HTTPSTest < Minitest::Test
connection_count = http.pool.connection_count
assert connection_count == 2, "expected to have 2 connections, instead have #{connection_count}"
assert http.connection_exausted, "expected 1 connnection to have exhausted"
# ssl session ought to be reused
conn = http.pool.connections.first
assert conn.io.instance_variable_get(:@io).session_reused? unless RUBY_ENGINE == "jruby"
end
end