savon 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|