savon 0.7.1 → 0.7.2
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 +8 -0
- data/lib/savon/request.rb +2 -8
- data/lib/savon/response.rb +10 -7
- data/lib/savon/soap.rb +42 -4
- data/lib/savon/wsse.rb +17 -3
- data/spec/endpoint_helper.rb +4 -4
- data/spec/integration/http_basic_auth_spec.rb +8 -4
- data/spec/savon/response_spec.rb +7 -0
- data/spec/savon/soap_spec.rb +40 -0
- data/spec/savon/wsse_spec.rb +6 -6
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.7.2 (2010-01-17)
|
2
|
+
* Exposed the Net::HTTP response (added by Kevin Ingolfsland). Use the "http" accessor (response.http) on your
|
3
|
+
Savon::Response to access the Net::HTTP response object.
|
4
|
+
* Fix for Github issue #21 (savon is stripping ?SOAP off the end of WSDL locations).
|
5
|
+
* Fix for Github issue #22 (REXML::ParseException parsing 401 Unauthorized response body).
|
6
|
+
* Fix for Github issue #19 (Unable to set attribute in name-spaced WSSE password element).
|
7
|
+
* Added support for global header and namespaces. See Github issue #9 (Setting headers and namespaces).
|
8
|
+
|
1
9
|
== 0.7.1 (2010-01-10)
|
2
10
|
* The Hash of HTTP headers for SOAP calls is now public via Savon::Request#headers.
|
3
11
|
Patch for: http://github.com/rubiii/savon/issues/#issue/8
|
data/lib/savon/request.rb
CHANGED
@@ -122,20 +122,14 @@ module Savon
|
|
122
122
|
# to an optional block.
|
123
123
|
def request(type)
|
124
124
|
request = case type
|
125
|
-
when :wsdl then Net::HTTP::Get.new
|
126
|
-
when :soap then Net::HTTP::Post.new @soap.endpoint.
|
125
|
+
when :wsdl then Net::HTTP::Get.new @endpoint.to_s
|
126
|
+
when :soap then Net::HTTP::Post.new @soap.endpoint.to_s, headers.merge(soap_headers)
|
127
127
|
end
|
128
128
|
request.basic_auth *@basic_auth if @basic_auth
|
129
129
|
yield request if block_given?
|
130
130
|
request
|
131
131
|
end
|
132
132
|
|
133
|
-
# Returns the WSDL endpoint.
|
134
|
-
def wsdl_endpoint
|
135
|
-
return @endpoint.path unless @endpoint.query
|
136
|
-
"#{@endpoint.path}?#{@endpoint.query}"
|
137
|
-
end
|
138
|
-
|
139
133
|
# Returns a Hash containing the SOAP headers for an HTTP request.
|
140
134
|
def soap_headers
|
141
135
|
{ "Content-Type" => ContentType[@soap.version], "SOAPAction" => @soap.action }
|
data/lib/savon/response.rb
CHANGED
@@ -19,8 +19,8 @@ module Savon
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Expects a Net::HTTPResponse and handles errors.
|
22
|
-
def initialize(
|
23
|
-
@
|
22
|
+
def initialize(http)
|
23
|
+
@http = http
|
24
24
|
|
25
25
|
handle_soap_fault
|
26
26
|
handle_http_error
|
@@ -44,14 +44,17 @@ module Savon
|
|
44
44
|
|
45
45
|
# Returns the SOAP response body as a Hash.
|
46
46
|
def to_hash
|
47
|
-
@body ||= Crack::XML.parse(@
|
47
|
+
@body ||= (Crack::XML.parse(@http.body) rescue {}).find_soap_body
|
48
48
|
end
|
49
49
|
|
50
50
|
# Returns the SOAP response XML.
|
51
51
|
def to_xml
|
52
|
-
@
|
52
|
+
@http.body
|
53
53
|
end
|
54
54
|
|
55
|
+
# Returns the HTTP response object.
|
56
|
+
attr_reader :http
|
57
|
+
|
55
58
|
alias :to_s :to_xml
|
56
59
|
|
57
60
|
private
|
@@ -85,9 +88,9 @@ module Savon
|
|
85
88
|
# Handles HTTP errors. Raises a Savon::HTTPError unless the default
|
86
89
|
# behavior of raising errors was turned off.
|
87
90
|
def handle_http_error
|
88
|
-
if @
|
89
|
-
@http_error = "#{@
|
90
|
-
@http_error << ": #{@
|
91
|
+
if @http.code.to_i >= 300
|
92
|
+
@http_error = "#{@http.message} (#{@http.code})"
|
93
|
+
@http_error << ": #{@http.body}" unless @http.body.empty?
|
91
94
|
raise Savon::HTTPError, http_error if self.class.raise_errors?
|
92
95
|
end
|
93
96
|
end
|
data/lib/savon/soap.rb
CHANGED
@@ -27,6 +27,30 @@ module Savon
|
|
27
27
|
@@version = version if Savon::SOAPVersions.include? version
|
28
28
|
end
|
29
29
|
|
30
|
+
# Sets the global SOAP header. Expected to be a Hash that can be translated
|
31
|
+
# to XML via Hash.to_soap_xml or any other Object responding to to_s.
|
32
|
+
def self.header=(header)
|
33
|
+
@@header = header
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the global SOAP header. Defaults to an empty Hash.
|
37
|
+
def self.header
|
38
|
+
@@header ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sets the global namespaces. Expected to be a Hash containing the
|
42
|
+
# namespaces (keys) and the corresponding URI's (values).
|
43
|
+
def self.namespaces=(namespaces)
|
44
|
+
@@namespaces = namespaces if namespaces.kind_of? Hash
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the global namespaces. A Hash containing the namespaces (keys)
|
48
|
+
# and the corresponding URI's (values).
|
49
|
+
def self.namespaces
|
50
|
+
@@namespaces ||= {}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Initialzes the SOAP object.
|
30
54
|
def initialize
|
31
55
|
@builder = Builder::XmlMarkup.new
|
32
56
|
end
|
@@ -70,8 +94,8 @@ module Savon
|
|
70
94
|
# (keys) and the corresponding URI's (values).
|
71
95
|
attr_writer :namespaces
|
72
96
|
|
73
|
-
# Returns the namespaces. A Hash containing the namespaces (keys)
|
74
|
-
# the corresponding URI's (values).
|
97
|
+
# Returns the namespaces. A Hash containing the namespaces (keys)
|
98
|
+
# and the corresponding URI's (values).
|
75
99
|
def namespaces
|
76
100
|
@namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
|
77
101
|
end
|
@@ -94,7 +118,7 @@ module Savon
|
|
94
118
|
# Returns the SOAP envelope XML.
|
95
119
|
def to_xml
|
96
120
|
unless @xml_body
|
97
|
-
@xml_body = @builder.env :Envelope,
|
121
|
+
@xml_body = @builder.env :Envelope, all_namespaces do |xml|
|
98
122
|
xml_header xml
|
99
123
|
xml_body xml
|
100
124
|
end
|
@@ -107,7 +131,16 @@ module Savon
|
|
107
131
|
# Adds a SOAP XML header to a given +xml+ Object.
|
108
132
|
def xml_header(xml)
|
109
133
|
xml.env(:Header) do
|
110
|
-
xml <<
|
134
|
+
xml << all_header + wsse_header
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns a String containing the global and per request header.
|
139
|
+
def all_header
|
140
|
+
if self.class.header.kind_of?(Hash) && header.kind_of?(Hash)
|
141
|
+
self.class.header.merge(header).to_soap_xml
|
142
|
+
else
|
143
|
+
self.class.header.to_s + header.to_s
|
111
144
|
end
|
112
145
|
end
|
113
146
|
|
@@ -120,6 +153,11 @@ module Savon
|
|
120
153
|
end
|
121
154
|
end
|
122
155
|
|
156
|
+
# Returns a Hash containing the global and per request namespaces.
|
157
|
+
def all_namespaces
|
158
|
+
self.class.namespaces.merge namespaces
|
159
|
+
end
|
160
|
+
|
123
161
|
# Returns an Array of SOAP input names to append to the :wsdl namespace.
|
124
162
|
# Defaults to use the name of the SOAP action and may be an empty Array
|
125
163
|
# in case the specified SOAP input seems invalid.
|
data/lib/savon/wsse.rb
CHANGED
@@ -5,11 +5,20 @@ module Savon
|
|
5
5
|
# Represents parameters for WSSE authentication.
|
6
6
|
class WSSE
|
7
7
|
|
8
|
+
# Base address for WSSE docs.
|
9
|
+
BaseAddress = "http://docs.oasis-open.org/wss/2004/01"
|
10
|
+
|
8
11
|
# Namespace for WS Security Secext.
|
9
|
-
WSENamespace = "
|
12
|
+
WSENamespace = BaseAddress + "/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
10
13
|
|
11
14
|
# Namespace for WS Security Utility.
|
12
|
-
WSUNamespace = "
|
15
|
+
WSUNamespace = BaseAddress + "/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
16
|
+
|
17
|
+
# URI for "wsse:Password/@Type" #PasswordText.
|
18
|
+
PasswordTextURI = BaseAddress + "/oasis-200401-wss-username-token-profile-1.0#PasswordText"
|
19
|
+
|
20
|
+
# URI for "wsse:Password/@Type" #PasswordDigest.
|
21
|
+
PasswordDigestURI = BaseAddress + "/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
|
13
22
|
|
14
23
|
# Global WSSE username.
|
15
24
|
@@username = nil
|
@@ -93,7 +102,7 @@ module Savon
|
|
93
102
|
xml.wsse :Username, username
|
94
103
|
xml.wsse :Nonce, nonce
|
95
104
|
xml.wsu :Created, timestamp
|
96
|
-
xml.wsse :Password, password_node
|
105
|
+
xml.wsse :Password, password_node, :Type => password_type
|
97
106
|
end
|
98
107
|
end
|
99
108
|
end
|
@@ -108,6 +117,11 @@ module Savon
|
|
108
117
|
Base64.encode64(Digest::SHA1.hexdigest(token)).chomp!
|
109
118
|
end
|
110
119
|
|
120
|
+
# Returns the URI for the "wsse:Password/@Type" attribute.
|
121
|
+
def password_type
|
122
|
+
digest? ? PasswordDigestURI : PasswordTextURI
|
123
|
+
end
|
124
|
+
|
111
125
|
# Returns a WSSE nonce.
|
112
126
|
def nonce
|
113
127
|
@nonce ||= Digest::SHA1.hexdigest String.random + timestamp
|
data/spec/endpoint_helper.rb
CHANGED
@@ -5,16 +5,16 @@ class EndpointHelper
|
|
5
5
|
case type
|
6
6
|
when :no_namespace then "http://nons.example.com/Service?wsdl"
|
7
7
|
when :namespaced_actions then "http://nsactions.example.com/Service?wsdl"
|
8
|
-
else soap_endpoint(type)
|
8
|
+
else soap_endpoint(type)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
# Returns the SOAP endpoint for a given +type+ of request.
|
13
13
|
def self.soap_endpoint(type = nil)
|
14
14
|
case type
|
15
|
-
when :soap_fault then "http://soapfault.example.com/Service"
|
16
|
-
when :http_error then "http://httperror.example.com/Service"
|
17
|
-
when :invalid then "http://invalid.example.com/Service"
|
15
|
+
when :soap_fault then "http://soapfault.example.com/Service?wsdl"
|
16
|
+
when :http_error then "http://httperror.example.com/Service?wsdl"
|
17
|
+
when :invalid then "http://invalid.example.com/Service?wsdl"
|
18
18
|
else "http://example.com/validation/1.0/AuthenticationService"
|
19
19
|
end
|
20
20
|
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
require "basic_spec_helper"
|
2
2
|
|
3
3
|
describe Savon do
|
4
|
-
before { @
|
4
|
+
before { @client = Savon::Client.new "http://localhost:8080/http-basic-auth" }
|
5
5
|
|
6
6
|
it "should be able to handle HTTP basic authentication" do
|
7
|
-
client
|
8
|
-
client.
|
9
|
-
response = client.do_something!
|
7
|
+
@client.request.basic_auth "user", "password"
|
8
|
+
response = @client.do_something!
|
10
9
|
response.to_hash[:authenticate_response][:return][:success].should == true
|
11
10
|
end
|
11
|
+
|
12
|
+
it "should raise a Savon::HTTPError in case authentication failed" do
|
13
|
+
lambda { @client.do_something! }.should raise_error(Savon::HTTPError)
|
14
|
+
end
|
15
|
+
|
12
16
|
end
|
data/spec/savon/response_spec.rb
CHANGED
@@ -110,6 +110,13 @@ describe Savon::Response do
|
|
110
110
|
@response.to_s.should == ResponseFixture.authentication
|
111
111
|
end
|
112
112
|
|
113
|
+
it "should return the Net::HTTP response object" do
|
114
|
+
@response.http.should be_a(Mocha::Mock)
|
115
|
+
@response.http.should respond_to(:code)
|
116
|
+
@response.http.should respond_to(:message)
|
117
|
+
@response.http.should respond_to(:body)
|
118
|
+
end
|
119
|
+
|
113
120
|
def savon_response_with(error_type)
|
114
121
|
mock = case error_type
|
115
122
|
when :soap_fault then http_response_mock 200, ResponseFixture.soap_fault
|
data/spec/savon/soap_spec.rb
CHANGED
@@ -46,6 +46,14 @@ describe Savon::SOAP do
|
|
46
46
|
@soap.input = "FindUserRequest"
|
47
47
|
end
|
48
48
|
|
49
|
+
it "has both getter and setter for global SOAP headers" do
|
50
|
+
header = { "some" => "header" }
|
51
|
+
Savon::SOAP.header = header
|
52
|
+
Savon::SOAP.header.should == header
|
53
|
+
|
54
|
+
Savon::SOAP.header = {}
|
55
|
+
end
|
56
|
+
|
49
57
|
it "has both getter and setter for the SOAP header" do
|
50
58
|
@soap.header.should be_a(Hash)
|
51
59
|
@soap.header.should be_empty
|
@@ -76,6 +84,14 @@ describe Savon::SOAP do
|
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
87
|
+
it "has both getter and setter for global namespaces" do
|
88
|
+
namespaces = { "some" => "namespace" }
|
89
|
+
Savon::SOAP.namespaces = namespaces
|
90
|
+
Savon::SOAP.namespaces.should == namespaces
|
91
|
+
|
92
|
+
Savon::SOAP.namespaces = {}
|
93
|
+
end
|
94
|
+
|
79
95
|
it "has a convenience method for setting the 'xmlns:wsdl' namespace" do
|
80
96
|
@soap.namespaces.should == { "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/" }
|
81
97
|
|
@@ -126,6 +142,30 @@ describe Savon::SOAP do
|
|
126
142
|
Savon::SOAP.version = 2
|
127
143
|
@soap.to_xml.should include(Savon::SOAP::SOAPNamespace[2])
|
128
144
|
end
|
145
|
+
|
146
|
+
it "merges global and per request headers defined as Hashes" do
|
147
|
+
Savon::SOAP.header = { "API-KEY" => "secret", "SOME-KEY" => "something" }
|
148
|
+
@soap.header["SOME-KEY"] = "somethingelse"
|
149
|
+
|
150
|
+
@soap.to_xml.should include("<API-KEY>secret</API-KEY>")
|
151
|
+
@soap.to_xml.should include("<SOME-KEY>somethingelse</SOME-KEY>")
|
152
|
+
end
|
153
|
+
|
154
|
+
it "joins global and per request headers defined as Strings" do
|
155
|
+
Savon::SOAP.header = "<API-KEY>secret</API-KEY>"
|
156
|
+
@soap.header = "<SOME-KEY>somethingelse</SOME-KEY>"
|
157
|
+
|
158
|
+
@soap.to_xml.should include("<API-KEY>secret</API-KEY>")
|
159
|
+
@soap.to_xml.should include("<SOME-KEY>somethingelse</SOME-KEY>")
|
160
|
+
end
|
161
|
+
|
162
|
+
it "merges the global and per request namespaces" do
|
163
|
+
Savon::SOAP.namespaces = { "xmlns:wsdl" => "namespace", "xmlns:v1" => "v1namespace" }
|
164
|
+
@soap.namespaces["xmlns:v1"] = "newV1namespace"
|
165
|
+
|
166
|
+
@soap.to_xml.should include('xmlns:wsdl="namespace"')
|
167
|
+
@soap.to_xml.should include('xmlns:v1="newV1namespace"')
|
168
|
+
end
|
129
169
|
end
|
130
170
|
|
131
171
|
end
|
data/spec/savon/wsse_spec.rb
CHANGED
@@ -2,12 +2,8 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Savon::WSSE do
|
4
4
|
before do
|
5
|
-
Savon::WSSE.username = nil
|
6
|
-
Savon::WSSE.
|
7
|
-
Savon::WSSE.digest = false
|
8
|
-
|
9
|
-
@wsse = Savon::WSSE.new
|
10
|
-
@username, @password = "gorilla", "secret"
|
5
|
+
Savon::WSSE.username, Savon::WSSE.password, Savon::WSSE.digest = nil, nil, false
|
6
|
+
@wsse, @username, @password = Savon::WSSE.new, "gorilla", "secret"
|
11
7
|
end
|
12
8
|
|
13
9
|
it "contains the namespace for WS Security Secext" do
|
@@ -84,6 +80,7 @@ describe Savon::WSSE do
|
|
84
80
|
header.should include_security_namespaces
|
85
81
|
header.should include(@username)
|
86
82
|
header.should include(@password)
|
83
|
+
header.should include(Savon::WSSE::PasswordTextURI)
|
87
84
|
end
|
88
85
|
|
89
86
|
it "with WSSE credentials specified via defaults" do
|
@@ -94,6 +91,7 @@ describe Savon::WSSE do
|
|
94
91
|
header.should include_security_namespaces
|
95
92
|
header.should include(@username)
|
96
93
|
header.should include(@password)
|
94
|
+
header.should include(Savon::WSSE::PasswordTextURI)
|
97
95
|
end
|
98
96
|
end
|
99
97
|
|
@@ -107,6 +105,7 @@ describe Savon::WSSE do
|
|
107
105
|
header.should include_security_namespaces
|
108
106
|
header.should include(@username)
|
109
107
|
header.should_not include(@password)
|
108
|
+
header.should include(Savon::WSSE::PasswordDigestURI)
|
110
109
|
end
|
111
110
|
|
112
111
|
it "via defaults" do
|
@@ -118,6 +117,7 @@ describe Savon::WSSE do
|
|
118
117
|
header.should include_security_namespaces
|
119
118
|
header.should include(@username)
|
120
119
|
header.should_not include(@password)
|
120
|
+
header.should include(Savon::WSSE::PasswordDigestURI)
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: savon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-17 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|