epp 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -2
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/epp.gemspec +18 -5
- data/lib/epp/exceptions.rb +7 -3
- data/lib/epp/server.rb +63 -106
- data/test/test_epp.rb +361 -0
- data/test/test_helper.rb +2 -0
- data/test/xml/error.xml +14 -0
- data/test/xml/login_request.xml +1 -0
- data/test/xml/login_response.xml +12 -0
- data/test/xml/login_with_extensions_request.xml +1 -0
- data/test/xml/logout_request.xml +1 -0
- data/test/xml/logout_response.xml +12 -0
- data/test/xml/new_request.xml +1 -0
- data/test/xml/socket_preparation.xml +27 -0
- data/test/xml/test_request.xml +4 -0
- data/test/xml/test_response.xml +26 -0
- metadata +33 -9
- data/test/epp_test.rb +0 -7
data/README.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
= EPP (by {Ultraspeed}[http://ultraspeed.co.uk])
|
1
|
+
= EPP v1.3.0 (by {Ultraspeed}[http://ultraspeed.co.uk])
|
2
2
|
|
3
|
-
The EPP gem provides basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers.
|
3
|
+
The EPP gem provides basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers. It has been fully tested against the RFC 5730 & 5734 specification.
|
4
|
+
|
5
|
+
Currently, major providers Centralnic and Nominet have been integrated using this gem. CoCCA is currently in testing.
|
4
6
|
|
5
7
|
* {Nominet Standard EPP Documentation}[http://www.nominet.org.uk/registrars/systems/standardepp/]
|
6
8
|
* {Centralnic Labs EPP Documentation}[http://labs.centralnic.com/epp/]
|
data/Rakefile
CHANGED
@@ -14,6 +14,7 @@ begin
|
|
14
14
|
|
15
15
|
# Dependencies
|
16
16
|
gem.add_development_dependency "shoulda"
|
17
|
+
gem.add_development_dependency "mocha"
|
17
18
|
gem.add_dependency "activesupport"
|
18
19
|
gem.add_dependency "hpricot"
|
19
20
|
end
|
@@ -24,7 +25,7 @@ end
|
|
24
25
|
require 'rake/testtask'
|
25
26
|
Rake::TestTask.new(:test) do |test|
|
26
27
|
test.libs << 'lib' << 'test'
|
27
|
-
test.pattern = 'test
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
28
29
|
test.verbose = true
|
29
30
|
end
|
30
31
|
|
@@ -33,7 +34,7 @@ begin
|
|
33
34
|
|
34
35
|
Rcov::RcovTask.new do |test|
|
35
36
|
test.libs << 'test'
|
36
|
-
test.pattern = 'test
|
37
|
+
test.pattern = 'test/**/test_*.rb'
|
37
38
|
test.verbose = true
|
38
39
|
end
|
39
40
|
rescue LoadError
|
@@ -45,7 +46,6 @@ end
|
|
45
46
|
task :test => :check_dependencies
|
46
47
|
task :default => :test
|
47
48
|
|
48
|
-
require 'sdoc'
|
49
49
|
require 'rake/rdoctask'
|
50
50
|
Rake::RDocTask.new do |rdoc|
|
51
51
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/epp.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{epp}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Josh Delsman"]
|
12
|
-
s.date = %q{2010-07-
|
12
|
+
s.date = %q{2010-07-07}
|
13
13
|
s.description = %q{Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers}
|
14
14
|
s.email = %q{jdelsman@ultraspeed.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,8 +26,18 @@ Gem::Specification.new do |s|
|
|
26
26
|
"lib/epp/exceptions.rb",
|
27
27
|
"lib/epp/server.rb",
|
28
28
|
"lib/require_parameters.rb",
|
29
|
-
"test/
|
30
|
-
"test/test_helper.rb"
|
29
|
+
"test/test_epp.rb",
|
30
|
+
"test/test_helper.rb",
|
31
|
+
"test/xml/error.xml",
|
32
|
+
"test/xml/login_request.xml",
|
33
|
+
"test/xml/login_response.xml",
|
34
|
+
"test/xml/login_with_extensions_request.xml",
|
35
|
+
"test/xml/logout_request.xml",
|
36
|
+
"test/xml/logout_response.xml",
|
37
|
+
"test/xml/new_request.xml",
|
38
|
+
"test/xml/socket_preparation.xml",
|
39
|
+
"test/xml/test_request.xml",
|
40
|
+
"test/xml/test_response.xml"
|
31
41
|
]
|
32
42
|
s.homepage = %q{http://github.com/ultraspeed/epp}
|
33
43
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -35,7 +45,7 @@ Gem::Specification.new do |s|
|
|
35
45
|
s.rubygems_version = %q{1.3.7}
|
36
46
|
s.summary = %q{EPP (Extensible Provisioning Protocol) for Ruby}
|
37
47
|
s.test_files = [
|
38
|
-
"test/
|
48
|
+
"test/test_epp.rb",
|
39
49
|
"test/test_helper.rb"
|
40
50
|
]
|
41
51
|
|
@@ -45,15 +55,18 @@ Gem::Specification.new do |s|
|
|
45
55
|
|
46
56
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
57
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
48
59
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
49
60
|
s.add_runtime_dependency(%q<hpricot>, [">= 0"])
|
50
61
|
else
|
51
62
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
63
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
52
64
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
53
65
|
s.add_dependency(%q<hpricot>, [">= 0"])
|
54
66
|
end
|
55
67
|
else
|
56
68
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
69
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
57
70
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
58
71
|
s.add_dependency(%q<hpricot>, [">= 0"])
|
59
72
|
end
|
data/lib/epp/exceptions.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
class EppErrorResponse < StandardError #:nodoc:
|
2
|
+
include RequiresParameters
|
3
|
+
|
2
4
|
attr_accessor :response_xml, :response_code, :message
|
3
5
|
|
4
6
|
# Generic EPP exception. Accepts a response code and a message
|
5
7
|
def initialize(attributes = {})
|
6
|
-
|
7
|
-
|
8
|
-
@
|
8
|
+
requires!(attributes, :xml, :code, :message)
|
9
|
+
|
10
|
+
@response_xml = attributes[:xml]
|
11
|
+
@response_code = attributes[:code]
|
12
|
+
@message = attributes[:message]
|
9
13
|
end
|
10
14
|
|
11
15
|
def to_s
|
data/lib/epp/server.rb
CHANGED
@@ -3,7 +3,7 @@ module Epp #:nodoc:
|
|
3
3
|
include REXML
|
4
4
|
include RequiresParameters
|
5
5
|
|
6
|
-
attr_accessor :tag, :password, :server, :port, :
|
6
|
+
attr_accessor :tag, :password, :server, :port, :services, :lang, :extensions, :version
|
7
7
|
|
8
8
|
# ==== Required Attrbiutes
|
9
9
|
#
|
@@ -15,7 +15,6 @@ module Epp #:nodoc:
|
|
15
15
|
#
|
16
16
|
# * <tt>:port</tt> - The EPP standard port is 700. However, you can choose a different port to use.
|
17
17
|
# * <tt>:clTRID</tt> - The client transaction identifier is an element that EPP specifies MAY be used to uniquely identify the command to the server. You are responsible for maintaining your own transaction identifier space to ensure uniqueness. Defaults to "ABC-12345"
|
18
|
-
# * <tt>:old_server</tt> - Set to true to read and write frames in a way that is compatible with older EPP servers. Default is false.
|
19
18
|
# * <tt>:lang</tt> - Set custom language attribute. Default is 'en'.
|
20
19
|
# * <tt>:services</tt> - Use custom EPP services in the <login> frame. The defaults use the EPP standard domain, contact and host 1.0 services.
|
21
20
|
# * <tt>:extensions</tt> - URLs to custom extensions to standard EPP. Use these to extend the standard EPP (e.g., Nominet uses extensions). Defaults to none.
|
@@ -27,45 +26,16 @@ module Epp #:nodoc:
|
|
27
26
|
@password = attributes[:password]
|
28
27
|
@server = attributes[:server]
|
29
28
|
@port = attributes[:port] || 700
|
30
|
-
@old_server = attributes[:old_server] || false
|
31
29
|
@lang = attributes[:lang] || "en"
|
32
30
|
@services = attributes[:services] || ["urn:ietf:params:xml:ns:domain-1.0", "urn:ietf:params:xml:ns:contact-1.0", "urn:ietf:params:xml:ns:host-1.0"]
|
33
31
|
@extensions = attributes[:extensions] || []
|
34
|
-
@version = attributes[:
|
35
|
-
@debug_log = attributes[:debug_log] || false
|
32
|
+
@version = attributes[:version] || "1.0"
|
36
33
|
|
37
34
|
@logged_in = false
|
38
35
|
end
|
39
36
|
|
40
|
-
# Sends an XML request to the EPP server, and receives an XML response.
|
41
|
-
# <tt><login></tt> and <tt><logout></tt> requests are also wrapped
|
42
|
-
# around the request, so we can close the socket immediately after
|
43
|
-
# the request is made.
|
44
|
-
def request(xml)
|
45
|
-
open_connection
|
46
|
-
|
47
|
-
@logged_in = true if login
|
48
|
-
|
49
|
-
begin
|
50
|
-
puts "** EPP - Sending frame..." if @debug_log
|
51
|
-
@response = send_request(xml)
|
52
|
-
ensure
|
53
|
-
if @logged_in && !old_server
|
54
|
-
@logged_in = false if logout
|
55
|
-
end
|
56
|
-
|
57
|
-
close_connection
|
58
|
-
end
|
59
|
-
|
60
|
-
return @response
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
37
|
# Sends a standard login request to the EPP server.
|
66
|
-
def login
|
67
|
-
puts "** EPP - Attempting login..." if @debug_log
|
68
|
-
|
38
|
+
def login
|
69
39
|
xml = new_epp_request
|
70
40
|
|
71
41
|
command = xml.root.add_element("command")
|
@@ -83,7 +53,6 @@ module Epp #:nodoc:
|
|
83
53
|
services.add_element("objURI").text = "urn:ietf:params:xml:ns:contact-1.0"
|
84
54
|
services.add_element("objURI").text = "urn:ietf:params:xml:ns:host-1.0"
|
85
55
|
|
86
|
-
# Include schema extensions for registrars which require it
|
87
56
|
extensions_container = services.add_element("svcExtension") unless extensions.empty?
|
88
57
|
|
89
58
|
for uri in extensions
|
@@ -92,14 +61,12 @@ module Epp #:nodoc:
|
|
92
61
|
|
93
62
|
command.add_element("clTRID").text = "ABC-12345"
|
94
63
|
|
95
|
-
# Receive the login response
|
96
64
|
response = Hpricot.XML(send_request(xml.to_s))
|
97
65
|
|
98
66
|
result_message = (response/"epp"/"response"/"result"/"msg").text.strip
|
99
67
|
result_code = (response/"epp"/"response"/"result").attr("code").to_i
|
100
68
|
|
101
69
|
if result_code == 1000
|
102
|
-
puts "** EPP - Successfully logged in." if @debug_log
|
103
70
|
return true
|
104
71
|
else
|
105
72
|
raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
|
@@ -107,22 +74,18 @@ module Epp #:nodoc:
|
|
107
74
|
end
|
108
75
|
|
109
76
|
# Sends a standard logout request to the EPP server.
|
110
|
-
def logout
|
111
|
-
puts "** EPP - Attempting logout..." if @debug_log
|
112
|
-
|
77
|
+
def logout
|
113
78
|
xml = new_epp_request
|
114
79
|
|
115
80
|
command = xml.root.add_element("command")
|
116
81
|
login = command.add_element("logout")
|
117
82
|
|
118
|
-
# Receive the logout response
|
119
83
|
response = Hpricot.XML(send_request(xml.to_s))
|
120
84
|
|
121
85
|
result_message = (response/"epp"/"response"/"result"/"msg").text.strip
|
122
86
|
result_code = (response/"epp"/"response"/"result").attr("code").to_i
|
123
87
|
|
124
88
|
if result_code == 1500
|
125
|
-
puts "** EPP - Successfully logged out." if @debug_log
|
126
89
|
return true
|
127
90
|
else
|
128
91
|
raise EppErrorResponse.new(:xml => response, :code => result_code, :message => result_message)
|
@@ -142,6 +105,36 @@ module Epp #:nodoc:
|
|
142
105
|
return xml
|
143
106
|
end
|
144
107
|
|
108
|
+
def connection
|
109
|
+
@connection ||= TCPSocket.new(server, port)
|
110
|
+
end
|
111
|
+
|
112
|
+
def socket
|
113
|
+
@socket ||= OpenSSL::SSL::SSLSocket.new(connection) if connection
|
114
|
+
end
|
115
|
+
|
116
|
+
# Sends an XML request to the EPP server, and receives an XML response.
|
117
|
+
# <tt><login></tt> and <tt><logout></tt> requests are also wrapped
|
118
|
+
# around the request, so we can close the socket immediately after
|
119
|
+
# the request is made.
|
120
|
+
def request(xml)
|
121
|
+
open_connection
|
122
|
+
|
123
|
+
@logged_in = true if login
|
124
|
+
|
125
|
+
begin
|
126
|
+
@response = send_request(xml)
|
127
|
+
ensure
|
128
|
+
if @logged_in
|
129
|
+
@logged_in = false if logout
|
130
|
+
end
|
131
|
+
|
132
|
+
close_connection
|
133
|
+
end
|
134
|
+
|
135
|
+
return @response
|
136
|
+
end
|
137
|
+
|
145
138
|
# Wrapper which sends an XML frame to the server, and receives
|
146
139
|
# the response frame in return.
|
147
140
|
def send_request(xml)
|
@@ -154,40 +147,18 @@ module Epp #:nodoc:
|
|
154
147
|
# the EPP <tt><greeting></tt> frame which is sent by the
|
155
148
|
# server upon connection.
|
156
149
|
def open_connection
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
@socket.sync_close
|
162
|
-
|
163
|
-
# Connect
|
164
|
-
@socket.connect
|
165
|
-
|
166
|
-
# Get the initial frame
|
167
|
-
frame = get_frame
|
168
|
-
|
169
|
-
if frame
|
170
|
-
puts "EPP - Connection opened." if @debug_log
|
171
|
-
return frame
|
172
|
-
end
|
150
|
+
socket.sync_close
|
151
|
+
socket.connect
|
152
|
+
|
153
|
+
get_frame
|
173
154
|
end
|
174
155
|
|
175
156
|
# Closes the connection to the EPP server.
|
176
157
|
def close_connection
|
177
|
-
|
178
|
-
|
179
|
-
@socket = nil
|
180
|
-
end
|
181
|
-
|
182
|
-
if defined?(@connection) and @connection.is_a?(TCPSocket)
|
183
|
-
@connection.close
|
184
|
-
@connection = nil
|
185
|
-
end
|
158
|
+
socket.close
|
159
|
+
connection.close
|
186
160
|
|
187
|
-
|
188
|
-
puts "EPP - Connection closed." if @debug_log
|
189
|
-
return true
|
190
|
-
end
|
161
|
+
connection.closed? and socket.closed?
|
191
162
|
end
|
192
163
|
|
193
164
|
# Receive an EPP frame from the server. Since the connection is blocking,
|
@@ -195,48 +166,34 @@ module Epp #:nodoc:
|
|
195
166
|
# the connection is broken, a SocketError will be raised. Otherwise,
|
196
167
|
# it will return a string containing the XML from the server.
|
197
168
|
def get_frame
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
while char = @socket.read(1)
|
210
|
-
data << char
|
211
|
-
|
212
|
-
return data if data =~ %r|<\/epp>\n$|mi # at end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
else
|
216
|
-
header = @socket.read(4)
|
217
|
-
|
218
|
-
if header.nil? and @socket.eof?
|
219
|
-
raise SocketError.new("Connection closed by remote server")
|
220
|
-
elsif header.nil?
|
221
|
-
raise SocketError.new("Error reading frame from remote server")
|
222
|
-
else
|
223
|
-
unpacked_header = header.unpack("N")
|
224
|
-
length = unpacked_header[0]
|
225
|
-
|
226
|
-
if length < 5
|
227
|
-
raise SocketError.new("Got bad frame header length of #{length} bytes from the server")
|
228
|
-
else
|
229
|
-
response = @socket.read(length - 4)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
169
|
+
header = socket.read(4)
|
170
|
+
|
171
|
+
raise SocketError.new("Connection closed by remote server") if header.nil? and socket.eof?
|
172
|
+
raise SocketError.new("Error reading frame from remote server") if header.nil?
|
173
|
+
|
174
|
+
length = header_size(header)
|
175
|
+
|
176
|
+
raise SocketError.new("Got bad frame header length of #{length} bytes from the server") if length < 5
|
177
|
+
|
178
|
+
response = socket.read(length - 4)
|
233
179
|
end
|
234
180
|
|
235
181
|
# Send an XML frame to the server. Should return the total byte
|
236
182
|
# size of the frame sent to the server. If the socket returns EOF,
|
237
183
|
# the connection has closed and a SocketError is raised.
|
238
184
|
def send_frame(xml)
|
239
|
-
|
185
|
+
socket.write(packed(xml) + xml)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Pack the XML as a header for the EPP server.
|
189
|
+
def packed(xml)
|
190
|
+
[xml.size + 4].pack("N")
|
191
|
+
end
|
192
|
+
|
193
|
+
# Returns size of header of response from the EPP server.
|
194
|
+
def header_size(header)
|
195
|
+
unpacked_header = header.unpack("N")
|
196
|
+
unpacked_header[0]
|
240
197
|
end
|
241
198
|
end
|
242
199
|
end
|
data/test/test_epp.rb
ADDED
@@ -0,0 +1,361 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EppTest < Test::Unit::TestCase
|
4
|
+
context "EPP" do
|
5
|
+
context "server" do
|
6
|
+
setup do
|
7
|
+
@epp = Epp::Server.new(
|
8
|
+
:server => "test-epp.nominet.org.uk",
|
9
|
+
:tag => "TEST",
|
10
|
+
:password => "test"
|
11
|
+
)
|
12
|
+
|
13
|
+
@tcp_sock = mock('TCPSocket')
|
14
|
+
@ssl_sock = mock('OpenSSL::SSL::SSLSocket')
|
15
|
+
end
|
16
|
+
|
17
|
+
should "verify class name is Epp::Server" do
|
18
|
+
assert @epp.is_a?(Epp::Server)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "require server, tag and password attributes" do
|
22
|
+
assert_raises ArgumentError do
|
23
|
+
epp = Epp::Server.new(:tag => "a", :password => "a")
|
24
|
+
end
|
25
|
+
|
26
|
+
assert_raises ArgumentError do
|
27
|
+
epp = Epp::Server.new(:server => "a", :password => "a")
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_raises ArgumentError do
|
31
|
+
epp = Epp::Server.new(:server => "a", :tag => "a")
|
32
|
+
end
|
33
|
+
|
34
|
+
assert_nothing_raised do
|
35
|
+
epp = Epp::Server.new(:server => "a", :tag => "a", :password => "a")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
should "set instance variables for attributes" do
|
40
|
+
epp = Epp::Server.new(
|
41
|
+
:tag => "TAG",
|
42
|
+
:password => "f00bar",
|
43
|
+
:server => "nominet-epp.server.org.uk",
|
44
|
+
:port => 8700,
|
45
|
+
:lang => "es",
|
46
|
+
:services => ["urn:ietf:params:xml:ns:domain-nom-ext-1.1.xsd"],
|
47
|
+
:extensions => ["domain-nom-ext-1.1.xsd"],
|
48
|
+
:version => "90.0"
|
49
|
+
)
|
50
|
+
|
51
|
+
assert_equal "TAG", epp.tag
|
52
|
+
assert_equal "f00bar", epp.password
|
53
|
+
assert_equal "nominet-epp.server.org.uk", epp.server
|
54
|
+
assert_equal 8700, epp.port
|
55
|
+
assert_equal "es", epp.lang
|
56
|
+
assert_equal ["urn:ietf:params:xml:ns:domain-nom-ext-1.1.xsd"], epp.services
|
57
|
+
assert_equal ["domain-nom-ext-1.1.xsd"], epp.extensions
|
58
|
+
assert_equal "90.0", epp.version
|
59
|
+
end
|
60
|
+
|
61
|
+
should "build a new XML request" do
|
62
|
+
xml = xml_file("new_request.xml")
|
63
|
+
|
64
|
+
assert @epp.new_epp_request.is_a?(REXML::Document)
|
65
|
+
assert_equal xml, @epp.new_epp_request.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
should "have a TCP socket" do
|
69
|
+
TCPSocket.expects(:new).returns(@tcp_sock)
|
70
|
+
|
71
|
+
assert @epp.connection
|
72
|
+
end
|
73
|
+
|
74
|
+
should "have a SSL socket" do
|
75
|
+
TCPSocket.expects(:new).returns(@tcp_sock)
|
76
|
+
OpenSSL::SSL::SSLSocket.expects(:new).returns(@ssl_sock)
|
77
|
+
|
78
|
+
assert @epp.socket
|
79
|
+
end
|
80
|
+
|
81
|
+
should "open connection and receive a greeting" do
|
82
|
+
prepare_socket!
|
83
|
+
|
84
|
+
assert @epp.open_connection
|
85
|
+
end
|
86
|
+
|
87
|
+
should "return true if connection closed" do
|
88
|
+
prepare_socket!
|
89
|
+
|
90
|
+
@epp.open_connection
|
91
|
+
|
92
|
+
@tcp_sock.expects(:close).returns(nil)
|
93
|
+
@ssl_sock.expects(:close).returns(nil)
|
94
|
+
@tcp_sock.expects(:closed?).returns(true)
|
95
|
+
@ssl_sock.expects(:closed?).returns(true)
|
96
|
+
|
97
|
+
assert @epp.close_connection
|
98
|
+
end
|
99
|
+
|
100
|
+
should "return false if TCP socket not closed" do
|
101
|
+
prepare_socket!
|
102
|
+
|
103
|
+
@epp.open_connection
|
104
|
+
|
105
|
+
@tcp_sock.expects(:close).returns(nil)
|
106
|
+
@ssl_sock.expects(:close).returns(nil)
|
107
|
+
@tcp_sock.expects(:closed?).returns(false)
|
108
|
+
|
109
|
+
assert !@epp.close_connection
|
110
|
+
end
|
111
|
+
|
112
|
+
should "return false if SSL socket not closed" do
|
113
|
+
prepare_socket!
|
114
|
+
|
115
|
+
@epp.open_connection
|
116
|
+
|
117
|
+
@tcp_sock.expects(:close).returns(nil)
|
118
|
+
@ssl_sock.expects(:close).returns(nil)
|
119
|
+
@tcp_sock.expects(:closed?).returns(true)
|
120
|
+
@ssl_sock.expects(:closed?).returns(false)
|
121
|
+
|
122
|
+
assert !@epp.close_connection
|
123
|
+
end
|
124
|
+
|
125
|
+
should "get frame from new EPP servers with a header of four bytes" do
|
126
|
+
prepare_socket!
|
127
|
+
|
128
|
+
@epp.open_connection
|
129
|
+
|
130
|
+
response = xml_file("test_response.xml")
|
131
|
+
|
132
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\003\"")
|
133
|
+
@ssl_sock.expects(:read).with(798).returns(response)
|
134
|
+
|
135
|
+
assert response, @epp.get_frame
|
136
|
+
end
|
137
|
+
|
138
|
+
should "raise exception if socket closed unexpectedly while getting frame" do
|
139
|
+
prepare_socket!
|
140
|
+
simulate_close!
|
141
|
+
|
142
|
+
@epp.open_connection
|
143
|
+
@epp.close_connection
|
144
|
+
|
145
|
+
@ssl_sock.expects(:read).with(4).returns(nil)
|
146
|
+
@ssl_sock.expects(:eof?).returns(true)
|
147
|
+
|
148
|
+
assert_raises SocketError do
|
149
|
+
@epp.get_frame
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
should "raise exception if header cannot be read when getting frame" do
|
154
|
+
prepare_socket!
|
155
|
+
|
156
|
+
@epp.open_connection
|
157
|
+
|
158
|
+
@ssl_sock.expects(:read).with(4).returns(nil)
|
159
|
+
@ssl_sock.expects(:eof?).returns(false)
|
160
|
+
|
161
|
+
assert_raises SocketError do
|
162
|
+
@epp.get_frame
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
should "send frame to an EPP server" do
|
167
|
+
prepare_socket!
|
168
|
+
|
169
|
+
@epp.open_connection
|
170
|
+
|
171
|
+
send = xml_file("test_request.xml")
|
172
|
+
|
173
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send).returns(121)
|
174
|
+
|
175
|
+
assert_equal 121, @epp.send_frame(send)
|
176
|
+
end
|
177
|
+
|
178
|
+
should "create a packed header for EPP request" do
|
179
|
+
xml_to_send = "<xml><test/></xml>"
|
180
|
+
assert_equal "\000\000\000\026", @epp.packed(xml_to_send)
|
181
|
+
end
|
182
|
+
|
183
|
+
should "return size of header from EPP response" do
|
184
|
+
assert_equal [22], "\000\000\000\026".unpack("N")
|
185
|
+
assert_equal 22, @epp.header_size("\000\000\000\026")
|
186
|
+
end
|
187
|
+
|
188
|
+
should "send frame, and get response from server" do
|
189
|
+
prepare_socket!
|
190
|
+
|
191
|
+
@epp.open_connection
|
192
|
+
|
193
|
+
send = xml_file("test_request.xml")
|
194
|
+
receive = xml_file("test_response.xml")
|
195
|
+
|
196
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send).returns(121)
|
197
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\003\"")
|
198
|
+
@ssl_sock.expects(:read).with(798).returns(receive)
|
199
|
+
|
200
|
+
assert receive, @epp.send_request(send)
|
201
|
+
end
|
202
|
+
|
203
|
+
should "login to the server" do
|
204
|
+
prepare_socket!
|
205
|
+
|
206
|
+
@epp.open_connection
|
207
|
+
|
208
|
+
send = xml_file("login_request.xml")
|
209
|
+
receive = xml_file("login_response.xml")
|
210
|
+
|
211
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send)
|
212
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\0019")
|
213
|
+
@ssl_sock.expects(:read).with(309).returns(receive)
|
214
|
+
|
215
|
+
assert @epp.login
|
216
|
+
end
|
217
|
+
|
218
|
+
should "login to the server with extensions" do
|
219
|
+
prepare_socket!
|
220
|
+
|
221
|
+
epp = Epp::Server.new(
|
222
|
+
:server => "test-epp.nominet.org.uk",
|
223
|
+
:tag => "TEST",
|
224
|
+
:password => "test",
|
225
|
+
:extensions => ["urn:ietf:params:xml:ns:rgp-1.0"]
|
226
|
+
)
|
227
|
+
|
228
|
+
epp.open_connection
|
229
|
+
|
230
|
+
send = xml_file("login_with_extensions_request.xml")
|
231
|
+
receive = xml_file("login_response.xml")
|
232
|
+
|
233
|
+
@ssl_sock.expects(:write).with(epp.packed(send) + send)
|
234
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\0019")
|
235
|
+
@ssl_sock.expects(:read).with(309).returns(receive)
|
236
|
+
|
237
|
+
assert epp.login
|
238
|
+
end
|
239
|
+
|
240
|
+
should "raise exception if login returns anything other than 1500 response" do
|
241
|
+
prepare_socket!
|
242
|
+
|
243
|
+
@epp.open_connection
|
244
|
+
|
245
|
+
send = xml_file("login_request.xml")
|
246
|
+
receive = xml_file("error.xml")
|
247
|
+
|
248
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send)
|
249
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\001\231")
|
250
|
+
@ssl_sock.expects(:read).with(405).returns(receive)
|
251
|
+
|
252
|
+
assert_raises EppErrorResponse do
|
253
|
+
@epp.login
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
should "log out of the server" do
|
258
|
+
prepare_socket!
|
259
|
+
|
260
|
+
@epp.open_connection
|
261
|
+
|
262
|
+
send = xml_file("logout_request.xml")
|
263
|
+
receive = xml_file("logout_response.xml")
|
264
|
+
|
265
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send)
|
266
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\001I")
|
267
|
+
@ssl_sock.expects(:read).with(325).returns(receive)
|
268
|
+
|
269
|
+
assert @epp.logout
|
270
|
+
end
|
271
|
+
|
272
|
+
should "raise exception if logout returns anything other than 1500 response" do
|
273
|
+
prepare_socket!
|
274
|
+
|
275
|
+
@epp.open_connection
|
276
|
+
|
277
|
+
send = xml_file("logout_request.xml")
|
278
|
+
receive = xml_file("error.xml")
|
279
|
+
|
280
|
+
@ssl_sock.expects(:write).with(@epp.packed(send) + send)
|
281
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\001\231")
|
282
|
+
@ssl_sock.expects(:read).with(405).returns(receive)
|
283
|
+
|
284
|
+
assert_raises EppErrorResponse do
|
285
|
+
@epp.logout
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
should "wrap a request around a logging in and logging out request" do
|
290
|
+
prepare_socket!
|
291
|
+
simulate_close!
|
292
|
+
|
293
|
+
test_request = xml_file("test_request.xml")
|
294
|
+
test_response = xml_file("test_response.xml")
|
295
|
+
|
296
|
+
@epp.expects(:login).returns(true)
|
297
|
+
@epp.expects(:logout).returns(true)
|
298
|
+
@epp.expects(:send_request).with(test_request).returns(test_response)
|
299
|
+
|
300
|
+
@response = @epp.request(test_request)
|
301
|
+
|
302
|
+
assert_equal test_response, @response
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context "exceptions" do
|
307
|
+
should "require XML, code and message attributes" do
|
308
|
+
assert_raises ArgumentError do
|
309
|
+
e = EppErrorResponse.new(:code => "a", :message => "a")
|
310
|
+
end
|
311
|
+
|
312
|
+
assert_raises ArgumentError do
|
313
|
+
e = EppErrorResponse.new(:xml => "a", :message => "a")
|
314
|
+
end
|
315
|
+
|
316
|
+
assert_raises ArgumentError do
|
317
|
+
e = EppErrorResponse.new(:xml => "a", :code => "a")
|
318
|
+
end
|
319
|
+
|
320
|
+
assert_nothing_raised do
|
321
|
+
e = EppErrorResponse.new(:xml => "a", :code => "a", :message => "a")
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
should "print error message to string" do
|
326
|
+
e = EppErrorResponse.new(
|
327
|
+
:xml => "<xml></xml>",
|
328
|
+
:code => 400,
|
329
|
+
:message => "Test error message"
|
330
|
+
)
|
331
|
+
|
332
|
+
assert_equal "Test error message (code 400)", e.to_s
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
private
|
338
|
+
|
339
|
+
def prepare_socket!
|
340
|
+
@response = xml_file("test_request.xml")
|
341
|
+
|
342
|
+
TCPSocket.expects(:new).returns(@tcp_sock)
|
343
|
+
OpenSSL::SSL::SSLSocket.expects(:new).returns(@ssl_sock)
|
344
|
+
|
345
|
+
@ssl_sock.expects(:sync_close).returns(false)
|
346
|
+
@ssl_sock.expects(:connect).returns(@ssl_sock)
|
347
|
+
@ssl_sock.expects(:read).with(4).returns("\000\000\003\r")
|
348
|
+
@ssl_sock.expects(:read).with(777).returns(@response)
|
349
|
+
end
|
350
|
+
|
351
|
+
def simulate_close!
|
352
|
+
@ssl_sock.expects(:close).returns(nil)
|
353
|
+
@tcp_sock.expects(:close).returns(nil)
|
354
|
+
@ssl_sock.expects(:closed?).returns(true)
|
355
|
+
@tcp_sock.expects(:closed?).returns(true)
|
356
|
+
end
|
357
|
+
|
358
|
+
def xml_file(name)
|
359
|
+
File.read(File.dirname(__FILE__) + "/xml/#{name}")
|
360
|
+
end
|
361
|
+
end
|
data/test/test_helper.rb
CHANGED
data/test/xml/error.xml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
|
5
|
+
<response>
|
6
|
+
<result code="2200">
|
7
|
+
<msg>Authentication error</msg>
|
8
|
+
</result>
|
9
|
+
<trID>
|
10
|
+
<clTRID>ABC-12345</clTRID>
|
11
|
+
<svTRID>54321-XYZ</svTRID>
|
12
|
+
</trID>
|
13
|
+
</response>
|
14
|
+
</epp>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><login><clID>TEST</clID><pw>test</pw><options><version>1.0</version><lang>en</lang></options><svcs><objURI>urn:ietf:params:xml:ns:domain-1.0</objURI><objURI>urn:ietf:params:xml:ns:contact-1.0</objURI><objURI>urn:ietf:params:xml:ns:host-1.0</objURI></svcs></login><clTRID>ABC-12345</clTRID></command></epp>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
3
|
+
<response>
|
4
|
+
<result code="1000">
|
5
|
+
<msg>Command completed successfully</msg>
|
6
|
+
</result>
|
7
|
+
<trID>
|
8
|
+
<clTRID>ABC-12345</clTRID>
|
9
|
+
<svTRID>54321-XYZ</svTRID>
|
10
|
+
</trID>
|
11
|
+
</response>
|
12
|
+
</epp>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><login><clID>TEST</clID><pw>test</pw><options><version>1.0</version><lang>en</lang></options><svcs><objURI>urn:ietf:params:xml:ns:domain-1.0</objURI><objURI>urn:ietf:params:xml:ns:contact-1.0</objURI><objURI>urn:ietf:params:xml:ns:host-1.0</objURI><svcExtension><extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI></svcExtension></svcs></login><clTRID>ABC-12345</clTRID></command></epp>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'><command><logout/></command></epp>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
3
|
+
<response>
|
4
|
+
<result code="1500">
|
5
|
+
<msg>Command completed successfully; ending session</msg>
|
6
|
+
</result>
|
7
|
+
<trID>
|
8
|
+
<clTRID>ABC-12345</clTRID>
|
9
|
+
<svTRID>54321-XYZ</svTRID>
|
10
|
+
</trID>
|
11
|
+
</response>
|
12
|
+
</epp>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version='1.0' encoding='UTF-8' standalone='no'?><epp xsi:schemaLocation='urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='urn:ietf:params:xml:ns:epp-1.0'/>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
|
5
|
+
<greeting>
|
6
|
+
<svID>CoCCA EPP Server - epp.cocca.iors.cx</svID>
|
7
|
+
<svDate>2010-07-07T12:46:33.0536Z</svDate>
|
8
|
+
<svcMenu>
|
9
|
+
<version>1.0</version>
|
10
|
+
<lang>en</lang>
|
11
|
+
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
12
|
+
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
13
|
+
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
14
|
+
<svcExtension>
|
15
|
+
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
16
|
+
</svcExtension>
|
17
|
+
</svcMenu>
|
18
|
+
<dcp>
|
19
|
+
<access><all/></access>
|
20
|
+
<statement>
|
21
|
+
<purpose><admin/><prov/></purpose>
|
22
|
+
<recipient><ours/><public/></recipient>
|
23
|
+
<retention><stated/></retention>
|
24
|
+
</statement>
|
25
|
+
</dcp>
|
26
|
+
</greeting>
|
27
|
+
</epp>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
3
|
+
<greeting>
|
4
|
+
<svID>Example EPP server epp.example.com</svID>
|
5
|
+
<svDate>2000-06-08T22:00:00.0Z</svDate>
|
6
|
+
<svcMenu>
|
7
|
+
<version>1.0</version>
|
8
|
+
<lang>en</lang>
|
9
|
+
<lang>fr</lang>
|
10
|
+
<objURI>urn:ietf:params:xml:ns:obj1</objURI>
|
11
|
+
<objURI>urn:ietf:params:xml:ns:obj2</objURI>
|
12
|
+
<objURI>urn:ietf:params:xml:ns:obj3</objURI>
|
13
|
+
<svcExtension>
|
14
|
+
<extURI>http://custom/obj1ext-1.0</extURI>
|
15
|
+
</svcExtension>
|
16
|
+
</svcMenu>
|
17
|
+
<dcp>
|
18
|
+
<access><all/></access>
|
19
|
+
<statement>
|
20
|
+
<purpose><admin/><prov/></purpose>
|
21
|
+
<recipient><ours/><public/></recipient>
|
22
|
+
<retention><stated/></retention>
|
23
|
+
</statement>
|
24
|
+
</dcp>
|
25
|
+
</greeting>
|
26
|
+
</epp>
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 1.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Josh Delsman
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-07-
|
18
|
+
date: 2010-07-07 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
type: :development
|
34
34
|
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
36
|
+
name: mocha
|
37
37
|
prerelease: false
|
38
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
segments:
|
45
45
|
- 0
|
46
46
|
version: "0"
|
47
|
-
type: :
|
47
|
+
type: :development
|
48
48
|
version_requirements: *id002
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
50
|
+
name: activesupport
|
51
51
|
prerelease: false
|
52
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
@@ -60,6 +60,20 @@ dependencies:
|
|
60
60
|
version: "0"
|
61
61
|
type: :runtime
|
62
62
|
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: hpricot
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :runtime
|
76
|
+
version_requirements: *id004
|
63
77
|
description: Basic functionality for connecting and making requests on EPP (Extensible Provisioning Protocol) servers
|
64
78
|
email: jdelsman@ultraspeed.com
|
65
79
|
executables: []
|
@@ -79,8 +93,18 @@ files:
|
|
79
93
|
- lib/epp/exceptions.rb
|
80
94
|
- lib/epp/server.rb
|
81
95
|
- lib/require_parameters.rb
|
82
|
-
- test/
|
96
|
+
- test/test_epp.rb
|
83
97
|
- test/test_helper.rb
|
98
|
+
- test/xml/error.xml
|
99
|
+
- test/xml/login_request.xml
|
100
|
+
- test/xml/login_response.xml
|
101
|
+
- test/xml/login_with_extensions_request.xml
|
102
|
+
- test/xml/logout_request.xml
|
103
|
+
- test/xml/logout_response.xml
|
104
|
+
- test/xml/new_request.xml
|
105
|
+
- test/xml/socket_preparation.xml
|
106
|
+
- test/xml/test_request.xml
|
107
|
+
- test/xml/test_response.xml
|
84
108
|
has_rdoc: true
|
85
109
|
homepage: http://github.com/ultraspeed/epp
|
86
110
|
licenses: []
|
@@ -116,5 +140,5 @@ signing_key:
|
|
116
140
|
specification_version: 3
|
117
141
|
summary: EPP (Extensible Provisioning Protocol) for Ruby
|
118
142
|
test_files:
|
119
|
-
- test/
|
143
|
+
- test/test_epp.rb
|
120
144
|
- test/test_helper.rb
|