From 3f7e7e5622a9c8b93c6c036b6ab3db2ce0f6ded3 Mon Sep 17 00:00:00 2001 From: Johanna Hartmann Date: Thu, 4 Mar 2021 16:02:24 +0100 Subject: [PATCH] Fix: Handle IPv6 hostname correctly (closes #806) --- lib/webmock/http_lib_adapters/net_http.rb | 13 +++++++++--- spec/acceptance/net_http/net_http_spec.rb | 26 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/webmock/http_lib_adapters/net_http.rb b/lib/webmock/http_lib_adapters/net_http.rb index 447bba2de..b33244f53 100644 --- a/lib/webmock/http_lib_adapters/net_http.rb +++ b/lib/webmock/http_lib_adapters/net_http.rb @@ -313,8 +313,6 @@ module WebMock module NetHTTPUtility def self.request_signature_from_request(net_http, request, body = nil) - protocol = net_http.use_ssl? ? "https" : "http" - path = request.path if path.respond_to?(:request_uri) #https://github.com/bblimke/webmock/issues/288 @@ -323,7 +321,7 @@ def self.request_signature_from_request(net_http, request, body = nil) path = WebMock::Util::URI.heuristic_parse(path).request_uri if path =~ /^http/ - uri = "#{protocol}://#{net_http.address}:#{net_http.port}#{path}" + uri = get_uri(net_http, path) method = request.method.downcase.to_sym headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}] @@ -343,6 +341,15 @@ def self.request_signature_from_request(net_http, request, body = nil) WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers) end + def self.get_uri(net_http, path) + protocol = net_http.use_ssl? ? "https" : "http" + + hostname = net_http.address + hostname = "[#{hostname}]" if /\A\[.*\]\z/ !~ hostname && /:/ =~ hostname + + "#{protocol}://#{hostname}:#{net_http.port}#{path}" + end + def self.validate_headers(headers) # For Ruby versions < 2.3.0, if you make a request with headers that are symbols # Net::HTTP raises a NoMethodError diff --git a/spec/acceptance/net_http/net_http_spec.rb b/spec/acceptance/net_http/net_http_spec.rb index fd4a9ada0..729c8afda 100644 --- a/spec/acceptance/net_http/net_http_spec.rb +++ b/spec/acceptance/net_http/net_http_spec.rb @@ -340,4 +340,30 @@ def perform_get_with_returning_block http.request(req, '') end end + + describe "hostname handling" do + it "should set brackets around the hostname if it is an IPv6 address" do + net_http = Net::HTTP.new('b2dc:5bdf:4f0d::3014:e0ca', 80) + path = '/example.jpg' + expect(WebMock::NetHTTPUtility.get_uri(net_http, path)).to eq('http://[b2dc:5bdf:4f0d::3014:e0ca]:80/example.jpg') + end + + it "should not set brackets around the hostname if it is already wrapped by brackets" do + net_http = Net::HTTP.new('[b2dc:5bdf:4f0d::3014:e0ca]', 80) + path = '/example.jpg' + expect(WebMock::NetHTTPUtility.get_uri(net_http, path)).to eq('http://[b2dc:5bdf:4f0d::3014:e0ca]:80/example.jpg') + end + + it "should not set brackets around the hostname if it is an IPv4 address" do + net_http = Net::HTTP.new('181.152.137.168', 80) + path = '/example.jpg' + expect(WebMock::NetHTTPUtility.get_uri(net_http, path)).to eq('http://181.152.137.168:80/example.jpg') + end + + it "should not set brackets around the hostname if it is a domain" do + net_http = Net::HTTP.new('www.example.com', 80) + path = '/example.jpg' + expect(WebMock::NetHTTPUtility.get_uri(net_http, path)).to eq('http://www.example.com:80/example.jpg') + end + end end