Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added support for multipart answers. This is useful in case of thin s…

…ervers such as .com or .net because the parser needs to know all different responses in order to load all single scanners.
  • Loading branch information...
commit 3b9938c76c25c93a211073cf8c796fdb543ab9b4 1 parent f507e9e
@weppos authored
View
2  CHANGELOG.rdoc
@@ -5,6 +5,8 @@
* ADDED: whois.denic.de (.de TLD) parser [Aaron Mueller]
+* ADDED: support for multipart answers. This is useful in case of thin servers such as .com or .net because the parser needs to know all different responses in order to load all single scanners.
+
* CHANGED: extracted all scanners into separated classes in order to make easier extract shared features.
View
43 lib/whois/response.rb
@@ -20,26 +20,28 @@
module Whois
class Response
+
attr_reader :server
- attr_reader :content
-
- def initialize(content, server = nil)
- @content = content
- @server = server
+ attr_reader :parts
+
+ def initialize(server, parts)
+ @parts = parts
+ @server = server
end
+
def to_s
- @content.to_s
+ content.to_s
end
def inspect
- @content.inspect
+ content.inspect
end
# Invokes <tt>match</tt> on response <tt>@content</tt>
# and returns the <tt>MatchData</tt> or <tt>nil</tt>.
def match(pattern)
- @content.match(pattern)
+ content.match(pattern)
end
# Returns true if the <tt>object</tt> is the same object,
@@ -56,6 +58,11 @@ def eql?(other)
self == other
end
+
+ def content
+ @content ||= parts.map { |response, host| response }.join("\n")
+ end
+
# Returns whether this response changed compared to <tt>other</tt>.
#
# Comparing the Response contents is not always as trivial as it seems.
@@ -80,7 +87,7 @@ def unchanged?(other)
# Invokes <tt>match</tt> and returns <tt>true</tt> if <tt>pattern</tt>
# matches <tt>@content</tt>, <tt>false</tt> otherwise.
def match?(pattern)
- !@content.match(pattern).nil?
+ !content.match(pattern).nil?
end
# Invokes <tt>match</tt> and returns the first useful match,
@@ -103,7 +110,7 @@ def i_m_feeling_lucky(pattern, &block)
# Lazy-loads and returns current response parser.
def parser
- @parser ||= self.class.parser_klass(@server).new(self)
+ @parser ||= self.class.parser_klass(parts.first.last).new(self)
end
@@ -119,24 +126,20 @@ def method_missing(method, *args, &block)
end
- def self.parser_klass(server)
- raise ParserError,
- "Unable to select a parser. " +
- "The server for this response is either nil or invalid." if server.nil? || server.host.nil?
-
- file = "whois/response/parsers/#{server.host}.rb"
+ def self.parser_klass(host)
+ file = "whois/response/parsers/#{host}.rb"
require file
- name = host_to_parser(server)
+ name = host_to_parser(host)
Parsers.const_get(name)
rescue LoadError
raise ParserNotFound,
- "Unable to find a parser for the server `#{server.host}'"
+ "Unable to find a parser for the server `#{host}'"
end
- def self.host_to_parser(server)
- server.host.to_s.
+ def self.host_to_parser(host)
+ host.to_s.
gsub(/\./, '_').
gsub(/(?:^|_)(.)/) { $1.upcase }
end
View
10 lib/whois/server/adapters/afilias.rb
@@ -22,11 +22,11 @@ class Afilias < Base
def request(qstring)
response = ask_the_socket(qstring, "whois.afilias-grs.info", DEFAULT_WHOIS_PORT)
- endpoint = extract_referral(response)
- if endpoint
- response + "\n" + ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
- else
- response
+ push_buffer response, "whois.afilias-grs.info"
+
+ if endpoint = extract_referral(response)
+ response = ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
+ push_buffer response, endpoint
end
end
View
32 lib/whois/server/adapters/base.rb
@@ -20,33 +20,55 @@ module Adapters
class Base
+ # Default Whois request port.
DEFAULT_WHOIS_PORT = 43
attr_reader :type
attr_reader :allocation
attr_reader :host
attr_reader :options
+ attr_reader :buffer
-
def initialize(type, allocation, host, options = {})
@type = type
@allocation = allocation
@host = host
@options = options || {}
end
-
+
+ # Performs a Whois query for <tt>qstring</tt>
+ # using current server adapter and returns a <tt>Whois::Response</tt>
+ # instance with the result of the request.
+ #
+ # server.query("google.com")
+ # # => Whois::Response
+ #
def query(qstring)
- response = request(qstring)
- Response.new(response, self)
+ with_buffer do |buffer|
+ request(qstring)
+ Response.new(self, buffer)
+ end
end
def request(qstring)
raise NotImplementedError
end
-
+
protected
+ def with_buffer(&block)
+ @buffer = []
+ result = yield(@buffer)
+ # @buffer = []
+ # result
+ end
+
+ # Store a pair of response and host in <tt>@buffer</tt>.
+ def push_buffer(response, host)
+ @buffer << [response, host]
+ end
+
def query_the_socket(qstring, host, port = nil)
ask_the_socket(qstring, host, port || options[:port] || DEFAULT_WHOIS_PORT)
end
View
10 lib/whois/server/adapters/pir.rb
@@ -22,11 +22,11 @@ class Pir < Base
def request(qstring)
response = ask_the_socket("FULL #{qstring}", "whois.publicinterestregistry.net", DEFAULT_WHOIS_PORT)
- endpoint = extract_referral(response)
- if endpoint
- response + "\n" + ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
- else
- response
+ push_buffer response, "whois.publicinterestregistry.net"
+
+ if endpoint = extract_referral(response)
+ response = ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
+ push_buffer response, endpoint
end
end
View
3  lib/whois/server/adapters/standard.rb
@@ -21,7 +21,8 @@ module Adapters
class Standard < Base
def request(qstring)
- query_the_socket(qstring, host)
+ response = query_the_socket(qstring, host)
+ push_buffer response, host
end
end
View
10 lib/whois/server/adapters/verisign.rb
@@ -22,11 +22,11 @@ class Verisign < Base
def request(qstring)
response = ask_the_socket("=#{qstring}", host, DEFAULT_WHOIS_PORT)
- endpoint = extract_referral(response)
- if endpoint
- response + "\n" + ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
- else
- response
+ push_buffer response, host
+
+ if endpoint = extract_referral(response)
+ response = ask_the_socket(qstring, endpoint, DEFAULT_WHOIS_PORT)
+ push_buffer response, endpoint
end
end
View
2  test/adapters/afilias_test.rb
@@ -14,6 +14,7 @@ def test_query
expected = response
@server.expects(:ask_the_socket).with("domain.foo", "whois.afilias-grs.info", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[response, "whois.afilias-grs.info"]], @server.buffer
end
def test_query_with_referral
@@ -23,6 +24,7 @@ def test_query_with_referral
@server.expects(:ask_the_socket).with("domain.foo", "whois.afilias-grs.info", 43).returns(referral)
@server.expects(:ask_the_socket).with("domain.foo", "whois.belizenic.bz", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[referral, "whois.afilias-grs.info"], [response, "whois.belizenic.bz"]], @server.buffer
end
end
View
2  test/adapters/pir_test.rb
@@ -14,6 +14,7 @@ def test_query
expected = response
@server.expects(:ask_the_socket).with("FULL domain.foo", "whois.publicinterestregistry.net", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[response, "whois.publicinterestregistry.net"]], @server.buffer
end
def test_query_with_referral
@@ -23,6 +24,7 @@ def test_query_with_referral
@server.expects(:ask_the_socket).with("FULL domain.foo", "whois.publicinterestregistry.net", 43).returns(referral)
@server.expects(:ask_the_socket).with("domain.foo", "whois.iana.org", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[referral, "whois.publicinterestregistry.net"], [response, "whois.iana.org"]], @server.buffer
end
end
View
2  test/adapters/standard_test.rb
@@ -13,6 +13,7 @@ def test_query
@server.expects(:ask_the_socket).with("domain.foo", "whois.foo", 43).returns("Whois Response")
response = @server.query("domain.foo")
assert_equal response, "Whois Response"
+ assert_equal [[response, "whois.foo"]], @server.buffer
end
def test_query_with_port
@@ -20,6 +21,7 @@ def test_query_with_port
@server.expects(:ask_the_socket).with("domain.foo", "whois.foo", 20).returns("Whois Response")
response = @server.query("domain.foo")
assert_equal response, "Whois Response"
+ assert_equal [[response, "whois.foo"]], @server.buffer
end
end
View
2  test/adapters/verisign_test.rb
@@ -14,6 +14,7 @@ def test_query
expected = response
@server.expects(:ask_the_socket).with("=domain.foo", "whois.foo", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[response, "whois.foo"]], @server.buffer
end
def test_query_with_referral
@@ -23,6 +24,7 @@ def test_query_with_referral
@server.expects(:ask_the_socket).with("=domain.foo", "whois.foo", 43).returns(referral)
@server.expects(:ask_the_socket).with("domain.foo", "whois.tucows.com", 43).returns(response)
assert_equal expected, @server.query("domain.foo").to_s
+ assert_equal [[referral, "whois.foo"], [response, "whois.tucows.com"]], @server.buffer
end
end
View
24 test/parsers/whois_denic_de_test.rb
@@ -2,6 +2,7 @@
require 'whois/response/parsers/whois.denic.de'
class WhoisDenicDeTest < Test::Unit::TestCase
+
TESTCASE_PATH = File.expand_path(File.dirname(__FILE__) + '/../testcases/responses/de')
def setup
@@ -135,20 +136,29 @@ def test_technical
end
def test_technical_for_avalable_domain
- assert_equal(nil, @class.new(load_response('/available.txt')).technical)
+ assert_equal nil,
+ @class.new(load_response('/available.txt')).technical
end
def test_nameservers
- assert_equal(%w(ns1.google.com ns4.google.com ns3.google.com ns2.google.com),
- @class.new(load_response('/registered.txt')).nameservers)
+ assert_equal %w(ns1.google.com ns4.google.com ns3.google.com ns2.google.com),
+ @class.new(load_response('/registered.txt')).nameservers
end
def test_nameservers_for_available_domain
- assert_equal(nil, @class.new(load_response('/available.txt')).nameservers)
+ assert_equal nil,
+ @class.new(load_response('/available.txt')).nameservers
end
+
protected
- def load_response(path)
- @response.new(File.read(TESTCASE_PATH + path), @server)
- end
+
+ def load_response(path)
+ new_response(@server, File.read(TESTCASE_PATH + path))
+ end
+
+ def new_response(server, content)
+ @response.new(server, [[content, server.host]])
+ end
+
end
View
22 test/parsers/whois_nic_it_test.rb
@@ -183,7 +183,7 @@ def test_changed_question_check_internals
end
def test_changed_question_check_self_with_available
- parser = @response.new(<<-RESPONSE, @server).parser
+ parser = new_response(@server, <<-RESPONSE).parser
Domain: google.it
Status: AVAILABLE
RESPONSE
@@ -192,16 +192,16 @@ def test_changed_question_check_self_with_available
end
def test_changed_question_check_internals_with_available
- parser = @response.new(<<-RESPONSE, @server).parser
+ parser = new_response(@server, <<-RESPONSE).parser
Domain: google.it
Status: AVAILABLE
RESPONSE
- assert parser.changed?(@response.new(<<-RESPONSE, @server).parser)
+ assert parser.changed?(new_response(@server, <<-RESPONSE).parser)
Domain: weppos.it
Status: AVAILABLE
RESPONSE
- assert !parser.changed?(@response.new(<<-RESPONSE, @server).parser)
+ assert !parser.changed?(new_response(@server, <<-RESPONSE).parser)
Domain: google.it
Status: AVAILABLE
RESPONSE
@@ -218,7 +218,7 @@ def test_unchanged_question_check_internals
end
def test_unchanged_question_check_self_with_available
- parser = @response.new(<<-RESPONSE, @server).parser
+ parser = new_response(@server, <<-RESPONSE).parser
Domain: google.it
Status: AVAILABLE
RESPONSE
@@ -227,16 +227,16 @@ def test_unchanged_question_check_self_with_available
end
def test_unchanged_question_check_internals_with_available
- parser = @response.new(<<-RESPONSE, @server).parser
+ parser = new_response(@server, <<-RESPONSE).parser
Domain: google.it
Status: AVAILABLE
RESPONSE
- assert parser.unchanged?(@response.new(<<-RESPONSE, @server).parser)
+ assert parser.unchanged?(new_response(@server, <<-RESPONSE).parser)
Domain: google.it
Status: AVAILABLE
RESPONSE
- assert !parser.unchanged?(@response.new(<<-RESPONSE, @server).parser)
+ assert !parser.unchanged?(new_response(@server, <<-RESPONSE).parser)
Domain: weppos.it
Status: AVAILABLE
RESPONSE
@@ -246,7 +246,11 @@ def test_unchanged_question_check_internals_with_available
protected
def load_response(path)
- @response.new(File.read(TESTCASE_PATH + path), @server)
+ new_response(@server, File.read(TESTCASE_PATH + path))
+ end
+
+ def new_response(server, content)
+ @response.new(server, [[content, server.host]])
end
end
View
6 test/parsers/whois_publicinterestregistry_net_test.rb
@@ -203,7 +203,11 @@ def test_nameservers_with_available
protected
def load_response(path)
- @response.new(File.read(TESTCASE_PATH + path), @server)
+ new_response(@server, File.read(TESTCASE_PATH + path))
+ end
+
+ def new_response(server, content)
+ @response.new(server, [[content, server.host]])
end
end
View
58 test/response_test.rb
@@ -5,24 +5,28 @@ class ResponseTest < Test::Unit::TestCase
def setup
@klass = Whois::Response
@server = Whois::Server.factory(:tld, ".foo", "whois.foo")
- @content = "This is a response for domain.foo."
- @response = @klass.new(@content, @server)
+ @parts = [["This is a response for domain.foo.", "foo.whois.com"], ["This is a response for domain.bar.", "bar.whois.com"]]
+ @content = "This is a response for domain.foo.\nThis is a response for domain.bar."
+ @response = @klass.new(@server, @parts)
end
-
+
+
def test_initialize
- response = @klass.new(@content)
+ response = @klass.new(@server, @parts)
assert_instance_of @klass, response
- assert_equal @content, response.content
- assert_equal nil, response.server
- end
-
- def test_initialize_with_server
- response = @klass.new(@content, @server)
- assert_instance_of @klass, response
- assert_equal @content, response.content
assert_equal @server, response.server
+ assert_equal @parts, response.parts
end
+ def test_initialize_should_require_server
+ assert_raise(ArgumentError) { @klass.new }
+ end
+
+ def test_initialize_should_require_responses
+ assert_raise(ArgumentError) { @klass.new(@server) }
+ end
+
+
def test_to_s
assert_equal @content, @response.to_s
end
@@ -51,14 +55,19 @@ def test_equality_check_string
end
def test_equality_check_content
- other = @klass.new(@content, @server)
+ other = @klass.new(@server, @parts)
assert_equal @response, other
assert_equal other, @response
assert @response.eql?(other)
assert other.eql?(@response)
end
-
+
+ def test_content
+ response = @klass.new(@server, @parts)
+ assert_equal @content, response.content
+ end
+
def test_match?
assert @response.match?(/domain\.foo/)
assert !@response.match?(/google/)
@@ -70,30 +79,22 @@ def test_i_m_feeling_lucky
end
+ require 'whois/response/parsers/whois.nic.it'
def test_parser
- server = Whois::Server.factory(:tld, ".it", "whois.nic.it")
- response = @klass.new("", server)
+ response = @klass.new(nil, [["", "whois.nic.it"]])
assert_instance_of Whois::Response::Parsers::WhoisNicIt,
response.parser
end
-
+
def test_parser_should_raise_with_missing_parser
- server = Whois::Server.factory(:tld, ".it", "invalid.nic.it")
- response = @klass.new("", server)
+ response = @klass.new(nil, [["", "invalid.nic.it"]])
error = assert_raise(Whois::ParserNotFound) { response.parser }
assert_match /Unable to find a parser/, error.message
end
-
- def test_parser_should_raise_with_missing_server
- response = @klass.new("")
- error = assert_raise(Whois::ParserError) { response.parser }
- assert_match /Unable to select a parser/, error.message
- end
Whois::Response::Parsers::Base.allowed_methods.each do |method|
define_method "test_should_delegate_#{method}_to_parser" do
- server = Whois::Server.factory(:tld, ".it", "whois.nic.it")
- response = @klass.new("", server)
+ response = @klass.new(nil, [["", "whois.nic.it"]])
parser = response.parser
parser.expects(method).returns(:value)
assert_equal :value, response.send(method)
@@ -101,8 +102,7 @@ def test_parser_should_raise_with_missing_server
end
def test_should_not_delegate_unallowed_method_to_parser
- server = Whois::Server.factory(:tld, ".it", "whois.nic.it")
- response = @klass.new("", server)
+ response = @klass.new(nil, [["", "whois.nic.it"]])
parser = response.parser
parser.expects("unallowed_method").never
assert_raise(NoMethodError) { response.send("unallowed_method") }
Please sign in to comment.
Something went wrong with that request. Please try again.