savon 2.2.0 → 2.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +157 -10
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +10 -2
- data/README.md +38 -13
- data/donate.png +0 -0
- data/lib/savon/builder.rb +81 -15
- data/lib/savon/client.rb +6 -2
- data/lib/savon/core_ext/string.rb +0 -1
- data/lib/savon/header.rb +68 -17
- data/lib/savon/log_message.rb +7 -3
- data/lib/savon/message.rb +6 -7
- data/lib/savon/mock/expectation.rb +12 -2
- data/lib/savon/model.rb +4 -0
- data/lib/savon/operation.rb +45 -38
- data/lib/savon/options.rb +149 -22
- data/lib/savon/qualified_message.rb +31 -25
- data/lib/savon/request.rb +24 -4
- data/lib/savon/request_logger.rb +48 -0
- data/lib/savon/response.rb +35 -18
- data/lib/savon/soap_fault.rb +11 -11
- data/lib/savon/version.rb +1 -3
- data/savon.gemspec +12 -11
- data/spec/fixtures/response/empty_soap_fault.xml +13 -0
- data/spec/fixtures/response/f5.xml +39 -0
- data/spec/fixtures/response/no_body.xml +1 -0
- data/spec/fixtures/response/soap_fault_funky.xml +8 -0
- data/spec/fixtures/wsdl/brand.xml +624 -0
- data/spec/fixtures/wsdl/elements_in_types.xml +43 -0
- data/spec/fixtures/wsdl/no_message_tag.xml +1267 -0
- data/spec/fixtures/wsdl/vies.xml +176 -0
- data/spec/integration/centra_spec.rb +67 -0
- data/spec/integration/email_example_spec.rb +1 -1
- data/spec/integration/random_quote_spec.rb +23 -0
- data/spec/integration/stockquote_example_spec.rb +7 -1
- data/spec/integration/support/application.rb +1 -1
- data/spec/integration/zipcode_example_spec.rb +1 -1
- data/spec/savon/builder_spec.rb +50 -0
- data/spec/savon/client_spec.rb +78 -0
- data/spec/savon/core_ext/string_spec.rb +9 -9
- data/spec/savon/features/message_tag_spec.rb +5 -0
- data/spec/savon/http_error_spec.rb +2 -2
- data/spec/savon/log_message_spec.rb +18 -1
- data/spec/savon/message_spec.rb +70 -0
- data/spec/savon/mock_spec.rb +31 -0
- data/spec/savon/model_spec.rb +28 -0
- data/spec/savon/operation_spec.rb +69 -3
- data/spec/savon/options_spec.rb +515 -87
- data/spec/savon/qualified_message_spec.rb +101 -0
- data/spec/savon/request_logger_spec.rb +37 -0
- data/spec/savon/request_spec.rb +85 -10
- data/spec/savon/response_spec.rb +118 -27
- data/spec/savon/soap_fault_spec.rb +25 -5
- data/spec/savon/softlayer_spec.rb +27 -0
- data/spec/spec_helper.rb +5 -2
- data/spec/support/adapters.rb +48 -0
- data/spec/support/integration.rb +1 -1
- metadata +76 -93
data/lib/savon/client.rb
CHANGED
@@ -21,7 +21,7 @@ module Savon
|
|
21
21
|
build_wsdl_document
|
22
22
|
end
|
23
23
|
|
24
|
-
attr_reader :globals
|
24
|
+
attr_reader :globals, :wsdl
|
25
25
|
|
26
26
|
def operations
|
27
27
|
raise_missing_wsdl_error! unless @wsdl.document?
|
@@ -41,6 +41,10 @@ module Savon
|
|
41
41
|
@wsdl.service_name
|
42
42
|
end
|
43
43
|
|
44
|
+
def build_request(operation_name, locals = {}, &block)
|
45
|
+
operation(operation_name).request(locals, &block)
|
46
|
+
end
|
47
|
+
|
44
48
|
private
|
45
49
|
|
46
50
|
def set_globals(globals, block)
|
@@ -56,7 +60,7 @@ module Savon
|
|
56
60
|
@wsdl.document = @globals[:wsdl] if @globals.include? :wsdl
|
57
61
|
@wsdl.endpoint = @globals[:endpoint] if @globals.include? :endpoint
|
58
62
|
@wsdl.namespace = @globals[:namespace] if @globals.include? :namespace
|
59
|
-
@wsdl.
|
63
|
+
@wsdl.adapter = @globals[:adapter] if @globals.include? :adapter
|
60
64
|
|
61
65
|
@wsdl.request = WSDLRequest.new(@globals).build
|
62
66
|
end
|
data/lib/savon/header.rb
CHANGED
@@ -1,41 +1,92 @@
|
|
1
1
|
require "akami"
|
2
2
|
require "gyoku"
|
3
|
+
require "securerandom"
|
3
4
|
|
4
5
|
module Savon
|
5
6
|
class Header
|
6
7
|
|
7
8
|
def initialize(globals, locals)
|
8
|
-
@
|
9
|
-
|
10
|
-
@
|
9
|
+
@gyoku_options = { :key_converter => globals[:convert_request_keys_to] }
|
10
|
+
|
11
|
+
@wsse_auth = locals[:wsse_auth].nil? ? globals[:wsse_auth] : locals[:wsse_auth]
|
12
|
+
@wsse_timestamp = locals[:wsse_timestamp].nil? ? globals[:wsse_timestamp] : locals[:wsse_timestamp]
|
13
|
+
@wsse_signature = locals[:wsse_signature].nil? ? globals[:wsse_signature] : locals[:wsse_signature]
|
14
|
+
|
15
|
+
@global_header = globals[:soap_header]
|
16
|
+
@local_header = locals[:soap_header]
|
17
|
+
|
18
|
+
@globals = globals
|
19
|
+
@locals = locals
|
20
|
+
|
21
|
+
@header = build
|
11
22
|
end
|
12
23
|
|
24
|
+
attr_reader :local_header, :global_header, :gyoku_options,
|
25
|
+
:wsse_auth, :wsse_timestamp, :wsse_signature
|
26
|
+
|
13
27
|
def empty?
|
14
|
-
|
28
|
+
@header.empty?
|
15
29
|
end
|
16
30
|
|
17
31
|
def to_s
|
18
|
-
|
19
|
-
|
20
|
-
gyoku_options = { :key_converter => @globals[:convert_request_keys_to] }
|
21
|
-
@header = (Hash === header ? Gyoku.xml(header, gyoku_options) : header) + wsse_header
|
32
|
+
@header
|
22
33
|
end
|
23
34
|
|
24
35
|
private
|
25
36
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
def build
|
38
|
+
build_header + build_wsa_header + build_wsse_header
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_header
|
42
|
+
header =
|
43
|
+
if global_header.kind_of?(Hash) && local_header.kind_of?(Hash)
|
44
|
+
global_header.merge(local_header)
|
45
|
+
elsif local_header
|
46
|
+
local_header
|
47
|
+
else
|
48
|
+
global_header
|
49
|
+
end
|
50
|
+
|
51
|
+
convert_to_xml(header)
|
31
52
|
end
|
32
53
|
|
33
|
-
def
|
34
|
-
|
54
|
+
def build_wsse_header
|
55
|
+
wsse_header = akami
|
56
|
+
wsse_header.respond_to?(:to_xml) ? wsse_header.to_xml : ""
|
35
57
|
end
|
36
58
|
|
37
|
-
def
|
38
|
-
|
59
|
+
def build_wsa_header
|
60
|
+
return '' unless @globals[:use_wsa_headers]
|
61
|
+
convert_to_xml({
|
62
|
+
'wsa:Action' => @locals[:soap_action],
|
63
|
+
'wsa:To' => @globals[:endpoint],
|
64
|
+
'wsa:MessageID' => "urn:uuid:#{SecureRandom.uuid}",
|
65
|
+
attributes!: {
|
66
|
+
'wsa:MessageID' => {
|
67
|
+
"xmlns:wsa" => "http://schemas.xmlsoap.org/ws/2004/08/addressing"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
})
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_to_xml(hash_or_string)
|
74
|
+
if hash_or_string.kind_of? Hash
|
75
|
+
Gyoku.xml(hash_or_string, gyoku_options)
|
76
|
+
else
|
77
|
+
hash_or_string.to_s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def akami
|
82
|
+
wsse = Akami.wsse
|
83
|
+
wsse.credentials(*wsse_auth) if wsse_auth
|
84
|
+
wsse.timestamp = wsse_timestamp if wsse_timestamp
|
85
|
+
if wsse_signature && wsse_signature.have_document?
|
86
|
+
wsse.signature = wsse_signature
|
87
|
+
end
|
88
|
+
|
89
|
+
wsse
|
39
90
|
end
|
40
91
|
|
41
92
|
end
|
data/lib/savon/log_message.rb
CHANGED
@@ -35,13 +35,17 @@ module Savon
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def apply_filter!(document, filter)
|
38
|
-
|
39
|
-
|
38
|
+
if filter.instance_of? Proc
|
39
|
+
filter.call document
|
40
|
+
else
|
41
|
+
document.xpath("//*[local-name()='#{filter}']").each do |node|
|
42
|
+
node.content = "***FILTERED***"
|
43
|
+
end
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
43
47
|
def nokogiri_options
|
44
|
-
@pretty_print ? { :indent => 2 } : {}
|
48
|
+
@pretty_print ? { :indent => 2 } : { :save_with => Nokogiri::XML::Node::SaveOptions::AS_XML }
|
45
49
|
end
|
46
50
|
|
47
51
|
end
|
data/lib/savon/message.rb
CHANGED
@@ -4,8 +4,8 @@ require "gyoku"
|
|
4
4
|
module Savon
|
5
5
|
class Message
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
7
|
+
def initialize(message_tag, namespace_identifier, types, used_namespaces, message, element_form_default, key_converter, unwrap)
|
8
|
+
@message_tag = message_tag
|
9
9
|
@namespace_identifier = namespace_identifier
|
10
10
|
@types = types
|
11
11
|
@used_namespaces = used_namespaces
|
@@ -13,22 +13,21 @@ module Savon
|
|
13
13
|
@message = message
|
14
14
|
@element_form_default = element_form_default
|
15
15
|
@key_converter = key_converter
|
16
|
+
@unwrap = unwrap
|
16
17
|
end
|
17
18
|
|
18
19
|
def to_s
|
19
20
|
return @message.to_s unless @message.kind_of? Hash
|
20
21
|
|
21
22
|
if @element_form_default == :qualified
|
22
|
-
|
23
|
-
# XXX: there is no `@request_key_converter` instance variable!
|
24
|
-
# the third argument is therefore always `nil`. [dh, 2013-03-09]
|
25
|
-
@message = QualifiedMessage.new(@types, @used_namespaces, @request_key_converter).to_hash(@message, [translated_operation_name])
|
23
|
+
@message = QualifiedMessage.new(@types, @used_namespaces, @key_converter).to_hash(@message, [@message_tag.to_s])
|
26
24
|
end
|
27
25
|
|
28
26
|
gyoku_options = {
|
29
27
|
:element_form_default => @element_form_default,
|
30
28
|
:namespace => @namespace_identifier,
|
31
|
-
:key_converter => @key_converter
|
29
|
+
:key_converter => @key_converter,
|
30
|
+
:unwrap => @unwrap
|
32
31
|
}
|
33
32
|
|
34
33
|
Gyoku.xml(@message, gyoku_options)
|
@@ -54,7 +54,8 @@ module Savon
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def verify_message!
|
57
|
-
|
57
|
+
return if @expected[:message].eql? :any
|
58
|
+
unless equals_except_any(@expected[:message], @actual[:message])
|
58
59
|
expected_message = " with this message: #{@expected[:message].inspect}" if @expected[:message]
|
59
60
|
expected_message ||= " with no message."
|
60
61
|
|
@@ -62,9 +63,18 @@ module Savon
|
|
62
63
|
actual_message ||= " with no message."
|
63
64
|
|
64
65
|
raise ExpectationError, "Expected a request to the #{@expected[:operation_name].inspect} operation\n#{expected_message}\n" \
|
65
|
-
|
66
|
+
"Received a request to the #{@actual[:operation_name].inspect} operation\n#{actual_message}"
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
70
|
+
def equals_except_any(msg_expected, msg_real)
|
71
|
+
return true if msg_expected === msg_real
|
72
|
+
return false if (msg_expected.nil? || msg_real.nil?) # If both are nil has returned true
|
73
|
+
msg_expected.each do |key, expected_value|
|
74
|
+
next if (expected_value == :any && msg_real.include?(key))
|
75
|
+
return false if expected_value != msg_real[key]
|
76
|
+
end
|
77
|
+
return true
|
78
|
+
end
|
69
79
|
end
|
70
80
|
end
|
data/lib/savon/model.rb
CHANGED
data/lib/savon/operation.rb
CHANGED
@@ -3,7 +3,8 @@ require "savon/block_interface"
|
|
3
3
|
require "savon/request"
|
4
4
|
require "savon/builder"
|
5
5
|
require "savon/response"
|
6
|
-
require "savon/
|
6
|
+
require "savon/request_logger"
|
7
|
+
require "savon/http_error"
|
7
8
|
|
8
9
|
module Savon
|
9
10
|
class Operation
|
@@ -22,6 +23,8 @@ module Savon
|
|
22
23
|
raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
|
23
24
|
"Operations provided by your service: #{wsdl.soap_actions.inspect}"
|
24
25
|
end
|
26
|
+
rescue Wasabi::Resolver::HTTPError => e
|
27
|
+
raise HTTPError.new(e.response)
|
25
28
|
end
|
26
29
|
|
27
30
|
def self.ensure_name_is_symbol!(operation_name)
|
@@ -35,6 +38,8 @@ module Savon
|
|
35
38
|
@name = name
|
36
39
|
@wsdl = wsdl
|
37
40
|
@globals = globals
|
41
|
+
|
42
|
+
@logger = RequestLogger.new(globals)
|
38
43
|
end
|
39
44
|
|
40
45
|
def build(locals = {}, &block)
|
@@ -46,15 +51,38 @@ module Savon
|
|
46
51
|
builder = build(locals, &block)
|
47
52
|
|
48
53
|
response = Savon.notify_observers(@name, builder, @globals, @locals)
|
49
|
-
response ||=
|
54
|
+
response ||= call_with_logging build_request(builder)
|
50
55
|
|
51
56
|
raise_expected_httpi_response! unless response.kind_of?(HTTPI::Response)
|
52
57
|
|
53
|
-
|
58
|
+
create_response(response)
|
59
|
+
end
|
60
|
+
|
61
|
+
def request(locals = {}, &block)
|
62
|
+
builder = build(locals, &block)
|
63
|
+
build_request(builder)
|
54
64
|
end
|
55
65
|
|
56
66
|
private
|
57
67
|
|
68
|
+
def create_response(response)
|
69
|
+
if multipart_supported?
|
70
|
+
Multipart::Response.new(response, @globals, @locals)
|
71
|
+
else
|
72
|
+
Response.new(response, @globals, @locals)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def multipart_supported?
|
77
|
+
return false unless @globals[:multipart] || @locals[:multipart]
|
78
|
+
|
79
|
+
if Savon.const_defined? :Multipart
|
80
|
+
true
|
81
|
+
else
|
82
|
+
raise 'Unable to find Savon::Multipart. Make sure the savon-multipart gem is installed and loaded.'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
58
86
|
def set_locals(locals, block)
|
59
87
|
locals = LocalOptions.new(locals)
|
60
88
|
BlockInterface.new(locals).evaluate(block) if block
|
@@ -62,18 +90,18 @@ module Savon
|
|
62
90
|
@locals = locals
|
63
91
|
end
|
64
92
|
|
65
|
-
def
|
66
|
-
|
67
|
-
response = HTTPI.post(request)
|
68
|
-
log_response(response) if log?
|
69
|
-
|
70
|
-
response
|
93
|
+
def call_with_logging(request)
|
94
|
+
@logger.log(request) { HTTPI.post(request, @globals[:adapter]) }
|
71
95
|
end
|
72
96
|
|
73
97
|
def build_request(builder)
|
98
|
+
@locals[:soap_action] ||= soap_action
|
99
|
+
@globals[:endpoint] ||= endpoint
|
100
|
+
|
74
101
|
request = SOAPRequest.new(@globals).build(
|
75
102
|
:soap_action => soap_action,
|
76
|
-
:cookies => @locals[:cookies]
|
103
|
+
:cookies => @locals[:cookies],
|
104
|
+
:headers => @locals[:headers]
|
77
105
|
)
|
78
106
|
|
79
107
|
request.url = endpoint
|
@@ -99,34 +127,13 @@ module Savon
|
|
99
127
|
end
|
100
128
|
|
101
129
|
def endpoint
|
102
|
-
@globals[:endpoint] || @wsdl.endpoint
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
def log_response(response)
|
112
|
-
logger.info "SOAP response (status #{response.code})"
|
113
|
-
logger.debug body_to_log(response.body)
|
114
|
-
end
|
115
|
-
|
116
|
-
def headers_to_log(headers)
|
117
|
-
headers.map { |key, value| "#{key}: #{value}" }.join(", ")
|
118
|
-
end
|
119
|
-
|
120
|
-
def body_to_log(body)
|
121
|
-
LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s
|
122
|
-
end
|
123
|
-
|
124
|
-
def logger
|
125
|
-
@globals[:logger]
|
126
|
-
end
|
127
|
-
|
128
|
-
def log?
|
129
|
-
@globals[:log]
|
130
|
+
@globals[:endpoint] || @wsdl.endpoint.tap do |url|
|
131
|
+
if @globals[:host]
|
132
|
+
host_url = URI.parse(@globals[:host])
|
133
|
+
url.host = host_url.host
|
134
|
+
url.port = host_url.port
|
135
|
+
end
|
136
|
+
end
|
130
137
|
end
|
131
138
|
|
132
139
|
def raise_expected_httpi_response!
|
data/lib/savon/options.rb
CHANGED
@@ -35,25 +35,63 @@ module Savon
|
|
35
35
|
def method_missing(option, _)
|
36
36
|
raise UnknownOptionError, "Unknown #{option_type} option: #{option.inspect}"
|
37
37
|
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module SharedOptions
|
41
|
+
# WSSE auth credentials for Akami.
|
42
|
+
# Local will override the global wsse_auth value, e.g.
|
43
|
+
# global == [user, pass] && local == [user2, pass2] => [user2, pass2]
|
44
|
+
# global == [user, pass] && local == false => false
|
45
|
+
# global == [user, pass] && local == nil => [user, pass]
|
46
|
+
def wsse_auth(*credentials)
|
47
|
+
credentials.flatten!
|
48
|
+
if credentials.size == 1
|
49
|
+
@options[:wsse_auth] = credentials.first
|
50
|
+
else
|
51
|
+
@options[:wsse_auth] = credentials
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Instruct Akami to enable wsu:Timestamp headers.
|
56
|
+
# Local will override the global wsse_timestamp value, e.g.
|
57
|
+
# global == true && local == true => true
|
58
|
+
# global == true && local == false => false
|
59
|
+
# global == true && local == nil => true
|
60
|
+
def wsse_timestamp(timestamp = true)
|
61
|
+
@options[:wsse_timestamp] = timestamp
|
62
|
+
end
|
38
63
|
|
64
|
+
def wsse_signature(signature)
|
65
|
+
@options[:wsse_signature] = signature
|
66
|
+
end
|
39
67
|
end
|
40
68
|
|
41
69
|
class GlobalOptions < Options
|
70
|
+
include SharedOptions
|
42
71
|
|
43
72
|
def initialize(options = {})
|
44
73
|
@option_type = :global
|
45
74
|
|
46
75
|
defaults = {
|
47
|
-
:encoding
|
48
|
-
:soap_version
|
49
|
-
:namespaces
|
50
|
-
:logger
|
51
|
-
:log
|
52
|
-
:filters
|
53
|
-
:pretty_print_xml
|
54
|
-
:raise_errors
|
55
|
-
:strip_namespaces
|
56
|
-
:
|
76
|
+
:encoding => "UTF-8",
|
77
|
+
:soap_version => 1,
|
78
|
+
:namespaces => {},
|
79
|
+
:logger => Logger.new($stdout),
|
80
|
+
:log => false,
|
81
|
+
:filters => [],
|
82
|
+
:pretty_print_xml => false,
|
83
|
+
:raise_errors => true,
|
84
|
+
:strip_namespaces => true,
|
85
|
+
:delete_namespace_attributes => false,
|
86
|
+
:convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym},
|
87
|
+
:convert_attributes_to => lambda { |k,v| [k,v] },
|
88
|
+
:multipart => false,
|
89
|
+
:adapter => nil,
|
90
|
+
:use_wsa_headers => false,
|
91
|
+
:no_message_tag => false,
|
92
|
+
:follow_redirects => false,
|
93
|
+
:unwrap => false,
|
94
|
+
:host => nil
|
57
95
|
}
|
58
96
|
|
59
97
|
options = defaults.merge(options)
|
@@ -72,6 +110,11 @@ module Savon
|
|
72
110
|
@options[:wsdl] = wsdl_address
|
73
111
|
end
|
74
112
|
|
113
|
+
# set different host for actions in WSDL
|
114
|
+
def host(host)
|
115
|
+
@options[:host] = host
|
116
|
+
end
|
117
|
+
|
75
118
|
# SOAP endpoint.
|
76
119
|
def endpoint(endpoint)
|
77
120
|
@options[:endpoint] = endpoint
|
@@ -94,7 +137,7 @@ module Savon
|
|
94
137
|
|
95
138
|
# Proxy server to use for all requests.
|
96
139
|
def proxy(proxy)
|
97
|
-
@options[:proxy] = proxy
|
140
|
+
@options[:proxy] = proxy unless proxy.nil?
|
98
141
|
end
|
99
142
|
|
100
143
|
# A Hash of HTTP headers.
|
@@ -117,12 +160,12 @@ module Savon
|
|
117
160
|
@options[:encoding] = encoding
|
118
161
|
end
|
119
162
|
|
120
|
-
# The global SOAP header. Expected to be a Hash.
|
163
|
+
# The global SOAP header. Expected to be a Hash or responding to #to_s.
|
121
164
|
def soap_header(header)
|
122
165
|
@options[:soap_header] = header
|
123
166
|
end
|
124
167
|
|
125
|
-
# Sets whether elements should be :qualified or unqualified.
|
168
|
+
# Sets whether elements should be :qualified or :unqualified.
|
126
169
|
# If you need to use this option, please open an issue and make
|
127
170
|
# sure to add your WSDL document for debugging.
|
128
171
|
def element_form_default(element_form_default)
|
@@ -154,6 +197,7 @@ module Savon
|
|
154
197
|
|
155
198
|
# The logger to use. Defaults to a Savon::Logger instance.
|
156
199
|
def logger(logger)
|
200
|
+
HTTPI.logger = logger
|
157
201
|
@options[:logger] = logger
|
158
202
|
end
|
159
203
|
|
@@ -194,6 +238,11 @@ module Savon
|
|
194
238
|
@options[:ssl_cert_key_file] = file
|
195
239
|
end
|
196
240
|
|
241
|
+
# Sets the cert key to use.
|
242
|
+
def ssl_cert_key(key)
|
243
|
+
@options[:ssl_cert_key] = key
|
244
|
+
end
|
245
|
+
|
197
246
|
# Sets the cert key password to use.
|
198
247
|
def ssl_cert_key_password(password)
|
199
248
|
@options[:ssl_cert_key_password] = password
|
@@ -204,11 +253,35 @@ module Savon
|
|
204
253
|
@options[:ssl_cert_file] = file
|
205
254
|
end
|
206
255
|
|
256
|
+
# Sets the cert to use.
|
257
|
+
def ssl_cert(cert)
|
258
|
+
@options[:ssl_cert] = cert
|
259
|
+
end
|
260
|
+
|
207
261
|
# Sets the ca cert file to use.
|
208
262
|
def ssl_ca_cert_file(file)
|
209
263
|
@options[:ssl_ca_cert_file] = file
|
210
264
|
end
|
211
265
|
|
266
|
+
# Sets the ca cert to use.
|
267
|
+
def ssl_ca_cert(cert)
|
268
|
+
@options[:ssl_ca_cert] = cert
|
269
|
+
end
|
270
|
+
|
271
|
+
def ssl_ciphers(ciphers)
|
272
|
+
@options[:ssl_ciphers] = ciphers
|
273
|
+
end
|
274
|
+
|
275
|
+
# Sets the ca cert path.
|
276
|
+
def ssl_ca_cert_path(path)
|
277
|
+
@options[:ssl_ca_cert_path] = path
|
278
|
+
end
|
279
|
+
|
280
|
+
# Sets the ssl cert store.
|
281
|
+
def ssl_cert_store(store)
|
282
|
+
@options[:ssl_cert_store] = store
|
283
|
+
end
|
284
|
+
|
212
285
|
# HTTP basic auth credentials.
|
213
286
|
def basic_auth(*credentials)
|
214
287
|
@options[:basic_auth] = credentials.flatten
|
@@ -219,14 +292,9 @@ module Savon
|
|
219
292
|
@options[:digest_auth] = credentials.flatten
|
220
293
|
end
|
221
294
|
|
222
|
-
#
|
223
|
-
def
|
224
|
-
@options[:
|
225
|
-
end
|
226
|
-
|
227
|
-
# Instruct Akami to enable wsu:Timestamp headers.
|
228
|
-
def wsse_timestamp(*timestamp)
|
229
|
-
@options[:wsse_timestamp] = timestamp.flatten
|
295
|
+
# NTLM auth credentials.
|
296
|
+
def ntlm(*credentials)
|
297
|
+
@options[:ntlm] = credentials.flatten
|
230
298
|
end
|
231
299
|
|
232
300
|
# Instruct Nori whether to strip namespaces from XML nodes.
|
@@ -234,33 +302,84 @@ module Savon
|
|
234
302
|
@options[:strip_namespaces] = strip_namespaces
|
235
303
|
end
|
236
304
|
|
305
|
+
# Instruct Nori whether to delete namespace attributes from XML nodes.
|
306
|
+
def delete_namespace_attributes(delete_namespace_attributes)
|
307
|
+
@options[:delete_namespace_attributes] = delete_namespace_attributes
|
308
|
+
end
|
309
|
+
|
237
310
|
# Tell Gyoku how to convert Hash key Symbols to XML tags.
|
238
311
|
# Accepts one of :lower_camelcase, :camelcase, :upcase, or :none.
|
239
312
|
def convert_request_keys_to(converter)
|
240
313
|
@options[:convert_request_keys_to] = converter
|
241
314
|
end
|
242
315
|
|
316
|
+
# Tell Gyoku to unwrap Array of Hashes
|
317
|
+
# Accepts a boolean, default to false
|
318
|
+
def unwrap(unwrap)
|
319
|
+
@options[:unwrap] = unwrap
|
320
|
+
end
|
321
|
+
|
243
322
|
# Tell Nori how to convert XML tags from the SOAP response into Hash keys.
|
244
323
|
# Accepts a lambda or a block which receives an XML tag and returns a Hash key.
|
245
324
|
# Defaults to convert tags to snakecase Symbols.
|
246
325
|
def convert_response_tags_to(converter = nil, &block)
|
247
326
|
@options[:convert_response_tags_to] = block || converter
|
248
327
|
end
|
328
|
+
|
329
|
+
# Tell Nori how to convert XML attributes on tags from the SOAP response into Hash keys.
|
330
|
+
# Accepts a lambda or a block which receives an XML tag and returns a Hash key.
|
331
|
+
# Defaults to doing nothing
|
332
|
+
def convert_attributes_to(converter = nil, &block)
|
333
|
+
@options[:convert_attributes_to] = block || converter
|
334
|
+
end
|
335
|
+
|
336
|
+
# Instruct Savon to create a multipart response if available.
|
337
|
+
def multipart(multipart)
|
338
|
+
@options[:multipart] = multipart
|
339
|
+
end
|
340
|
+
|
341
|
+
# Instruct Savon what HTTPI adapter it should use instead of default
|
342
|
+
def adapter(adapter)
|
343
|
+
@options[:adapter] = adapter
|
344
|
+
end
|
345
|
+
|
346
|
+
# Enable inclusion of WS-Addressing headers.
|
347
|
+
def use_wsa_headers(use)
|
348
|
+
@options[:use_wsa_headers] = use
|
349
|
+
end
|
350
|
+
|
351
|
+
def no_message_tag(bool)
|
352
|
+
@options[:no_message_tag] = bool
|
353
|
+
end
|
354
|
+
|
355
|
+
# Instruct requests to follow HTTP redirects.
|
356
|
+
def follow_redirects(follow_redirects)
|
357
|
+
@options[:follow_redirects] = follow_redirects
|
358
|
+
end
|
249
359
|
end
|
250
360
|
|
251
361
|
class LocalOptions < Options
|
362
|
+
include SharedOptions
|
252
363
|
|
253
364
|
def initialize(options = {})
|
254
365
|
@option_type = :local
|
255
366
|
|
256
367
|
defaults = {
|
257
368
|
:advanced_typecasting => true,
|
258
|
-
:response_parser => :nokogiri
|
369
|
+
:response_parser => :nokogiri,
|
370
|
+
:multipart => false
|
259
371
|
}
|
260
372
|
|
261
373
|
super defaults.merge(options)
|
262
374
|
end
|
263
375
|
|
376
|
+
# The local SOAP header. Expected to be a Hash or respond to #to_s.
|
377
|
+
# Will be merged with the global SOAP header if both are Hashes.
|
378
|
+
# Otherwise the local option will be prefered.
|
379
|
+
def soap_header(header)
|
380
|
+
@options[:soap_header] = header
|
381
|
+
end
|
382
|
+
|
264
383
|
# The SOAP message to send. Expected to be a Hash or a String.
|
265
384
|
def message(message)
|
266
385
|
@options[:message] = message
|
@@ -302,5 +421,13 @@ module Savon
|
|
302
421
|
@options[:response_parser] = parser
|
303
422
|
end
|
304
423
|
|
424
|
+
# Instruct Savon to create a multipart response if available.
|
425
|
+
def multipart(multipart)
|
426
|
+
@options[:multipart] = multipart
|
427
|
+
end
|
428
|
+
|
429
|
+
def headers(headers)
|
430
|
+
@options[:headers] = headers
|
431
|
+
end
|
305
432
|
end
|
306
433
|
end
|