savon 3.0.0.rc1 → 3.0.0.rc2

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: 3f58a5268715a082369bc199231506447defea5f760fae67cb51507a9011836c
4
- data.tar.gz: d349d7d546fb236e45f433047bd575dd6f6ec206254707094f02420ec58dfc07
3
+ metadata.gz: 217170b4a884638cf811c1b5334c9acbbfa7e5b88b1554f29c3e043557be5195
4
+ data.tar.gz: c36c7221ec92faa8df1064d4776c21269885d8db5d8d047db69dc3f598f05220
5
5
  SHA512:
6
- metadata.gz: 91d6cd948edbb82b643fa5aaeef265dcfeef5037459478f0815f01bdacbe04cb159165301a9f0ebc75fd897470ff2a0b51de1fa256123843698a14925f5ebf43
7
- data.tar.gz: 3a9fe95352e4f85e9e88f7eaffba5fb04df58085380ed7c62e8c0f31c0b110b5127c494125f373e97489c789991b6c1271e68df000606c3e1a3311a17edc951a
6
+ metadata.gz: 8da94da891a4d4db8e6a8ee2fbf08d2d230e2fcd7ea709f474649c4a06161c301a989a2174e58b73d27ca05a7141d8f1690e86526555e9f17d78665cca54e645
7
+ data.tar.gz: 1cb489bdd51b813057ad4b5b6c9f81739b89fa08276cc5ddca096271daf530b5c63307723d78b2202970a1f8f23270d71acf9f11daea5f43ca25c523067f7bbc
data/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  ## Unreleased
4
4
  * Add your PR changelog line here
5
5
 
6
+ ## 3.0.0.rc2 (2025-08-12)
7
+ * MTOM support with tests by @pcai in https://github.com/savonrb/savon/pull/1012
8
+ * Upgrade notes on ssl_verify_mode by @ehutzelman in https://github.com/savonrb/savon/pull/1013
9
+ * Pass the provided Savon/custom logger to Faraday by @larskanis in https://github.com/savonrb/savon/pull/1017
10
+ * Add ruby 3.4 to CI by @doconnor-clintel in https://github.com/savonrb/savon/pull/1024
11
+ * Restore support for SSL Ciphers by @doconnor-clintel in https://github.com/savonrb/savon/pull/1020
12
+ * Drop ruby 3.0 from CI by @doconnor-clintel in https://github.com/savonrb/savon/pull/1025
13
+ * Don't block minor updates to faraday by @larskanis in https://github.com/savonrb/savon/pull/1028
14
+ * Add gzip middleware when Accept-Encoding includes gzip by @kjeldahl in https://github.com/savonrb/savon/pull/1030
15
+ * Add option to provide connection middlewares. by @amartinfraguas in https://github.com/savonrb/savon/pull/1026
16
+
6
17
  ## 3.0.0.rc1 (2024-07-15)
7
18
 
8
19
  * Use Faraday instead of HTTPI
data/lib/savon/builder.rb CHANGED
@@ -38,18 +38,23 @@ module Savon
38
38
  end
39
39
 
40
40
  def build_document
41
- xml_result = build_xml
41
+ # check if xml was already provided
42
+ if @locals.include? :xml
43
+ xml_result = @locals[:xml]
44
+ else
45
+ xml_result = build_xml
42
46
 
43
- # if we have a signature sign the document
44
- if @signature
45
- @signature.document = xml_result
47
+ # if we have a signature sign the document
48
+ if @signature
49
+ @signature.document = xml_result
46
50
 
47
- 2.times do
48
- @header = nil
49
- @signature.document = build_xml
50
- end
51
+ 2.times do
52
+ @header = nil
53
+ @signature.document = build_xml
54
+ end
51
55
 
52
- xml_result = @signature.document
56
+ xml_result = @signature.document
57
+ end
53
58
  end
54
59
 
55
60
  # if there are attachments for the request, we should build a multipart message according to
@@ -70,7 +75,6 @@ module Savon
70
75
  end
71
76
 
72
77
  def to_s
73
- return @locals[:xml] if @locals.include? :xml
74
78
  build_document
75
79
  end
76
80
 
@@ -254,15 +258,28 @@ module Savon
254
258
 
255
259
  # the mail.body.encoded algorithm reorders the parts, default order is [ "text/plain", "text/enriched", "text/html" ]
256
260
  # should redefine the sort order, because the soap request xml should be the first
257
- multipart_message.body.set_sort_order [ "text/xml" ]
261
+ multipart_message.body.set_sort_order ['application/xop+xml', 'text/xml']
258
262
 
259
263
  multipart_message.body.encoded(multipart_message.content_transfer_encoding)
260
264
  end
261
265
 
262
266
  def init_multipart_message(message_xml)
263
267
  multipart_message = Mail.new
268
+
269
+ # MTOM differs from general SOAP attachments:
270
+ # 1. binary encoding
271
+ # 2. application/xop+xml mime type
272
+ if @locals[:mtom]
273
+ type = "application/xop+xml; charset=#{@globals[:encoding]}; type=\"text/xml\""
274
+
275
+ multipart_message.transport_encoding = 'binary'
276
+ message_xml.force_encoding('BINARY')
277
+ else
278
+ type = 'text/xml'
279
+ end
280
+
264
281
  xml_part = Mail::Part.new do
265
- content_type 'text/xml'
282
+ content_type type
266
283
  body message_xml
267
284
  # in Content-Type the start parameter is recommended (RFC 2387)
268
285
  content_id '<soap-request-body@soap>'
@@ -17,6 +17,7 @@ module Savon
17
17
  1 => "text/xml",
18
18
  2 => "application/soap+xml"
19
19
  }
20
+ SOAP_REQUEST_TYPE_MTOM = "application/xop+xml"
20
21
 
21
22
  def self.create(operation_name, wsdl, globals)
22
23
  if wsdl.document?
@@ -118,18 +119,21 @@ module Savon
118
119
  :headers => @locals[:headers]
119
120
  ) do |connection|
120
121
  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("; ")
122
+ ctype_headers = ["multipart/related"]
123
+ if @locals[:mtom]
124
+ ctype_headers << "type=\"#{SOAP_REQUEST_TYPE_MTOM}\""
125
+ ctype_headers << "start-info=\"text/xml\""
126
+ else
127
+ ctype_headers << "type=\"#{SOAP_REQUEST_TYPE[@globals[:soap_version]]}\""
128
+ connection.request :gzip
129
+ end
130
+ connection.headers["Content-Type"] = (ctype_headers + ["start=\"#{builder.multipart[:start]}\"",
131
+ "boundary=\"#{builder.multipart[:multipart_boundary]}\""]).join("; ")
126
132
  connection.headers["MIME-Version"] = "1.0"
127
133
  end
128
134
 
129
135
  connection.headers["Content-Length"] = @locals[:body].bytesize.to_s
130
136
  end
131
-
132
-
133
137
  end
134
138
 
135
139
  def soap_action
data/lib/savon/options.rb CHANGED
@@ -92,6 +92,7 @@ module Savon
92
92
  :convert_attributes_to => lambda { |k,v| [k,v] },
93
93
  :multipart => false,
94
94
  :adapter => nil,
95
+ :middlewares => [],
95
96
  :use_wsa_headers => false,
96
97
  :no_message_tag => false,
97
98
  :follow_redirects => false,
@@ -296,7 +297,6 @@ module Savon
296
297
  end
297
298
 
298
299
  def ssl_ciphers(ciphers)
299
- deprecate('ssl_ciphers')
300
300
  @options[:ssl_ciphers] = ciphers
301
301
  end
302
302
 
@@ -385,6 +385,25 @@ module Savon
385
385
  def follow_redirects(follow_redirects)
386
386
  @options[:follow_redirects] = follow_redirects
387
387
  end
388
+
389
+ # Provide middlewares for Faraday connections.
390
+ # The argument is an array, with each element being another array
391
+ # that contains the middleware class and its arguments, in the same way
392
+ # as a normal call to Faraday::RackBuilder#use
393
+ #
394
+ # See https://lostisland.github.io/faraday/#/middleware/index?id=using-middleware
395
+ # For example:
396
+ #
397
+ # client = Savon.client(
398
+ # middlewares: [
399
+ # [Faraday::Request::UrlEncoded],
400
+ # [Faraday::Response::Logger, { bodies: true }],
401
+ # [Faraday::Adapter::NetHttp]
402
+ # ]
403
+ # )
404
+ def middlewares(middlewares)
405
+ @options[:middlewares] = middlewares
406
+ end
388
407
  end
389
408
 
390
409
  class LocalOptions < Options
@@ -397,7 +416,8 @@ module Savon
397
416
  :advanced_typecasting => true,
398
417
  :response_parser => :nokogiri,
399
418
  :multipart => false,
400
- :body => false
419
+ :body => false,
420
+ :mtom => false
401
421
  }
402
422
 
403
423
  super defaults.merge(options)
@@ -460,6 +480,11 @@ module Savon
460
480
  @options[:attachments] = attachments
461
481
  end
462
482
 
483
+ # Instruct Savon to send attachments using MTOM https://www.w3.org/TR/soap12-mtom/
484
+ def mtom(mtom)
485
+ @options[:mtom] = mtom
486
+ end
487
+
463
488
  # Value of the SOAPAction HTTP header.
464
489
  def soap_action(soap_action)
465
490
  @options[:soap_action] = soap_action
@@ -489,6 +514,11 @@ module Savon
489
514
  @options[:response_parser] = parser
490
515
  end
491
516
 
517
+ # Pass already configured Nori instance.
518
+ def nori(nori)
519
+ @options[:nori] = nori
520
+ end
521
+
492
522
  # Instruct Savon to create a multipart response if available.
493
523
  def multipart(multipart)
494
524
  @options[:multipart] = multipart
data/lib/savon/request.rb CHANGED
@@ -36,12 +36,12 @@ module Savon
36
36
  connection.ssl.version = @globals[:ssl_version] if @globals.include? :ssl_version
37
37
  connection.ssl.min_version = @globals[:ssl_min_version] if @globals.include? :ssl_min_version
38
38
  connection.ssl.max_version = @globals[:ssl_max_version] if @globals.include? :ssl_max_version
39
+ connection.ssl.ciphers = @globals[:ssl_ciphers] if @globals.include? :ssl_ciphers
39
40
 
40
41
  # No Faraday Equivalent out of box, see: https://lostisland.github.io/faraday/#/customization/ssl-options
41
42
  # connection.ssl.cert_file = @globals[:ssl_cert_file] if @globals.include? :ssl_cert_file
42
43
  # connection.ssl.cert_key_file = @globals[:ssl_cert_key_file] if @globals.include? :ssl_cert_key_file
43
44
  # 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
45
  # connection.ssl.cert_key_password = @globals[:ssl_cert_key_password] if @globals.include? :ssl_cert_key_password
46
46
 
47
47
  end
@@ -77,7 +77,19 @@ module Savon
77
77
  end
78
78
 
79
79
  def configure_logging
80
- connection.response(:logger, nil, headers: @globals[:log_headers], level: @globals[:logger].level) if @globals[:log]
80
+ connection.response(:logger, @globals[:logger], headers: @globals[:log_headers]) if @globals[:log]
81
+ end
82
+
83
+ def configure_middlewares
84
+ @globals[:middlewares].each do |middleware_args|
85
+ connection.use(*middleware_args)
86
+ end
87
+ end
88
+
89
+ def configure_gzip
90
+ if connection.headers['Accept-Encoding'] && connection.headers['Accept-Encoding'].include?('gzip')
91
+ connection.request :gzip
92
+ end
81
93
  end
82
94
 
83
95
  protected
@@ -92,8 +104,10 @@ module Savon
92
104
  configure_ssl
93
105
  configure_auth
94
106
  configure_adapter
107
+ configure_middlewares
95
108
  configure_logging
96
109
  configure_headers
110
+ configure_gzip
97
111
  connection
98
112
  end
99
113
 
@@ -119,8 +133,10 @@ module Savon
119
133
  configure_headers(options[:soap_action], options[:headers])
120
134
  configure_cookies(options[:cookies])
121
135
  configure_adapter
136
+ configure_middlewares
122
137
  configure_logging
123
138
  configure_redirect_handling
139
+ configure_gzip
124
140
  yield(connection) if block_given?
125
141
  connection
126
142
  end
@@ -50,7 +50,7 @@ module Savon
50
50
  end
51
51
 
52
52
  def body_to_log(body)
53
- LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s
53
+ LogMessage.new(body, @globals[:filters], @globals[:pretty_print_xml]).to_s.force_encoding(@globals[:encoding])
54
54
  end
55
55
 
56
56
  end
@@ -142,20 +142,16 @@ module Savon
142
142
  end
143
143
 
144
144
  def nori
145
- return @nori if @nori
145
+ return @locals[:nori] if @locals[:nori]
146
146
 
147
- nori_options = {
148
- :delete_namespace_attributes => @globals[:delete_namespace_attributes],
149
- :strip_namespaces => @globals[:strip_namespaces],
150
- :convert_tags_to => @globals[:convert_response_tags_to],
151
- :convert_attributes_to => @globals[:convert_attributes_to],
152
- :advanced_typecasting => @locals[:advanced_typecasting],
153
- :parser => @locals[:response_parser]
154
- }
155
-
156
- non_nil_nori_options = nori_options.reject { |_, value| value.nil? }
157
- @nori = Nori.new(non_nil_nori_options)
147
+ @nori ||= Nori.new({
148
+ :delete_namespace_attributes => @globals[:delete_namespace_attributes],
149
+ :strip_namespaces => @globals[:strip_namespaces],
150
+ :convert_tags_to => @globals[:convert_response_tags_to],
151
+ :convert_attributes_to => @globals[:convert_attributes_to],
152
+ :advanced_typecasting => @locals[:advanced_typecasting],
153
+ :parser => @locals[:response_parser]
154
+ }.reject { |_, value| value.nil? })
158
155
  end
159
-
160
156
  end
161
157
  end
@@ -3,7 +3,14 @@ module Savon
3
3
  class SOAPFault < Error
4
4
 
5
5
  def self.present?(http, xml = nil)
6
- xml ||= http.body
6
+ xml_orig ||= http.body
7
+ if xml_orig.valid_encoding?
8
+ xml = xml_orig
9
+ else
10
+ xml = xml_orig.encode(
11
+ 'UTF-8', "ISO-8859-1", invalid: :replace, undef: :replace, replace: ''
12
+ )
13
+ end
7
14
  fault_node = xml.include?("Fault>")
8
15
  soap1_fault = xml.match(/faultcode\/?>/) && xml.match(/faultstring\/?>/)
9
16
  soap2_fault = xml.include?("Code>") && xml.include?("Reason>")
data/lib/savon/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Savon
3
- VERSION = '3.0.0.rc1'
3
+ VERSION = '3.0.0.rc2'
4
4
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: savon
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc1
4
+ version: 3.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-07-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: nori
@@ -30,14 +29,14 @@ dependencies:
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: '2.8'
32
+ version: '2.11'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: '2.8'
39
+ version: '2.11'
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: faraday-gzip
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -240,6 +239,20 @@ dependencies:
240
239
  - - ">="
241
240
  - !ruby/object:Gem::Version
242
241
  version: '0'
242
+ - !ruby/object:Gem::Dependency
243
+ name: ostruct
244
+ requirement: !ruby/object:Gem::Requirement
245
+ requirements:
246
+ - - "~>"
247
+ - !ruby/object:Gem::Version
248
+ version: '0.6'
249
+ type: :development
250
+ prerelease: false
251
+ version_requirements: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - "~>"
254
+ - !ruby/object:Gem::Version
255
+ version: '0.6'
243
256
  - !ruby/object:Gem::Dependency
244
257
  name: byebug
245
258
  requirement: !ruby/object:Gem::Requirement
@@ -346,7 +359,6 @@ licenses:
346
359
  - MIT
347
360
  metadata:
348
361
  rubygems_mfa_required: 'true'
349
- post_install_message:
350
362
  rdoc_options: []
351
363
  require_paths:
352
364
  - lib
@@ -361,8 +373,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
373
  - !ruby/object:Gem::Version
362
374
  version: '0'
363
375
  requirements: []
364
- rubygems_version: 3.5.6
365
- signing_key:
376
+ rubygems_version: 3.6.7
366
377
  specification_version: 4
367
378
  summary: Heavy metal SOAP client
368
379
  test_files: []