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 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
@@ -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 wsdl_endpoint
126
- when :soap then Net::HTTP::Post.new @soap.endpoint.path, headers.merge(soap_headers)
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 }
@@ -19,8 +19,8 @@ module Savon
19
19
  end
20
20
 
21
21
  # Expects a Net::HTTPResponse and handles errors.
22
- def initialize(response)
23
- @response = response
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(@response.body).find_soap_body
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
- @response.body
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 @response.code.to_i >= 300
89
- @http_error = "#{@response.message} (#{@response.code})"
90
- @http_error << ": #{@response.body}" unless @response.body.empty?
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
@@ -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) and
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, namespaces do |xml|
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 << (header.to_soap_xml rescue header.to_s) + wsse_header
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.
@@ -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 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
12
+ WSENamespace = BaseAddress + "/oasis-200401-wss-wssecurity-secext-1.0.xsd"
10
13
 
11
14
  # Namespace for WS Security Utility.
12
- WSUNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
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
@@ -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) + "?wsdl"
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 { @endpoint = "http://localhost:8080/http-basic-auth" }
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 = Savon::Client.new @endpoint
8
- client.request.basic_auth "user", "password"
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
@@ -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
@@ -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
@@ -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.password = nil
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.1
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-10 00:00:00 +01:00
12
+ date: 2010-01-17 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency