Skip to content

Commit

Permalink
Added available info for whois.cnnic.cn. Full test coverage (I think?…
Browse files Browse the repository at this point in the history
…). Also added 'reserved' status I have come across with 'gov.cn' and others.
  • Loading branch information
ezkl committed Feb 18, 2011
1 parent 744266d commit 3fa017c
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 15 deletions.
190 changes: 175 additions & 15 deletions lib/whois/answer/parser/whois.cnnic.cn.rb
Expand Up @@ -20,20 +20,20 @@
module Whois
class Answer
class Parser


#
# = whois.cnnic.cn parser
#
# Parser for the whois.cnnic.cn server.
#
# NOTE: This parser is just a stub and provides only a few basic methods
# to check for domain availability and get domain status.
# Please consider to contribute implementing missing methods.
# See WhoisNicIt parser for an explanation of all available methods
# and examples.
#
class WhoisCnnicCn < Base

include Ast

property_not_supported :disclaimer

property_supported :domain do
node('Domain Name') { |raw| raw.downcase }
end

property_not_supported :domain_id


property_supported :status do
content_for_scanner.scan(/Domain Status:\s+(.+)\n/).flatten
end
Expand All @@ -43,7 +43,7 @@ class WhoisCnnicCn < Base
end

property_supported :registered? do
!available?
(content_for_scanner.strip == "the domain you want to register is reserved") || !available?
end


Expand All @@ -60,16 +60,176 @@ class WhoisCnnicCn < Base
Time.parse($1)
end
end

property_supported :registrar do
if registered?
sponsor = node("Sponsoring Registrar")
Answer::Registrar.new(
:id => sponsor,
:name => sponsor,
)
end
end

property_supported :registrant_contact do
contact("Registrant", Whois::Answer::Contact::TYPE_REGISTRANT) unless available?
end

property_supported :admin_contact do
contact("Administrative", Whois::Answer::Contact::TYPE_ADMIN) unless available?
end

property_not_supported :technical_contact


property_supported :nameservers do
content_for_scanner.scan(/Name Server:(.+)\n/).flatten.map do |name|
Answer::Nameserver.new(name.downcase)
end
end


protected

def parse
Scanner.new(content_for_scanner).parse
end

def contact(element, type)
Answer::Contact.new(
:type => type,
:name => node("#{element} Name"),
:organization => node("#{element} Organization"),
:email => node("#{element} Email")
)
end

class Scanner

def initialize(content)
@input = StringScanner.new(content)
end

def parse
@ast = {}
while !@input.eos?
trim_newline ||
parse_content
end
@ast
end

private

def parse_content
parse_disclaimer ||
parse_pair ||
parse_section ||
error("Unexpected token")
end

def trim_newline
@input.scan(/\n/)
end

def parse_pair
if @input.scan(/(.*?):(.*?)\n/)
key, value = @input[1].strip, @input[2].strip
@ast[key] = value
else
false
end
end

def parse_disclaimer
if @input.match?(/\*(.*?)\*\n/)
disclaimer = []
while @input.scan(/\*(.*?)\*\n/)
matched = @input[1].strip
disclaimer << matched if matched =~ /\w+/
end
@ast["Disclaimer"] = disclaimer.join(" ")
else
false
end
end

def parse_section
if @input.scan(/([^:]*?)\n/)
section = @input[1].strip
content = parse_section_pairs ||
parse_section_items
@input.match?(/\n+/) || error("Unexpected end of section")
@ast[section] = content
else
false
end
end

def parse_section_items
if @input.match?(/(\s+)([^:]*?)\n/)
items = []
indentation = @input[1].length
while item = parse_section_items_item(indentation)
items << item
end
items
else
false
end
end

def parse_section_items_item(indentation)
if @input.scan(/\s{#{indentation}}(.*)\n/)
@input[1]
else
false
end
end

def parse_section_pairs
contents = {}
while content = parse_section_pair
contents.merge!(content)
end
if !contents.empty?
contents
else
false
end
end

def parse_section_pair
if @input.scan(/(\s+)(.*?):(\s+)(.*?)\n/)
key = @input[2].strip
values = [@input[4].strip]
indentation = @input[1].length + @input[2].length + 1 + @input[3].length
while value = parse_section_pair_newlinevalue(indentation)
values << value
end
{ key => values.join("\n") }
else
false
end
end

def parse_section_pair_newlinevalue(indentation)
if @input.scan(/\s{#{indentation}}(.*)\n/)
@input[1]
else
false
end
end

def error(message)
if @input.eos?
raise "Unexpected end of input."
else
raise "#{message}: #{@input.peek(@input.string.length)}"
end
end
end

end

end
end
end
1 change: 1 addition & 0 deletions spec/fixtures/responses/whois.cnnic.cn/reserved.txt
@@ -0,0 +1 @@
the domain you want to register is reserved
70 changes: 70 additions & 0 deletions test/whois/answer/parser/whois.cnnic.cn_test.rb
Expand Up @@ -7,6 +7,12 @@ def setup
@klass = Whois::Answer::Parser::WhoisCnnicCn
@host = "whois.cnnic.cn"
end

def test_domain
parser = @klass.new(load_part('registered.txt'))
expected = "google.cn"
assert_equal_and_cached expected, parser, :domain
end


def test_status
Expand All @@ -21,6 +27,10 @@ def test_available?
parser = @klass.new(load_part('registered.txt'))
expected = false
assert_equal_and_cached expected, parser, :available?

parser = @klass.new(load_part('reserved.txt'))
expected = false
assert_equal_and_cached expected, parser, :available?

parser = @klass.new(load_part('available.txt'))
expected = true
Expand All @@ -31,6 +41,10 @@ def test_registered?
parser = @klass.new(load_part('registered.txt'))
expected = true
assert_equal_and_cached expected, parser, :registered?

parser = @klass.new(load_part('reserved.txt'))
expected = true
assert_equal_and_cached expected, parser, :registered?

parser = @klass.new(load_part('available.txt'))
expected = false
Expand Down Expand Up @@ -62,6 +76,62 @@ def test_expires_on
expected = nil
assert_equal_and_cached expected, parser, :expires_on
end

def test_registrar_with_registered
parser = @klass.new(load_part('registered.txt'))
expected = parser.registrar
assert_equal_and_cached expected, parser, :registrar

assert_instance_of Whois::Answer::Registrar, expected
assert_equal "MarkMonitor, Inc.", expected.id
assert_equal "MarkMonitor, Inc.", expected.name
end

def test_registrar_with_available
parser = @klass.new(load_part('available.txt'))
expected = nil
assert_equal_and_cached expected, parser, :registrar
end

def test_registrant_contact_with_registered
parser = @klass.new(load_part('registered.txt'))
expected = parser.registrant_contact
assert_equal_and_cached expected, parser, :registrant_contact

assert_instance_of Whois::Answer::Contact, expected
assert_equal "Google Ireland Holdings", expected.organization
assert_equal Whois::Answer::Contact::TYPE_REGISTRANT, expected.type
assert_equal "Domain Admin", expected.name
end

def test_registrant_contact_with_available
parser = @klass.new(load_part('available.txt'))
expected = nil

assert_equal_and_cached expected, parser, :registrant_contact
end

def test_admin_contact_with_registered
parser = @klass.new(load_part('registered.txt'))
expected = parser.admin_contact
assert_equal_and_cached expected, parser, :admin_contact

assert_instance_of Whois::Answer::Contact, expected
assert_equal Whois::Answer::Contact::TYPE_ADMIN, expected.type
assert_equal "dns-admin@google.com", expected.email
end

def test_admin_contact_with_available
parser = @klass.new(load_part('available.txt'))
expected = nil

assert_equal_and_cached expected, parser, :admin_contact
end

def test_technical_contact
assert_raise(Whois::PropertyNotSupported) { @klass.new(load_part('registered.txt')).updated_on }
assert_raise(Whois::PropertyNotSupported) { @klass.new(load_part('available.txt')).updated_on }
end


def test_nameservers
Expand Down

0 comments on commit 3fa017c

Please sign in to comment.