savon 2.2.0 → 2.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +157 -10
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +10 -2
- data/README.md +38 -13
- data/donate.png +0 -0
- data/lib/savon/builder.rb +81 -15
- data/lib/savon/client.rb +6 -2
- data/lib/savon/core_ext/string.rb +0 -1
- data/lib/savon/header.rb +68 -17
- data/lib/savon/log_message.rb +7 -3
- data/lib/savon/message.rb +6 -7
- data/lib/savon/mock/expectation.rb +12 -2
- data/lib/savon/model.rb +4 -0
- data/lib/savon/operation.rb +45 -38
- data/lib/savon/options.rb +149 -22
- data/lib/savon/qualified_message.rb +31 -25
- data/lib/savon/request.rb +24 -4
- data/lib/savon/request_logger.rb +48 -0
- data/lib/savon/response.rb +35 -18
- data/lib/savon/soap_fault.rb +11 -11
- data/lib/savon/version.rb +1 -3
- data/savon.gemspec +12 -11
- data/spec/fixtures/response/empty_soap_fault.xml +13 -0
- data/spec/fixtures/response/f5.xml +39 -0
- data/spec/fixtures/response/no_body.xml +1 -0
- data/spec/fixtures/response/soap_fault_funky.xml +8 -0
- data/spec/fixtures/wsdl/brand.xml +624 -0
- data/spec/fixtures/wsdl/elements_in_types.xml +43 -0
- data/spec/fixtures/wsdl/no_message_tag.xml +1267 -0
- data/spec/fixtures/wsdl/vies.xml +176 -0
- data/spec/integration/centra_spec.rb +67 -0
- data/spec/integration/email_example_spec.rb +1 -1
- data/spec/integration/random_quote_spec.rb +23 -0
- data/spec/integration/stockquote_example_spec.rb +7 -1
- data/spec/integration/support/application.rb +1 -1
- data/spec/integration/zipcode_example_spec.rb +1 -1
- data/spec/savon/builder_spec.rb +50 -0
- data/spec/savon/client_spec.rb +78 -0
- data/spec/savon/core_ext/string_spec.rb +9 -9
- data/spec/savon/features/message_tag_spec.rb +5 -0
- data/spec/savon/http_error_spec.rb +2 -2
- data/spec/savon/log_message_spec.rb +18 -1
- data/spec/savon/message_spec.rb +70 -0
- data/spec/savon/mock_spec.rb +31 -0
- data/spec/savon/model_spec.rb +28 -0
- data/spec/savon/operation_spec.rb +69 -3
- data/spec/savon/options_spec.rb +515 -87
- data/spec/savon/qualified_message_spec.rb +101 -0
- data/spec/savon/request_logger_spec.rb +37 -0
- data/spec/savon/request_spec.rb +85 -10
- data/spec/savon/response_spec.rb +118 -27
- data/spec/savon/soap_fault_spec.rb +25 -5
- data/spec/savon/softlayer_spec.rb +27 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/support/adapters.rb +48 -0
- data/spec/support/integration.rb +1 -1
- metadata +76 -93
@@ -2,44 +2,50 @@ require "gyoku"
|
|
2
2
|
|
3
3
|
module Savon
|
4
4
|
class QualifiedMessage
|
5
|
-
|
6
5
|
def initialize(types, used_namespaces, key_converter)
|
7
|
-
@types
|
6
|
+
@types = types
|
8
7
|
@used_namespaces = used_namespaces
|
9
|
-
@key_converter
|
8
|
+
@key_converter = key_converter
|
10
9
|
end
|
11
10
|
|
12
11
|
def to_hash(hash, path)
|
13
|
-
return unless hash
|
14
|
-
return hash.map { |value| to_hash(value, path) } if hash.
|
15
|
-
return hash.to_s unless hash.
|
16
|
-
|
17
|
-
hash.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
newhash
|
23
|
-
"#{@used_namespaces[newpath]}:#{translated_key}" =>
|
24
|
-
to_hash(value, @types[newpath] ? [@types[newpath]] : newpath)
|
25
|
-
)
|
12
|
+
return hash unless hash
|
13
|
+
return hash.map { |value| to_hash(value, path) } if hash.is_a?(Array)
|
14
|
+
return hash.to_s unless hash.is_a?(Hash)
|
15
|
+
|
16
|
+
hash.each_with_object({}) do |(key, value), newhash|
|
17
|
+
case key
|
18
|
+
when :order!
|
19
|
+
newhash[key] = add_namespaces_to_values(value, path)
|
20
|
+
when :attributes!, :content!
|
21
|
+
newhash[key] = to_hash(value, path)
|
26
22
|
else
|
27
|
-
|
28
|
-
|
23
|
+
if key.to_s =~ /!$/
|
24
|
+
newhash[key] = value
|
25
|
+
else
|
26
|
+
translated_key = translate_tag(key)
|
27
|
+
newkey = add_namespaces_to_values(key, path).first
|
28
|
+
newpath = path + [translated_key]
|
29
|
+
newhash[newkey] = to_hash(value, @types[newpath] ? [@types[newpath]] : newpath)
|
30
|
+
end
|
29
31
|
end
|
32
|
+
newhash
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
33
36
|
private
|
34
37
|
|
35
|
-
def
|
36
|
-
|
37
|
-
camelcased_value = Gyoku.xml_tag(value, :key_converter => @key_converter)
|
38
|
-
namespace_path = path + [camelcased_value.to_s]
|
39
|
-
namespace = @used_namespaces[namespace_path]
|
40
|
-
"#{namespace.blank? ? '' : namespace + ":"}#{camelcased_value}"
|
41
|
-
}
|
38
|
+
def translate_tag(key)
|
39
|
+
Gyoku.xml_tag(key, :key_converter => @key_converter).to_s
|
42
40
|
end
|
43
41
|
|
42
|
+
def add_namespaces_to_values(values, path)
|
43
|
+
Array(values).collect do |value|
|
44
|
+
translated_value = translate_tag(value)
|
45
|
+
namespace_path = path + [translated_value]
|
46
|
+
namespace = @used_namespaces[namespace_path]
|
47
|
+
namespace.blank? ? value : "#{namespace}:#{translated_value}"
|
48
|
+
end
|
49
|
+
end
|
44
50
|
end
|
45
51
|
end
|
data/lib/savon/request.rb
CHANGED
@@ -26,10 +26,16 @@ module Savon
|
|
26
26
|
def configure_ssl
|
27
27
|
@http_request.auth.ssl.ssl_version = @globals[:ssl_version] if @globals.include? :ssl_version
|
28
28
|
@http_request.auth.ssl.verify_mode = @globals[:ssl_verify_mode] if @globals.include? :ssl_verify_mode
|
29
|
+
@http_request.auth.ssl.ciphers = @globals[:ssl_ciphers] if @globals.include? :ssl_ciphers
|
29
30
|
|
30
31
|
@http_request.auth.ssl.cert_key_file = @globals[:ssl_cert_key_file] if @globals.include? :ssl_cert_key_file
|
32
|
+
@http_request.auth.ssl.cert_key = @globals[:ssl_cert_key] if @globals.include? :ssl_cert_key
|
31
33
|
@http_request.auth.ssl.cert_file = @globals[:ssl_cert_file] if @globals.include? :ssl_cert_file
|
34
|
+
@http_request.auth.ssl.cert = @globals[:ssl_cert] if @globals.include? :ssl_cert
|
32
35
|
@http_request.auth.ssl.ca_cert_file = @globals[:ssl_ca_cert_file] if @globals.include? :ssl_ca_cert_file
|
36
|
+
@http_request.auth.ssl.ca_cert_path = @globals[:ssl_ca_cert_path] if @globals.include? :ssl_ca_cert_path
|
37
|
+
@http_request.auth.ssl.ca_cert = @globals[:ssl_ca_cert] if @globals.include? :ssl_ca_cert
|
38
|
+
@http_request.auth.ssl.cert_store = @globals[:ssl_cert_store] if @globals.include? :ssl_cert_store
|
33
39
|
|
34
40
|
@http_request.auth.ssl.cert_key_password = @globals[:ssl_cert_key_password] if @globals.include? :ssl_cert_key_password
|
35
41
|
end
|
@@ -37,8 +43,14 @@ module Savon
|
|
37
43
|
def configure_auth
|
38
44
|
@http_request.auth.basic(*@globals[:basic_auth]) if @globals.include? :basic_auth
|
39
45
|
@http_request.auth.digest(*@globals[:digest_auth]) if @globals.include? :digest_auth
|
46
|
+
@http_request.auth.ntlm(*@globals[:ntlm]) if @globals.include? :ntlm
|
40
47
|
end
|
41
48
|
|
49
|
+
def configure_redirect_handling
|
50
|
+
if @globals.include? :follow_redirects
|
51
|
+
@http_request.follow_redirect = @globals[:follow_redirects]
|
52
|
+
end
|
53
|
+
end
|
42
54
|
end
|
43
55
|
|
44
56
|
class WSDLRequest < HTTPRequest
|
@@ -46,12 +58,19 @@ module Savon
|
|
46
58
|
def build
|
47
59
|
configure_proxy
|
48
60
|
configure_timeouts
|
61
|
+
configure_headers
|
49
62
|
configure_ssl
|
50
63
|
configure_auth
|
64
|
+
configure_redirect_handling
|
51
65
|
|
52
66
|
@http_request
|
53
67
|
end
|
54
68
|
|
69
|
+
private
|
70
|
+
|
71
|
+
def configure_headers
|
72
|
+
@http_request.headers = @globals[:headers] if @globals.include? :headers
|
73
|
+
end
|
55
74
|
end
|
56
75
|
|
57
76
|
class SOAPRequest < HTTPRequest
|
@@ -63,11 +82,12 @@ module Savon
|
|
63
82
|
|
64
83
|
def build(options = {})
|
65
84
|
configure_proxy
|
66
|
-
configure_cookies options[:cookies]
|
67
85
|
configure_timeouts
|
68
|
-
configure_headers options[:soap_action]
|
86
|
+
configure_headers options[:soap_action], options[:headers]
|
87
|
+
configure_cookies options[:cookies]
|
69
88
|
configure_ssl
|
70
89
|
configure_auth
|
90
|
+
configure_redirect_handling
|
71
91
|
|
72
92
|
@http_request
|
73
93
|
end
|
@@ -78,11 +98,11 @@ module Savon
|
|
78
98
|
@http_request.set_cookies(cookies) if cookies
|
79
99
|
end
|
80
100
|
|
81
|
-
def configure_headers(soap_action)
|
101
|
+
def configure_headers(soap_action, headers)
|
82
102
|
@http_request.headers = @globals[:headers] if @globals.include? :headers
|
103
|
+
@http_request.headers.merge!(headers) if headers
|
83
104
|
@http_request.headers["SOAPAction"] ||= %{"#{soap_action}"} if soap_action
|
84
105
|
@http_request.headers["Content-Type"] ||= CONTENT_TYPE[@globals[:soap_version]] % @globals[:encoding]
|
85
106
|
end
|
86
|
-
|
87
107
|
end
|
88
108
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "savon/log_message"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
class RequestLogger
|
5
|
+
|
6
|
+
def initialize(globals)
|
7
|
+
@globals = globals
|
8
|
+
end
|
9
|
+
|
10
|
+
def log(request, &http_request)
|
11
|
+
log_request(request) if log?
|
12
|
+
response = http_request.call
|
13
|
+
log_response(response) if log?
|
14
|
+
|
15
|
+
response
|
16
|
+
end
|
17
|
+
|
18
|
+
def logger
|
19
|
+
@globals[:logger]
|
20
|
+
end
|
21
|
+
|
22
|
+
def log?
|
23
|
+
@globals[:log]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def log_request(request)
|
29
|
+
logger.info { "SOAP request: #{request.url}" }
|
30
|
+
logger.info { headers_to_log(request.headers) }
|
31
|
+
logger.debug { body_to_log(request.body) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_response(response)
|
35
|
+
logger.info { "SOAP response (status #{response.code})" }
|
36
|
+
logger.debug { body_to_log(response.body) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def headers_to_log(headers)
|
40
|
+
headers.map { |key, value| "#{key}: #{value}" }.join(", ")
|
41
|
+
end
|
42
|
+
|
43
|
+
def body_to_log(body)
|
44
|
+
LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/savon/response.rb
CHANGED
@@ -10,18 +10,19 @@ module Savon
|
|
10
10
|
@globals = globals
|
11
11
|
@locals = locals
|
12
12
|
|
13
|
+
build_soap_and_http_errors!
|
13
14
|
raise_soap_and_http_errors! if @globals[:raise_errors]
|
14
15
|
end
|
15
16
|
|
16
|
-
attr_reader :http, :globals, :locals
|
17
|
+
attr_reader :http, :globals, :locals, :soap_fault, :http_error
|
17
18
|
|
18
19
|
def success?
|
19
20
|
!soap_fault? && !http_error?
|
20
21
|
end
|
21
|
-
|
22
|
+
alias_method :successful?, :success?
|
22
23
|
|
23
24
|
def soap_fault?
|
24
|
-
SOAPFault.present?
|
25
|
+
SOAPFault.present?(@http, xml)
|
25
26
|
end
|
26
27
|
|
27
28
|
def http_error?
|
@@ -29,15 +30,14 @@ module Savon
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def header
|
32
|
-
|
33
|
-
hash[:envelope][:header]
|
33
|
+
find('Header')
|
34
34
|
end
|
35
35
|
|
36
36
|
def body
|
37
|
-
|
38
|
-
hash[:envelope][:body]
|
37
|
+
find('Body')
|
39
38
|
end
|
40
|
-
|
39
|
+
|
40
|
+
alias_method :to_hash, :body
|
41
41
|
|
42
42
|
def to_array(*path)
|
43
43
|
result = path.inject body do |memo, key|
|
@@ -49,30 +49,45 @@ module Savon
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def hash
|
52
|
-
@hash ||= nori.parse(
|
52
|
+
@hash ||= nori.parse(xml)
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
55
|
+
def xml
|
56
56
|
@http.body
|
57
57
|
end
|
58
58
|
|
59
|
+
alias_method :to_xml, :xml
|
60
|
+
alias_method :to_s, :xml
|
61
|
+
|
59
62
|
def doc
|
60
|
-
@doc ||= Nokogiri.XML(
|
63
|
+
@doc ||= Nokogiri.XML(xml)
|
61
64
|
end
|
62
65
|
|
63
66
|
def xpath(path, namespaces = nil)
|
64
67
|
doc.xpath(path, namespaces || xml_namespaces)
|
65
68
|
end
|
66
69
|
|
70
|
+
def find(*path)
|
71
|
+
envelope = nori.find(hash, 'Envelope')
|
72
|
+
raise_invalid_response_error! unless envelope.is_a?(Hash)
|
73
|
+
|
74
|
+
nori.find(envelope, *path)
|
75
|
+
end
|
76
|
+
|
67
77
|
private
|
68
78
|
|
79
|
+
def build_soap_and_http_errors!
|
80
|
+
@soap_fault = SOAPFault.new(@http, nori, xml) if soap_fault?
|
81
|
+
@http_error = HTTPError.new(@http) if http_error?
|
82
|
+
end
|
83
|
+
|
69
84
|
def raise_soap_and_http_errors!
|
70
|
-
raise
|
71
|
-
raise
|
85
|
+
raise soap_fault if soap_fault?
|
86
|
+
raise http_error if http_error?
|
72
87
|
end
|
73
88
|
|
74
89
|
def raise_invalid_response_error!
|
75
|
-
raise InvalidResponseError, "Unable to parse response body:\n" +
|
90
|
+
raise InvalidResponseError, "Unable to parse response body:\n" + xml.inspect
|
76
91
|
end
|
77
92
|
|
78
93
|
def xml_namespaces
|
@@ -83,10 +98,12 @@ module Savon
|
|
83
98
|
return @nori if @nori
|
84
99
|
|
85
100
|
nori_options = {
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
101
|
+
:delete_namespace_attributes => @globals[:delete_namespace_attributes],
|
102
|
+
:strip_namespaces => @globals[:strip_namespaces],
|
103
|
+
:convert_tags_to => @globals[:convert_response_tags_to],
|
104
|
+
:convert_attributes_to => @globals[:convert_attributes_to],
|
105
|
+
:advanced_typecasting => @locals[:advanced_typecasting],
|
106
|
+
:parser => @locals[:response_parser]
|
90
107
|
}
|
91
108
|
|
92
109
|
non_nil_nori_options = nori_options.reject { |_, value| value.nil? }
|
data/lib/savon/soap_fault.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
-
require "savon"
|
2
|
-
|
3
1
|
module Savon
|
4
2
|
class SOAPFault < Error
|
5
3
|
|
6
|
-
def self.present?(http)
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def self.present?(http, xml = nil)
|
5
|
+
xml ||= http.body
|
6
|
+
fault_node = xml.include?("Fault>")
|
7
|
+
soap1_fault = xml.match(/faultcode\/?\>/) && xml.match(/faultstring\/?\>/)
|
8
|
+
soap2_fault = xml.include?("Code>") && xml.include?("Reason>")
|
10
9
|
|
11
10
|
fault_node && (soap1_fault || soap2_fault)
|
12
11
|
end
|
13
12
|
|
14
|
-
def initialize(http, nori)
|
13
|
+
def initialize(http, nori, xml = nil)
|
14
|
+
@xml = xml
|
15
15
|
@http = http
|
16
16
|
@nori = nori
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :http, :nori
|
19
|
+
attr_reader :http, :nori, :xml
|
20
20
|
|
21
21
|
def to_s
|
22
|
-
fault = nori.find(to_hash, 'Fault')
|
22
|
+
fault = nori.find(to_hash, 'Fault') || nori.find(to_hash, 'ServiceFault')
|
23
23
|
message_by_version(fault)
|
24
24
|
end
|
25
25
|
|
26
26
|
def to_hash
|
27
|
-
parsed = nori.parse(
|
28
|
-
nori.find(parsed, 'Envelope', 'Body')
|
27
|
+
parsed = nori.parse(xml || http.body)
|
28
|
+
nori.find(parsed, 'Envelope', 'Body') || {}
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
data/lib/savon/version.rb
CHANGED
data/savon.gemspec
CHANGED
@@ -12,24 +12,25 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.homepage = "http://savonrb.com"
|
13
13
|
s.summary = "Heavy metal SOAP client"
|
14
14
|
s.description = s.summary
|
15
|
+
s.required_ruby_version = '>= 1.9.2'
|
15
16
|
|
16
17
|
s.rubyforge_project = s.name
|
18
|
+
s.license = 'MIT'
|
17
19
|
|
18
|
-
s.add_dependency "nori", "~> 2.
|
19
|
-
s.add_dependency "httpi", "~> 2.
|
20
|
-
s.add_dependency "wasabi", "~> 3.
|
21
|
-
s.add_dependency "akami", "~> 1.2
|
22
|
-
s.add_dependency "gyoku", "~> 1.
|
23
|
-
|
20
|
+
s.add_dependency "nori", "~> 2.4"
|
21
|
+
s.add_dependency "httpi", "~> 2.3"
|
22
|
+
s.add_dependency "wasabi", "~> 3.4"
|
23
|
+
s.add_dependency "akami", "~> 1.2"
|
24
|
+
s.add_dependency "gyoku", "~> 1.2"
|
24
25
|
s.add_dependency "builder", ">= 2.1.2"
|
25
|
-
s.add_dependency "nokogiri", ">= 1.
|
26
|
+
s.add_dependency "nokogiri", ">= 1.8.1"
|
26
27
|
|
27
28
|
s.add_development_dependency "rack"
|
28
|
-
s.add_development_dependency "puma", "
|
29
|
+
s.add_development_dependency "puma", "~> 3.0"
|
29
30
|
|
30
|
-
s.add_development_dependency "rake", "~>
|
31
|
-
s.add_development_dependency "rspec", "~> 2.
|
32
|
-
s.add_development_dependency "mocha", "~> 0.
|
31
|
+
s.add_development_dependency "rake", "~> 10.1"
|
32
|
+
s.add_development_dependency "rspec", "~> 2.14"
|
33
|
+
s.add_development_dependency "mocha", "~> 0.14"
|
33
34
|
s.add_development_dependency "json", "~> 1.7"
|
34
35
|
|
35
36
|
ignores = File.readlines(".gitignore").grep(/\S+/).map(&:chomp)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
|
2
|
+
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
3
|
+
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
|
4
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
5
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
6
|
+
<SOAP-ENV:Body>
|
7
|
+
<SOAP-ENV:Fault>
|
8
|
+
<faultcode/>
|
9
|
+
<faultstring/>
|
10
|
+
<detail><soapVal><ERRNO xsi:type="xsd:string">80:1289245853:55</ERRNO></soapVal></detail>
|
11
|
+
</SOAP-ENV:Fault>
|
12
|
+
</SOAP-ENV:Body>
|
13
|
+
</SOAP-ENV:Envelope>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<E:Envelope
|
2
|
+
xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"
|
3
|
+
xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"
|
4
|
+
xmlns:s="http://www.w3.org/2001/XMLSchema-instance"
|
5
|
+
xmlns:y="http://www.w3.org/2001/XMLSchema"
|
6
|
+
xmlns:iControl="urn:iControl"
|
7
|
+
E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
8
|
+
<E:Body>
|
9
|
+
<m:get_agent_listen_addressResponse
|
10
|
+
xmlns:m="urn:iControl:Management/SNMPConfiguration">
|
11
|
+
<return
|
12
|
+
s:type="A:Array"
|
13
|
+
A:arrayType="iControl:Management.SNMPConfiguration.AgentListenAddressPort[2]">
|
14
|
+
<item>
|
15
|
+
<transport
|
16
|
+
s:type="iControl:Management.SNMPConfiguration.TransportType">TRANSPORT_TCP6</transport>
|
17
|
+
<ipport
|
18
|
+
s:type="iControl:Common.IPPortDefinition">
|
19
|
+
<address
|
20
|
+
s:type="y:string"></address>
|
21
|
+
<port
|
22
|
+
s:type="y:long">161</port>
|
23
|
+
</ipport>
|
24
|
+
</item>
|
25
|
+
<item>
|
26
|
+
<transport
|
27
|
+
s:type="iControl:Management.SNMPConfiguration.TransportType">TRANSPORT_UDP6</transport>
|
28
|
+
<ipport
|
29
|
+
s:type="iControl:Common.IPPortDefinition">
|
30
|
+
<address
|
31
|
+
s:type="y:string"></address>
|
32
|
+
<port
|
33
|
+
s:type="y:long">161</port>
|
34
|
+
</ipport>
|
35
|
+
</item>
|
36
|
+
</return>
|
37
|
+
</m:get_agent_listen_addressResponse>
|
38
|
+
</E:Body>
|
39
|
+
</E:Envelope>
|