diff --git a/async-http.gemspec b/async-http.gemspec index b134eb0d..69a63320 100644 --- a/async-http.gemspec +++ b/async-http.gemspec @@ -26,7 +26,7 @@ Gem::Specification.new do |spec| spec.add_dependency "async", ">= 2.35.1" spec.add_dependency "async-pool", "~> 0.11" - spec.add_dependency "io-endpoint", "~> 0.14" + spec.add_dependency "io-endpoint", "~> 0.18" spec.add_dependency "io-stream", "~> 0.14" spec.add_dependency "protocol-http", "~> 0.66" spec.add_dependency "protocol-http1", "~> 0.39" diff --git a/lib/async/http/endpoint.rb b/lib/async/http/endpoint.rb index 3f693814..469d3fe8 100644 --- a/lib/async/http/endpoint.rb +++ b/lib/async/http/endpoint.rb @@ -70,6 +70,7 @@ def self.[](url) # @option hostname [String] the hostname to connect to (or bind to), overrides the URL hostname (used for SNI). # @option port [Integer] the port to bind to, overrides the URL port. # @option ssl_context [OpenSSL::SSL::SSLContext] the context to use for TLS. + # @option tls_configuration [IO::Endpoint::TLS::Configuration] the transport-neutral TLS configuration. # @option alpn_protocols [Array(String)] the alpn protocols to negotiate. def initialize(url, endpoint = nil, **options) super(**options) @@ -206,6 +207,11 @@ def ssl_context end end + # @returns [IO::Endpoint::TLS::Configuration | Nil] The transport-neutral TLS configuration. + def tls_configuration + @options[:tls_configuration] + end + # Build a suitable endpoint, optionally wrapping in TLS for secure connections. # @parameter endpoint [IO::Endpoint::Generic | Nil] An optional underlying endpoint to wrap. # @returns [IO::Endpoint::Generic] The constructed endpoint. @@ -216,6 +222,7 @@ def build_endpoint(endpoint = nil) # Wrap it in SSL: return ::IO::Endpoint::SSLEndpoint.new(endpoint, ssl_context: self.ssl_context, + tls_configuration: self.tls_configuration, hostname: @url.hostname, timeout: self.timeout, ) @@ -280,6 +287,7 @@ def tcp_options options.delete(:port) options.delete(:hostname) options.delete(:ssl_context) + options.delete(:tls_configuration) options.delete(:alpn_protocols) options.delete(:protocol) diff --git a/releases.md b/releases.md index 0247e6b8..91c02a3b 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + + - Added transport-neutral TLS configuration support to `Async::HTTP::Endpoint`. + ## v0.99.0 - Retry safe requests when a remote HTTP/2 endpoint resets the stream with `INTERNAL_ERROR` before returning a response. diff --git a/test/async/http/endpoint.rb b/test/async/http/endpoint.rb index 31a7283b..2b166e29 100644 --- a/test/async/http/endpoint.rb +++ b/test/async/http/endpoint.rb @@ -57,6 +57,23 @@ end end + with "#tls_configuration" do + let(:tls_configuration) do + IO::Endpoint::TLS::Configuration.new(verification: :none) + end + + it "forwards the TLS configuration to the SSL endpoint" do + endpoint = subject.parse("https://example.com", tls_configuration: tls_configuration) + ssl_endpoint = endpoint.endpoint + + expect(endpoint.tls_configuration).to be_equal(tls_configuration) + expect(ssl_endpoint).to be_a(IO::Endpoint::SSLEndpoint) + expect(ssl_endpoint.tls_configuration).to be_equal(tls_configuration) + expect(ssl_endpoint.context.verify_mode).to be == OpenSSL::SSL::VERIFY_NONE + expect(ssl_endpoint.endpoint.options).not.to be(:key?, :tls_configuration) + end + end + with ".for" do describe Async::HTTP::Endpoint.for("http", "localhost") do it "should have correct attributes" do