savon 2.15.1 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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