When sending a request, the client code adds a "Host" header. It does the by taking the given address, appending a colon, and then appending the port. This creates a fragment of a URL such as "google.com:80". However, when instead of "google.com", the address is an IPv6 address is given (such as 8383:3223::1333:DE12), simply appending a colon is not adequate. It yields 8383:3223::1333:DE12:80, which is hard to parse mess.
RFC3986 stipulates that the host should be surrounded by square brackets, which would have the Host header as: [8383:3223::1333:DE12]:80.
I've added tests for rest-client that show the affected Ruby versions. Net::HTTP support for IPv6 URIs was broken in 2.0 before 2.0.0-p643 and 2.1 before 2.1.6, so there is a narrow window of versions that work.
There is a separate bug that makes it impossible to explicitly set an IPv6 host header in affected ruby versions. Because Net::HTTP slices the end of the provided Host header after the first :, an IPv6 Host header will be rendered invalid.
$ ruby ipv6_test.rb --set-host
/versions/2.3.1/lib/ruby/2.3.0/uri/generic.rb:595:in `check_host': bad component(expected host component): [ (URI::InvalidComponentError)
from /versions/2.3.1/lib/ruby/2.3.0/uri/generic.rb:636:in `host='
from /versions/2.3.1/lib/ruby/2.3.0/net/http/generic_request.rb:151:in `update_uri'
from /versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1493:in `begin_transport'
from /versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1433:in `transport_request'
from /versions/2.3.1/lib/ruby/2.3.0/net/http.rb:1407:in `request'
from ipv6_test.rb:42:in `block in <main>'
from /versions/2.3.1/lib/ruby/2.3.0/net/http.rb:853:in `start'
Below monkey patching code works for me. Is there a better way?
moduleMonkeyPatchmoduleNetmoduleHTTPendendendmoduleMonkeyPatch::Net::HTTP# workaround for https://bugs.ruby-lang.org/issues/12642# Ruby does not pass Host header with brackets if host is ipv6 addressdefaddr_portaddr=address()# if it is ipv6 add brackets around itifaddr=~Resolv::IPv6::Regexaddr="[#{addr}]"endifuse_ssl?addr+(port==Net::HTTP.https_default_port?'':":#{port()}")elseaddr+(port==Net::HTTP.http_default_port?'':":#{port()}")endendendNet::HTTP.prepend(MonkeyPatch::Net::HTTP)