From 00e42e17a156402ca0f0a74ab8378d863ba99ce0 Mon Sep 17 00:00:00 2001 From: Ray Zane Date: Sun, 22 May 2022 13:20:03 -0400 Subject: [PATCH 1/4] Construct a URI without a path --- lib/webmock/http_lib_adapters/net_http.rb | 2 +- spec/acceptance/net_http/net_http_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/webmock/http_lib_adapters/net_http.rb b/lib/webmock/http_lib_adapters/net_http.rb index b33244f5..70d2701e 100644 --- a/lib/webmock/http_lib_adapters/net_http.rb +++ b/lib/webmock/http_lib_adapters/net_http.rb @@ -341,7 +341,7 @@ 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) + def self.get_uri(net_http, path = nil) protocol = net_http.use_ssl? ? "https" : "http" hostname = net_http.address diff --git a/spec/acceptance/net_http/net_http_spec.rb b/spec/acceptance/net_http/net_http_spec.rb index 729c8afd..4bca8b07 100644 --- a/spec/acceptance/net_http/net_http_spec.rb +++ b/spec/acceptance/net_http/net_http_spec.rb @@ -365,5 +365,10 @@ def perform_get_with_returning_block path = '/example.jpg' expect(WebMock::NetHTTPUtility.get_uri(net_http, path)).to eq('http://www.example.com:80/example.jpg') end + + it "does not require a path" do + net_http = Net::HTTP.new('www.example.com', 80) + expect(WebMock::NetHTTPUtility.get_uri(net_http)).to eq('http://www.example.com:80') + end end end From b1b5a2ed04fe9d37541d695bc2696f7eca33b51f Mon Sep 17 00:00:00 2001 From: Ray Zane Date: Sun, 22 May 2022 13:22:22 -0400 Subject: [PATCH 2/4] Allow filtering based on `net_http_connect_on_start` --- lib/webmock/http_lib_adapters/net_http.rb | 6 ++++-- lib/webmock/webmock.rb | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/webmock/http_lib_adapters/net_http.rb b/lib/webmock/http_lib_adapters/net_http.rb index 70d2701e..ca0c5b7d 100644 --- a/lib/webmock/http_lib_adapters/net_http.rb +++ b/lib/webmock/http_lib_adapters/net_http.rb @@ -98,7 +98,7 @@ def request(request, body = nil, &block) after_request.call(response) } if started? - if WebMock::Config.instance.net_http_connect_on_start + if WebMock.net_http_connect_on_start?(request_signature.uri) super_with_after_request.call else start_with_connect_without_finish { @@ -144,7 +144,9 @@ def start_with_connect_without_finish # :yield: http alias_method :start_with_connect, :start def start(&block) - if WebMock::Config.instance.net_http_connect_on_start + uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self)) + + if WebMock.net_http_connect_on_start?(uri) super(&block) else start_without_connect(&block) diff --git a/lib/webmock/webmock.rb b/lib/webmock/webmock.rb index 2e2cb8e9..5ecb7f29 100644 --- a/lib/webmock/webmock.rb +++ b/lib/webmock/webmock.rb @@ -70,6 +70,10 @@ def self.net_connect_allowed?(uri = nil) Config.instance.allow && net_connect_explicit_allowed?(Config.instance.allow, uri) ) end + def self.net_http_connect_on_start?(uri) + Config.instance.net_http_connect_on_start + end + def self.net_connect_explicit_allowed?(allowed, uri=nil) case allowed when Array From de69d998639a65b898b51940751e42175f2a2456 Mon Sep 17 00:00:00 2001 From: Ray Zane Date: Sun, 22 May 2022 13:31:46 -0400 Subject: [PATCH 3/4] Allow `:net_http_connect_on_start` to specify which hosts should be connected to --- lib/webmock/webmock.rb | 8 +++++- spec/unit/webmock_spec.rb | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/webmock/webmock.rb b/lib/webmock/webmock.rb index 5ecb7f29..a6a9e610 100644 --- a/lib/webmock/webmock.rb +++ b/lib/webmock/webmock.rb @@ -71,7 +71,13 @@ def self.net_connect_allowed?(uri = nil) end def self.net_http_connect_on_start?(uri) - Config.instance.net_http_connect_on_start + allowed = Config.instance.net_http_connect_on_start || false + + if [true, false].include?(allowed) + allowed + else + net_connect_explicit_allowed?(allowed, uri) + end end def self.net_connect_explicit_allowed?(allowed, uri=nil) diff --git a/spec/unit/webmock_spec.rb b/spec/unit/webmock_spec.rb index a29801eb..b1931b33 100644 --- a/spec/unit/webmock_spec.rb +++ b/spec/unit/webmock_spec.rb @@ -57,4 +57,58 @@ end end end + + describe ".net_http_connect_on_start?" do + let(:uri) { Addressable::URI.parse("http://example.org:5432") } + + it "will not connect on start when false" do + WebMock.disable_net_connect! + expect(WebMock.net_http_connect_on_start?(uri)).to be(false) + end + + it "will connect on start when true" do + WebMock.disable_net_connect!(net_http_connect_on_start: true) + expect(WebMock.net_http_connect_on_start?(uri)).to be(true) + end + + it "will connect on start when regexp matches" do + WebMock.disable_net_connect!(net_http_connect_on_start: /example/) + expect(WebMock.net_http_connect_on_start?(uri)).to be(true) + end + + it "will not connect on start when regexp does not match" do + WebMock.disable_net_connect!(net_http_connect_on_start: /nope/) + expect(WebMock.net_http_connect_on_start?(uri)).to be(false) + end + + it "will connect on start when host matches" do + WebMock.disable_net_connect!(net_http_connect_on_start: "example.org") + expect(WebMock.net_http_connect_on_start?(uri)).to be(true) + end + + it "will not connect on start when host does not match" do + WebMock.disable_net_connect!(net_http_connect_on_start: "localhost") + expect(WebMock.net_http_connect_on_start?(uri)).to be(false) + end + + it "will connect on start when host + port matches" do + WebMock.disable_net_connect!(net_http_connect_on_start: "example.org:5432") + expect(WebMock.net_http_connect_on_start?(uri)).to be(true) + end + + it "will not connect on start when host + port does not match" do + WebMock.disable_net_connect!(net_http_connect_on_start: "example.org:80") + expect(WebMock.net_http_connect_on_start?(uri)).to be(false) + end + + it "will connect on start when scheme + host + port matches" do + WebMock.disable_net_connect!(net_http_connect_on_start: "http://example.org:5432") + expect(WebMock.net_http_connect_on_start?(uri)).to be(true) + end + + it "will not connect on start when scheme + host + port does not match" do + WebMock.disable_net_connect!(net_http_connect_on_start: "https://example.org:5432") + expect(WebMock.net_http_connect_on_start?(uri)).to be(false) + end + end end From fecb72cc15835611935967ef450b42ef0fedeb2e Mon Sep 17 00:00:00 2001 From: Ray Zane Date: Sun, 22 May 2022 13:53:02 -0400 Subject: [PATCH 4/4] Add acceptance tests for new `:net_http_connect_on_start` allowed values --- spec/acceptance/net_http/net_http_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spec/acceptance/net_http/net_http_spec.rb b/spec/acceptance/net_http/net_http_spec.rb index 4bca8b07..b3bb57ce 100644 --- a/spec/acceptance/net_http/net_http_spec.rb +++ b/spec/acceptance/net_http/net_http_spec.rb @@ -254,6 +254,21 @@ class TestMarshalingInWebMockNetHTTP } end + it "should connect to the server on start when allowlisted", net_connect: true do + WebMock.disable_net_connect!(allow: "www.google.com", net_http_connect_on_start: "www.google.com") + @http.start {|conn| + cert = OpenSSL::X509::Certificate.new conn.peer_cert + expect(cert).to be_a(OpenSSL::X509::Certificate) + } + end + + it "should not connect to the server on start when not allowlisted", net_connect: true do + WebMock.disable_net_connect!(allow: "www.google.com", net_http_connect_on_start: "www.yahoo.com") + @http.start {|conn| + expect(conn.peer_cert).to be_nil + } + end + it "should connect to the server if the URI matches an regex", net_connect: true do WebMock.disable_net_connect!(allow: /google.com/) Net::HTTP.get('www.google.com','/') @@ -282,6 +297,13 @@ class TestMarshalingInWebMockNetHTTP it_should_behave_like "Net::HTTP" end + describe "when net_http_connect_on_start is a specific host" do + before(:each) do + WebMock.allow_net_connect!(net_http_connect_on_start: "localhost") + end + it_should_behave_like "Net::HTTP" + end + describe 'after_request callback support', net_connect: true do let(:expected_body_regex) { /hello world/ }