savon 2.17.3 → 2.17.4
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 +17 -1
- data/lib/savon/addressing.rb +60 -0
- data/lib/savon/builder.rb +26 -4
- data/lib/savon/effective_options.rb +124 -0
- data/lib/savon/header.rb +81 -34
- data/lib/savon/operation.rb +14 -16
- data/lib/savon/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bba4a9ced6c62286d20de586b56ce7263413fa5e4b51771e87fded4c2433f39
|
|
4
|
+
data.tar.gz: 9327a65ee629c258691084a822b635738b4d31ea38c5bd38f8e3399f11b16cd9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a1d50a4b5f588cc1e094189f41aada85a2bbecf7b6dbf92b27c6041d7b3eb882808ec69c0d2f0e907cc572cea73c17bad18f82d74c400e4019836200ce1255e9
|
|
7
|
+
data.tar.gz: 9a61b3a21ae8a2c16761fb851c85355cd3e2575e540447ec7ac0fa5cbd42ae5bfa456c26813a5dce907fb9924f2cd6dece545f841f65a970a87445123fe90005
|
data/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,26 @@ 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.
|
|
8
|
+
## [2.17.4] - 2026-07-03
|
|
9
|
+
|
|
10
|
+
**Restore WS-Addressing headers and fix `:wsse_signature` resolution**
|
|
9
11
|
|
|
10
12
|
### Fixed
|
|
11
13
|
|
|
14
|
+
* **WS-Addressing headers are populated from the WSDL again** ([#1057](https://github.com/savonrb/savon/issues/1057)). With `use_wsa_headers: true` and no explicit `:soap_action` or `:endpoint`, Savon emitted empty `<wsa:Action xsi:nil="true"/>` and `<wsa:To xsi:nil="true"/>` elements instead of the operation's SOAPAction and service endpoint. Up to 2.16.0 those values were populated as a side effect of building the HTTP request. The 2.17.0 transport refactor removed that step.
|
|
15
|
+
* **A global `:host` override no longer rewrites the WSDL's endpoint.** Resolving the request endpoint with `:host` set replaced host and port of the parsed WSDL address in place, visible as a permanently changed `client.wsdl.endpoint` after the first call. Endpoint and SOAPAction resolution moved into `Savon::EffectiveOptions`, which applies the override to a copy and never touches the WSDL document.
|
|
16
|
+
* **A local `:wsse_signature` no longer crashes when set to `false`.** Passing `wsse_signature: false` to a call raised `NoMethodError: undefined method 'have_document?' for false` while building the WSSE header. The envelope builder and the SOAP header also resolved the option with different rules, so they could disagree on which signature applies. Both now read it through `Savon::EffectiveOptions`, the one place that resolves options settable in both the global and the local scope. A falsy local `:wsse_signature` falls back to the global one. Setting a signature object in either scope is unaffected.
|
|
17
|
+
|
|
18
|
+
### Deprecated
|
|
19
|
+
|
|
20
|
+
* **`Savon::Builder::WSA_NAMESPACE`.** WS-Addressing emission moved into `Savon::Addressing`, which owns the namespace as `Savon::Addressing::NAMESPACE`. The constant on `Savon::Builder` stays available as an alias and will be removed in Savon 3.
|
|
21
|
+
|
|
22
|
+
## [2.17.3] - 2026-06-23
|
|
23
|
+
|
|
12
24
|
**Fix Savon::HTTPError compatibility with Faraday transport**
|
|
13
25
|
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
14
28
|
* **`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
29
|
|
|
16
30
|
## [2.17.2] - 2026-06-10
|
|
@@ -1248,6 +1262,8 @@ Pay attention to the following list and read the updated Wiki: http://wiki.githu
|
|
|
1248
1262
|
|
|
1249
1263
|
* Complete rewrite and public release.
|
|
1250
1264
|
|
|
1265
|
+
[2.17.4]: https://github.com/savonrb/savon/compare/v2.17.3...v2.17.4
|
|
1266
|
+
[2.17.3]: https://github.com/savonrb/savon/compare/v2.17.2...v2.17.3
|
|
1251
1267
|
[2.17.2]: https://github.com/savonrb/savon/compare/v2.17.1...v2.17.2
|
|
1252
1268
|
[2.17.1]: https://github.com/savonrb/savon/compare/v2.17.0...v2.17.1
|
|
1253
1269
|
[2.17.0]: https://github.com/savonrb/savon/compare/v2.16.0...v2.17.0
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "gyoku"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
module Savon
|
|
7
|
+
# Emits the WS-Addressing message addressing properties of a request
|
|
8
|
+
# (WS-Addressing 1.0 - Core §3.2): +wsa:Action+, +wsa:To+ and +wsa:MessageID+.
|
|
9
|
+
#
|
|
10
|
+
# This object owns everything Savon knows about WS-Addressing: the namespace,
|
|
11
|
+
# whether the headers are emitted at all, and how the resolved SOAPAction and
|
|
12
|
+
# endpoint map onto the addressing properties. It works on plain values.
|
|
13
|
+
# {Savon::Header} resolves them via {Savon::EffectiveOptions} and constructs
|
|
14
|
+
# this object, keeping option resolution and WSA emission separate.
|
|
15
|
+
class Addressing
|
|
16
|
+
# The WS-Addressing 1.0 namespace,
|
|
17
|
+
# https://www.w3.org/TR/ws-addr-core/#namespaces.
|
|
18
|
+
NAMESPACE = "http://www.w3.org/2005/08/addressing"
|
|
19
|
+
|
|
20
|
+
# @param enabled [Object] whether the headers are emitted, any truthy value
|
|
21
|
+
# counts (the +:use_wsa_headers+ global)
|
|
22
|
+
# @param action [String, nil] the resolved SOAPAction, emitted as
|
|
23
|
+
# +wsa:Action+, or +nil+ when the caller disabled it
|
|
24
|
+
# @param to [URI, String, nil] the resolved endpoint, emitted as +wsa:To+
|
|
25
|
+
def initialize(enabled:, action: nil, to: nil)
|
|
26
|
+
@enabled = enabled
|
|
27
|
+
@action = action
|
|
28
|
+
@to = to
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Boolean] whether the WS-Addressing headers are emitted
|
|
32
|
+
def enabled?
|
|
33
|
+
!!@enabled
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the namespace declaration the enclosing Header element needs.
|
|
37
|
+
# The +wsa+ prefix is declared once on the Header, not on each child.
|
|
38
|
+
#
|
|
39
|
+
# @return [Hash{String => String}] +{"xmlns:wsa" => NAMESPACE}+, or an
|
|
40
|
+
# empty Hash when disabled
|
|
41
|
+
def namespace_attributes
|
|
42
|
+
enabled? ? { "xmlns:wsa" => NAMESPACE } : {}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Renders the three addressing properties, each rendering with a freshly
|
|
46
|
+
# generated +wsa:MessageID+. A +nil+ action or destination is emitted as
|
|
47
|
+
# an +xsi:nil+ element rather than being dropped.
|
|
48
|
+
#
|
|
49
|
+
# @return [String] the header elements, or an empty String when disabled
|
|
50
|
+
def to_xml
|
|
51
|
+
return "" unless enabled?
|
|
52
|
+
|
|
53
|
+
Gyoku.xml(
|
|
54
|
+
"wsa:Action" => @action,
|
|
55
|
+
"wsa:To" => @to,
|
|
56
|
+
"wsa:MessageID" => "urn:uuid:#{SecureRandom.uuid}"
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/savon/builder.rb
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "savon/addressing"
|
|
3
4
|
require "savon/header"
|
|
4
5
|
require "savon/message"
|
|
6
|
+
require "savon/effective_options"
|
|
5
7
|
require "nokogiri"
|
|
6
8
|
require "builder"
|
|
7
9
|
require "gyoku"
|
|
8
10
|
|
|
9
11
|
module Savon
|
|
12
|
+
# Builds the SOAP request for an operation: the XML envelope, or
|
|
13
|
+
# a multipart/related message when the request carries attachments
|
|
14
|
+
# (SOAP with Attachments, https://www.w3.org/TR/SOAP-attachments).
|
|
15
|
+
#
|
|
16
|
+
# It owns the envelope structure, its namespace declarations, and the body,
|
|
17
|
+
# and signs the document when a WSSE signature is present. Message-body
|
|
18
|
+
# serialization is delegated to {Savon::Message}, the Header element to
|
|
19
|
+
# {Savon::Header}, and Hash-to-XML conversion to Gyoku.
|
|
10
20
|
class Builder
|
|
11
21
|
attr_reader :multipart
|
|
12
22
|
|
|
@@ -20,15 +30,23 @@ module Savon
|
|
|
20
30
|
2 => "http://www.w3.org/2003/05/soap-envelope"
|
|
21
31
|
}.freeze
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
# @deprecated Use {Savon::Addressing::NAMESPACE} instead. This alias will
|
|
34
|
+
# be removed in Savon 3.0.
|
|
35
|
+
WSA_NAMESPACE = Addressing::NAMESPACE
|
|
24
36
|
|
|
37
|
+
# @param operation_name [Symbol] the SOAP operation being called
|
|
38
|
+
# @param wsdl [Wasabi::Document] the parsed WSDL, or an empty document when
|
|
39
|
+
# the client was configured without one
|
|
40
|
+
# @param globals [Savon::GlobalOptions] client-level options
|
|
41
|
+
# @param locals [Savon::LocalOptions] per-request options
|
|
25
42
|
def initialize(operation_name, wsdl, globals, locals)
|
|
26
43
|
@operation_name = operation_name
|
|
27
44
|
|
|
28
45
|
@wsdl = wsdl
|
|
29
46
|
@globals = globals
|
|
30
47
|
@locals = locals
|
|
31
|
-
@
|
|
48
|
+
@effective = EffectiveOptions.new(operation_name, wsdl, globals, locals)
|
|
49
|
+
@signature = @effective.wsse_signature
|
|
32
50
|
|
|
33
51
|
@types = convert_type_definitions_to_hash
|
|
34
52
|
@used_namespaces = convert_type_namespaces_to_hash
|
|
@@ -62,8 +80,12 @@ module Savon
|
|
|
62
80
|
end
|
|
63
81
|
end
|
|
64
82
|
|
|
83
|
+
# Returns the XML attributes of the envelope's Header element, provided
|
|
84
|
+
# by the header's sections.
|
|
85
|
+
#
|
|
86
|
+
# @return [Hash{String => String}]
|
|
65
87
|
def header_attributes
|
|
66
|
-
|
|
88
|
+
header.attributes
|
|
67
89
|
end
|
|
68
90
|
|
|
69
91
|
def body_attributes
|
|
@@ -139,7 +161,7 @@ module Savon
|
|
|
139
161
|
end
|
|
140
162
|
|
|
141
163
|
def header
|
|
142
|
-
@header ||= Header.new(@globals, @
|
|
164
|
+
@header ||= Header.new(@globals, @effective)
|
|
143
165
|
end
|
|
144
166
|
|
|
145
167
|
def namespaced_message_tag
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "gyoku"
|
|
4
|
+
require "uri"
|
|
5
|
+
|
|
6
|
+
module Savon
|
|
7
|
+
# Resolves the effective value of options whose answer combines more than
|
|
8
|
+
# one source: the per-request options, the client options, the WSDL
|
|
9
|
+
# document, and built-in defaults.
|
|
10
|
+
#
|
|
11
|
+
# {Savon::GlobalOptions} and {Savon::LocalOptions} store what the caller
|
|
12
|
+
# said. EffectiveOptions answers what the request uses. It owns the
|
|
13
|
+
# precedence rules and exposes one reader per resolvable option, so every
|
|
14
|
+
# consumer of an option resolves it identically. Resolution is a pure read.
|
|
15
|
+
# It never mutates the options or the WSDL document.
|
|
16
|
+
class EffectiveOptions
|
|
17
|
+
# @param operation_name [Symbol] the SOAP operation being called
|
|
18
|
+
# @param wsdl [Wasabi::Document] the parsed WSDL, or an empty document
|
|
19
|
+
# when the client was configured without one
|
|
20
|
+
# @param globals [Savon::GlobalOptions] the client-level options
|
|
21
|
+
# @param locals [Savon::LocalOptions] the per-request options
|
|
22
|
+
def initialize(operation_name, wsdl, globals, locals)
|
|
23
|
+
@operation_name = operation_name
|
|
24
|
+
@wsdl = wsdl
|
|
25
|
+
@globals = globals
|
|
26
|
+
@locals = locals
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Resolves the SOAPAction of the request (SOAP 1.1 §6.1.1).
|
|
30
|
+
#
|
|
31
|
+
# An explicit local +:soap_action+ wins. A local +false+ or +nil+ disables
|
|
32
|
+
# the action, so no SOAPAction HTTP header is sent and an enabled
|
|
33
|
+
# +wsa:Action+ header stays empty. Without a local value the WSDL provides
|
|
34
|
+
# the soapAction of the operation. Without a WSDL document the operation
|
|
35
|
+
# name is converted to an XML tag as a best-effort default.
|
|
36
|
+
#
|
|
37
|
+
# @return [String, nil] the action, or +nil+ when explicitly disabled
|
|
38
|
+
def soap_action
|
|
39
|
+
return if @locals.include?(:soap_action) && !@locals[:soap_action]
|
|
40
|
+
|
|
41
|
+
@locals[:soap_action] ||
|
|
42
|
+
(@wsdl.document? && @wsdl.soap_action(@operation_name.to_sym)) ||
|
|
43
|
+
Gyoku.xml_tag(@operation_name, key_converter: @globals[:convert_request_keys_to])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Resolves the endpoint URL the request is sent to.
|
|
47
|
+
#
|
|
48
|
+
# A global +:endpoint+ wins over the service address of the WSDL. The
|
|
49
|
+
# global +:host+ option replaces host and port of the WSDL address and
|
|
50
|
+
# keeps scheme, path and query. The override is applied to a copy. The
|
|
51
|
+
# WSDL document keeps its parsed address.
|
|
52
|
+
#
|
|
53
|
+
# @return [URI, String, nil] the endpoint as provided by the winning source
|
|
54
|
+
def endpoint
|
|
55
|
+
return @globals[:endpoint] if @globals[:endpoint]
|
|
56
|
+
return @wsdl.endpoint unless @globals[:host]
|
|
57
|
+
|
|
58
|
+
host_url = URI.parse(@globals[:host])
|
|
59
|
+
url = @wsdl.endpoint.dup
|
|
60
|
+
url.host = host_url.host
|
|
61
|
+
url.port = host_url.port
|
|
62
|
+
url
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Resolves the WSSE auth credentials passed to Akami. A local value takes
|
|
66
|
+
# precedence over the global one. A local +false+ disables auth even when a
|
|
67
|
+
# global value is set. A local +nil+ leaves the option unset and falls
|
|
68
|
+
# through to the global value.
|
|
69
|
+
#
|
|
70
|
+
# @return [Array<String>, false, nil] the credentials, +false+ to disable,
|
|
71
|
+
# or +nil+ when unset in both scopes
|
|
72
|
+
def wsse_auth
|
|
73
|
+
prefer_local(:wsse_auth)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Resolves whether Akami emits a +wsu:Timestamp+ header, using the same
|
|
77
|
+
# local-over-global rule as {#wsse_auth}. A local +false+ disables it and a
|
|
78
|
+
# local +nil+ keeps the global value.
|
|
79
|
+
#
|
|
80
|
+
# @return [Boolean, nil]
|
|
81
|
+
def wsse_timestamp
|
|
82
|
+
prefer_local(:wsse_timestamp)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Resolves the WSSE signature used to sign the request. This option is a
|
|
86
|
+
# signature object or +nil+ and has no "disable" value, so any falsy local
|
|
87
|
+
# value falls back to the global one. {Savon::Builder} and {Savon::Header}
|
|
88
|
+
# both read it and must resolve it identically.
|
|
89
|
+
#
|
|
90
|
+
# @return [Akami::WSSE::Signature, nil]
|
|
91
|
+
def wsse_signature
|
|
92
|
+
@locals[:wsse_signature] || @globals[:wsse_signature]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Resolves the SOAP header content. When both scopes provide a Hash the two
|
|
96
|
+
# are merged and local keys win. Otherwise the local value is preferred and
|
|
97
|
+
# falls back to the global one. A Hash is rendered to XML by Gyoku. A String,
|
|
98
|
+
# or any object responding to +#to_s+, is used verbatim.
|
|
99
|
+
#
|
|
100
|
+
# @return [Hash, String, nil]
|
|
101
|
+
def soap_header
|
|
102
|
+
global = @globals[:soap_header]
|
|
103
|
+
local = @locals[:soap_header]
|
|
104
|
+
|
|
105
|
+
if global.is_a?(Hash) && local.is_a?(Hash)
|
|
106
|
+
global.merge(local)
|
|
107
|
+
else
|
|
108
|
+
local || global
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
# Resolves an option where a local +false+ is meaningful and disables it.
|
|
115
|
+
# Only a local +nil+ falls through to the global value. Contrast with
|
|
116
|
+
# {#wsse_signature}, which treats any falsy local as unset.
|
|
117
|
+
#
|
|
118
|
+
# @param key [Symbol] the option name
|
|
119
|
+
# @return [Object, nil] the local value unless it is +nil+, else the global
|
|
120
|
+
def prefer_local(key)
|
|
121
|
+
@locals[key].nil? ? @globals[key] : @locals[key]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
data/lib/savon/header.rb
CHANGED
|
@@ -2,71 +2,113 @@
|
|
|
2
2
|
|
|
3
3
|
require "akami"
|
|
4
4
|
require "gyoku"
|
|
5
|
-
require "
|
|
5
|
+
require "savon/addressing"
|
|
6
6
|
|
|
7
7
|
module Savon
|
|
8
|
+
# Assembles the SOAP +Header+ element of a request envelope and renders it to
|
|
9
|
+
# XML.
|
|
10
|
+
#
|
|
11
|
+
# A SOAP Header carries a request's out-of-band metadata. This object is
|
|
12
|
+
# responsible for every header block Savon can emit, concatenated in this
|
|
13
|
+
# order:
|
|
14
|
+
#
|
|
15
|
+
# 1. application headers supplied by the caller (the +soap_header+ option),
|
|
16
|
+
# 2. the WS-Addressing headers, rendered by {Savon::Addressing},
|
|
17
|
+
# 3. the WS-Security header with UsernameToken credentials, a +wsu:Timestamp+
|
|
18
|
+
# and an XML Signature (OASIS WSS SOAP Message Security 1.1).
|
|
19
|
+
#
|
|
20
|
+
# WS-Security markup is delegated to Akami and Hash-to-XML conversion to Gyoku.
|
|
8
21
|
class Header
|
|
9
|
-
|
|
22
|
+
# @param globals [Savon::GlobalOptions] client-level options, read for the
|
|
23
|
+
# Gyoku key converter (+:convert_request_keys_to+) and the WS-Addressing
|
|
24
|
+
# toggle (+:use_wsa_headers+)
|
|
25
|
+
# @param effective [Savon::EffectiveOptions] resolves the WSSE, soap_header,
|
|
26
|
+
# soap_action and endpoint values for the request
|
|
27
|
+
def initialize(globals, effective)
|
|
10
28
|
@gyoku_options = { key_converter: globals[:convert_request_keys_to] }
|
|
11
29
|
|
|
12
|
-
@wsse_auth =
|
|
13
|
-
@wsse_timestamp =
|
|
14
|
-
@wsse_signature =
|
|
30
|
+
@wsse_auth = effective.wsse_auth
|
|
31
|
+
@wsse_timestamp = effective.wsse_timestamp
|
|
32
|
+
@wsse_signature = effective.wsse_signature
|
|
33
|
+
@soap_header = effective.soap_header
|
|
15
34
|
|
|
16
|
-
@
|
|
17
|
-
@
|
|
35
|
+
@addressing = build_addressing(globals, effective)
|
|
36
|
+
@header = build
|
|
37
|
+
end
|
|
18
38
|
|
|
19
|
-
|
|
20
|
-
@locals = locals
|
|
39
|
+
attr_reader :gyoku_options, :wsse_auth, :wsse_timestamp, :wsse_signature
|
|
21
40
|
|
|
22
|
-
|
|
41
|
+
# Returns the XML attributes of the enclosing Header element. Only the
|
|
42
|
+
# WS-Addressing section declares one, the +xmlns:wsa+ prefix.
|
|
43
|
+
#
|
|
44
|
+
# @return [Hash{String => String}]
|
|
45
|
+
def attributes
|
|
46
|
+
@addressing.namespace_attributes
|
|
23
47
|
end
|
|
24
48
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
49
|
+
# @return [Boolean] whether the rendered header is empty, i.e. there is no
|
|
50
|
+
# header content to include in the envelope
|
|
28
51
|
def empty?
|
|
29
52
|
@header.empty?
|
|
30
53
|
end
|
|
31
54
|
|
|
55
|
+
# Returns the rendered SOAP header XML. The header is built once during
|
|
56
|
+
# construction and cached, so this is a cheap, repeatable read.
|
|
57
|
+
#
|
|
58
|
+
# @return [String] the header XML (may be empty)
|
|
32
59
|
def to_s
|
|
33
60
|
@header
|
|
34
61
|
end
|
|
35
62
|
|
|
36
63
|
private
|
|
37
64
|
|
|
65
|
+
# Constructs the WS-Addressing section from the resolved request values.
|
|
66
|
+
# Resolving the endpoint raises without a WSDL document and without a
|
|
67
|
+
# global +:endpoint+, so action and endpoint are only resolved when the
|
|
68
|
+
# +:use_wsa_headers+ global asks for the headers.
|
|
69
|
+
#
|
|
70
|
+
# @return [Savon::Addressing]
|
|
71
|
+
def build_addressing(globals, effective)
|
|
72
|
+
return Addressing.new(enabled: false) unless globals[:use_wsa_headers]
|
|
73
|
+
|
|
74
|
+
Addressing.new(
|
|
75
|
+
enabled: true,
|
|
76
|
+
action: effective.soap_action,
|
|
77
|
+
to: effective.endpoint
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Concatenates the three header sections in document order: caller content,
|
|
82
|
+
# WS-Addressing, then WSSE security.
|
|
83
|
+
#
|
|
84
|
+
# @return [String]
|
|
38
85
|
def build
|
|
39
|
-
build_header +
|
|
86
|
+
build_header + @addressing.to_xml + build_wsse_header
|
|
40
87
|
end
|
|
41
88
|
|
|
89
|
+
# Renders the resolved soap_header. {Savon::EffectiveOptions#soap_header}
|
|
90
|
+
# merges the global and local values, so there is nothing to combine here.
|
|
91
|
+
# Hash-to-XML conversion only. Strings pass through.
|
|
92
|
+
#
|
|
93
|
+
# @return [String]
|
|
42
94
|
def build_header
|
|
43
|
-
|
|
44
|
-
if global_header.is_a?(Hash) && local_header.is_a?(Hash)
|
|
45
|
-
global_header.merge(local_header)
|
|
46
|
-
elsif local_header
|
|
47
|
-
local_header
|
|
48
|
-
else
|
|
49
|
-
global_header
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
convert_to_xml(header)
|
|
95
|
+
convert_to_xml(@soap_header)
|
|
53
96
|
end
|
|
54
97
|
|
|
98
|
+
# Builds the WS-Security header via Akami, or an empty string when no WSSE
|
|
99
|
+
# content (credentials, timestamp or signature) applies.
|
|
100
|
+
#
|
|
101
|
+
# @return [String]
|
|
55
102
|
def build_wsse_header
|
|
56
103
|
wsse_header = akami
|
|
57
104
|
wsse_header.respond_to?(:to_xml) ? wsse_header.to_xml : ""
|
|
58
105
|
end
|
|
59
106
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
'wsa:To' => @globals[:endpoint],
|
|
66
|
-
'wsa:MessageID' => "urn:uuid:#{SecureRandom.uuid}"
|
|
67
|
-
})
|
|
68
|
-
end
|
|
69
|
-
|
|
107
|
+
# Renders a header value to XML. A Hash goes through Gyoku (honouring the
|
|
108
|
+
# configured key converter), anything else is coerced with +#to_s+.
|
|
109
|
+
#
|
|
110
|
+
# @param hash_or_string [Hash, #to_s] the header content
|
|
111
|
+
# @return [String]
|
|
70
112
|
def convert_to_xml(hash_or_string)
|
|
71
113
|
if hash_or_string.is_a? Hash
|
|
72
114
|
Gyoku.xml(hash_or_string, gyoku_options)
|
|
@@ -75,6 +117,11 @@ module Savon
|
|
|
75
117
|
end
|
|
76
118
|
end
|
|
77
119
|
|
|
120
|
+
# Configures an Akami WSSE object from the resolved WSSE options. Sets the
|
|
121
|
+
# UsernameToken credentials, enables the wsu:Timestamp, and attaches the XML
|
|
122
|
+
# Signature when a document has been assigned to it.
|
|
123
|
+
#
|
|
124
|
+
# @return [Akami::WSSE] configured, not yet serialized
|
|
78
125
|
def akami
|
|
79
126
|
wsse = Akami.wsse
|
|
80
127
|
wsse.credentials(*wsse_auth) if wsse_auth
|
data/lib/savon/operation.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "savon/options"
|
|
4
|
+
require "savon/effective_options"
|
|
4
5
|
require "savon/block_interface"
|
|
5
6
|
require "savon/builder"
|
|
6
7
|
require "savon/response"
|
|
@@ -114,6 +115,13 @@ module Savon
|
|
|
114
115
|
@locals = locals
|
|
115
116
|
end
|
|
116
117
|
|
|
118
|
+
# The effective options view for the current request. Built on demand
|
|
119
|
+
# instead of being cached, so it always reflects the current per-request
|
|
120
|
+
# options.
|
|
121
|
+
def effective_options
|
|
122
|
+
EffectiveOptions.new(@name, @wsdl, @globals, @locals)
|
|
123
|
+
end
|
|
124
|
+
|
|
117
125
|
# Assembles the SOAP-level request headers for the given builder.
|
|
118
126
|
#
|
|
119
127
|
# Our responsibility regardless of transport:
|
|
@@ -143,26 +151,16 @@ module Savon
|
|
|
143
151
|
headers
|
|
144
152
|
end
|
|
145
153
|
|
|
154
|
+
# The resolved SOAPAction of the request, used for the HTTP header.
|
|
155
|
+
# {Savon::EffectiveOptions#soap_action} owns the precedence rules.
|
|
146
156
|
def soap_action
|
|
147
|
-
|
|
148
|
-
return if @locals.include?(:soap_action) && !@locals[:soap_action]
|
|
149
|
-
|
|
150
|
-
# get the soap_action from local options
|
|
151
|
-
@locals[:soap_action] ||
|
|
152
|
-
# with no local option, but a wsdl, ask it for the soap_action
|
|
153
|
-
@wsdl.document? && @wsdl.soap_action(@name.to_sym) ||
|
|
154
|
-
# if there is no soap_action up to this point, fallback to a simple default
|
|
155
|
-
Gyoku.xml_tag(@name, key_converter: @globals[:convert_request_keys_to])
|
|
157
|
+
effective_options.soap_action
|
|
156
158
|
end
|
|
157
159
|
|
|
160
|
+
# The resolved endpoint URL the request is sent to.
|
|
161
|
+
# {Savon::EffectiveOptions#endpoint} owns the precedence rules.
|
|
158
162
|
def endpoint
|
|
159
|
-
|
|
160
|
-
if @globals[:host]
|
|
161
|
-
host_url = URI.parse(@globals[:host])
|
|
162
|
-
url.host = host_url.host
|
|
163
|
-
url.port = host_url.port
|
|
164
|
-
end
|
|
165
|
-
end
|
|
163
|
+
effective_options.endpoint
|
|
166
164
|
end
|
|
167
165
|
|
|
168
166
|
# Normalizes an observer return value into a Transport::Response.
|
data/lib/savon/version.rb
CHANGED
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: 2.17.
|
|
4
|
+
version: 2.17.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Harrington
|
|
@@ -256,9 +256,11 @@ files:
|
|
|
256
256
|
- README.md
|
|
257
257
|
- Rakefile
|
|
258
258
|
- lib/savon.rb
|
|
259
|
+
- lib/savon/addressing.rb
|
|
259
260
|
- lib/savon/block_interface.rb
|
|
260
261
|
- lib/savon/builder.rb
|
|
261
262
|
- lib/savon/client.rb
|
|
263
|
+
- lib/savon/effective_options.rb
|
|
262
264
|
- lib/savon/faraday_migration_hint.rb
|
|
263
265
|
- lib/savon/header.rb
|
|
264
266
|
- lib/savon/http_error.rb
|