whois 0.5.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG.rdoc +55 -0
  2. data/Manifest +43 -8
  3. data/README.rdoc +53 -20
  4. data/lib/whois.rb +69 -1
  5. data/lib/whois/answer.rb +126 -0
  6. data/lib/whois/answer/contact.rb +55 -0
  7. data/lib/whois/answer/parser.rb +110 -0
  8. data/lib/whois/answer/parser/README.rdoc +21 -0
  9. data/lib/whois/answer/parser/base.rb +144 -0
  10. data/lib/whois/answer/parser/blank.rb +45 -0
  11. data/lib/whois/answer/parser/whois.crsnic.net.rb +209 -0
  12. data/lib/whois/answer/parser/whois.denic.de.rb +202 -0
  13. data/lib/whois/answer/parser/whois.nic.it.rb +330 -0
  14. data/lib/whois/answer/parser/whois.publicinterestregistry.net.rb +232 -0
  15. data/lib/whois/answer/part.rb +35 -0
  16. data/lib/whois/answer/registrar.rb +42 -0
  17. data/lib/whois/answer/super_struct.rb +57 -0
  18. data/lib/whois/client.rb +6 -0
  19. data/lib/whois/definitions/tlds.rb +2 -2
  20. data/lib/whois/errors.rb +25 -8
  21. data/lib/whois/server.rb +0 -1
  22. data/lib/whois/server/adapters/afilias.rb +5 -5
  23. data/lib/whois/server/adapters/base.rb +31 -4
  24. data/lib/whois/server/adapters/formatted.rb +3 -1
  25. data/lib/whois/server/adapters/none.rb +20 -1
  26. data/lib/whois/server/adapters/pir.rb +5 -5
  27. data/lib/whois/server/adapters/standard.rb +13 -2
  28. data/lib/whois/server/adapters/verisign.rb +5 -5
  29. data/lib/whois/server/adapters/web.rb +15 -0
  30. data/lib/whois/version.rb +2 -2
  31. data/lib/whois/whois.rb +2 -2
  32. data/test/answer/parser/base_test.rb +27 -0
  33. data/test/answer/parser/blank_test.rb +19 -0
  34. data/test/answer/parser/whois_crsnic_net_test.rb +175 -0
  35. data/test/answer/parser/whois_denic_de_test.rb +209 -0
  36. data/test/answer/parser/whois_nic_it_test.rb +255 -0
  37. data/test/answer/parser/whois_publicinterestregistry_net_test.rb +210 -0
  38. data/test/answer/parser_test.rb +77 -0
  39. data/test/answer_test.rb +99 -0
  40. data/test/client_test.rb +3 -3
  41. data/test/integration_test.rb +31 -0
  42. data/test/{adapters → server/adapters}/afilias_test.rb +10 -5
  43. data/test/server/adapters/base_test.rb +15 -0
  44. data/test/server/adapters/formatted_test.rb +26 -0
  45. data/test/{adapters → server/adapters}/none_test.rb +0 -0
  46. data/test/{adapters → server/adapters}/not_implemented_test.rb +0 -0
  47. data/test/{adapters → server/adapters}/pir_test.rb +10 -5
  48. data/test/server/adapters/standard_test.rb +29 -0
  49. data/test/{adapters → server/adapters}/verisign_test.rb +10 -5
  50. data/test/{adapters → server/adapters}/web_test.rb +0 -0
  51. data/test/server_test.rb +5 -1
  52. data/test/testcases/responses/super_struct_test.rb +25 -0
  53. data/test/testcases/responses/whois.crsnic.net/available.txt +43 -0
  54. data/test/testcases/responses/whois.crsnic.net/registered.txt +57 -0
  55. data/test/testcases/responses/whois.denic.de/available.txt +30 -0
  56. data/test/testcases/responses/whois.denic.de/registered.txt +77 -0
  57. data/test/testcases/responses/whois.nic.it/available.txt +2 -0
  58. data/test/testcases/responses/{it.txt → whois.nic.it/registered.txt} +1 -0
  59. data/test/testcases/responses/whois.nic.it/status_active.txt +53 -0
  60. data/test/testcases/responses/whois.nic.it/status_available.txt +2 -0
  61. data/test/testcases/responses/whois.publicinterestregistry.net/available.txt +1 -0
  62. data/test/testcases/responses/whois.publicinterestregistry.net/registered.txt +85 -0
  63. data/test/whois_test.rb +23 -1
  64. data/utils/bm_delegation_vs_inheritance.rb +150 -0
  65. data/whois.gemspec +6 -6
  66. metadata +78 -18
  67. data/test/adapters/standard_test.rb +0 -23
@@ -0,0 +1,232 @@
1
+ #
2
+ # = Ruby Whois
3
+ #
4
+ # An intelligent pure Ruby WHOIS client.
5
+ #
6
+ #
7
+ # Category:: Net
8
+ # Package:: Whois
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'whois/answer/parser/base'
18
+
19
+
20
+ module Whois
21
+ class Answer
22
+ class Parser
23
+
24
+ #
25
+ # = whois.publicinterestregistry.net parser
26
+ #
27
+ # Parser for the whois.publicinterestregistry.net server.
28
+ #
29
+ class WhoisPublicinterestregistryNet < Base
30
+
31
+ register_method :disclaimer do
32
+ node("Disclaimer")
33
+ end
34
+
35
+
36
+ register_method :domain do
37
+ node("Domain Name") { |value| value.downcase }
38
+ end
39
+
40
+ register_method :domain_id do
41
+ node("Domain ID")
42
+ end
43
+
44
+
45
+ register_method :status do
46
+ node("Status")
47
+ end
48
+
49
+ register_method :available? do
50
+ node("Domain ID").nil?
51
+ end
52
+
53
+ register_method :registered? do
54
+ !available?
55
+ end
56
+
57
+
58
+ register_method :created_on do
59
+ node("Created On") { |value| Time.parse(value) }
60
+ end
61
+
62
+ register_method :updated_on do
63
+ node("Last Updated On") { |value| Time.parse(value) }
64
+ end
65
+
66
+ register_method :expires_on do
67
+ node("Expiration Date") { |value| Time.parse(value) }
68
+ end
69
+
70
+
71
+ register_method :registrar do
72
+ node("Sponsoring Registrar") do |registrar|
73
+ id, name = if registrar =~ /(.*?)\((.*?)\)/
74
+ [$2.strip, $1.strip]
75
+ else
76
+ [nil, registrar]
77
+ end
78
+ Answer::Registrar.new(
79
+ :id => id,
80
+ :name => name
81
+ )
82
+ end
83
+ end
84
+
85
+ register_method :registrant do
86
+ contact("Registrant")
87
+ end
88
+
89
+ register_method :admin do
90
+ contact("Admin")
91
+ end
92
+
93
+ register_method :technical do
94
+ contact("Tech")
95
+ end
96
+
97
+
98
+ register_method :nameservers do
99
+ node("Name Server") { |server| server.reject { |value| value.empty? }.map { |value| value.downcase }}
100
+ end
101
+
102
+
103
+ register_method :changed? do |other|
104
+ !unchanged?(other)
105
+ end
106
+
107
+ register_method :unchanged? do |other|
108
+ self == other ||
109
+ self.content.to_s == other.content.to_s
110
+ end
111
+
112
+
113
+ protected
114
+
115
+ def contact(element)
116
+ node("#{element} ID") do |registrant_id|
117
+ Answer::Contact.new(
118
+ :id => registrant_id,
119
+ :name => node("#{element} Name"),
120
+ :organization => node("#{element} Organization"),
121
+ :address => [node("#{element} Street1"),
122
+ node("#{element} Street2"),
123
+ node("#{element} Street3")].reject { |value| value.to_s.empty? }.join(" "),
124
+ :city => node("#{element} City"),
125
+ :zip => node("#{element} Postal Code"),
126
+ :state => node("#{element} State/Province"),
127
+ :country_code => node("#{element} Country"),
128
+ :phone => node("#{element} Phone"),
129
+ :fax => node("#{element} FAX"),
130
+ :email => node("#{element} Email")
131
+ )
132
+ end
133
+ end
134
+
135
+
136
+ def ast
137
+ @ast ||= parse
138
+ end
139
+
140
+ def node(key, &block)
141
+ if block_given?
142
+ value = ast[key]
143
+ value = yield(value) unless value.nil?
144
+ value
145
+ else
146
+ ast[key]
147
+ end
148
+ end
149
+
150
+ def node?(key)
151
+ !ast[key].nil?
152
+ end
153
+
154
+ def parse
155
+ Scanner.new(content.to_s).parse
156
+ end
157
+
158
+
159
+ class Scanner
160
+
161
+ def initialize(content)
162
+ @input = StringScanner.new(content.to_s)
163
+ end
164
+
165
+ def parse
166
+ @ast = {}
167
+ while !@input.eos?
168
+ parse_content
169
+ end
170
+ @ast
171
+ end
172
+
173
+ private
174
+
175
+ def parse_content
176
+ trim_newline ||
177
+ parse_not_found ||
178
+ parse_disclaimer ||
179
+ parse_pair ||
180
+ error("Unexpected token")
181
+ end
182
+
183
+ def trim_newline
184
+ # The last line is \r\n\n
185
+ @input.scan(/\r\n+/)
186
+ end
187
+
188
+ def parse_not_found
189
+ @input.scan(/NOT FOUND\n/)
190
+ end
191
+
192
+ def parse_disclaimer
193
+ if @input.match?(/NOTICE:/)
194
+ lines = []
195
+ while !@input.match?(/\r\n/) && @input.scan(/(.*)\r\n/)
196
+ lines << @input[1].strip
197
+ end
198
+ @ast["Disclaimer"] = lines.join(" ")
199
+ else
200
+ false
201
+ end
202
+ end
203
+
204
+ def parse_pair
205
+ if @input.scan(/(.*?):(.*?)\r\n/)
206
+ key, value = @input[1].strip, @input[2].strip
207
+ if @ast[key].nil?
208
+ @ast[key] = value
209
+ else
210
+ @ast[key].is_a?(Array) || @ast[key] = [@ast[key]]
211
+ @ast[key] << value
212
+ end
213
+ else
214
+ false
215
+ end
216
+ end
217
+
218
+ def error(message)
219
+ if @input.eos?
220
+ raise "Unexpected end of input."
221
+ else
222
+ raise "#{message}: #{@input.peek(@input.string.length)}"
223
+ end
224
+ end
225
+
226
+ end
227
+
228
+ end
229
+
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,35 @@
1
+ #
2
+ # = Ruby Whois
3
+ #
4
+ # An intelligent pure Ruby WHOIS client.
5
+ #
6
+ #
7
+ # Category:: Net
8
+ # Package:: Whois
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'whois/answer/super_struct'
18
+
19
+
20
+ module Whois
21
+ class Answer
22
+
23
+ #
24
+ # = Part
25
+ #
26
+ # A single <tt>Whois::Answer</tt> fragment. For instance,
27
+ # in case of thin server, an <tt>Whois::Answer</tt> may be composed by
28
+ # one or more parts corresponding to all responses
29
+ # returned by the WHOIS servers.
30
+ #
31
+ class Part < SuperStruct.new(:response, :host)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # = Ruby Whois
3
+ #
4
+ # An intelligent pure Ruby WHOIS client.
5
+ #
6
+ #
7
+ # Category:: Net
8
+ # Package:: Whois
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'whois/answer/super_struct'
18
+
19
+
20
+ module Whois
21
+ class Answer
22
+
23
+ #
24
+ # = Registrar
25
+ #
26
+ # Holds the details of the Registrar extracted from the WHOIS answer.
27
+ #
28
+ # A Registrar is composed by the following attributes:
29
+ #
30
+ # <tt>:id</tt>::
31
+ # <tt>:name</tt>::
32
+ # <tt>:organization</tt>::
33
+ # <tt>:url</tt>::
34
+ #
35
+ # Be aware that every WHOIS server can return a different number of details
36
+ # or no details at all.
37
+ #
38
+ class Registrar < SuperStruct.new(:id, :name, :organization, :url)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # = Ruby Whois
3
+ #
4
+ # An intelligent pure Ruby WHOIS client.
5
+ #
6
+ #
7
+ # Category:: Net
8
+ # Package:: Whois
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'ostruct'
18
+
19
+
20
+ #
21
+ # = SuperStruct
22
+ #
23
+ # SuperStruct is an enhanced version of the Ruby Standar library <tt>Struct</tt>.
24
+ #
25
+ # Compared with the original version, it provides the following additional features:
26
+ # * ability to initialize an instance from Hash
27
+ # * ability to pass a block on creation
28
+ #
29
+ class SuperStruct < Struct
30
+
31
+ # Overwrites the standard Struct initializer
32
+ # to add the ability to create an instance from a Hash of parameters.
33
+ #
34
+ # attributes = { :foo => 1, :bar => "baz" }
35
+ # Struct.new(attributes)
36
+ # # => #<Struct foo=1, bar="baz">
37
+ #
38
+ # If block is given, the block is called on self.
39
+ #
40
+ def initialize(*args, &block)
41
+ if args.first.is_a? Hash
42
+ initialize_with_hash(args.first)
43
+ else
44
+ super
45
+ end
46
+ yield(self) if block_given?
47
+ end
48
+
49
+ private
50
+
51
+ def initialize_with_hash(attributes = {})
52
+ attributes.each do |key, value|
53
+ self[key] = value
54
+ end
55
+ end
56
+
57
+ end
@@ -60,6 +60,12 @@ module Whois
60
60
  end
61
61
 
62
62
 
63
+ # Queries the right whois server for <tt>qstring</tt> and returns
64
+ # a <tt>Whois::Answer</tt> instance containing the response from the server.
65
+ #
66
+ # client.query("google.com")
67
+ # # => #<Whois::Answer>
68
+ #
63
69
  def query(qstring)
64
70
  Timeout::timeout(timeout) do
65
71
  @server = Server.guess(qstring)
@@ -34,7 +34,7 @@ Whois::Server.define :tld, ".arpa", "whois.iana.org"
34
34
  Whois::Server.define :tld, ".aero", "whois.aero"
35
35
  Whois::Server.define :tld, ".asia", "whois.nic.asia"
36
36
  Whois::Server.define :tld, ".biz", "whois.nic.biz"
37
- Whois::Server.define :tld, ".cat", "whois.cat", {:format => "-C US-ASCII ace %s"}
37
+ Whois::Server.define :tld, ".cat", "whois.cat", {:adapter=>Whois::Server::Adapters::Formatted, :format => "-C US-ASCII ace %s"}
38
38
  Whois::Server.define :tld, ".coop", "whois.nic.coop"
39
39
  Whois::Server.define :tld, ".info", "whois.afilias.info"
40
40
  Whois::Server.define :tld, ".jobs", "jobswhois.verisign-grs.com", {:adapter=>Whois::Server::Adapters::Verisign}
@@ -102,7 +102,7 @@ Whois::Server.define :tld, ".cv", nil, {:adapter=>Whois::Server::Adapters::None}
102
102
  Whois::Server.define :tld, ".cx", "whois.nic.cx"
103
103
  Whois::Server.define :tld, ".cy", nil, {:web=>"http://www.nic.cy/nslookup/online_database.php", :adapter=>Whois::Server::Adapters::Web}
104
104
  Whois::Server.define :tld, ".cz", "whois.nic.cz"
105
- Whois::Server.define :tld, ".de", "whois.denic.de", {:format => "-T dn,ace -C US-ASCII %s"}
105
+ Whois::Server.define :tld, ".de", "whois.denic.de", {:adapter=>Whois::Server::Adapters::Formatted, :format => "-T dn,ace -C US-ASCII %s"}
106
106
  Whois::Server.define :tld, ".dj", "whois.domain.dj"
107
107
  Whois::Server.define :tld, ".dk", "whois.dk-hostmaster.dk"
108
108
  Whois::Server.define :tld, ".dm", "whois.nic.dm"
@@ -25,33 +25,30 @@ module Whois
25
25
  class ServerError < Error
26
26
  end
27
27
 
28
-
29
- # Definition not found
28
+ # Server Definition not found
30
29
 
31
30
  # Raised when the class hasn't been able to select a valid server
32
31
  # probably because definitions are outdated.
33
32
  class ServerNotFound < ServerError
34
33
  end
35
34
 
36
-
37
- # Definition found
35
+ # Server Definition found
38
36
 
39
37
  class InterfaceNotSupported < ServerError
40
38
  end
41
39
 
42
40
  # Raised when a server is known to not be available for this kind of object
43
- # or because this specific object doesn't support whois. (\x03)
41
+ # or because this specific object doesn't support WHOIS. (\x03)
44
42
  class NoInterfaceError < InterfaceNotSupported
45
43
  end
46
44
 
47
45
  # Raised when the class has found a server but it doesn't support the
48
46
  # standard whois interface via port 43. This is the case of some
49
- # specific domains that only provide a web–based whois interface. (\x01)
47
+ # specific domains that only provide a web–based WHOIS interface. (\x01)
50
48
  class WebInterfaceError < InterfaceNotSupported
51
49
  end
52
50
 
53
-
54
- # Known object, Definition unavailable
51
+ # Server Known object, Definition unavailable
55
52
 
56
53
  # Raised when we know about a specific functionality
57
54
  # but this functionality has not been implemented yet.
@@ -66,5 +63,25 @@ module Whois
66
63
  # Raised when unknown AS numer of IP network. (\x06)
67
64
  class AllocationUnknown < ServerError
68
65
  end
66
+
67
+
68
+ # Generic Parser exception class.
69
+ class ParserError < Error
70
+ end
71
+
72
+ # Raised when the class hasn't been able to load a valid parser
73
+ # according to current settings.
74
+ class ParserNotFound < ParserError
75
+ end
76
+
77
+ # Raised when the property method has not been overwritten (implemented)
78
+ # in a child parser class.
79
+ class PropertyNotImplemented < ParserError
80
+ end
81
+
82
+ # Raised when you are trying to access a property that is not supported
83
+ # by any of the parsers available for current WHOIS answer.
84
+ class PropertyNotSupported < ParserError
85
+ end
69
86
 
70
87
  end