savon 2.15.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df435a9b3a37060f3dbbfe5ba2f8b36c33ad66b6474afa08771396b6812fb4b3
4
- data.tar.gz: ac8cccabad1588894528b1d2ad073e576224a6b4a5b25d10a0437fb5a807e538
3
+ metadata.gz: 3f58a5268715a082369bc199231506447defea5f760fae67cb51507a9011836c
4
+ data.tar.gz: d349d7d546fb236e45f433047bd575dd6f6ec206254707094f02420ec58dfc07
5
5
  SHA512:
6
- metadata.gz: 79a1dd54bd1d171afc117927c9b5419f7c6d2e2a5e2b1cfad0072397e786f5932bb3180b40f7ea9d55a08194c1554afddf3efe558959157cdcc7e8b13243beb9
7
- data.tar.gz: 9e9f944a60f6f655da4abfed31020befb23a9823bb3437ccb46e527b1b8e091fac81c776fc3057f88985a80bbae3c8bb9746bf8c1e9c3966ac8992bc0ee7f936
6
+ metadata.gz: 91d6cd948edbb82b643fa5aaeef265dcfeef5037459478f0815f01bdacbe04cb159165301a9f0ebc75fd897470ff2a0b51de1fa256123843698a14925f5ebf43
7
+ data.tar.gz: 3a9fe95352e4f85e9e88f7eaffba5fb04df58085380ed7c62e8c0f31c0b110b5127c494125f373e97489c789991b6c1271e68df000606c3e1a3311a17edc951a
data/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  ## Unreleased
4
4
  * Add your PR changelog line here
5
5
 
6
+ ## 3.0.0.rc1 (2024-07-15)
7
+
8
+ * Use Faraday instead of HTTPI
9
+ * BC BREAKING Cookies are handled differently now
10
+ * BC BREAKING Multiple pieces of functionality will rely on faraday libraries to be provided by the consuming codebase
11
+ * BC BREAKING Adapter overrides now utilize the faraday model
12
+ * BC BREAKING Multiple hard deprecations due to a lack of feature parity between Faraday and HTTPI
13
+ * Deprecates digest auth
14
+ * Deprecates ssl_cert_key_file auth, upgrade path is to read the key
15
+ in and provide it
16
+ * Deprecates encrypted ssl keys, upgrade path is to
17
+ decrypt the key and pass it to faraday in code
18
+ * Deprecates providing a ca cert, upgrade path is to provide a ca cert file
19
+ * deprecates overriding ssl ciphers, as faraday does not support this
20
+
6
21
  ## 2.15.1 (2024-07-08)
7
22
 
8
23
  * Ruby 3.0+ is required in the gemspec.
data/README.md CHANGED
@@ -10,6 +10,7 @@ Heavy metal SOAP client
10
10
  [![Code Climate](https://codeclimate.com/github/savonrb/savon.svg)](https://codeclimate.com/github/savonrb/savon)
11
11
  [![Coverage Status](https://coveralls.io/repos/savonrb/savon/badge.svg)](https://coveralls.io/r/savonrb/savon)
12
12
 
13
+ If you're reading this on GitHub, note that this README is for the main branch and that features/changes described here might not correspond to your version. You can find the documentation for your release [at rubydoc.info](https://www.rubydoc.info/find/gems?q=savon).
13
14
 
14
15
  ## Installation
15
16
 
@@ -22,7 +23,7 @@ $ gem install savon
22
23
  or add it to your Gemfile like this:
23
24
 
24
25
  ```
25
- gem 'savon', '~> 2.15.0'
26
+ gem 'savon', '~> 3.0.0'
26
27
  ```
27
28
 
28
29
  ## Usage example
@@ -52,6 +53,10 @@ response.body
52
53
  For more examples, you should check out the
53
54
  [integration tests](https://github.com/savonrb/savon/tree/version2/spec/integration).
54
55
 
56
+ ## Upgrading from v2.x to v3.x
57
+
58
+ See [UPGRADING.md](UPGRADING.md) for more information.
59
+
55
60
  ## Ruby version support
56
61
 
57
62
  Every savon release is tested with contemporary supported versions of ruby. Historical compatibility information:
@@ -4,7 +4,7 @@ module Savon
4
4
  class HTTPError < Error
5
5
 
6
6
  def self.present?(http)
7
- http.error?
7
+ !http.success?
8
8
  end
9
9
 
10
10
  def initialize(http)
@@ -14,13 +14,13 @@ module Savon
14
14
  attr_reader :http
15
15
 
16
16
  def to_s
17
- String.new("HTTP error (#{@http.code})").tap do |str_error|
17
+ String.new("HTTP error (#{@http.status})").tap do |str_error|
18
18
  str_error << ": #{@http.body}" unless @http.body.empty?
19
19
  end
20
20
  end
21
21
 
22
22
  def to_hash
23
- { :code => @http.code, :headers => @http.headers, :body => @http.body }
23
+ { :code => @http.status, :headers => @http.headers, :body => @http.body }
24
24
  end
25
25
 
26
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require "httpi"
2
+ require "faraday"
3
3
 
4
4
  module Savon
5
5
  class MockExpectation
@@ -41,8 +41,8 @@ module Savon
41
41
  unless @response
42
42
  raise ExpectationError, "This expectation was not set up with a response."
43
43
  end
44
-
45
- HTTPI::Response.new(@response[:code], @response[:headers], @response[:body])
44
+ env = Faraday::Env.from(status: @response[:code], response_headers: @response[:headers], response_body: @response[:body])
45
+ Faraday::Response.new(env)
46
46
  end
47
47
 
48
48
  private
@@ -75,7 +75,7 @@ module Savon
75
75
  next if (expected_value == :any && msg_real.include?(key))
76
76
  return false if expected_value != msg_real[key]
77
77
  end
78
- return true
78
+ true
79
79
  end
80
80
  end
81
81
  end
@@ -7,6 +7,8 @@ require "savon/response"
7
7
  require "savon/request_logger"
8
8
  require "savon/http_error"
9
9
  require "mail"
10
+ require 'faraday/gzip'
11
+
10
12
 
11
13
  module Savon
12
14
  class Operation
@@ -58,16 +60,20 @@ module Savon
58
60
  builder = build(locals, &block)
59
61
 
60
62
  response = Savon.notify_observers(@name, builder, @globals, @locals)
61
- response ||= call_with_logging build_request(builder)
63
+ response ||= call_with_logging build_connection(builder)
62
64
 
63
- raise_expected_httpi_response! unless response.kind_of?(HTTPI::Response)
65
+ raise_expected_faraday_response! unless response.kind_of?(Faraday::Response)
64
66
 
65
67
  create_response(response)
66
68
  end
67
69
 
68
70
  def request(locals = {}, &block)
69
71
  builder = build(locals, &block)
70
- build_request(builder)
72
+ connection = build_connection(builder)
73
+ connection.build_request(:post) do |req|
74
+ req.url(@globals[:endpoint])
75
+ req.body = @locals[:body]
76
+ end
71
77
  end
72
78
 
73
79
  private
@@ -83,37 +89,47 @@ module Savon
83
89
  @locals = locals
84
90
  end
85
91
 
86
- def call_with_logging(request)
87
- @logger.log(request) { HTTPI.post(request, @globals[:adapter]) }
92
+ def call_with_logging(connection)
93
+ ntlm_auth = handle_ntlm(connection) if @globals.include?(:ntlm)
94
+ @logger.log_response(connection.post(@globals[:endpoint]) { |request|
95
+ request.body = @locals[:body]
96
+ request.headers['Authorization'] = "NTLM #{auth.encode64}" if ntlm_auth
97
+ @logger.log_request(request)
98
+ })
88
99
  end
89
100
 
90
- def build_request(builder)
91
- @locals[:soap_action] ||= soap_action
92
- @globals[:endpoint] ||= endpoint
101
+ def handle_ntlm(connection)
102
+ ntlm_message = Net::NTLM::Message
103
+ response = connection.get(@globals[:endpoint]) do |request|
104
+ request.headers['Authorization'] = 'NTLM ' + ntlm_message::Type1.new.encode64
105
+ end
106
+ challenge = response.headers['www-authenticate'][/(?:NTLM|Negotiate) (.*)$/, 1]
107
+ message = ntlm_message::Type2.decode64(challenge)
108
+ message.response([:user, :password, :domain].zip(@globals[:ntlm]).to_h)
109
+ end
93
110
 
94
- request = SOAPRequest.new(@globals).build(
111
+ def build_connection(builder)
112
+ @globals[:endpoint] ||= endpoint
113
+ @locals[:soap_action] ||= soap_action
114
+ @locals[:body] = builder.to_s
115
+ @connection = SOAPRequest.new(@globals).build(
95
116
  :soap_action => soap_action,
96
117
  :cookies => @locals[:cookies],
97
118
  :headers => @locals[:headers]
98
- )
99
-
100
- request.url = endpoint
101
- request.body = builder.to_s
102
-
103
- if builder.multipart
104
- request.gzip
105
- request.headers["Content-Type"] = ["multipart/related",
106
- "type=\"#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}\"",
107
- "start=\"#{builder.multipart[:start]}\"",
108
- "boundary=\"#{builder.multipart[:multipart_boundary]}\""].join("; ")
109
- request.headers["MIME-Version"] = "1.0"
119
+ ) do |connection|
120
+ if builder.multipart
121
+ connection.request :gzip
122
+ connection.headers["Content-Type"] = %W[multipart/related
123
+ type="#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}",
124
+ start="#{builder.multipart[:start]}",
125
+ boundary="#{builder.multipart[:multipart_boundary]}"].join("; ")
126
+ connection.headers["MIME-Version"] = "1.0"
127
+ end
128
+
129
+ connection.headers["Content-Length"] = @locals[:body].bytesize.to_s
110
130
  end
111
131
 
112
- # TODO: could HTTPI do this automatically in case the header
113
- # was not specified manually? [dh, 2013-01-04]
114
- request.headers["Content-Length"] = request.body.bytesize.to_s
115
132
 
116
- request
117
133
  end
118
134
 
119
135
  def soap_action
@@ -138,8 +154,8 @@ module Savon
138
154
  end
139
155
  end
140
156
 
141
- def raise_expected_httpi_response!
142
- raise Error, "Observers need to return an HTTPI::Response to mock " \
157
+ def raise_expected_faraday_response!
158
+ raise Error, "Observers need to return a Faraday::Response to mock " \
143
159
  "the request or nil to execute the request."
144
160
  end
145
161
 
data/lib/savon/options.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require "logger"
3
- require "httpi"
4
3
 
5
4
  module Savon
6
5
  class Options
@@ -10,6 +9,10 @@ module Savon
10
9
  assign options
11
10
  end
12
11
 
12
+ def deprecate(option)
13
+ raise DeprecatedOptionError.new(option)
14
+ end
15
+
13
16
  attr_reader :option_type
14
17
 
15
18
  def [](option)
@@ -127,7 +130,7 @@ module Savon
127
130
  @options[:namespace] = namespace
128
131
  end
129
132
 
130
- # The namespace identifer.
133
+ # The namespace identifier.
131
134
  def namespace_identifier(identifier)
132
135
  @options[:namespace_identifier] = identifier
133
136
  end
@@ -198,13 +201,11 @@ module Savon
198
201
 
199
202
  # Whether or not to log.
200
203
  def log(log)
201
- HTTPI.log = log
202
204
  @options[:log] = log
203
205
  end
204
206
 
205
207
  # The logger to use. Defaults to a Savon::Logger instance.
206
208
  def logger(logger)
207
- HTTPI.logger = logger
208
209
  @options[:logger] = logger
209
210
  end
210
211
 
@@ -257,6 +258,7 @@ module Savon
257
258
 
258
259
  # Sets the cert key file to use.
259
260
  def ssl_cert_key_file(file)
261
+ deprecate('ssl_cert_key_file')
260
262
  @options[:ssl_cert_key_file] = file
261
263
  end
262
264
 
@@ -267,11 +269,13 @@ module Savon
267
269
 
268
270
  # Sets the cert key password to use.
269
271
  def ssl_cert_key_password(password)
272
+ deprecate('ssl_cert_key_password')
270
273
  @options[:ssl_cert_key_password] = password
271
274
  end
272
275
 
273
276
  # Sets the cert file to use.
274
277
  def ssl_cert_file(file)
278
+ deprecate('ssl_cert_file')
275
279
  @options[:ssl_cert_file] = file
276
280
  end
277
281
 
@@ -287,10 +291,12 @@ module Savon
287
291
 
288
292
  # Sets the ca cert to use.
289
293
  def ssl_ca_cert(cert)
294
+ deprecate('ssl_ca_cert')
290
295
  @options[:ssl_ca_cert] = cert
291
296
  end
292
297
 
293
298
  def ssl_ciphers(ciphers)
299
+ deprecate('ssl_ciphers')
294
300
  @options[:ssl_ciphers] = ciphers
295
301
  end
296
302
 
@@ -311,6 +317,7 @@ module Savon
311
317
 
312
318
  # HTTP digest auth credentials.
313
319
  def digest_auth(*credentials)
320
+ deprecate('digest_auth')
314
321
  @options[:digest_auth] = credentials.flatten
315
322
  end
316
323
 
@@ -360,7 +367,7 @@ module Savon
360
367
  @options[:multipart] = multipart
361
368
  end
362
369
 
363
- # Instruct Savon what HTTPI adapter it should use instead of default
370
+ # Instruct Savon what Faraday adapter it should use instead of default
364
371
  def adapter(adapter)
365
372
  @options[:adapter] = adapter
366
373
  end
@@ -389,7 +396,8 @@ module Savon
389
396
  defaults = {
390
397
  :advanced_typecasting => true,
391
398
  :response_parser => :nokogiri,
392
- :multipart => false
399
+ :multipart => false,
400
+ :body => false
393
401
  }
394
402
 
395
403
  super defaults.merge(options)
@@ -397,7 +405,7 @@ module Savon
397
405
 
398
406
  # The local SOAP header. Expected to be a Hash or respond to #to_s.
399
407
  # Will be merged with the global SOAP header if both are Hashes.
400
- # Otherwise the local option will be prefered.
408
+ # Otherwise the local option will be preferred.
401
409
  def soap_header(header)
402
410
  @options[:soap_header] = header
403
411
  end
@@ -457,7 +465,11 @@ module Savon
457
465
  @options[:soap_action] = soap_action
458
466
  end
459
467
 
460
- # 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"
461
473
  def cookies(cookies)
462
474
  @options[:cookies] = cookies
463
475
  end
@@ -485,5 +497,9 @@ module Savon
485
497
  def headers(headers)
486
498
  @options[:headers] = headers
487
499
  end
500
+
501
+ def body(body)
502
+ @options[:body] = body
503
+ end
488
504
  end
489
505
  end
data/lib/savon/request.rb CHANGED
@@ -1,61 +1,87 @@
1
1
  # frozen_string_literal: true
2
- require "httpi"
2
+ require "faraday"
3
3
 
4
4
  module Savon
5
5
  class HTTPRequest
6
6
 
7
- def initialize(globals, http_request = nil)
7
+ def initialize(globals, connection = nil)
8
8
  @globals = globals
9
- @http_request = http_request || HTTPI::Request.new
10
- end
11
-
12
- def build
13
- @http_request
9
+ @connection = connection || Faraday::Connection.new
14
10
  end
15
11
 
16
12
  private
17
13
 
18
14
  def configure_proxy
19
- @http_request.proxy = @globals[:proxy] if @globals.include? :proxy
15
+ connection.proxy = @globals[:proxy] if @globals.include? :proxy
20
16
  end
21
17
 
22
18
  def configure_timeouts
23
- @http_request.open_timeout = @globals[:open_timeout] if @globals.include? :open_timeout
24
- @http_request.read_timeout = @globals[:read_timeout] if @globals.include? :read_timeout
25
- @http_request.write_timeout = @globals[:write_timeout] if @globals.include? :write_timeout
19
+ connection.options.open_timeout = @globals[:open_timeout] if @globals.include? :open_timeout
20
+ connection.options.read_timeout = @globals[:read_timeout] if @globals.include? :read_timeout
21
+ connection.options.write_timeout = @globals[:write_timeout] if @globals.include? :write_timeout
26
22
  end
27
23
 
28
24
  def configure_ssl
29
- @http_request.auth.ssl.ssl_version = @globals[:ssl_version] if @globals.include? :ssl_version
30
- @http_request.auth.ssl.min_version = @globals[:ssl_min_version] if @globals.include? :ssl_min_version
31
- @http_request.auth.ssl.max_version = @globals[:ssl_max_version] if @globals.include? :ssl_max_version
32
-
33
- @http_request.auth.ssl.verify_mode = @globals[:ssl_verify_mode] if @globals.include? :ssl_verify_mode
34
- @http_request.auth.ssl.ciphers = @globals[:ssl_ciphers] if @globals.include? :ssl_ciphers
35
-
36
- @http_request.auth.ssl.cert_key_file = @globals[:ssl_cert_key_file] if @globals.include? :ssl_cert_key_file
37
- @http_request.auth.ssl.cert_key = @globals[:ssl_cert_key] if @globals.include? :ssl_cert_key
38
- @http_request.auth.ssl.cert_file = @globals[:ssl_cert_file] if @globals.include? :ssl_cert_file
39
- @http_request.auth.ssl.cert = @globals[:ssl_cert] if @globals.include? :ssl_cert
40
- @http_request.auth.ssl.ca_cert_file = @globals[:ssl_ca_cert_file] if @globals.include? :ssl_ca_cert_file
41
- @http_request.auth.ssl.ca_cert_path = @globals[:ssl_ca_cert_path] if @globals.include? :ssl_ca_cert_path
42
- @http_request.auth.ssl.ca_cert = @globals[:ssl_ca_cert] if @globals.include? :ssl_ca_cert
43
- @http_request.auth.ssl.cert_store = @globals[:ssl_cert_store] if @globals.include? :ssl_cert_store
44
-
45
- @http_request.auth.ssl.cert_key_password = @globals[:ssl_cert_key_password] if @globals.include? :ssl_cert_key_password
25
+ connection.ssl.verify = @globals[:ssl_verify] if @globals.include? :ssl_verify
26
+ connection.ssl.ca_file = @globals[:ssl_ca_cert_file] if @globals.include? :ssl_ca_cert_file
27
+ connection.ssl.verify_hostname = @globals[:verify_hostname] if @globals.include? :verify_hostname
28
+ connection.ssl.ca_path = @globals[:ssl_ca_cert_path] if @globals.include? :ssl_ca_cert_path
29
+ connection.ssl.verify_mode = @globals[:ssl_verify_mode] if @globals.include? :ssl_verify_mode
30
+ connection.ssl.cert_store = @globals[:ssl_cert_store] if @globals.include? :ssl_cert_store
31
+ connection.ssl.client_cert = @globals[:ssl_cert] if @globals.include? :ssl_cert
32
+ connection.ssl.client_key = @globals[:ssl_cert_key] if @globals.include? :ssl_cert_key
33
+ connection.ssl.certificate = @globals[:ssl_certificate] if @globals.include? :ssl_certificate
34
+ connection.ssl.private_key = @globals[:ssl_private_key] if @globals.include? :ssl_private_key
35
+ connection.ssl.verify_depth = @globals[:verify_depth] if @globals.include? :verify_depth
36
+ connection.ssl.version = @globals[:ssl_version] if @globals.include? :ssl_version
37
+ connection.ssl.min_version = @globals[:ssl_min_version] if @globals.include? :ssl_min_version
38
+ connection.ssl.max_version = @globals[:ssl_max_version] if @globals.include? :ssl_max_version
39
+
40
+ # No Faraday Equivalent out of box, see: https://lostisland.github.io/faraday/#/customization/ssl-options
41
+ # connection.ssl.cert_file = @globals[:ssl_cert_file] if @globals.include? :ssl_cert_file
42
+ # connection.ssl.cert_key_file = @globals[:ssl_cert_key_file] if @globals.include? :ssl_cert_key_file
43
+ # connection.ssl.ca_cert = @globals[:ssl_ca_cert] if @globals.include? :ssl_ca_cert
44
+ # connection.ssl.ciphers = @globals[:ssl_ciphers] if @globals.include? :ssl_ciphers
45
+ # connection.ssl.cert_key_password = @globals[:ssl_cert_key_password] if @globals.include? :ssl_cert_key_password
46
+
46
47
  end
47
48
 
48
49
  def configure_auth
49
- @http_request.auth.basic(*@globals[:basic_auth]) if @globals.include? :basic_auth
50
- @http_request.auth.digest(*@globals[:digest_auth]) if @globals.include? :digest_auth
51
- @http_request.auth.ntlm(*@globals[:ntlm]) if @globals.include? :ntlm
50
+ basic_auth if @globals.include?(:basic_auth)
51
+ ntlm_auth if @globals.include?(:ntlm)
52
+ end
53
+
54
+ def basic_auth
55
+ connection.request(:authorization, :basic, *@globals[:basic_auth])
56
+ end
57
+
58
+ def ntlm_auth
59
+ begin
60
+ require 'rubyntlm'
61
+ require 'faraday/net_http_persistent'
62
+ connection.adapter :net_http_persistent, pool_size: 5
63
+ rescue LoadError
64
+ raise LoadError, 'Using NTLM Auth requires both `rubyntlm` and `faraday-net_http_persistent` to be installed.'
65
+ end
52
66
  end
53
67
 
54
68
  def configure_redirect_handling
55
- if @globals.include? :follow_redirects
56
- @http_request.follow_redirect = @globals[:follow_redirects]
69
+ if @globals[:follow_redirects]
70
+ require 'faraday/follow_redirects'
71
+ connection.response :follow_redirects
57
72
  end
58
73
  end
74
+
75
+ def configure_adapter
76
+ connection.adapter(*@globals[:adapter]) unless @globals[:adapter].nil?
77
+ end
78
+
79
+ def configure_logging
80
+ connection.response(:logger, nil, headers: @globals[:log_headers], level: @globals[:logger].level) if @globals[:log]
81
+ end
82
+
83
+ protected
84
+ attr_reader :connection
59
85
  end
60
86
 
61
87
  class WSDLRequest < HTTPRequest
@@ -63,18 +89,18 @@ module Savon
63
89
  def build
64
90
  configure_proxy
65
91
  configure_timeouts
66
- configure_headers
67
92
  configure_ssl
68
93
  configure_auth
69
- configure_redirect_handling
70
-
71
- @http_request
94
+ configure_adapter
95
+ configure_logging
96
+ configure_headers
97
+ connection
72
98
  end
73
99
 
74
100
  private
75
101
 
76
102
  def configure_headers
77
- @http_request.headers = @globals[:headers] if @globals.include? :headers
103
+ connection.headers = @globals[:headers] if @globals.include? :headers
78
104
  end
79
105
  end
80
106
 
@@ -88,26 +114,34 @@ module Savon
88
114
  def build(options = {})
89
115
  configure_proxy
90
116
  configure_timeouts
91
- configure_headers options[:soap_action], options[:headers]
92
- configure_cookies options[:cookies]
93
117
  configure_ssl
94
118
  configure_auth
119
+ configure_headers(options[:soap_action], options[:headers])
120
+ configure_cookies(options[:cookies])
121
+ configure_adapter
122
+ configure_logging
95
123
  configure_redirect_handling
96
-
97
- @http_request
124
+ yield(connection) if block_given?
125
+ connection
98
126
  end
99
127
 
100
128
  private
101
129
 
102
130
  def configure_cookies(cookies)
103
- @http_request.set_cookies(cookies) if cookies
131
+ connection.headers['Cookie'] = cookies.map do |key, value|
132
+ if value.nil?
133
+ key
134
+ else
135
+ "#{key}=#{value}"
136
+ end
137
+ end.join('; ') if cookies
104
138
  end
105
139
 
106
140
  def configure_headers(soap_action, headers)
107
- @http_request.headers = @globals[:headers] if @globals.include? :headers
108
- @http_request.headers.merge!(headers) if headers
109
- @http_request.headers["SOAPAction"] ||= %{"#{soap_action}"} if soap_action
110
- @http_request.headers["Content-Type"] ||= CONTENT_TYPE[@globals[:soap_version]] % @globals[:encoding]
141
+ connection.headers = @globals[:headers] if @globals.include? :headers
142
+ connection.headers.merge!(headers) if headers
143
+ connection.headers["SOAPAction"] ||= %{"#{soap_action}"} if soap_action
144
+ connection.headers["Content-Type"] ||= CONTENT_TYPE[@globals[:soap_version]] % @globals[:encoding]
111
145
  end
112
146
  end
113
147
  end
@@ -27,21 +27,24 @@ module Savon
27
27
  def log_headers?
28
28
  @globals[:log_headers]
29
29
  end
30
-
31
- private
32
-
33
30
  def log_request(request)
34
- logger.info { "SOAP request: #{request.url}" }
31
+ return unless log?
32
+ logger.info { "SOAP request: #{request.path}" }
35
33
  logger.info { headers_to_log(request.headers) } if log_headers?
36
34
  logger.debug { body_to_log(request.body) }
37
35
  end
38
36
 
39
37
  def log_response(response)
40
- logger.info { "SOAP response (status #{response.code})" }
38
+ return response unless log?
39
+ logger.info { "SOAP response (status #{response.status})" }
41
40
  logger.debug { headers_to_log(response.headers) } if log_headers?
42
41
  logger.debug { body_to_log(response.body) }
42
+ response
43
43
  end
44
44
 
45
+ private
46
+
47
+
45
48
  def headers_to_log(headers)
46
49
  headers.map { |key, value| "#{key}: #{value}" }.join("\n")
47
50
  end
@@ -5,7 +5,7 @@ module Savon
5
5
  def self.present?(http, xml = nil)
6
6
  xml ||= http.body
7
7
  fault_node = xml.include?("Fault>")
8
- soap1_fault = xml.match(/faultcode\/?\>/) && xml.match(/faultstring\/?\>/)
8
+ soap1_fault = xml.match(/faultcode\/?>/) && xml.match(/faultstring\/?>/)
9
9
  soap2_fault = xml.include?("Code>") && xml.include?("Reason>")
10
10
 
11
11
  fault_node && (soap1_fault || soap2_fault)
data/lib/savon/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Savon
3
- VERSION = '2.15.1'
3
+ VERSION = '3.0.0.rc1'
4
4
  end
data/lib/savon.rb CHANGED
@@ -7,6 +7,14 @@ module Savon
7
7
  UnknownOperationError = Class.new(Error)
8
8
  InvalidResponseError = Class.new(Error)
9
9
 
10
+ class DeprecatedOptionError < Error
11
+ attr_accessor :option
12
+ def initialize(option)
13
+ @option = option
14
+ super("#{option} is deprecated as it is not supported in Faraday. See https://github.com/savonrb/savon/blob/main/UPGRADING.md for more information.")
15
+ end
16
+ end
17
+
10
18
  def self.client(globals = {}, &block)
11
19
  Client.new(globals, &block)
12
20
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: savon
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.15.1
4
+ version: 3.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-08 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nori
@@ -25,45 +25,61 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.4'
27
27
  - !ruby/object:Gem::Dependency
28
- name: httpi
28
+ name: faraday
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '4'
34
- - - "<"
33
+ version: '2.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
35
39
  - !ruby/object:Gem::Version
36
- version: '5'
40
+ version: '2.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday-gzip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
37
48
  type: :runtime
38
49
  prerelease: false
39
50
  version_requirements: !ruby/object:Gem::Requirement
40
51
  requirements:
41
- - - ">="
52
+ - - "~>"
42
53
  - !ruby/object:Gem::Version
43
- version: '4'
44
- - - "<"
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday-follow_redirects
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
45
60
  - !ruby/object:Gem::Version
46
- version: '5'
61
+ version: '0.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.3'
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: wasabi
49
71
  requirement: !ruby/object:Gem::Requirement
50
72
  requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '3.7'
54
- - - "<"
73
+ - - ">"
55
74
  - !ruby/object:Gem::Version
56
- version: '6'
75
+ version: '5'
57
76
  type: :runtime
58
77
  prerelease: false
59
78
  version_requirements: !ruby/object:Gem::Requirement
60
79
  requirements:
61
- - - ">="
80
+ - - ">"
62
81
  - !ruby/object:Gem::Version
63
- version: '3.7'
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '6'
82
+ version: '5'
67
83
  - !ruby/object:Gem::Dependency
68
84
  name: akami
69
85
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +150,34 @@ dependencies:
134
150
  - - "~>"
135
151
  - !ruby/object:Gem::Version
136
152
  version: '2.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: faraday-net_http_persistent
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubyntlm
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0.6'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0.6'
137
181
  - !ruby/object:Gem::Dependency
138
182
  name: rack
139
183
  requirement: !ruby/object:Gem::Requirement
@@ -168,6 +212,34 @@ dependencies:
168
212
  - - "<"
169
213
  - !ruby/object:Gem::Version
170
214
  version: '7'
215
+ - !ruby/object:Gem::Dependency
216
+ name: httpclient
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ - !ruby/object:Gem::Dependency
230
+ name: mutex_m
231
+ requirement: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
236
+ type: :development
237
+ prerelease: false
238
+ version_requirements: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: '0'
171
243
  - !ruby/object:Gem::Dependency
172
244
  name: byebug
173
245
  requirement: !ruby/object:Gem::Requirement