Permalink
Browse files

Extract default Socket query handler into its own class

This allows swappable query handler.

Do you want to use an EM async handler? Write the class and set Base.query_handler to your handler.
Do you want a test handler to avoid external connections in testing? Yes, I do!
  • Loading branch information...
1 parent 66538fc commit 99fc791319f9e736d6160626039a99d0629e7baa @weppos committed Oct 16, 2012
View
84 lib/whois/server/adapters/base.rb
@@ -18,22 +18,57 @@ module Adapters
class Base
+ # The SocketHandler is the default query handler provided with the
+ # Whois library. It performs the WHOIS query using a synchronous
+ # socket connection.
+ class SocketHandler
+
+ # Array of connection errors to rescue
+ # and wrap into a {Whois::ConnectionError}
+ RESCUABLE_CONNECTION_ERRORS = [
+ Errno::ECONNRESET,
+ Errno::EHOSTUNREACH,
+ Errno::ECONNREFUSED,
+ SocketError,
+ ]
+
+ # TODO: *args might probably be a Hash
+ def call(query, *args)
+ execute(query, *args)
+ rescue *RESCUABLE_CONNECTION_ERRORS => error
+ raise ConnectionError, "#{error.class}: #{error.message}"
+ end
+
+ # Executes the low-level Socket connection.
+ #
+ # It opens the socket passing given +args+,
+ # sends the +query+ and reads the response.
+ #
+ # This is for internal use only!
+ #
+ # @param [String] query
+ # @param [Array] args
+ # @return [String]
+ #
+ # @api private
+ def execute(query, *args)
+ client = TCPSocket.new(*args)
+ client.write("#{query}\r\n") # I could use put(foo) and forget the \n
+ client.read # but write/read is more symmetric than puts/read
+ ensure # and I really want to use read instead of gets.
+ client.close if client # If != client something went wrong.
+ end
+ end
+
# Default WHOIS request port.
DEFAULT_WHOIS_PORT = 43
-
# Default bind hostname.
DEFAULT_BIND_HOST = "0.0.0.0"
- # Array of connection errors to rescue and wrap into a {Whois::ConnectionError}
- RESCUABLE_CONNECTION_ERRORS = [
- Errno::ECONNRESET,
- Errno::EHOSTUNREACH,
- Errno::ECONNREFUSED,
- SocketError,
- ]
-
+ class_attribute :query_handler
+ self.query_handler = SocketHandler.new
- # @return [Symbol] The type of WHOIS server
+ # @return [Symbol] The type of WHOIS server.
attr_reader :type
# @return [String] The allocation this server is responsible for.
attr_reader :allocation
@@ -175,38 +210,11 @@ def query_prepare(query, host, port = nil)
args.push(options[:bind_port]) if options[:bind_port]
end
- query_handle(query, *args)
+ self.class.query_handler.call(query, *args)
end
alias :query_the_socket :query_prepare
- # @api private
- def query_handle(query, *args)
- query_socket(query, *args)
- rescue *RESCUABLE_CONNECTION_ERRORS => error
- raise ConnectionError, "#{error.class}: #{error.message}"
- end
-
- # Executes the low-level Socket connection.
- #
- # It opens the socket passing given +args+,
- # sends the +query+ and reads the response.
- #
- # This is for internal use only!
- #
- # @param [String] query
- # @param [Array] args
- # @return [String]
- #
- # @api private
- def query_socket(query, *args)
- client = TCPSocket.new(*args)
- client.write("#{query}\r\n") # I could use put(foo) and forget the \n
- client.read # but write/read is more symmetric than puts/read
- ensure # and I really want to use read instead of gets.
- client.close if client # If != client something went wrong.
- end
-
end
end
View
28 spec/integration_spec.rb
@@ -8,10 +8,10 @@
it "works" do
with_definitions do
Whois::Server.define(:tld, ".it", "whois.nic.it")
- Whois::Server::Adapters::Standard.any_instance \
- .expects(:query_socket) \
- .with("example.it", "whois.nic.it", 43) \
- .returns(response)
+ Whois::Server::Adapters::Base.
+ query_handler.expects(:call).
+ with("example.it", "whois.nic.it", 43).
+ returns(response)
record = Whois.query("example.it")
@@ -29,10 +29,10 @@
it "binds the WHOIS query to given host and port" do
with_definitions do
Whois::Server.define(:tld, ".it", "whois.nic.it")
- Whois::Server::Adapters::Standard.any_instance \
- .expects(:query_socket) \
- .with("example.it", "whois.nic.it", 43, "192.168.1.1", 3000) \
- .returns(response)
+ Whois::Server::Adapters::Base.
+ query_handler.expects(:call).
+ with("example.it", "whois.nic.it", 43, "192.168.1.1", 3000).
+ returns(response)
client = Whois::Client.new(:bind_host => "192.168.1.1", :bind_port => 3000)
client.query("example.it")
@@ -44,10 +44,10 @@
it "binds the WHOIS query to given port and defaults host" do
with_definitions do
Whois::Server.define(:tld, ".it", "whois.nic.it")
- Whois::Server::Adapters::Standard.any_instance \
- .expects(:query_socket) \
- .with("example.it", "whois.nic.it", 43, Whois::Server::Adapters::Base::DEFAULT_BIND_HOST, 3000) \
- .returns(response)
+ Whois::Server::Adapters::Base.
+ query_handler.expects(:call).
+ with("example.it", "whois.nic.it", 43, Whois::Server::Adapters::Base::DEFAULT_BIND_HOST, 3000).
+ returns(response)
client = Whois::Client.new(:bind_port => 3000)
client.query("example.it")
@@ -59,8 +59,8 @@
it "forces the WHOIS query to given host" do
with_definitions do
Whois::Server.define(:tld, ".it", "whois.nic.it")
- Whois::Server::Adapters::Standard.any_instance.
- expects(:query_socket).
+ Whois::Server::Adapters::Base.
+ query_handler.expects(:call).
with("example.it", "whois.example.com", 43).
returns(response)
View
2 spec/support/helpers/spec_helper.rb
@@ -11,7 +11,7 @@ def fixture(*names)
File.join(SPEC_ROOT, "fixtures", *names)
end
-private
+ private
# Temporary resets Server @@definitions
# to let the test setup a custom definition list.
View
16 spec/whois/server/adapters/afilias_spec.rb
@@ -2,20 +2,18 @@
describe Whois::Server::Adapters::Afilias do
- before(:each) do
- @definition = [:tld, ".test", "whois.afilias-grs.info", {}]
- @server = klass.new(*@definition)
- end
+ let(:definition) { [:tld, ".test", "whois.afilias-grs.info", {}] }
+ let(:server) { klass.new(*definition) }
describe "#query" do
context "without referral" do
it "returns the WHOIS record" do
response = "No match for DOMAIN.TEST."
expected = response
- @server.expects(:query_socket).with("domain.test", "whois.afilias-grs.info", 43).returns(response)
+ server.query_handler.expects(:call).with("domain.test", "whois.afilias-grs.info", 43).returns(response)
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.to_s.should == expected
record.parts.should have(1).part
record.parts.should == [Whois::Record::Part.new(:body => response, :host => "whois.afilias-grs.info")]
@@ -27,10 +25,10 @@
referral = File.read(fixture("referrals/afilias.bz.txt"))
response = "Match for DOMAIN.TEST."
expected = referral + "\n" + response
- @server.expects(:query_socket).with("domain.test", "whois.afilias-grs.info", 43).returns(referral)
- @server.expects(:query_socket).with("domain.test", "whois.belizenic.bz", 43).returns(response)
+ server.query_handler.expects(:call).with("domain.test", "whois.afilias-grs.info", 43).returns(referral)
+ server.query_handler.expects(:call).with("domain.test", "whois.belizenic.bz", 43).returns(response)
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.to_s.should == expected
record.parts.should have(2).parts
record.parts.should == [Whois::Record::Part.new(:body => referral, :host => "whois.afilias-grs.info"), Whois::Record::Part.new(:body => response, :host => "whois.belizenic.bz")]
View
38 spec/whois/server/adapters/base_spec.rb
@@ -114,52 +114,46 @@
describe "#query_the_socket" do
[ Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, SocketError ].each do |error|
it "re-raises #{error} as Whois::ConnectionError" do
- klass.any_instance.expects(:query_socket).raises(error)
+ klass.query_handler.expects(:execute).raises(error)
expect {
klass.new(*definition).send(:query_the_socket, "example.com", "whois.test")
}.to raise_error(Whois::ConnectionError, "#{error}: #{error.new.message}")
end
end
context "without :bind_host or :bind_port options" do
- before(:each) do
- @base = klass.new(:tld, ".test", "whois.test", {})
- end
+ let(:server) { klass.new(:tld, ".test", "whois.test", {}) }
it "does not bind the WHOIS query" do
- @base \
- .expects(:query_socket) \
- .with("example.test", "whois.test", 43)
+ klass.
+ query_handler.expects(:call).
+ with("example.test", "whois.test", 43)
- @base.send(:query_the_socket, "example.test", "whois.test", 43)
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
end
end
context "with :bind_host and :bind_port options" do
- before(:each) do
- @base = klass.new(:tld, ".test", "whois.test", { :bind_host => "192.168.1.1", :bind_port => 3000 })
- end
+ let(:server) { klass.new(:tld, ".test", "whois.test", { :bind_host => "192.168.1.1", :bind_port => 3000 }) }
it "binds the WHOIS query to given host and port" do
- @base \
- .expects(:query_socket) \
- .with("example.test", "whois.test", 43, "192.168.1.1", 3000)
+ klass.
+ query_handler.expects(:call).
+ with("example.test", "whois.test", 43, "192.168.1.1", 3000)
- @base.send(:query_the_socket, "example.test", "whois.test", 43)
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
end
end
context "with :bind_port and without :bind_host options" do
- before(:each) do
- @base = klass.new(:tld, ".test", "whois.test", { :bind_port => 3000 })
- end
+ let(:server) { klass.new(:tld, ".test", "whois.test", { :bind_port => 3000 }) }
it "binds the WHOIS query to given port and defaults host" do
- @base \
- .expects(:query_socket) \
- .with("example.test", "whois.test", 43, klass::DEFAULT_BIND_HOST, 3000)
+ klass.
+ query_handler.expects(:call).
+ with("example.test", "whois.test", 43, klass::DEFAULT_BIND_HOST, 3000)
- @base.send(:query_the_socket, "example.test", "whois.test", 43)
+ server.send(:query_the_socket, "example.test", "whois.test", 43)
end
end
end
View
14 spec/whois/server/adapters/formatted_spec.rb
@@ -2,17 +2,15 @@
describe Whois::Server::Adapters::Formatted do
- before(:each) do
- @definition = [:tld, ".de", "whois.denic.de", { :format => "-T dn,ace -C US-ASCII %s" }]
- end
+ let(:definition) { [:tld, ".de", "whois.denic.de", { :format => "-T dn,ace -C US-ASCII %s" }] }
describe "#query" do
it "returns the WHOIS record" do
response = "Whois Response"
expected = response
- server = klass.new(*@definition)
- server.expects(:query_socket).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 43).returns(response)
+ server = klass.new(*definition)
+ server.query_handler.expects(:call).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 43).returns(response)
record = server.query("domain.de")
record.to_s.should == expected
@@ -23,7 +21,7 @@
it "raises an error" do
lambda do
server = klass.new(*[:tld, ".de", "whois.denic.de", {}])
- server.expects(:query_socket).never
+ server.query_handler.expects(:call).never
server.query("domain.de")
end.should raise_error(Whois::ServerError)
end
@@ -33,7 +31,7 @@
it "sends the request to given port" do
response = "Whois Response"
server = klass.new(:tld, ".de", "whois.denic.de", { :format => "-T dn,ace -C US-ASCII %s", :port => 20 })
- server.expects(:query_socket).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 20).returns(response)
+ server.query_handler.expects(:call).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 20).returns(response)
server.query("domain.de")
end
@@ -44,7 +42,7 @@
response = "Whois Response"
server = klass.new(:tld, ".de", "whois.denic.de", { :format => "-T dn,ace -C US-ASCII %s" })
server.configure(:bind_host => "192.168.1.1", :bind_port => 3000)
- server.expects(:query_socket).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 43, "192.168.1.1", 3000).returns(response)
+ server.query_handler.expects(:call).with("-T dn,ace -C US-ASCII domain.de", "whois.denic.de", 43, "192.168.1.1", 3000).returns(response)
server.query("domain.de")
end
View
12 spec/whois/server/adapters/standard_spec.rb
@@ -2,17 +2,15 @@
describe Whois::Server::Adapters::Standard do
- before(:each) do
- @definition = [:tld, ".test", "whois.test", {}]
- end
+ let(:definition) { [:tld, ".test", "whois.test", {}] }
describe "#query" do
it "returns the WHOIS record" do
response = "Whois Response"
expected = response
- server = klass.new(*@definition)
- server.expects(:query_socket).with("domain.test", "whois.test", 43).returns(response)
+ server = klass.new(*definition)
+ server.query_handler.expects(:call).with("domain.test", "whois.test", 43).returns(response)
record = server.query("domain.test")
record.to_s.should == expected
@@ -23,7 +21,7 @@
it "sends the request to given port" do
response = "Whois Response"
server = klass.new(:tld, ".test", "whois.test", { :port => 20 })
- server.expects(:query_socket).with("domain.test", "whois.test", 20).returns(response)
+ server.query_handler.expects(:call).with("domain.test", "whois.test", 20).returns(response)
server.query("domain.test")
end
@@ -34,7 +32,7 @@
response = "Whois Response"
server = klass.new(:tld, ".test", "whois.test", { :port => 20 })
server.configure(:bind_host => "192.168.1.100", :bind_port => 3000)
- server.expects(:query_socket).with("domain.test", "whois.test", 20, "192.168.1.100", 3000).returns(response)
+ server.query_handler.expects(:call).with("domain.test", "whois.test", 20, "192.168.1.100", 3000).returns(response)
server.query("domain.test")
end
View
34 spec/whois/server/adapters/verisign_spec.rb
@@ -2,20 +2,18 @@
describe Whois::Server::Adapters::Verisign do
- before(:each) do
- @definition = [:tld, ".test", "whois.test", {}]
- @server = klass.new(*@definition)
- end
+ let(:definition) { [:tld, ".test", "whois.test", {}] }
+ let(:server) { klass.new(*definition) }
describe "#query" do
context "without referral" do
it "returns the WHOIS record" do
response = "No match for DOMAIN.TEST."
expected = response
- @server.expects(:query_socket).with("=domain.test", "whois.test", 43).returns(response)
+ server.query_handler.expects(:call).with("=domain.test", "whois.test", 43).returns(response)
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.to_s.should == expected
record.parts.should have(1).part
record.parts.should == [Whois::Record::Part.new(:body => response, :host => "whois.test")]
@@ -27,41 +25,41 @@
referral = File.read(fixture("referrals/crsnic.com.txt"))
response = "Match for DOMAIN.TEST."
expected = referral + "\n" + response
- @server.expects(:query_socket).with("=domain.test", "whois.test", 43).returns(referral)
- @server.expects(:query_socket).with("domain.test", "whois.markmonitor.com", 43).returns(response)
+ server.query_handler.expects(:call).with("=domain.test", "whois.test", 43).returns(referral)
+ server.query_handler.expects(:call).with("domain.test", "whois.markmonitor.com", 43).returns(response)
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.to_s.should == expected
record.parts.should have(2).parts
record.parts.should == [Whois::Record::Part.new(:body => referral, :host => "whois.test"), Whois::Record::Part.new(:body => response, :host => "whois.markmonitor.com")]
end
it "extracts the closest referral when multiple referrals" do
referral = File.read(fixture("referrals/crsnic.com_referral_multiple.txt"))
- @server.expects(:query_socket).with("=domain.test", "whois.test", 43).returns(referral)
- @server.expects(:query_socket).with("domain.test", "whois.markmonitor.com", 43).returns("")
+ server.query_handler.expects(:call).with("=domain.test", "whois.test", 43).returns(referral)
+ server.query_handler.expects(:call).with("domain.test", "whois.markmonitor.com", 43).returns("")
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.parts.should have(2).parts
end
it "ignores referral when is not defined" do
referral = File.read(fixture("referrals/crsnic.com_referral_not_defined.txt"))
- @server.expects(:query_socket).with("=domain.test", "whois.test", 43).returns(referral)
- @server.expects(:query_socket).never
+ server.query_handler.expects(:call).with("=domain.test", "whois.test", 43).returns(referral)
+ server.query_handler.expects(:call).never
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.parts.should have(1).part
end
# (see #103)
# This is the case of vrsn-20100925-dnssecmonitor86.net
it "gracefully ignores referral when is missing" do
referral = File.read(fixture("referrals/crsnic.com_referral_missing.txt"))
- @server.expects(:query_socket).with("=domain.test", "whois.test", 43).returns(referral)
- @server.expects(:query_socket).never
+ server.query_handler.expects(:call).with("=domain.test", "whois.test", 43).returns(referral)
+ server.query_handler.expects(:call).never
- record = @server.query("domain.test")
+ record = server.query("domain.test")
record.parts.should have(1).part
end
end

0 comments on commit 99fc791

Please sign in to comment.