savon 0.6.0 → 0.7.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.
- data/CHANGELOG +112 -0
- data/README.textile +42 -35
- data/Rakefile +28 -33
- data/lib/savon/client.rb +42 -19
- data/lib/savon/core_ext/hash.rb +35 -22
- data/lib/savon/core_ext/net_http.rb +20 -0
- data/lib/savon/core_ext/object.rb +7 -0
- data/lib/savon/core_ext/string.rb +1 -1
- data/lib/savon/core_ext.rb +2 -2
- data/lib/savon/request.rb +73 -33
- data/lib/savon/response.rb +23 -36
- data/lib/savon/soap.rb +63 -30
- data/lib/savon/wsdl.rb +82 -35
- data/lib/savon/wsse.rb +41 -35
- data/lib/savon.rb +3 -2
- data/spec/basic_spec_helper.rb +12 -0
- data/spec/endpoint_helper.rb +22 -0
- data/spec/fixtures/response/response_fixture.rb +36 -0
- data/spec/fixtures/response/xml/authentication.xml +14 -0
- data/spec/fixtures/response/xml/multi_ref.xml +39 -0
- data/spec/fixtures/response/xml/soap_fault12.xml +18 -0
- data/spec/fixtures/wsdl/wsdl_fixture.rb +37 -0
- data/spec/fixtures/wsdl/xml/authentication.xml +63 -0
- data/spec/fixtures/wsdl/xml/namespaced_actions.xml +307 -0
- data/spec/fixtures/wsdl/xml/no_namespace.xml +115 -0
- data/spec/http_stubs.rb +17 -19
- data/spec/integration/http_basic_auth_spec.rb +12 -0
- data/spec/integration/server.rb +51 -0
- data/spec/savon/client_spec.rb +52 -44
- data/spec/savon/core_ext/datetime_spec.rb +2 -2
- data/spec/savon/core_ext/hash_spec.rb +34 -31
- data/spec/savon/core_ext/net_http_spec.rb +38 -0
- data/spec/savon/core_ext/object_spec.rb +16 -2
- data/spec/savon/core_ext/string_spec.rb +4 -4
- data/spec/savon/core_ext/symbol_spec.rb +1 -1
- data/spec/savon/core_ext/uri_spec.rb +1 -1
- data/spec/savon/request_spec.rb +49 -63
- data/spec/savon/response_spec.rb +48 -51
- data/spec/savon/savon_spec.rb +12 -19
- data/spec/savon/soap_spec.rb +81 -90
- data/spec/savon/wsdl_spec.rb +62 -30
- data/spec/savon/wsse_spec.rb +58 -84
- data/spec/spec_helper.rb +3 -13
- metadata +29 -15
- data/VERSION +0 -1
- data/spec/fixtures/multiple_user_response.xml +0 -22
- data/spec/fixtures/user_fixture.rb +0 -54
- data/spec/fixtures/user_response.xml +0 -15
- data/spec/fixtures/user_wsdl.xml +0 -124
- data/spec/spec_helper_methods.rb +0 -33
- /data/spec/fixtures/{soap_fault.xml → response/xml/soap_fault.xml} +0 -0
data/lib/savon/request.rb
CHANGED
|
@@ -8,66 +8,97 @@ module Savon
|
|
|
8
8
|
# Content-Types by SOAP version.
|
|
9
9
|
ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
|
|
11
|
+
# Whether to log HTTP requests.
|
|
12
|
+
@@log = true
|
|
13
13
|
|
|
14
14
|
# The default logger.
|
|
15
|
-
|
|
15
|
+
@@logger = Logger.new STDOUT
|
|
16
16
|
|
|
17
17
|
# The default log level.
|
|
18
|
-
|
|
18
|
+
@@log_level = :debug
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
# Sets whether to log HTTP requests.
|
|
21
|
+
def self.log=(log)
|
|
22
|
+
@@log = log
|
|
23
|
+
end
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
# Returns whether to log HTTP requests.
|
|
26
|
+
def self.log?
|
|
27
|
+
@@log
|
|
28
|
+
end
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
# Sets the logger.
|
|
31
|
+
def self.logger=(logger)
|
|
32
|
+
@@logger = logger
|
|
33
|
+
end
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
# Returns the logger.
|
|
36
|
+
def self.logger
|
|
37
|
+
@@logger
|
|
34
38
|
end
|
|
35
39
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/^(http|https):\/\// === endpoint
|
|
40
|
+
# Sets the log level.
|
|
41
|
+
def self.log_level=(log_level)
|
|
42
|
+
@@log_level = log_level
|
|
43
|
+
end
|
|
41
44
|
|
|
45
|
+
# Returns the log level.
|
|
46
|
+
def self.log_level
|
|
47
|
+
@@log_level
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Expects a SOAP +endpoint+ String. Also accepts an optional Hash
|
|
51
|
+
# of +options+ for specifying a proxy server.
|
|
52
|
+
def initialize(endpoint, options = {})
|
|
42
53
|
@endpoint = URI endpoint
|
|
54
|
+
@proxy = options[:proxy] ? URI(options[:proxy]) : URI("")
|
|
43
55
|
end
|
|
44
56
|
|
|
45
57
|
# Returns the endpoint URI.
|
|
46
58
|
attr_reader :endpoint
|
|
47
59
|
|
|
48
|
-
#
|
|
60
|
+
# Returns the proxy URI.
|
|
61
|
+
attr_reader :proxy
|
|
62
|
+
|
|
63
|
+
# Sets the +username+ and +password+ for HTTP basic authentication.
|
|
64
|
+
def basic_auth(username, password)
|
|
65
|
+
@basic_auth = [username, password]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Retrieves WSDL document and returns the Net::HTTP response.
|
|
49
69
|
def wsdl
|
|
50
70
|
log "Retrieving WSDL from: #{@endpoint}"
|
|
51
|
-
http.
|
|
71
|
+
http.endpoint @endpoint.host, @endpoint.port
|
|
72
|
+
http.use_ssl = @endpoint.ssl?
|
|
73
|
+
http.start { |h| h.request request(:wsdl) }
|
|
52
74
|
end
|
|
53
75
|
|
|
54
76
|
# Executes a SOAP request using a given Savon::SOAP instance and
|
|
55
|
-
# returns the Net::
|
|
77
|
+
# returns the Net::HTTP response.
|
|
56
78
|
def soap(soap)
|
|
57
79
|
@soap = soap
|
|
80
|
+
http.endpoint @soap.endpoint.host, @soap.endpoint.port
|
|
81
|
+
http.use_ssl = @soap.endpoint.ssl?
|
|
58
82
|
|
|
59
83
|
log_request
|
|
60
|
-
@response = http.
|
|
84
|
+
@response = http.start do |h|
|
|
85
|
+
h.request request(:soap) { |request| request.body = @soap.to_xml }
|
|
86
|
+
end
|
|
61
87
|
log_response
|
|
62
88
|
@response
|
|
63
89
|
end
|
|
64
90
|
|
|
91
|
+
# Returns the Net::HTTP object.
|
|
92
|
+
def http
|
|
93
|
+
@http ||= Net::HTTP::Proxy(@proxy.host, @proxy.port).new @endpoint.host, @endpoint.port
|
|
94
|
+
end
|
|
95
|
+
|
|
65
96
|
private
|
|
66
97
|
|
|
67
98
|
# Logs the SOAP request.
|
|
68
99
|
def log_request
|
|
69
|
-
log "SOAP request: #{@endpoint}"
|
|
70
|
-
log http_header.map { |key, value| "#{key}: #{value}" }.join
|
|
100
|
+
log "SOAP request: #{@soap.endpoint}"
|
|
101
|
+
log http_header.map { |key, value| "#{key}: #{value}" }.join(", ")
|
|
71
102
|
log @soap.to_xml
|
|
72
103
|
end
|
|
73
104
|
|
|
@@ -77,13 +108,22 @@ module Savon
|
|
|
77
108
|
log @response.body
|
|
78
109
|
end
|
|
79
110
|
|
|
80
|
-
# Returns a Net::HTTP
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
111
|
+
# Returns a Net::HTTP request for a given +type+. Yields the request
|
|
112
|
+
# to an optional block.
|
|
113
|
+
def request(type)
|
|
114
|
+
request = case type
|
|
115
|
+
when :wsdl then Net::HTTP::Get.new wsdl_endpoint
|
|
116
|
+
when :soap then Net::HTTP::Post.new @soap.endpoint.path, http_header
|
|
85
117
|
end
|
|
86
|
-
@
|
|
118
|
+
request.basic_auth *@basic_auth if @basic_auth
|
|
119
|
+
yield request if block_given?
|
|
120
|
+
request
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Returns the WSDL endpoint.
|
|
124
|
+
def wsdl_endpoint
|
|
125
|
+
return @endpoint.path unless @endpoint.query
|
|
126
|
+
"#{@endpoint.path}?#{@endpoint.query}"
|
|
87
127
|
end
|
|
88
128
|
|
|
89
129
|
# Returns a Hash containing the header for an HTTP request.
|
|
@@ -96,7 +136,7 @@ module Savon
|
|
|
96
136
|
self.class.logger.send self.class.log_level, message if log?
|
|
97
137
|
end
|
|
98
138
|
|
|
99
|
-
# Returns whether
|
|
139
|
+
# Returns whether to log.
|
|
100
140
|
def log?
|
|
101
141
|
self.class.log? && self.class.logger.respond_to?(self.class.log_level)
|
|
102
142
|
end
|
data/lib/savon/response.rb
CHANGED
|
@@ -5,19 +5,17 @@ module Savon
|
|
|
5
5
|
# Represents the HTTP and SOAP response.
|
|
6
6
|
class Response
|
|
7
7
|
|
|
8
|
-
# The
|
|
9
|
-
|
|
8
|
+
# The global setting of whether to raise errors.
|
|
9
|
+
@@raise_errors = true
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Returns the default of whether to raise errors.
|
|
17
|
-
def raise_errors?
|
|
18
|
-
@raise_errors
|
|
19
|
-
end
|
|
11
|
+
# Sets the global setting of whether to raise errors.
|
|
12
|
+
def self.raise_errors=(raise_errors)
|
|
13
|
+
@@raise_errors = raise_errors
|
|
14
|
+
end
|
|
20
15
|
|
|
16
|
+
# Returns the global setting of whether to raise errors.
|
|
17
|
+
def self.raise_errors?
|
|
18
|
+
@@raise_errors
|
|
21
19
|
end
|
|
22
20
|
|
|
23
21
|
# Expects a Net::HTTPResponse and handles errors.
|
|
@@ -30,7 +28,7 @@ module Savon
|
|
|
30
28
|
|
|
31
29
|
# Returns whether there was a SOAP fault.
|
|
32
30
|
def soap_fault?
|
|
33
|
-
@soap_fault
|
|
31
|
+
@soap_fault ? true : false
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
# Returns the SOAP fault message.
|
|
@@ -38,15 +36,15 @@ module Savon
|
|
|
38
36
|
|
|
39
37
|
# Returns whether there was an HTTP error.
|
|
40
38
|
def http_error?
|
|
41
|
-
@http_error
|
|
39
|
+
@http_error ? true : false
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
# Returns the HTTP error message.
|
|
45
43
|
attr_reader :http_error
|
|
46
44
|
|
|
47
|
-
# Returns the SOAP response as a Hash.
|
|
45
|
+
# Returns the SOAP response body as a Hash.
|
|
48
46
|
def to_hash
|
|
49
|
-
@body.
|
|
47
|
+
@body ||= Crack::XML.parse(@response.body).find_soap_body
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
# Returns the SOAP response XML.
|
|
@@ -54,44 +52,33 @@ module Savon
|
|
|
54
52
|
@response.body
|
|
55
53
|
end
|
|
56
54
|
|
|
57
|
-
alias :to_s
|
|
55
|
+
alias :to_s :to_xml
|
|
58
56
|
|
|
59
57
|
private
|
|
60
58
|
|
|
61
|
-
# Returns the SOAP response body as a Hash.
|
|
62
|
-
def body
|
|
63
|
-
unless @body
|
|
64
|
-
body = Crack::XML.parse @response.body
|
|
65
|
-
@body = body.find_regexp [/.+:Envelope/, /.+:Body/]
|
|
66
|
-
end
|
|
67
|
-
@body
|
|
68
|
-
end
|
|
69
|
-
|
|
70
59
|
# Handles SOAP faults. Raises a Savon::SOAPFault unless the default
|
|
71
60
|
# behavior of raising errors was turned off.
|
|
72
61
|
def handle_soap_fault
|
|
73
62
|
if soap_fault_message
|
|
74
63
|
@soap_fault = soap_fault_message
|
|
75
|
-
raise Savon::SOAPFault,
|
|
64
|
+
raise Savon::SOAPFault, @soap_fault if self.class.raise_errors?
|
|
76
65
|
end
|
|
77
66
|
end
|
|
78
67
|
|
|
79
68
|
# Returns a SOAP fault message in case a SOAP fault was found.
|
|
80
69
|
def soap_fault_message
|
|
81
|
-
|
|
82
|
-
soap_fault = body.find_regexp [/.+:Fault/]
|
|
83
|
-
@soap_fault_message = soap_fault_message_by_version(soap_fault)
|
|
84
|
-
end
|
|
85
|
-
@soap_fault_message
|
|
70
|
+
@soap_fault_message ||= soap_fault_message_by_version to_hash[:fault]
|
|
86
71
|
end
|
|
87
72
|
|
|
88
73
|
# Expects a Hash that might contain information about a SOAP fault.
|
|
89
74
|
# Returns the SOAP fault message in case one was found.
|
|
90
75
|
def soap_fault_message_by_version(soap_fault)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"(#{soap_fault[
|
|
76
|
+
return unless soap_fault
|
|
77
|
+
|
|
78
|
+
if soap_fault.keys.include? :faultcode
|
|
79
|
+
"(#{soap_fault[:faultcode]}) #{soap_fault[:faultstring]}"
|
|
80
|
+
elsif soap_fault.keys.include? :code
|
|
81
|
+
"(#{soap_fault[:code][:value]}) #{soap_fault[:reason][:text]}"
|
|
95
82
|
end
|
|
96
83
|
end
|
|
97
84
|
|
|
@@ -100,7 +87,7 @@ module Savon
|
|
|
100
87
|
def handle_http_error
|
|
101
88
|
if @response.code.to_i >= 300
|
|
102
89
|
@http_error = "#{@response.message} (#{@response.code})"
|
|
103
|
-
@http_error
|
|
90
|
+
@http_error << ": #{@response.body}" unless @response.body.empty?
|
|
104
91
|
raise Savon::HTTPError, http_error if self.class.raise_errors?
|
|
105
92
|
end
|
|
106
93
|
end
|
data/lib/savon/soap.rb
CHANGED
|
@@ -14,32 +14,44 @@ module Savon
|
|
|
14
14
|
# Content-Types by SOAP version.
|
|
15
15
|
ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
|
|
16
16
|
|
|
17
|
-
# The
|
|
18
|
-
|
|
17
|
+
# The global SOAP version.
|
|
18
|
+
@@version = 1
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# Sets the default SOAP version.
|
|
26
|
-
def version=(version)
|
|
27
|
-
@version = version if Savon::SOAPVersions.include? version
|
|
28
|
-
end
|
|
20
|
+
# Returns the global SOAP version.
|
|
21
|
+
def self.version
|
|
22
|
+
@@version
|
|
23
|
+
end
|
|
29
24
|
|
|
25
|
+
# Sets the global SOAP version.
|
|
26
|
+
def self.version=(version)
|
|
27
|
+
@@version = version if Savon::SOAPVersions.include? version
|
|
30
28
|
end
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@action = action_map[:name]
|
|
35
|
-
@input = action_map[:input]
|
|
30
|
+
def initialize
|
|
31
|
+
@builder = Builder::XmlMarkup.new
|
|
36
32
|
end
|
|
37
33
|
|
|
38
34
|
# Sets the WSSE options.
|
|
39
35
|
attr_writer :wsse
|
|
40
36
|
|
|
41
|
-
#
|
|
42
|
-
|
|
37
|
+
# Sets the SOAP action.
|
|
38
|
+
attr_writer :action
|
|
39
|
+
|
|
40
|
+
# Returns the SOAP action.
|
|
41
|
+
def action
|
|
42
|
+
@action ||= ""
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Sets the SOAP input.
|
|
46
|
+
attr_writer :input
|
|
47
|
+
|
|
48
|
+
# Returns the SOAP input.
|
|
49
|
+
def input
|
|
50
|
+
@input ||= ""
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Accessor for the SOAP endpoint.
|
|
54
|
+
attr_accessor :endpoint
|
|
43
55
|
|
|
44
56
|
# Sets the SOAP header. Expected to be a Hash that can be translated
|
|
45
57
|
# to XML via Hash.to_soap_xml or any other Object responding to to_s.
|
|
@@ -64,6 +76,11 @@ module Savon
|
|
|
64
76
|
@namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
|
|
65
77
|
end
|
|
66
78
|
|
|
79
|
+
# Convenience method for setting the "xmlns:wsdl" namespace.
|
|
80
|
+
def namespace=(namespace)
|
|
81
|
+
namespaces["xmlns:wsdl"] = namespace
|
|
82
|
+
end
|
|
83
|
+
|
|
67
84
|
# Sets the SOAP version.
|
|
68
85
|
def version=(version)
|
|
69
86
|
@version = version if Savon::SOAPVersions.include? version
|
|
@@ -77,17 +94,9 @@ module Savon
|
|
|
77
94
|
# Returns the SOAP envelope XML.
|
|
78
95
|
def to_xml
|
|
79
96
|
unless @xml_body
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
xml.env(:Header) do
|
|
84
|
-
xml << (header.to_soap_xml rescue header.to_s) + wsse_header
|
|
85
|
-
end
|
|
86
|
-
xml.env(:Body) do
|
|
87
|
-
xml.wsdl(@input.to_sym) do
|
|
88
|
-
xml << (@body.to_soap_xml rescue @body.to_s)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
97
|
+
@xml_body = @builder.env :Envelope, namespaces do |xml|
|
|
98
|
+
xml_header xml
|
|
99
|
+
xml_body xml
|
|
91
100
|
end
|
|
92
101
|
end
|
|
93
102
|
@xml_body
|
|
@@ -95,10 +104,34 @@ module Savon
|
|
|
95
104
|
|
|
96
105
|
private
|
|
97
106
|
|
|
107
|
+
# Adds a SOAP XML header to a given +xml+ Object.
|
|
108
|
+
def xml_header(xml)
|
|
109
|
+
xml.env(:Header) do
|
|
110
|
+
xml << (header.to_soap_xml rescue header.to_s) + wsse_header
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Adds a SOAP XML body to a given +xml+ Object.
|
|
115
|
+
def xml_body(xml)
|
|
116
|
+
xml.env(:Body) do
|
|
117
|
+
xml.tag!(:wsdl, *input_array) do
|
|
118
|
+
xml << (@body.to_soap_xml rescue @body.to_s)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Returns an Array of SOAP input names to append to the :wsdl namespace.
|
|
124
|
+
# Defaults to use the name of the SOAP action and may be an empty Array
|
|
125
|
+
# in case the specified SOAP input seems invalid.
|
|
126
|
+
def input_array
|
|
127
|
+
return [input.to_sym] unless input.blank?
|
|
128
|
+
return [action.to_sym] unless action.blank?
|
|
129
|
+
[]
|
|
130
|
+
end
|
|
131
|
+
|
|
98
132
|
# Returns the WSSE header or an empty String in case WSSE was not set.
|
|
99
133
|
def wsse_header
|
|
100
|
-
|
|
101
|
-
@wsse.header
|
|
134
|
+
@wsse.respond_to?(:header) ? @wsse.header : ""
|
|
102
135
|
end
|
|
103
136
|
|
|
104
137
|
end
|
data/lib/savon/wsdl.rb
CHANGED
|
@@ -2,74 +2,121 @@ module Savon
|
|
|
2
2
|
|
|
3
3
|
# Savon::WSDL
|
|
4
4
|
#
|
|
5
|
-
# Represents
|
|
5
|
+
# Represents the WSDL document.
|
|
6
6
|
class WSDL
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Initializer, expects a Savon::Request.
|
|
9
9
|
def initialize(request)
|
|
10
10
|
@request = request
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# Sets whether to use the WSDL.
|
|
14
|
+
attr_writer :enabled
|
|
15
|
+
|
|
16
|
+
# Returns whether to use the WSDL. Defaults to +true+.
|
|
17
|
+
def enabled?
|
|
18
|
+
@enabled.nil? ? true : @enabled
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns the namespace URI of the WSDL.
|
|
14
22
|
def namespace_uri
|
|
15
|
-
@namespace_uri ||=
|
|
23
|
+
@namespace_uri ||= stream.namespace_uri
|
|
16
24
|
end
|
|
17
25
|
|
|
18
|
-
# Returns
|
|
19
|
-
# and their original names and inputs in another Hash (values).
|
|
26
|
+
# Returns an Array of available SOAP actions.
|
|
20
27
|
def soap_actions
|
|
21
|
-
@soap_actions ||=
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
@soap_actions ||= stream.operations.keys
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns a Hash of SOAP operations including their corresponding
|
|
32
|
+
# SOAP actions and inputs.
|
|
33
|
+
def operations
|
|
34
|
+
@operations ||= stream.operations
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns the SOAP endpoint.
|
|
38
|
+
def soap_endpoint
|
|
39
|
+
@soap_endpoint ||= stream.soap_endpoint
|
|
24
40
|
end
|
|
25
41
|
|
|
26
42
|
# Returns +true+ for available methods and SOAP actions.
|
|
27
43
|
def respond_to?(method)
|
|
28
|
-
return true if soap_actions.
|
|
44
|
+
return true if soap_actions.include? method
|
|
29
45
|
super
|
|
30
46
|
end
|
|
31
47
|
|
|
32
|
-
# Returns the WSDL document.
|
|
48
|
+
# Returns the raw WSDL document.
|
|
33
49
|
def to_s
|
|
34
|
-
|
|
50
|
+
@document ||= @request.wsdl.body
|
|
35
51
|
end
|
|
36
52
|
|
|
37
53
|
private
|
|
38
54
|
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
raise ArgumentError, "Invalid WSDL: #{@request.endpoint}" if soap_actions.empty?
|
|
55
|
+
# Returns the Savon::WSDLStream.
|
|
56
|
+
def stream
|
|
57
|
+
unless @stream
|
|
58
|
+
@stream = WSDLStream.new
|
|
59
|
+
REXML::Document.parse_stream to_s, @stream
|
|
45
60
|
end
|
|
46
|
-
@
|
|
61
|
+
@stream
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Savon::WSDLStream
|
|
67
|
+
#
|
|
68
|
+
# Stream listener for parsing the WSDL document.
|
|
69
|
+
class WSDLStream
|
|
70
|
+
|
|
71
|
+
# The main sections of a WSDL document.
|
|
72
|
+
Sections = %w(definitions types message portType binding service)
|
|
73
|
+
|
|
74
|
+
def initialize
|
|
75
|
+
@depth, @operations = 0, {}
|
|
47
76
|
end
|
|
48
77
|
|
|
49
|
-
# Returns
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
# Returns the namespace URI.
|
|
79
|
+
attr_reader :namespace_uri
|
|
80
|
+
|
|
81
|
+
# Returns the SOAP operations.
|
|
82
|
+
attr_reader :operations
|
|
83
|
+
|
|
84
|
+
# Returns the SOAP endpoint.
|
|
85
|
+
attr_reader :soap_endpoint
|
|
86
|
+
|
|
87
|
+
# Hook method called when the stream parser encounters a starting tag.
|
|
88
|
+
def tag_start(tag, attrs)
|
|
89
|
+
@depth += 1
|
|
90
|
+
tag = tag.strip_namespace
|
|
91
|
+
|
|
92
|
+
@section = tag.to_sym if @depth <= 2 && Sections.include?(tag)
|
|
93
|
+
@namespace_uri ||= attrs["targetNamespace"] if @section == :definitions
|
|
94
|
+
@soap_endpoint ||= URI(attrs["location"]) if @section == :service && tag == "address"
|
|
95
|
+
|
|
96
|
+
operation_from tag, attrs if @section == :binding && tag == "operation"
|
|
52
97
|
end
|
|
53
98
|
|
|
54
|
-
#
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
definitions.attributes["targetNamespace"] if definitions
|
|
99
|
+
# Hook method called when the stream parser encounters a closing tag.
|
|
100
|
+
def tag_end(tag)
|
|
101
|
+
@depth -= 1
|
|
58
102
|
end
|
|
59
103
|
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
wsdl_binding = document.elements["//wsdl:binding"]
|
|
64
|
-
return {} unless wsdl_binding
|
|
104
|
+
# Stores available operations from a given tag +name+ and +attrs+.
|
|
105
|
+
def operation_from(tag, attrs)
|
|
106
|
+
@input = attrs["name"] if attrs["name"]
|
|
65
107
|
|
|
66
|
-
|
|
67
|
-
action =
|
|
68
|
-
|
|
108
|
+
if attrs["soapAction"]
|
|
109
|
+
@action = !attrs["soapAction"].blank? ? attrs["soapAction"] : @input
|
|
110
|
+
@input = @action.split("/").last if !@input || @input.empty?
|
|
69
111
|
|
|
70
|
-
|
|
112
|
+
@operations[@input.snakecase.to_sym] = { :action => @action, :input => @input }
|
|
113
|
+
@input, @action = nil, nil
|
|
71
114
|
end
|
|
72
115
|
end
|
|
73
116
|
|
|
117
|
+
# Catches calls to unimplemented hook methods.
|
|
118
|
+
def method_missing(method, *args)
|
|
119
|
+
end
|
|
120
|
+
|
|
74
121
|
end
|
|
75
122
|
end
|
data/lib/savon/wsse.rb
CHANGED
|
@@ -11,73 +11,79 @@ module Savon
|
|
|
11
11
|
# Namespace for WS Security Utility.
|
|
12
12
|
WSUNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
|
13
13
|
|
|
14
|
-
#
|
|
15
|
-
|
|
14
|
+
# Global WSSE username.
|
|
15
|
+
@@username = nil
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@digest = false
|
|
22
|
-
|
|
23
|
-
class << self
|
|
17
|
+
# Returns the global WSSE username.
|
|
18
|
+
def self.username
|
|
19
|
+
@@username
|
|
20
|
+
end
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
# Sets the global WSSE username.
|
|
23
|
+
def self.username=(username)
|
|
24
|
+
@@username = username.to_s if username.respond_to? :to_s
|
|
25
|
+
@@username = nil if username.nil?
|
|
26
|
+
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@username = username.to_s if username.respond_to? :to_s
|
|
31
|
-
end
|
|
28
|
+
# Global WSSE password.
|
|
29
|
+
@@password = nil
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
# Returns the global WSSE password.
|
|
32
|
+
def self.password
|
|
33
|
+
@@password
|
|
34
|
+
end
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
# Sets the global WSSE password.
|
|
37
|
+
def self.password=(password)
|
|
38
|
+
@@password = password.to_s if password.respond_to? :to_s
|
|
39
|
+
@@password = nil if password.nil?
|
|
40
|
+
end
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
# Global setting of whether to use WSSE digest.
|
|
43
|
+
@@digest = false
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
# Returns the global setting of whether to use WSSE digest.
|
|
46
|
+
def self.digest?
|
|
47
|
+
@@digest
|
|
48
|
+
end
|
|
48
49
|
|
|
50
|
+
# Global setting of whether to use WSSE digest.
|
|
51
|
+
def self.digest=(digest)
|
|
52
|
+
@@digest = digest
|
|
49
53
|
end
|
|
50
54
|
|
|
51
|
-
# Sets the WSSE username.
|
|
55
|
+
# Sets the WSSE username per request.
|
|
52
56
|
def username=(username)
|
|
53
57
|
@username = username.to_s if username.respond_to? :to_s
|
|
58
|
+
@username = nil if username.nil?
|
|
54
59
|
end
|
|
55
60
|
|
|
56
|
-
# Returns the WSSE username. Defaults to the global
|
|
61
|
+
# Returns the WSSE username. Defaults to the global setting.
|
|
57
62
|
def username
|
|
58
63
|
@username || self.class.username
|
|
59
64
|
end
|
|
60
65
|
|
|
61
|
-
# Sets the WSSE password.
|
|
66
|
+
# Sets the WSSE password per request.
|
|
62
67
|
def password=(password)
|
|
63
68
|
@password = password.to_s if password.respond_to? :to_s
|
|
69
|
+
@password = nil if password.nil?
|
|
64
70
|
end
|
|
65
71
|
|
|
66
|
-
# Returns the WSSE password. Defaults to the global
|
|
72
|
+
# Returns the WSSE password. Defaults to the global setting.
|
|
67
73
|
def password
|
|
68
74
|
@password || self.class.password
|
|
69
75
|
end
|
|
70
76
|
|
|
71
|
-
# Sets whether to use WSSE digest.
|
|
77
|
+
# Sets whether to use WSSE digest per request.
|
|
72
78
|
attr_writer :digest
|
|
73
79
|
|
|
74
|
-
# Returns whether to use WSSE digest. Defaults to the global
|
|
80
|
+
# Returns whether to use WSSE digest. Defaults to the global setting.
|
|
75
81
|
def digest?
|
|
76
82
|
@digest || self.class.digest?
|
|
77
83
|
end
|
|
78
84
|
|
|
79
|
-
# Returns the XML for a WSSE header or an empty String unless
|
|
80
|
-
# and password
|
|
85
|
+
# Returns the XML for a WSSE header or an empty String unless both
|
|
86
|
+
# username and password were specified.
|
|
81
87
|
def header
|
|
82
88
|
return "" unless username && password
|
|
83
89
|
|