savon 2.17.2 → 2.17.3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/savon/http_error.rb +8 -6
- data/lib/savon/operation.rb +14 -22
- data/lib/savon/response.rb +17 -13
- data/lib/savon/transport/faraday.rb +9 -6
- data/lib/savon/transport/httpi.rb +10 -7
- data/lib/savon/transport/response.rb +29 -0
- data/lib/savon/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cde79beaab26839d499267e94eee281c4f35f34906fd6dfdd4fc4590dc2c710a
|
|
4
|
+
data.tar.gz: 93f661f0156d8331a68e440176d9aaef92d2744974858ee4f866e63f14a210a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f7436bc2d8c53b89a96a373ab015ce7461b86501549034b99a5ae585a8f25d113bd7e1d1897acc613360d8487bb198eeccf5d0cf4835be7e8f8e44dd4b637a3
|
|
7
|
+
data.tar.gz: 8e45f5f6494c8256878b54b4092f7a253686ddc5c9ea1f98cd372c9ed4b0c784a4b7c885604c70036a1398fe0ac5ff08847a13def8ed931c8ce7d5da6f7475df
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.17.3] - 2026-06-23
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
**Fix Savon::HTTPError compatibility with Faraday transport**
|
|
13
|
+
|
|
14
|
+
* **`Savon::HTTPError` works with the Faraday transport** ([#1050](https://github.com/savonrb/savon/issues/1050)). When a the WSDL could not be fetched under `transport: :faraday`, `Savon::HTTPError#to_s` and `#to_hash` raised `NoMethodError: undefined method 'code'` because they were handed a raw `Faraday::Response`, which exposes `#status` rather than `#code`. Transports now normalize adapter-specific response objects into `Savon::Transport::Response` before they reach `Savon::HTTPError`.
|
|
15
|
+
|
|
8
16
|
## [2.17.2] - 2026-06-10
|
|
9
17
|
|
|
10
18
|
**Fix CVE-2026-53510 and restore 2.17.0 cookie regressions**
|
data/lib/savon/http_error.rb
CHANGED
|
@@ -6,20 +6,22 @@ module Savon
|
|
|
6
6
|
http.error?
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def initialize(
|
|
10
|
-
@
|
|
9
|
+
def initialize(transport_response)
|
|
10
|
+
@transport_response = transport_response
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
def http
|
|
14
|
+
@transport_response
|
|
15
|
+
end
|
|
14
16
|
|
|
15
17
|
def to_s
|
|
16
|
-
String.new("HTTP error (#{
|
|
17
|
-
str_error << ": #{
|
|
18
|
+
String.new("HTTP error (#{http.code})").tap do |str_error|
|
|
19
|
+
str_error << ": #{http.body}" unless http.body.empty?
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def to_hash
|
|
22
|
-
{ code:
|
|
24
|
+
{ code: http.code, headers: http.headers, body: http.body }
|
|
23
25
|
end
|
|
24
26
|
end
|
|
25
27
|
end
|
data/lib/savon/operation.rb
CHANGED
|
@@ -33,19 +33,20 @@ module Savon
|
|
|
33
33
|
def self.create(operation_name, wsdl, globals, transport)
|
|
34
34
|
if wsdl.document?
|
|
35
35
|
ensure_name_is_symbol! operation_name
|
|
36
|
-
ensure_exists! operation_name, wsdl
|
|
36
|
+
ensure_exists! operation_name, wsdl, transport
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
new(operation_name, wsdl, globals, transport)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
# Verifies the operation is provided by the WSDL.
|
|
43
|
+
def self.ensure_exists!(operation_name, wsdl, transport)
|
|
43
44
|
unless wsdl.soap_actions.include? operation_name
|
|
44
45
|
raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
|
|
45
46
|
"Operations provided by your service: #{wsdl.soap_actions.inspect}"
|
|
46
47
|
end
|
|
47
48
|
rescue Wasabi::Resolver::HTTPError => e
|
|
48
|
-
raise HTTPError, e.response
|
|
49
|
+
raise HTTPError, transport.normalize_response(e.response)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def self.ensure_name_is_symbol!(operation_name)
|
|
@@ -73,19 +74,19 @@ module Savon
|
|
|
73
74
|
# Transport::Response (or legacy HTTPI::Response), the HTTP call
|
|
74
75
|
# is skipped and that response is used directly.
|
|
75
76
|
def call(locals = {}, &block)
|
|
76
|
-
builder
|
|
77
|
-
|
|
77
|
+
builder = build(locals, &block)
|
|
78
|
+
observer_response = Savon.notify_observers(@name, builder, @globals, @locals)
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
if
|
|
80
|
+
transport_response =
|
|
81
|
+
if observer_response.nil?
|
|
81
82
|
body = builder.to_s
|
|
82
83
|
headers = soap_headers(builder)
|
|
83
84
|
@transport.post(endpoint.to_s, headers, body, @locals)
|
|
84
85
|
else
|
|
85
|
-
normalize_observer_response(
|
|
86
|
+
normalize_observer_response(observer_response)
|
|
86
87
|
end
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
Response.new(transport_response, @globals, @locals)
|
|
89
90
|
end
|
|
90
91
|
|
|
91
92
|
# Builds and returns the HTTPI::Request that would be sent for this
|
|
@@ -106,10 +107,6 @@ module Savon
|
|
|
106
107
|
|
|
107
108
|
private
|
|
108
109
|
|
|
109
|
-
def create_response(response)
|
|
110
|
-
Response.new(response, @globals, @locals)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
110
|
def set_locals(locals, block)
|
|
114
111
|
locals = LocalOptions.new(locals)
|
|
115
112
|
BlockInterface.new(locals).evaluate(block) if block
|
|
@@ -173,17 +170,12 @@ module Savon
|
|
|
173
170
|
# Accepts Transport::Response directly (current contract), wraps
|
|
174
171
|
# HTTPI::Response with a deprecation warning (legacy observer support),
|
|
175
172
|
# and raises on anything else.
|
|
176
|
-
def normalize_observer_response(
|
|
177
|
-
return
|
|
173
|
+
def normalize_observer_response(observer_response)
|
|
174
|
+
return observer_response if observer_response.is_a?(Transport::Response)
|
|
178
175
|
|
|
179
|
-
if
|
|
176
|
+
if observer_response.is_a?(HTTPI::Response)
|
|
180
177
|
warn "Observers returning HTTPI::Response is deprecated - return Savon::Transport::Response instead.", uplevel: 1
|
|
181
|
-
return Transport::Response.
|
|
182
|
-
response.code,
|
|
183
|
-
response.headers,
|
|
184
|
-
response.body,
|
|
185
|
-
cookies: HTTPI::Cookie.list_from_headers(response.headers)
|
|
186
|
-
)
|
|
178
|
+
return Transport::Response.from_httpi(observer_response)
|
|
187
179
|
end
|
|
188
180
|
|
|
189
181
|
raise Error, "Observers need to return a Savon::Transport::Response " \
|
data/lib/savon/response.rb
CHANGED
|
@@ -9,19 +9,23 @@ module Savon
|
|
|
9
9
|
CRLF = /\r\n/
|
|
10
10
|
WSP = /[\t ]/
|
|
11
11
|
|
|
12
|
-
def initialize(
|
|
13
|
-
@
|
|
14
|
-
@globals
|
|
15
|
-
@locals
|
|
16
|
-
@attachments
|
|
17
|
-
@xml
|
|
18
|
-
@has_parsed_body
|
|
12
|
+
def initialize(transport_response, globals, locals)
|
|
13
|
+
@transport_response = transport_response
|
|
14
|
+
@globals = globals
|
|
15
|
+
@locals = locals
|
|
16
|
+
@attachments = []
|
|
17
|
+
@xml = ''
|
|
18
|
+
@has_parsed_body = false
|
|
19
19
|
|
|
20
20
|
build_soap_and_http_errors!
|
|
21
21
|
raise_soap_and_http_errors! if @globals[:raise_errors]
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
attr_reader :
|
|
24
|
+
attr_reader :globals, :locals, :soap_fault, :http_error
|
|
25
|
+
|
|
26
|
+
def http
|
|
27
|
+
@transport_response
|
|
28
|
+
end
|
|
25
29
|
|
|
26
30
|
def success?
|
|
27
31
|
!soap_fault? && !http_error?
|
|
@@ -29,11 +33,11 @@ module Savon
|
|
|
29
33
|
alias successful? success?
|
|
30
34
|
|
|
31
35
|
def soap_fault?
|
|
32
|
-
SOAPFault.present?(
|
|
36
|
+
SOAPFault.present?(http, xml)
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
def http_error?
|
|
36
|
-
HTTPError.present?
|
|
40
|
+
HTTPError.present? http
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
def header
|
|
@@ -70,7 +74,7 @@ module Savon
|
|
|
70
74
|
parse_body unless @has_parsed_body
|
|
71
75
|
@xml
|
|
72
76
|
else
|
|
73
|
-
|
|
77
|
+
http.body
|
|
74
78
|
end
|
|
75
79
|
end
|
|
76
80
|
|
|
@@ -132,8 +136,8 @@ module Savon
|
|
|
132
136
|
end
|
|
133
137
|
|
|
134
138
|
def build_soap_and_http_errors!
|
|
135
|
-
@soap_fault = SOAPFault.new(
|
|
136
|
-
@http_error = HTTPError.new(
|
|
139
|
+
@soap_fault = SOAPFault.new(http, nori, xml) if soap_fault?
|
|
140
|
+
@http_error = HTTPError.new(http) if http_error?
|
|
137
141
|
end
|
|
138
142
|
|
|
139
143
|
def raise_soap_and_http_errors!
|
|
@@ -38,17 +38,20 @@ module Savon
|
|
|
38
38
|
log_request(url, headers, body) if log?
|
|
39
39
|
|
|
40
40
|
faraday_response = @connection.post(url, body, headers)
|
|
41
|
-
response =
|
|
42
|
-
faraday_response.status,
|
|
43
|
-
faraday_response.headers.to_h,
|
|
44
|
-
faraday_response.body,
|
|
45
|
-
cookies: self.class.parse_cookies(faraday_response.headers)
|
|
46
|
-
)
|
|
41
|
+
response = normalize_response(faraday_response)
|
|
47
42
|
|
|
48
43
|
log_response(response) if log?
|
|
49
44
|
response
|
|
50
45
|
end
|
|
51
46
|
|
|
47
|
+
# Normalizes a native Faraday::Response into a Transport::Response.
|
|
48
|
+
#
|
|
49
|
+
# @param faraday_response [Faraday::Response]
|
|
50
|
+
# @return [Transport::Response]
|
|
51
|
+
def normalize_response(faraday_response)
|
|
52
|
+
Response.from_faraday(faraday_response)
|
|
53
|
+
end
|
|
54
|
+
|
|
52
55
|
# Parses Set-Cookie headers into a Hash of name => value. Accepts both
|
|
53
56
|
# the Array and String form. Attributes after the first ';' are discarded.
|
|
54
57
|
def self.parse_cookies(headers)
|
|
@@ -33,18 +33,21 @@ module Savon
|
|
|
33
33
|
|
|
34
34
|
log_request(http_request.url, http_request.headers, http_request.body) if log?
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
response =
|
|
38
|
-
http_response.code,
|
|
39
|
-
http_response.headers,
|
|
40
|
-
http_response.body,
|
|
41
|
-
cookies: ::HTTPI::Cookie.list_from_headers(http_response.headers)
|
|
42
|
-
)
|
|
36
|
+
httpi_response = ::HTTPI.post(http_request, @globals[:adapter])
|
|
37
|
+
response = normalize_response(httpi_response)
|
|
43
38
|
|
|
44
39
|
log_response(response) if log?
|
|
45
40
|
response
|
|
46
41
|
end
|
|
47
42
|
|
|
43
|
+
# Normalizes a native HTTPI::Response into a Transport::Response.
|
|
44
|
+
#
|
|
45
|
+
# @param httpi_response [HTTPI::Response]
|
|
46
|
+
# @return [Transport::Response]
|
|
47
|
+
def normalize_response(httpi_response)
|
|
48
|
+
Response.from_httpi(httpi_response)
|
|
49
|
+
end
|
|
50
|
+
|
|
48
51
|
# Builds a fully-configured HTTPI::Request.
|
|
49
52
|
#
|
|
50
53
|
# @param url [String] the SOAP endpoint URL
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "httpi"
|
|
4
|
+
require "savon/transport/faraday"
|
|
5
|
+
|
|
3
6
|
module Savon
|
|
4
7
|
module Transport
|
|
5
8
|
# Transport-agnostic HTTP response value object.
|
|
@@ -11,6 +14,32 @@ module Savon
|
|
|
11
14
|
# Array of HTTPI::Cookie, while Faraday responses expose a plain Hash so
|
|
12
15
|
# Faraday users do not depend on HTTPI types.
|
|
13
16
|
class Response
|
|
17
|
+
# Builds a Response from an HTTPI::Response.
|
|
18
|
+
#
|
|
19
|
+
# @param httpi_response [HTTPI::Response]
|
|
20
|
+
# @return [Transport::Response]
|
|
21
|
+
def self.from_httpi(httpi_response)
|
|
22
|
+
new(
|
|
23
|
+
httpi_response.code,
|
|
24
|
+
httpi_response.headers,
|
|
25
|
+
httpi_response.body,
|
|
26
|
+
cookies: ::HTTPI::Cookie.list_from_headers(httpi_response.headers)
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Builds a Response from a Faraday::Response.
|
|
31
|
+
#
|
|
32
|
+
# @param faraday_response [Faraday::Response]
|
|
33
|
+
# @return [Transport::Response]
|
|
34
|
+
def self.from_faraday(faraday_response)
|
|
35
|
+
new(
|
|
36
|
+
faraday_response.status,
|
|
37
|
+
faraday_response.headers.to_h,
|
|
38
|
+
faraday_response.body,
|
|
39
|
+
cookies: Savon::Transport::Faraday.parse_cookies(faraday_response.headers)
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
14
43
|
# @param code [Integer] HTTP status code
|
|
15
44
|
# @param headers [Hash] response headers
|
|
16
45
|
# @param body [String] response body
|
data/lib/savon/version.rb
CHANGED