savon 2.17.2 → 3.0.0.rc1

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/lib/savon/options.rb CHANGED
@@ -1,19 +1,18 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require "logger"
4
- require "httpi"
5
- require "savon/faraday_migration_hint"
6
3
 
7
4
  module Savon
8
- # Base class for GlobalOptions and LocalOptions.
9
- # Stores options in a hash, dispatches setter calls by method name,
10
- # raises UnknownOptionError for anything not defined on the subclass.
11
5
  class Options
6
+
12
7
  def initialize(options = {})
13
8
  @options = {}
14
9
  assign options
15
10
  end
16
11
 
12
+ def deprecate(option)
13
+ raise DeprecatedOptionError.new(option)
14
+ end
15
+
17
16
  attr_reader :option_type
18
17
 
19
18
  def [](option)
@@ -22,7 +21,7 @@ module Savon
22
21
 
23
22
  def []=(option, value)
24
23
  value = [value].flatten
25
- send(option, *value)
24
+ self.send(option, *value)
26
25
  end
27
26
 
28
27
  def include?(option)
@@ -33,7 +32,7 @@ module Savon
33
32
 
34
33
  def assign(options)
35
34
  options.each do |option, value|
36
- send(option, value)
35
+ self.send(option, value)
37
36
  end
38
37
  end
39
38
 
@@ -42,8 +41,6 @@ module Savon
42
41
  end
43
42
  end
44
43
 
45
- # Options available in both GlobalOptions and LocalOptions.
46
- # Currently covers WSSE authentication and timestamp headers.
47
44
  module SharedOptions
48
45
  # WSSE auth credentials for Akami.
49
46
  # Local will override the global wsse_auth value, e.g.
@@ -52,12 +49,11 @@ module Savon
52
49
  # global == [user, pass] && local == nil => [user, pass]
53
50
  def wsse_auth(*credentials)
54
51
  credentials.flatten!
55
- @options[:wsse_auth] =
56
- if credentials.size == 1
57
- credentials.first
58
- else
59
- credentials
60
- end
52
+ if credentials.size == 1
53
+ @options[:wsse_auth] = credentials.first
54
+ else
55
+ @options[:wsse_auth] = credentials
56
+ end
61
57
  end
62
58
 
63
59
  # Instruct Akami to enable wsu:Timestamp headers.
@@ -74,186 +70,35 @@ module Savon
74
70
  end
75
71
  end
76
72
 
77
- # Options that belong to HTTPI's transport layer.
78
- #
79
- # They still work with the default HTTPI transport. With `transport: :faraday`,
80
- # Savon does not translate them because Faraday exposes its own setup API for
81
- # proxy, timeout, TLS, auth, redirects, and adapter choices.
82
- module HTTPITransportOptions
83
- TRANSPORT_DEFAULTS = {
84
- adapter: nil,
85
- follow_redirects: false
86
- }.freeze
87
-
88
- # These are rejected for `transport: :faraday` once the caller has set a
89
- # non-default value. The error points to the matching Faraday setup.
90
- FARADAY_INCOMPATIBLE_GLOBALS = FaradayMigrationHint::OPTIONS
91
-
92
- # Runs after all global options have been assigned, including options set in
93
- # the client block. Reports every HTTPI-only option in one error so callers
94
- # can move their transport setup to Faraday in one pass.
95
- def validate_transport!
96
- return unless self[:transport] == :faraday
97
-
98
- unless faraday_loaded?
99
- raise InitializationError,
100
- "transport: :faraday requires the faraday gem.\n" \
101
- "Add to your Gemfile: gem 'faraday'"
102
- end
103
-
104
- violations = FARADAY_INCOMPATIBLE_GLOBALS.filter_map { |option|
105
- next unless include?(option)
106
- next if default_transport_option?(option)
107
-
108
- FaradayMigrationHint.new(option, self[option]).message
109
- }
110
-
111
- return if violations.empty?
112
-
113
- raise InitializationError,
114
- "The following options are not supported with transport: :faraday:\n#{violations.join("\n")}"
115
- end
116
-
117
- # Proxy server to use for all requests.
118
- def proxy(proxy)
119
- @options[:proxy] = proxy unless proxy.nil?
120
- end
121
-
122
- # Open timeout in seconds.
123
- def open_timeout(open_timeout)
124
- @options[:open_timeout] = open_timeout
125
- end
126
-
127
- # Read timeout in seconds.
128
- def read_timeout(read_timeout)
129
- @options[:read_timeout] = read_timeout
130
- end
131
-
132
- # Write timeout in seconds.
133
- def write_timeout(write_timeout)
134
- @options[:write_timeout] = write_timeout
135
- end
136
-
137
- # Specifies the SSL version to use.
138
- def ssl_version(version)
139
- @options[:ssl_version] = version
140
- end
141
-
142
- # Specifies the minimum SSL version to use.
143
- def ssl_min_version(version)
144
- @options[:ssl_min_version] = version
145
- end
146
-
147
- # Specifies the maximum SSL version to use.
148
- def ssl_max_version(version)
149
- @options[:ssl_max_version] = version
150
- end
151
-
152
- # Whether and how to verify the SSL connection.
153
- def ssl_verify_mode(verify_mode)
154
- @options[:ssl_verify_mode] = verify_mode
155
- end
156
-
157
- # Sets the cert key file to use.
158
- def ssl_cert_key_file(file)
159
- @options[:ssl_cert_key_file] = file
160
- end
161
-
162
- # Sets the cert key to use.
163
- def ssl_cert_key(key)
164
- @options[:ssl_cert_key] = key
165
- end
166
-
167
- # Sets the cert key password to use.
168
- def ssl_cert_key_password(password)
169
- @options[:ssl_cert_key_password] = password
170
- end
171
-
172
- # Sets the cert file to use.
173
- def ssl_cert_file(file)
174
- @options[:ssl_cert_file] = file
175
- end
176
-
177
- # Sets the cert to use.
178
- def ssl_cert(cert)
179
- @options[:ssl_cert] = cert
180
- end
181
-
182
- # Sets the CA cert file to use.
183
- def ssl_ca_cert_file(file)
184
- @options[:ssl_ca_cert_file] = file
185
- end
186
-
187
- # Sets the CA cert to use.
188
- def ssl_ca_cert(cert)
189
- @options[:ssl_ca_cert] = cert
190
- end
191
-
192
- # Sets the SSL ciphers to use.
193
- def ssl_ciphers(ciphers)
194
- @options[:ssl_ciphers] = ciphers
195
- end
196
-
197
- # Sets the CA cert path.
198
- def ssl_ca_cert_path(path)
199
- @options[:ssl_ca_cert_path] = path
200
- end
201
-
202
- # Sets the SSL cert store.
203
- def ssl_cert_store(store)
204
- @options[:ssl_cert_store] = store
205
- end
206
-
207
- # HTTP basic auth credentials.
208
- def basic_auth(*credentials)
209
- @options[:basic_auth] = credentials.flatten
210
- end
211
-
212
- # HTTP digest auth credentials.
213
- def digest_auth(*credentials)
214
- @options[:digest_auth] = credentials.flatten
215
- end
216
-
217
- # NTLM auth credentials.
218
- def ntlm(*credentials)
219
- @options[:ntlm] = credentials.flatten
220
- end
221
-
222
- # Instruct requests to follow HTTP redirects.
223
- def follow_redirects(follow_redirects)
224
- @options[:follow_redirects] = follow_redirects
225
- end
226
-
227
- # Instruct Savon which HTTPI adapter to use instead of the default.
228
- def adapter(adapter)
229
- @options[:adapter] = adapter
230
- end
231
-
232
- private
233
-
234
- def default_transport_option?(option)
235
- TRANSPORT_DEFAULTS.key?(option) && self[option] == TRANSPORT_DEFAULTS[option]
236
- end
237
-
238
- # Attempts to load faraday. Returns true if available, false on LoadError.
239
- def faraday_loaded?
240
- require "faraday"
241
- true
242
- rescue LoadError
243
- false
244
- end
245
- end
246
-
247
- # Client-level options applied to every request made by a Savon::Client instance.
248
- # Covers service location, SOAP configuration, logging, response parsing,
249
- # and transport selection. HTTPI-specific options (proxy, timeouts, SSL, auth)
250
- # come from HTTPITransportOptions.
251
73
  class GlobalOptions < Options
252
74
  include SharedOptions
253
- include HTTPITransportOptions
254
75
 
255
76
  def initialize(options = {})
256
77
  @option_type = :global
78
+
79
+ defaults = {
80
+ :encoding => "UTF-8",
81
+ :soap_version => 1,
82
+ :namespaces => {},
83
+ :logger => Logger.new($stdout),
84
+ :log => false,
85
+ :log_headers => true,
86
+ :filters => [],
87
+ :pretty_print_xml => false,
88
+ :raise_errors => true,
89
+ :strip_namespaces => true,
90
+ :delete_namespace_attributes => false,
91
+ :convert_response_tags_to => lambda { |tag| StringUtils.snakecase(tag).to_sym},
92
+ :convert_attributes_to => lambda { |k,v| [k,v] },
93
+ :multipart => false,
94
+ :adapter => nil,
95
+ :use_wsa_headers => false,
96
+ :no_message_tag => false,
97
+ :follow_redirects => false,
98
+ :unwrap => false,
99
+ :host => nil
100
+ }
101
+
257
102
  options = defaults.merge(options)
258
103
 
259
104
  # this option is a shortcut on the logger which needs to be set
@@ -270,7 +115,7 @@ module Savon
270
115
  @options[:wsdl] = wsdl_address
271
116
  end
272
117
 
273
- # Set a different host for actions in the WSDL.
118
+ # set different host for actions in WSDL
274
119
  def host(host)
275
120
  @options[:host] = host
276
121
  end
@@ -295,11 +140,31 @@ module Savon
295
140
  @options[:namespaces] = namespaces
296
141
  end
297
142
 
298
- # A Hash of HTTP headers sent with every request.
143
+ # Proxy server to use for all requests.
144
+ def proxy(proxy)
145
+ @options[:proxy] = proxy unless proxy.nil?
146
+ end
147
+
148
+ # A Hash of HTTP headers.
299
149
  def headers(headers)
300
150
  @options[:headers] = headers
301
151
  end
302
152
 
153
+ # Open timeout in seconds.
154
+ def open_timeout(open_timeout)
155
+ @options[:open_timeout] = open_timeout
156
+ end
157
+
158
+ # Read timeout in seconds.
159
+ def read_timeout(read_timeout)
160
+ @options[:read_timeout] = read_timeout
161
+ end
162
+
163
+ # Write timeout in seconds.
164
+ def write_timeout(write_timeout)
165
+ @options[:write_timeout] = write_timeout
166
+ end
167
+
303
168
  # The encoding to use. Defaults to "UTF-8".
304
169
  def encoding(encoding)
305
170
  @options[:encoding] = encoding
@@ -336,19 +201,17 @@ module Savon
336
201
 
337
202
  # Whether or not to log.
338
203
  def log(log)
339
- HTTPI.log = log
340
204
  @options[:log] = log
341
205
  end
342
206
 
343
207
  # The logger to use. Defaults to a Savon::Logger instance.
344
208
  def logger(logger)
345
- HTTPI.logger = logger
346
209
  @options[:logger] = logger
347
210
  end
348
211
 
349
212
  # Changes the Logger's log level.
350
213
  def log_level(level)
351
- levels = { debug: 0, info: 1, warn: 2, error: 3, fatal: 4 }
214
+ levels = { :debug => 0, :info => 1, :warn => 2, :error => 3, :fatal => 4 }
352
215
 
353
216
  unless levels.include? level
354
217
  raise ArgumentError, "Invalid log level: #{level.inspect}\n" \
@@ -358,7 +221,7 @@ module Savon
358
221
  @options[:logger].level = levels[level]
359
222
  end
360
223
 
361
- # Whether to log headers.
224
+ # To log headers or not.
362
225
  def log_headers(log_headers)
363
226
  @options[:log_headers] = log_headers
364
227
  end
@@ -373,34 +236,104 @@ module Savon
373
236
  @options[:pretty_print_xml] = pretty_print_xml
374
237
  end
375
238
 
376
- # Instruct Nori whether to strip namespaces from XML nodes.
377
- def strip_namespaces(strip_namespaces)
378
- @options[:strip_namespaces] = strip_namespaces
239
+ # Specifies the SSL version to use.
240
+ def ssl_version(version)
241
+ @options[:ssl_version] = version
379
242
  end
380
243
 
381
- # Instruct Nori whether to delete namespace attributes from XML nodes.
382
- def delete_namespace_attributes(delete_namespace_attributes)
383
- @options[:delete_namespace_attributes] = delete_namespace_attributes
244
+ # Specifies the SSL version to use.
245
+ def ssl_min_version(version)
246
+ @options[:ssl_min_version] = version
384
247
  end
385
248
 
386
- # The value Nori assigns to empty XML tags in the SOAP response.
387
- # Defaults to nil, matching Nori's default; set to "" to map empty tags
388
- # to an empty String instead.
389
- def empty_tag_value(value)
390
- @options[:empty_tag_value] = value
249
+ # Specifies the SSL version to use.
250
+ def ssl_max_version(version)
251
+ @options[:ssl_max_version] = version
391
252
  end
392
253
 
393
- # Instruct Nori whether to convert dashes in response tag names to
394
- # underscores before they become Hash keys. Defaults to true.
395
- def convert_dashes_to_underscores(convert)
396
- @options[:convert_dashes_to_underscores] = convert
254
+ # Whether and how to to verify the connection.
255
+ def ssl_verify_mode(verify_mode)
256
+ @options[:ssl_verify_mode] = verify_mode
397
257
  end
398
258
 
399
- # Instruct Nori whether to scrub invalid byte sequences from the response
400
- # body before parsing it. Defaults to true, which lets responses containing
401
- # invalid characters still be parsed.
402
- def scrub_xml(scrub)
403
- @options[:scrub_xml] = scrub
259
+ # Sets the cert key file to use.
260
+ def ssl_cert_key_file(file)
261
+ deprecate('ssl_cert_key_file')
262
+ @options[:ssl_cert_key_file] = file
263
+ end
264
+
265
+ # Sets the cert key to use.
266
+ def ssl_cert_key(key)
267
+ @options[:ssl_cert_key] = key
268
+ end
269
+
270
+ # Sets the cert key password to use.
271
+ def ssl_cert_key_password(password)
272
+ deprecate('ssl_cert_key_password')
273
+ @options[:ssl_cert_key_password] = password
274
+ end
275
+
276
+ # Sets the cert file to use.
277
+ def ssl_cert_file(file)
278
+ deprecate('ssl_cert_file')
279
+ @options[:ssl_cert_file] = file
280
+ end
281
+
282
+ # Sets the cert to use.
283
+ def ssl_cert(cert)
284
+ @options[:ssl_cert] = cert
285
+ end
286
+
287
+ # Sets the ca cert file to use.
288
+ def ssl_ca_cert_file(file)
289
+ @options[:ssl_ca_cert_file] = file
290
+ end
291
+
292
+ # Sets the ca cert to use.
293
+ def ssl_ca_cert(cert)
294
+ deprecate('ssl_ca_cert')
295
+ @options[:ssl_ca_cert] = cert
296
+ end
297
+
298
+ def ssl_ciphers(ciphers)
299
+ deprecate('ssl_ciphers')
300
+ @options[:ssl_ciphers] = ciphers
301
+ end
302
+
303
+ # Sets the ca cert path.
304
+ def ssl_ca_cert_path(path)
305
+ @options[:ssl_ca_cert_path] = path
306
+ end
307
+
308
+ # Sets the ssl cert store.
309
+ def ssl_cert_store(store)
310
+ @options[:ssl_cert_store] = store
311
+ end
312
+
313
+ # HTTP basic auth credentials.
314
+ def basic_auth(*credentials)
315
+ @options[:basic_auth] = credentials.flatten
316
+ end
317
+
318
+ # HTTP digest auth credentials.
319
+ def digest_auth(*credentials)
320
+ deprecate('digest_auth')
321
+ @options[:digest_auth] = credentials.flatten
322
+ end
323
+
324
+ # NTLM auth credentials.
325
+ def ntlm(*credentials)
326
+ @options[:ntlm] = credentials.flatten
327
+ end
328
+
329
+ # Instruct Nori whether to strip namespaces from XML nodes.
330
+ def strip_namespaces(strip_namespaces)
331
+ @options[:strip_namespaces] = strip_namespaces
332
+ end
333
+
334
+ # Instruct Nori whether to delete namespace attributes from XML nodes.
335
+ def delete_namespace_attributes(delete_namespace_attributes)
336
+ @options[:delete_namespace_attributes] = delete_namespace_attributes
404
337
  end
405
338
 
406
339
  # Tell Gyoku how to convert Hash key Symbols to XML tags.
@@ -409,87 +342,51 @@ module Savon
409
342
  @options[:convert_request_keys_to] = converter
410
343
  end
411
344
 
412
- # Tell Gyoku to unwrap Array of Hashes.
413
- # Accepts a boolean, defaults to false.
345
+ # Tell Gyoku to unwrap Array of Hashes
346
+ # Accepts a boolean, default to false
414
347
  def unwrap(unwrap)
415
348
  @options[:unwrap] = unwrap
416
349
  end
417
350
 
418
351
  # Tell Nori how to convert XML tags from the SOAP response into Hash keys.
419
352
  # Accepts a lambda or a block which receives an XML tag and returns a Hash key.
420
- # Defaults to converting tags to snakecase Symbols.
353
+ # Defaults to convert tags to snakecase Symbols.
421
354
  def convert_response_tags_to(converter = nil, &block)
422
355
  @options[:convert_response_tags_to] = block || converter
423
356
  end
424
357
 
425
358
  # Tell Nori how to convert XML attributes on tags from the SOAP response into Hash keys.
426
359
  # Accepts a lambda or a block which receives an XML tag and returns a Hash key.
427
- # Defaults to doing nothing.
360
+ # Defaults to doing nothing
428
361
  def convert_attributes_to(converter = nil, &block)
429
362
  @options[:convert_attributes_to] = block || converter
430
363
  end
431
364
 
432
365
  # Instruct Savon to create a multipart response if available.
433
366
  def multipart(multipart)
434
- if multipart
435
- warn "The global :multipart option has been a no-op since v2.13.0. " \
436
- "Savon detects whether the response is multipart by checking if the " \
437
- "response Content-Type header contains 'multipart'. You can remove" \
438
- "this option from your code to make this warning disappear.", uplevel: 1
439
- end
440
367
  @options[:multipart] = multipart
441
368
  end
442
369
 
370
+ # Instruct Savon what Faraday adapter it should use instead of default
371
+ def adapter(adapter)
372
+ @options[:adapter] = adapter
373
+ end
374
+
443
375
  # Enable inclusion of WS-Addressing headers.
444
376
  def use_wsa_headers(use)
445
377
  @options[:use_wsa_headers] = use
446
378
  end
447
379
 
448
- # Suppress the message tag wrapper around the SOAP body.
449
380
  def no_message_tag(bool)
450
381
  @options[:no_message_tag] = bool
451
382
  end
452
383
 
453
- # HTTP transport to use. Accepts :httpi (default) or :faraday.
454
- # With :faraday, set proxy, timeout, TLS, auth, redirect, and adapter
455
- # details on `client.faraday`; the HTTPI transport options are not copied.
456
- def transport(transport)
457
- @options[:transport] = transport
458
- end
459
-
460
- private
461
-
462
- # The default value for every global option.
463
- def defaults
464
- HTTPITransportOptions::TRANSPORT_DEFAULTS.merge(
465
- encoding: "UTF-8",
466
- soap_version: 1,
467
- namespaces: {},
468
- logger: Logger.new($stdout),
469
- log: false,
470
- log_headers: true,
471
- filters: [],
472
- pretty_print_xml: false,
473
- raise_errors: true,
474
- strip_namespaces: true,
475
- delete_namespace_attributes: false,
476
- empty_tag_value: nil,
477
- convert_dashes_to_underscores: true,
478
- scrub_xml: true,
479
- convert_response_tags_to: ->(tag) { StringUtils.snakecase(tag).to_sym },
480
- convert_attributes_to: ->(k, v) { [k, v] },
481
- multipart: false,
482
- use_wsa_headers: false,
483
- no_message_tag: false,
484
- unwrap: false,
485
- host: nil,
486
- transport: :httpi
487
- )
384
+ # Instruct requests to follow HTTP redirects.
385
+ def follow_redirects(follow_redirects)
386
+ @options[:follow_redirects] = follow_redirects
488
387
  end
489
388
  end
490
389
 
491
- # Per-request options passed to client.call.
492
- # Overrides or extends the matching GlobalOptions for a single SOAP operation.
493
390
  class LocalOptions < Options
494
391
  include SharedOptions
495
392
 
@@ -497,9 +394,10 @@ module Savon
497
394
  @option_type = :local
498
395
 
499
396
  defaults = {
500
- advanced_typecasting: true,
501
- response_parser: :nokogiri,
502
- multipart: false
397
+ :advanced_typecasting => true,
398
+ :response_parser => :nokogiri,
399
+ :multipart => false,
400
+ :body => false
503
401
  }
504
402
 
505
403
  super defaults.merge(options)
@@ -567,7 +465,11 @@ module Savon
567
465
  @options[:soap_action] = soap_action
568
466
  end
569
467
 
570
- # Cookies to be used for the next request.
468
+ # Cookies to be used for the next request
469
+ # @param [Hash] cookies cookies associated to nil will be appended as array cookies, if you need a cookie equal to
470
+ # and empty string, set it to ""
471
+ # @example cookies({accept: 'application/json', some-cookie: 'foo', "empty-cookie": "", HttpOnly: nil})
472
+ # # => "accept=application/json; some-cookie=foo; empty-cookie=; HttpOnly"
571
473
  def cookies(cookies)
572
474
  @options[:cookies] = cookies
573
475
  end
@@ -589,18 +491,15 @@ module Savon
589
491
 
590
492
  # Instruct Savon to create a multipart response if available.
591
493
  def multipart(multipart)
592
- if multipart
593
- warn "The local :multipart option has been a no-op since v2.13.0. " \
594
- "Savon detects whether the response is multipart by checking if the " \
595
- "response Content-Type header contains 'multipart'. You can remove" \
596
- "this option from your code to make this warning disappear.", uplevel: 1
597
- end
598
494
  @options[:multipart] = multipart
599
495
  end
600
496
 
601
- # Per-request HTTP headers. Merged with global headers for each request.
602
497
  def headers(headers)
603
498
  @options[:headers] = headers
604
499
  end
500
+
501
+ def body(body)
502
+ @options[:body] = body
503
+ end
605
504
  end
606
505
  end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require "gyoku"
4
3
 
5
4
  module Savon
@@ -38,7 +37,7 @@ module Savon
38
37
  private
39
38
 
40
39
  def translate_tag(key)
41
- Gyoku.xml_tag(key, key_converter: @key_converter).to_s
40
+ Gyoku.xml_tag(key, :key_converter => @key_converter).to_s
42
41
  end
43
42
 
44
43
  def add_namespaces_to_values(values, path)