epp-client 0.0.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.simplecov +16 -0
- data/.travis.yml +11 -0
- data/.yardopts +4 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +1 -1
- data/README.md +75 -0
- data/Rakefile +2 -37
- data/epp-client.gemspec +15 -58
- data/gemfiles/Gemfile.ruby18 +13 -0
- data/lib/epp-client.rb +94 -7
- data/lib/epp-client/client.rb +117 -20
- data/lib/epp-client/commands/check.rb +11 -0
- data/lib/epp-client/commands/command.rb +24 -0
- data/lib/epp-client/commands/create.rb +11 -0
- data/lib/epp-client/commands/delete.rb +11 -0
- data/lib/epp-client/commands/info.rb +11 -0
- data/lib/epp-client/commands/login.rb +40 -0
- data/lib/epp-client/commands/logout.rb +11 -0
- data/lib/epp-client/commands/poll.rb +28 -0
- data/lib/epp-client/commands/read_write_command.rb +18 -0
- data/lib/epp-client/commands/renew.rb +11 -0
- data/lib/epp-client/commands/transfer.rb +25 -0
- data/lib/epp-client/commands/update.rb +11 -0
- data/lib/epp-client/contact/check.rb +23 -0
- data/lib/epp-client/contact/check_response.rb +22 -0
- data/lib/epp-client/contact/command.rb +87 -0
- data/lib/epp-client/contact/create.rb +34 -0
- data/lib/epp-client/contact/create_response.rb +14 -0
- data/lib/epp-client/contact/delete.rb +21 -0
- data/lib/epp-client/contact/delete_response.rb +9 -0
- data/lib/epp-client/contact/info.rb +21 -0
- data/lib/epp-client/contact/info_response.rb +74 -0
- data/lib/epp-client/contact/response.rb +34 -0
- data/lib/epp-client/contact/transfer.rb +21 -0
- data/lib/epp-client/contact/transfer_response.rb +26 -0
- data/lib/epp-client/contact/update.rb +80 -0
- data/lib/epp-client/contact/update_response.rb +9 -0
- data/lib/epp-client/domain/check.rb +23 -0
- data/lib/epp-client/domain/check_response.rb +22 -0
- data/lib/epp-client/domain/command.rb +92 -0
- data/lib/epp-client/domain/create.rb +49 -0
- data/lib/epp-client/domain/create_response.rb +17 -0
- data/lib/epp-client/domain/delete.rb +21 -0
- data/lib/epp-client/domain/delete_response.rb +9 -0
- data/lib/epp-client/domain/info.rb +21 -0
- data/lib/epp-client/domain/info_response.rb +66 -0
- data/lib/epp-client/domain/renew.rb +34 -0
- data/lib/epp-client/domain/renew_response.rb +14 -0
- data/lib/epp-client/domain/response.rb +34 -0
- data/lib/epp-client/domain/transfer.rb +27 -0
- data/lib/epp-client/domain/transfer_response.rb +29 -0
- data/lib/epp-client/domain/update.rb +81 -0
- data/lib/epp-client/domain/update_response.rb +9 -0
- data/lib/epp-client/host/check.rb +23 -0
- data/lib/epp-client/host/check_response.rb +22 -0
- data/lib/epp-client/host/command.rb +47 -0
- data/lib/epp-client/host/create.rb +24 -0
- data/lib/epp-client/host/create_response.rb +14 -0
- data/lib/epp-client/host/delete.rb +21 -0
- data/lib/epp-client/host/delete_response.rb +9 -0
- data/lib/epp-client/host/info.rb +21 -0
- data/lib/epp-client/host/info_response.rb +42 -0
- data/lib/epp-client/host/response.rb +34 -0
- data/lib/epp-client/host/update.rb +76 -0
- data/lib/epp-client/host/update_response.rb +9 -0
- data/lib/epp-client/request.rb +29 -74
- data/lib/epp-client/requests/abstract.rb +30 -0
- data/lib/epp-client/requests/command.rb +28 -0
- data/lib/epp-client/requests/extension.rb +28 -0
- data/lib/epp-client/requests/hello.rb +12 -0
- data/lib/epp-client/response.rb +45 -8
- data/lib/epp-client/response_helper.rb +25 -0
- data/lib/epp-client/server.rb +167 -63
- data/lib/epp-client/testing.rb +59 -0
- data/lib/epp-client/version.rb +3 -0
- data/lib/epp-client/xml_helper.rb +71 -0
- data/test/commands/test_check_command.rb +33 -0
- data/test/commands/test_create_command.rb +53 -0
- data/test/commands/test_delete_command.rb +28 -0
- data/test/commands/test_info_command.rb +28 -0
- data/test/commands/test_login_command.rb +56 -0
- data/test/commands/test_logout_command.rb +22 -0
- data/test/commands/test_poll_command.rb +54 -0
- data/test/commands/test_renew_command.rb +39 -0
- data/test/commands/test_transfer_command.rb +37 -0
- data/test/commands/test_update_command.rb +60 -0
- data/test/contact/test_contact_check.rb +33 -0
- data/test/contact/test_contact_check_response.rb +38 -0
- data/test/contact/test_contact_create.rb +70 -0
- data/test/contact/test_contact_create_response.rb +33 -0
- data/test/contact/test_contact_delete.rb +28 -0
- data/test/contact/test_contact_delete_response.rb +23 -0
- data/test/contact/test_contact_info.rb +28 -0
- data/test/contact/test_contact_info_response.rb +100 -0
- data/test/contact/test_contact_transfer.rb +28 -0
- data/test/contact/test_contact_transfer_response.rb +100 -0
- data/test/contact/test_contact_update.rb +83 -0
- data/test/contact/test_contact_update_response.rb +23 -0
- data/test/domain/test_domain_check.rb +33 -0
- data/test/domain/test_domain_check_response.rb +38 -0
- data/test/domain/test_domain_create.rb +53 -0
- data/test/domain/test_domain_create_response.rb +39 -0
- data/test/domain/test_domain_delete.rb +28 -0
- data/test/domain/test_domain_delete_response.rb +23 -0
- data/test/domain/test_domain_info.rb +28 -0
- data/test/domain/test_domain_info_response.rb +107 -0
- data/test/domain/test_domain_renew.rb +39 -0
- data/test/domain/test_domain_renew_response.rb +32 -0
- data/test/domain/test_domain_transfer.rb +37 -0
- data/test/domain/test_domain_transfer_response.rb +112 -0
- data/test/domain/test_domain_update.rb +73 -0
- data/test/domain/test_domain_update_response.rb +23 -0
- data/test/fixtures/responses/contact/check.xml +27 -0
- data/test/fixtures/responses/contact/create.xml +19 -0
- data/test/fixtures/responses/contact/delete.xml +12 -0
- data/test/fixtures/responses/contact/info.xml +49 -0
- data/test/fixtures/responses/contact/transfer-query.xml +23 -0
- data/test/fixtures/responses/contact/transfer-request.xml +23 -0
- data/test/fixtures/responses/contact/update.xml +12 -0
- data/test/fixtures/responses/domain/check.xml +27 -0
- data/test/fixtures/responses/domain/create.xml +20 -0
- data/test/fixtures/responses/domain/delete.xml +12 -0
- data/test/fixtures/responses/domain/info-no-exDate.xml +38 -0
- data/test/fixtures/responses/domain/info.xml +39 -0
- data/test/fixtures/responses/domain/renew.xml +19 -0
- data/test/fixtures/responses/domain/transfer-query.xml +24 -0
- data/test/fixtures/responses/domain/transfer-request.xml +24 -0
- data/test/fixtures/responses/domain/update.xml +12 -0
- data/test/fixtures/responses/greeting.xml +25 -0
- data/test/fixtures/responses/host/check.xml +27 -0
- data/test/fixtures/responses/host/create.xml +19 -0
- data/test/fixtures/responses/host/delete.xml +12 -0
- data/test/fixtures/responses/host/info.xml +30 -0
- data/test/fixtures/responses/host/update.xml +12 -0
- data/test/helper.rb +89 -0
- data/test/host/test_host_check.rb +33 -0
- data/test/host/test_host_check_response.rb +38 -0
- data/test/host/test_host_create.rb +37 -0
- data/test/host/test_host_create_response.rb +33 -0
- data/test/host/test_host_delete.rb +28 -0
- data/test/host/test_host_delete_response.rb +23 -0
- data/test/host/test_host_info.rb +28 -0
- data/test/host/test_host_info_response.rb +72 -0
- data/test/host/test_host_update.rb +68 -0
- data/test/host/test_host_update_response.rb +23 -0
- data/test/requests/test_command_request.rb +16 -0
- data/test/requests/test_extension_request.rb +55 -0
- data/test/requests/test_hello_request.rb +15 -0
- data/test/support/schemas/all.xsd +21 -0
- data/test/support/schemas/contact-1.0.xsd +387 -0
- data/test/support/schemas/domain-1.0.xsd +432 -0
- data/test/support/schemas/epp-1.0.xsd +403 -0
- data/test/support/schemas/eppcom-1.0.xsd +93 -0
- data/test/support/schemas/host-1.0.xsd +240 -0
- data/test/test_client.rb +54 -0
- data/test/test_request.rb +15 -0
- data/test/test_server.rb +57 -0
- metadata +270 -91
- data/.document +0 -5
- data/README.rdoc +0 -17
- data/VERSION +0 -1
- data/lib/epp-client/hello_request.rb +0 -9
- data/test/test_epp-client.rb +0 -7
data/lib/epp-client/request.rb
CHANGED
@@ -1,96 +1,51 @@
|
|
1
1
|
module EPP
|
2
2
|
# An EPP XML Request
|
3
3
|
class Request
|
4
|
-
|
5
|
-
#
|
6
|
-
# @overload initialize(command, payload, transaction_id)
|
7
|
-
# @param [String, #to_s] command EPP Command to call
|
8
|
-
# @param [XML::Node, XML::Document, String] payload XML Payload to transmit
|
9
|
-
# @param [String] transaction_id EPP Transaction ID
|
10
|
-
# @overload initialize(command, transaction_id) {|xml| payload }
|
11
|
-
# @param [String, #to_s] command EPP Command to call
|
12
|
-
# @param [String] transaction_id EPP Transaction ID
|
13
|
-
# @yield [xml] block to construct payload
|
14
|
-
# @yieldparam [XML::Node] xml XML Node of the command
|
15
|
-
# for the payload to be added into
|
16
|
-
def initialize(command, *args, &block)
|
17
|
-
@command = XML::Node.new(command)
|
18
|
-
|
19
|
-
cmd = XML::Node.new('command')
|
20
|
-
cmd << @command
|
21
|
-
xml.root << cmd
|
4
|
+
include XMLHelpers
|
22
5
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
else
|
29
|
-
@command << block.call
|
30
|
-
end
|
31
|
-
else
|
32
|
-
payload, tid = args
|
33
|
-
unless payload.nil?
|
34
|
-
@command << case payload.class
|
35
|
-
when XML::Node
|
36
|
-
payload
|
37
|
-
when XML::Document
|
38
|
-
xml.import(payload.root)
|
39
|
-
else
|
40
|
-
doc = XML::Parser.string(payload.to_s).parse
|
41
|
-
xml.import(doc.root)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
unless command == 'logout'
|
47
|
-
cmd << XML::Node.new('clTRID', tid || 'ABC-12345')
|
48
|
-
end
|
6
|
+
# Create and return a new EPP Request Payload
|
7
|
+
#
|
8
|
+
# @param [EPP::Request]
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
49
11
|
end
|
50
12
|
|
51
|
-
|
52
|
-
|
53
|
-
def command
|
54
|
-
@command.name
|
13
|
+
def namespaces
|
14
|
+
@namespaces
|
55
15
|
end
|
56
16
|
|
57
17
|
# Receiver in XML form
|
58
18
|
# @return [XML::Document] XML of the receiver
|
59
19
|
def to_xml
|
60
|
-
|
20
|
+
doc = XML::Document.new('1.0')
|
21
|
+
doc.root = XML::Node.new('epp')
|
22
|
+
root = doc.root
|
23
|
+
|
24
|
+
epp_ns = XML::Namespace.new(root, nil, 'urn:ietf:params:xml:ns:epp-1.0')
|
25
|
+
root.namespaces.namespace = epp_ns
|
26
|
+
|
27
|
+
xsi_ns = XML::Namespace.new(root, 'xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
28
|
+
xsi_sL = XML::Attr.new(root, 'schemaLocation', 'urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd')
|
29
|
+
xsi_sL.namespaces.namespace = xsi_ns
|
30
|
+
|
31
|
+
@namespaces = {'epp' => epp_ns, 'xsi' => xsi_ns}
|
32
|
+
|
33
|
+
@request.set_namespaces(@namespaces) if @request.respond_to?(:set_namespaces)
|
34
|
+
root << @request.to_xml
|
35
|
+
|
36
|
+
doc
|
61
37
|
end
|
62
38
|
|
63
39
|
# Convert the receiver to a string
|
64
40
|
#
|
65
41
|
# @param [Hash] opts Formatting options, passed to the XML::Document
|
66
42
|
def to_s(opts = {})
|
67
|
-
|
43
|
+
to_xml.to_s({:indent => false}.merge(opts))
|
68
44
|
end
|
69
45
|
|
70
46
|
# @see Object#inspect
|
71
|
-
def inspect
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
# Request XML Payload
|
77
|
-
# @see prepare_request
|
78
|
-
def xml
|
79
|
-
@xml ||= prepare_request
|
80
|
-
end
|
81
|
-
|
82
|
-
# Prepares the base XML for the request
|
83
|
-
#
|
84
|
-
# @return [XML::Document]
|
85
|
-
def prepare_request
|
86
|
-
xml = XML::Document.new('1.0')
|
87
|
-
xml.root = XML::Node.new('epp')
|
88
|
-
xml.root.namespaces.namespace =
|
89
|
-
XML::Namespace.new(xml.root, nil, 'urn:ietf:params:xml:ns:epp-1.0')
|
90
|
-
XML::Namespace.new(xml.root, 'xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
91
|
-
xml.root['xsi:schemaLocation'] = "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
|
92
|
-
|
93
|
-
xml
|
94
|
-
end
|
47
|
+
# def inspect
|
48
|
+
# "#<#{self.class}>"
|
49
|
+
# end
|
95
50
|
end
|
96
51
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module EPP
|
2
|
+
module Requests
|
3
|
+
# @note Abstract class, do not instanciate manually
|
4
|
+
class Abstract
|
5
|
+
include XMLHelpers
|
6
|
+
attr_reader :namespaces
|
7
|
+
|
8
|
+
def set_namespaces(namespaces)
|
9
|
+
@namespaces = namespaces
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
raise NotImplementedError, "#name must be overriden by subclasses"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Receiver in XML form
|
17
|
+
# @return [XML::Document] XML of the receiver
|
18
|
+
def to_xml
|
19
|
+
epp_node(name, @namespaces || {})
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convert the receiver to a string
|
23
|
+
#
|
24
|
+
# @param [Hash] opts Formatting options, passed to the XML::Document
|
25
|
+
def to_s(opts = {})
|
26
|
+
to_xml.to_s({:indent => false}.merge(opts))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path('../abstract', __FILE__)
|
2
|
+
|
3
|
+
module EPP
|
4
|
+
module Requests
|
5
|
+
class Command < Abstract
|
6
|
+
def initialize(tid, command, extension = nil)
|
7
|
+
@tid, @command, @extension = tid, command, extension
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
'command'
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml
|
15
|
+
node = super
|
16
|
+
|
17
|
+
@command.set_namespaces(@namespaces) if @command.respond_to?(:set_namespaces)
|
18
|
+
@extension.set_namespaces(@namespaces) if @extension && @extension.respond_to?(:set_namespaces)
|
19
|
+
|
20
|
+
node << as_xml(@command)
|
21
|
+
node << as_xml(@extension) if @extension
|
22
|
+
node << epp_node('clTRID', @tid, @namespaces)
|
23
|
+
|
24
|
+
node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path('../abstract', __FILE__)
|
2
|
+
|
3
|
+
module EPP
|
4
|
+
module Requests
|
5
|
+
class Extension < Abstract
|
6
|
+
def initialize(*extensions)
|
7
|
+
raise ArgumentError, "you must provide at least one extension" if extensions.compact.empty?
|
8
|
+
@extensions = extensions.compact
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
'extension'
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
node = super
|
17
|
+
|
18
|
+
Array(@extensions).each do |extension|
|
19
|
+
next if extension.nil?
|
20
|
+
extension.set_namespaces(@namespaces) if extension.respond_to?(:set_namespaces)
|
21
|
+
node << as_xml(extension)
|
22
|
+
end
|
23
|
+
|
24
|
+
node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/epp-client/response.rb
CHANGED
@@ -15,6 +15,10 @@ module EPP
|
|
15
15
|
code == 1000
|
16
16
|
end
|
17
17
|
|
18
|
+
def pending?
|
19
|
+
code == 1001
|
20
|
+
end
|
21
|
+
|
18
22
|
# Response code
|
19
23
|
# @return [Integer] response code
|
20
24
|
def code
|
@@ -27,14 +31,30 @@ module EPP
|
|
27
31
|
@message ||= result.find('e:msg/text()').first.content.strip
|
28
32
|
end
|
29
33
|
|
34
|
+
# Descriptive Error Information
|
35
|
+
# @return [XML::Node] error information
|
36
|
+
def error_value
|
37
|
+
@error_value ||= result.find('e:extValue/e:value/node()').first
|
38
|
+
end
|
39
|
+
|
40
|
+
# Error reason
|
41
|
+
# @return [String] error reason
|
42
|
+
def error_reason
|
43
|
+
unless defined?(@error_reason)
|
44
|
+
reason = result.find('e:extValue/e:reason/text()').first
|
45
|
+
@error_reason = reason && reason.content.strip
|
46
|
+
end
|
47
|
+
|
48
|
+
@error_reason
|
49
|
+
end
|
50
|
+
|
30
51
|
# Response data
|
31
|
-
# @return [
|
52
|
+
# @return [XML::Node, Array<XML::Node>] response data
|
32
53
|
def data
|
33
|
-
|
34
|
-
list = @xml.find('/e:epp/e:response/e:resData/node()').reject{|n| n.empty?}
|
35
|
-
|
54
|
+
@data ||= begin
|
55
|
+
list = @xml.find('/e:epp/e:response/e:resData/node()').reject { |n| n.empty? }
|
56
|
+
list.size > 1 ? list : list[0]
|
36
57
|
end
|
37
|
-
@data
|
38
58
|
end
|
39
59
|
|
40
60
|
# Response Message Queue
|
@@ -43,15 +63,32 @@ module EPP
|
|
43
63
|
@msgQ ||= @xml.find('/e:epp/e:response/e:msgQ').first
|
44
64
|
end
|
45
65
|
|
66
|
+
# Response extension block
|
67
|
+
# @return [XML::Node, Array<XML::Node>] extension
|
68
|
+
def extension
|
69
|
+
@extension ||= begin
|
70
|
+
list = @xml.find('/e:epp/e:response/e:extension/node()').reject { |n| n.empty? }
|
71
|
+
list.size > 1 ? list : list[0]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
46
75
|
# @see Object#inspect
|
47
76
|
def inspect
|
48
77
|
@xml.inspect
|
49
78
|
end
|
50
79
|
|
51
|
-
# Returns
|
52
|
-
# @return [
|
80
|
+
# Returns the XML response document
|
81
|
+
# @return [XML::Document] XML response document
|
53
82
|
def to_xml
|
54
|
-
@xml
|
83
|
+
@xml
|
84
|
+
end
|
85
|
+
|
86
|
+
# Convert the receiver to a string
|
87
|
+
#
|
88
|
+
# @param [Hash] opts Formatting options, passed to the XML::Document
|
89
|
+
# @return [String] formatted XML response
|
90
|
+
def to_s(opts = {})
|
91
|
+
@xml.to_s({:indent => false}.merge(opts))
|
55
92
|
end
|
56
93
|
|
57
94
|
private
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EPP
|
2
|
+
module ResponseHelper
|
3
|
+
def value_for_xpath(xpath, base = nil, &block)
|
4
|
+
values_for_xpath(xpath, base, &block).first
|
5
|
+
end
|
6
|
+
def values_for_xpath(xpath, base = nil)
|
7
|
+
nodes_for_xpath(xpath, base).map do |node|
|
8
|
+
if block_given?
|
9
|
+
yield node
|
10
|
+
else
|
11
|
+
case node
|
12
|
+
when XML::Node
|
13
|
+
node.content.strip
|
14
|
+
when XML::Attr
|
15
|
+
node.value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def nodes_for_xpath(xpath, base = nil)
|
21
|
+
base ||= @response.data
|
22
|
+
base.find(xpath, namespaces)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/epp-client/server.rb
CHANGED
@@ -1,18 +1,47 @@
|
|
1
1
|
module EPP
|
2
2
|
# A server error
|
3
|
-
class ServerError <
|
3
|
+
class ServerError < Error; end
|
4
|
+
|
5
|
+
# A connection error
|
6
|
+
class ConnectionError < Error
|
7
|
+
attr_reader :error, :addr, :peeraddr
|
8
|
+
def initialize(message, addr, peeraddr, error)
|
9
|
+
super(message)
|
10
|
+
@error = error
|
11
|
+
@addr = addr
|
12
|
+
@peeraddr = peeraddr
|
13
|
+
end
|
14
|
+
end
|
4
15
|
|
5
16
|
# Handles sending and receiving data to EPP servers.
|
6
17
|
# Supports new style EPP servers which include length of payloads in transmission.
|
7
18
|
class Server
|
19
|
+
# @!attribute DEFAULT_SERVICES
|
20
|
+
# Provided for legacy clients who might be using it.
|
21
|
+
# The constant has been moved into the EPP::Client class which
|
22
|
+
# is the primary client facing API.
|
23
|
+
#
|
24
|
+
# @deprecated please use EPP::Client::DEFAULT_SERVICES
|
25
|
+
# @see EPP::Client::DEFAULT_SERVICES
|
8
26
|
|
9
|
-
#
|
10
|
-
|
11
|
-
|
27
|
+
# Handles emitting warnings for deprecated constants.
|
28
|
+
#
|
29
|
+
# @private
|
30
|
+
# @param [Symbol] const_name Name of the missing constant
|
31
|
+
# @see Module.const_missing
|
32
|
+
def self.const_missing(const_name)
|
33
|
+
case const_name
|
34
|
+
when :DEFAULT_SERVICES
|
35
|
+
warn "EPP::Server::DEFAULT_SERVICES has been deprecated, please use EPP::Client::DEFAULT_SERVICES"
|
36
|
+
EPP::Client::DEFAULT_SERVICES
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
12
41
|
|
13
42
|
# Default connection options
|
14
43
|
DEFAULTS = { :port => 700, :compatibility => false, :lang => 'en', :version => '1.0',
|
15
|
-
:extensions => [], :services => DEFAULT_SERVICES }
|
44
|
+
:extensions => [], :services => EPP::Client::DEFAULT_SERVICES, :address_family => nil }
|
16
45
|
|
17
46
|
# Receive frame header length
|
18
47
|
# @private
|
@@ -28,6 +57,9 @@ module EPP
|
|
28
57
|
# @option options [String] :version EPP protocol version, default '1.0'
|
29
58
|
# @option options [Array<String>] :extensions EPP Extension URNs
|
30
59
|
# @option options [Array<String>] :services EPP Service URNs
|
60
|
+
# @option options [String] :address_family 'AF_INET' or 'AF_INET6' or either of the
|
61
|
+
# appropriate socket constants. Will cause connections to be
|
62
|
+
# limited to this address family. Default try all addresses.
|
31
63
|
def initialize(tag, passwd, host, options = {})
|
32
64
|
@tag, @passwd, @host = tag, passwd, host
|
33
65
|
@options = DEFAULTS.merge(options)
|
@@ -36,7 +68,9 @@ module EPP
|
|
36
68
|
# Sends a Hello Request to the server
|
37
69
|
# @return [Boolean] True if greeting was returned
|
38
70
|
def hello
|
39
|
-
|
71
|
+
hello = EPP::Requests::Hello.new
|
72
|
+
request = EPP::Request.new(hello)
|
73
|
+
send_frame(request)
|
40
74
|
return true if recv_frame =~ /<greeting>/
|
41
75
|
false
|
42
76
|
end
|
@@ -52,14 +86,31 @@ module EPP
|
|
52
86
|
# @yieldparam [XML::Node] xml XML Node of the command
|
53
87
|
# for the payload to be added into
|
54
88
|
# @return [Response] EPP Response object
|
55
|
-
def request(command, payload = nil, &block)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
89
|
+
# def request(command, payload = nil, extension = nil, &block)
|
90
|
+
# @req = if payload.nil? && block_given?
|
91
|
+
# Request.new(command, req_tid, &block)
|
92
|
+
# else
|
93
|
+
# Request.new(command, payload, extension, req_tid)
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# @resp = send_recv_frame(@req)
|
97
|
+
# end
|
98
|
+
|
99
|
+
# @note Primarily an internal method, exposed to enable testing
|
100
|
+
# @param [] command
|
101
|
+
# @param [] extension
|
102
|
+
# @return [EPP::Request]
|
103
|
+
# @see request
|
104
|
+
def prepare_request(command, extension = nil)
|
105
|
+
cmd = EPP::Requests::Command.new(req_tid, command, extension)
|
106
|
+
EPP::Request.new(cmd)
|
107
|
+
end
|
61
108
|
|
62
|
-
|
109
|
+
def request(command, extension = nil)
|
110
|
+
@req = command.is_a?(EPP::Request) ? command :
|
111
|
+
prepare_request(command, extension)
|
112
|
+
|
113
|
+
@resp = send_recv_frame(@req)
|
63
114
|
end
|
64
115
|
|
65
116
|
# Return the Request object created by the last call to #request
|
@@ -74,13 +125,33 @@ module EPP
|
|
74
125
|
def last_response
|
75
126
|
@resp
|
76
127
|
end
|
128
|
+
# Return the error from the last login or logout request
|
129
|
+
#
|
130
|
+
# @return [ResponseError] last error from login or logout
|
131
|
+
def last_error
|
132
|
+
@error
|
133
|
+
end
|
134
|
+
# Return the options the receiver was initialized with
|
135
|
+
#
|
136
|
+
# @return [Hash] configuration options
|
137
|
+
def options
|
138
|
+
@options
|
139
|
+
end
|
140
|
+
# Return the greeting XML received during the last connection
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
def greeting
|
144
|
+
@greeting
|
145
|
+
end
|
77
146
|
|
78
147
|
# Runs a block while logged into the receiver
|
79
148
|
#
|
80
149
|
# @yield logged in EPP server session
|
81
150
|
# @example typical usage
|
82
|
-
#
|
83
|
-
#
|
151
|
+
# connection do
|
152
|
+
# with_login do
|
153
|
+
# # .. do stuff with logged in session ..
|
154
|
+
# end
|
84
155
|
# end
|
85
156
|
def with_login
|
86
157
|
login!
|
@@ -106,57 +177,81 @@ module EPP
|
|
106
177
|
# end
|
107
178
|
# end
|
108
179
|
def connection
|
109
|
-
@
|
110
|
-
|
111
|
-
|
180
|
+
@connection_errors = []
|
181
|
+
addrinfo.each do |_,port,_,addr,_,_,_|
|
182
|
+
retried = false
|
183
|
+
begin
|
184
|
+
@conn = TCPSocket.new(addr, port)
|
185
|
+
rescue Errno::EINVAL => e
|
186
|
+
if retried
|
187
|
+
message = e.message.split(" - ")[1]
|
188
|
+
raise Errno::EINVAL, "#{message}: TCPSocket.new(#{addr.inspect}, #{port.inspect})"
|
189
|
+
end
|
112
190
|
|
113
|
-
|
114
|
-
|
115
|
-
|
191
|
+
retried = true
|
192
|
+
retry
|
193
|
+
end
|
116
194
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
195
|
+
@sock = OpenSSL::SSL::SSLSocket.new(@conn)
|
196
|
+
@sock.sync_close = true
|
197
|
+
|
198
|
+
begin
|
199
|
+
@sock.connect
|
200
|
+
@greeting = recv_frame # Perform initial recv
|
201
|
+
|
202
|
+
return yield
|
203
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH => e
|
204
|
+
@connection_errors << e
|
205
|
+
next # try the next address in the list
|
206
|
+
rescue OpenSSL::SSL::SSLError => e
|
207
|
+
# Connection error, most likely the IP isn't in the allow list
|
208
|
+
if e.message =~ /returned=5 errno=0/
|
209
|
+
@connection_errors << ConnectionError.new("SSL Connection error, IP may not be permitted to connect to #{@host}",
|
210
|
+
@conn.addr, @conn.peeraddr, e)
|
211
|
+
next
|
212
|
+
else
|
213
|
+
raise e
|
214
|
+
end
|
215
|
+
ensure
|
216
|
+
@sock.close # closes @conn
|
217
|
+
@conn = @sock = nil
|
218
|
+
end
|
122
219
|
end
|
220
|
+
|
221
|
+
# Should only get here if we didn't return from the block above
|
222
|
+
|
223
|
+
addrinfo(true) # Update our addrinfo in case the DNS has changed
|
224
|
+
raise @connection_errors.last unless @connection_errors.empty?
|
225
|
+
raise Errno::EHOSTUNREACH, "Failed to connect to host #{@host}"
|
123
226
|
end
|
124
227
|
private
|
125
|
-
|
126
|
-
|
127
|
-
@
|
128
|
-
@tid += 1
|
129
|
-
"%s-%06d" % [@tag, @tid]
|
228
|
+
def addrinfo(refresh = false)
|
229
|
+
@addrinfo = nil if refresh
|
230
|
+
@addrinfo ||= resolve_addrinfo
|
130
231
|
end
|
232
|
+
def resolve_addrinfo
|
233
|
+
family = case @options[:address_family]
|
234
|
+
when 'AF_INET', Socket::AF_INET then Socket::AF_INET
|
235
|
+
when 'AF_INET6', Socket::AF_INET6 then Socket::AF_INET6
|
236
|
+
else nil end
|
131
237
|
|
132
|
-
|
133
|
-
def login_request
|
134
|
-
Request.new('login', next_tid) do |login|
|
135
|
-
login << XML::Node.new('clID', @tag)
|
136
|
-
login << XML::Node.new('pw', @passwd)
|
137
|
-
|
138
|
-
options = XML::Node.new('options')
|
139
|
-
options << XML::Node.new('version', @options[:version])
|
140
|
-
options << XML::Node.new('lang', @options[:lang])
|
141
|
-
login << options
|
142
|
-
|
143
|
-
svcs = XML::Node.new('svcs')
|
144
|
-
@options[:services].each { |uri| svcs << XML::Node.new('objURI', uri) }
|
145
|
-
login << svcs
|
146
|
-
|
147
|
-
unless @options[:extensions].empty?
|
148
|
-
ext = XML::Node.new('svcExtension')
|
149
|
-
@options[:extensions].each do |uri|
|
150
|
-
ext << XML::Node.new('extURI', uri)
|
151
|
-
end
|
152
|
-
svcs << ext
|
153
|
-
end
|
154
|
-
end
|
238
|
+
Socket.getaddrinfo(@host, @options[:port], family, Socket::SOCK_STREAM)
|
155
239
|
end
|
156
240
|
|
157
|
-
# @return [
|
158
|
-
def
|
159
|
-
|
241
|
+
# @return [String] next transaction id
|
242
|
+
def req_tid
|
243
|
+
@req_tid ||= 0
|
244
|
+
@req_tid += 1
|
245
|
+
date = Time.now.strftime("%Y%m%d")
|
246
|
+
"%s-%s%06d" % [@tag, date, @req_tid]
|
247
|
+
end
|
248
|
+
|
249
|
+
# @return [String] next auth transaction id
|
250
|
+
def auth_tid
|
251
|
+
@auth_tid ||= 0
|
252
|
+
@auth_tid += 1
|
253
|
+
date = Time.now.strftime("%Y%m%d")
|
254
|
+
"%s-AUTH-%s%06d" % [@tag, date, @auth_tid]
|
160
255
|
end
|
161
256
|
|
162
257
|
# Perform login
|
@@ -165,10 +260,14 @@ module EPP
|
|
165
260
|
# @raise [ResponseError] login failed
|
166
261
|
# @see login_request
|
167
262
|
def login!
|
168
|
-
|
263
|
+
@error = nil
|
264
|
+
login = EPP::Commands::Login.new(@tag, @passwd, @options)
|
265
|
+
command = EPP::Requests::Command.new(auth_tid, login)
|
266
|
+
request = EPP::Request.new(command)
|
267
|
+
response = send_recv_frame(request)
|
169
268
|
|
170
269
|
return true if response.code == 1000
|
171
|
-
raise ResponseError.new(response.code, response.message, response.to_xml)
|
270
|
+
raise @error = ResponseError.new(response.code, response.message, response.to_xml)
|
172
271
|
end
|
173
272
|
|
174
273
|
# Perform logout
|
@@ -177,10 +276,13 @@ module EPP
|
|
177
276
|
# @raise [ResponseError] logout failed
|
178
277
|
# @see logout_request
|
179
278
|
def logout!
|
180
|
-
|
279
|
+
logout = EPP::Commands::Logout.new
|
280
|
+
command = EPP::Requests::Command.new(auth_tid, logout)
|
281
|
+
request = EPP::Request.new(command)
|
282
|
+
response = send_recv_frame(request)
|
181
283
|
|
182
284
|
return true if response.code == 1500
|
183
|
-
raise ResponseError.new(response.code, response.message, response.to_xml)
|
285
|
+
raise @error = ResponseError.new(response.code, response.message, response.to_xml)
|
184
286
|
end
|
185
287
|
|
186
288
|
# Send a frame and receive its response
|
@@ -195,9 +297,11 @@ module EPP
|
|
195
297
|
end
|
196
298
|
|
197
299
|
# Send XML frame
|
300
|
+
# @param [String,Request] xml Payload to send
|
198
301
|
# @return [Integer] number of bytes written
|
199
302
|
def send_frame(xml)
|
200
|
-
|
303
|
+
xml = xml.to_s if xml.kind_of?(Request)
|
304
|
+
@sock.write([xml.size + HEADER_LEN].pack("N") + xml)
|
201
305
|
end
|
202
306
|
|
203
307
|
# Receive XML frame
|
@@ -211,7 +315,7 @@ module EPP
|
|
211
315
|
raise ServerError, "Failed to read header from remote host"
|
212
316
|
else
|
213
317
|
len = header.unpack('N')[0]
|
214
|
-
|
318
|
+
|
215
319
|
raise ServerError, "Bad frame header from server, should be greater than #{HEADER_LEN}" unless len > HEADER_LEN
|
216
320
|
response = @sock.read(len - HEADER_LEN)
|
217
321
|
end
|