faraday 2.3.0 → 2.7.1

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: 51764b6108e230dfff244e6e6e9f275f92f5fc1bcd1bf8e43d36058d35442e14
4
- data.tar.gz: 2cdf2edfd3e3c0386f501c0c2609db4f5c879a2a1807869a7b7e690e4a22a77a
3
+ metadata.gz: 655acb55a8ad9a7088984d61b2e520fdf11e5aa3d9221212ef6e783349d72614
4
+ data.tar.gz: 620ec5a7c8c76109f6b82462b7a40b6440d79a96f6beaff33164be8743f1db7d
5
5
  SHA512:
6
- metadata.gz: 94ce1d0df0639d8e7a8472085331796a787236989e07943a47e463f6d5c68d83bf180b55636e87d37ac654400fe11660ee10898c9b43122c29a211310682b621
7
- data.tar.gz: 14af6c0c348cf3ca8ae7f7f8a95b3eb8b73b8a444d90a75c7eeb46d9edd4c840fa44dd2eda4e76653fd4924e6b20d13f32236e21bd303f90b589df1abc88da3d
6
+ metadata.gz: bc0321f9fed0b30548454555345bc4fa26af757142fd4dd767868c281bdc50b5833b73aa005c48dbc638c3c2f0dff00dddcde6d313a2e2cf25eae15dca928d3a
7
+ data.tar.gz: 3ebe07829ccb50bb0a0d1d0a5e77d2d91fb8ff6c57dd7d107792f8a6ef92656c4c8e67e650f2ac88862686f1051d36cabc1b9fd5ec933b59e70977d0777a5845
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2020 Rick Olson, Zack Hobson
1
+ Copyright (c) 2009-2022 Rick Olson, Zack Hobson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -42,7 +42,7 @@ Open the issues page and check for the `help wanted` label!
42
42
  But before you start coding, please read our [Contributing Guide][contributing]
43
43
 
44
44
  ## Copyright
45
- © 2009 - 2021, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
45
+ © 2009 - 2022, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
46
46
 
47
47
  [awesome]: https://github.com/lostisland/awesome-faraday/#adapters
48
48
  [website]: https://lostisland.github.io/faraday
@@ -17,6 +17,11 @@ class Client
17
17
  data = JSON.parse(res.body)
18
18
  data['origin']
19
19
  end
20
+
21
+ def foo(params)
22
+ res = @conn.post('/foo', JSON.dump(params))
23
+ res.status
24
+ end
20
25
  end
21
26
 
22
27
  RSpec.describe Client do
@@ -94,4 +99,21 @@ RSpec.describe Client do
94
99
  stubs.verify_stubbed_calls
95
100
  end
96
101
  end
102
+
103
+ context 'When you want to test the body, you can use a proc as well as string' do
104
+ it 'tests with a string' do
105
+ stubs.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
106
+
107
+ expect(client.foo(name: 'YK')).to eq 200
108
+ stubs.verify_stubbed_calls
109
+ end
110
+
111
+ it 'tests with a proc' do
112
+ check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
113
+ stubs.post('/foo', check) { [200, {}, ''] }
114
+
115
+ expect(client.foo(name: 'YK', created_at: Time.now)).to eq 200
116
+ stubs.verify_stubbed_calls
117
+ end
118
+ end
97
119
  end
@@ -18,6 +18,11 @@ class Client
18
18
  data = JSON.parse(res.body)
19
19
  data['origin']
20
20
  end
21
+
22
+ def foo(params)
23
+ res = @conn.post('/foo', JSON.dump(params))
24
+ res.status
25
+ end
21
26
  end
22
27
 
23
28
  # Example API client test
@@ -109,6 +114,27 @@ class ClientTest < Test::Unit::TestCase
109
114
  stubs.verify_stubbed_calls
110
115
  end
111
116
 
117
+ def test_with_string_body
118
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
119
+ stub.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
120
+ end
121
+ cli = client(stubs)
122
+ assert_equal 200, cli.foo(name: 'YK')
123
+
124
+ stubs.verify_stubbed_calls
125
+ end
126
+
127
+ def test_with_proc_body
128
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
129
+ check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
130
+ stub.post('/foo', check) { [200, {}, ''] }
131
+ end
132
+ cli = client(stubs)
133
+ assert_equal 200, cli.foo(name: 'YK', created_at: Time.now)
134
+
135
+ stubs.verify_stubbed_calls
136
+ end
137
+
112
138
  def client(stubs)
113
139
  conn = Faraday.new do |builder|
114
140
  builder.adapter :test, stubs
@@ -26,6 +26,15 @@ module Faraday
26
26
  # ]
27
27
  # end
28
28
  #
29
+ # # Test the request body is the same as the stubbed body
30
+ # stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] }
31
+ #
32
+ # # You can pass a proc as a stubbed body and check the request body in your way.
33
+ # # In this case, the proc should return true or false.
34
+ # stub.post('/foo', ->(request_body) do
35
+ # JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, '']
36
+ # end
37
+ #
29
38
  # # You can set strict_mode to exactly match the stubbed requests.
30
39
  # stub.strict_mode = true
31
40
  # end
@@ -42,6 +51,12 @@ module Faraday
42
51
  #
43
52
  # resp = test.get '/items/2'
44
53
  # resp.body # => 'showing item: 2'
54
+ #
55
+ # resp = test.post '/bar', 'name=YK&word=call'
56
+ # resp.status # => 200
57
+ #
58
+ # resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now)
59
+ # resp.status # => 200
45
60
  class Test < Faraday::Adapter
46
61
  attr_accessor :stubs
47
62
 
@@ -181,7 +196,7 @@ module Faraday
181
196
  [(host.nil? || host == request_host) &&
182
197
  path_match?(request_path, meta) &&
183
198
  params_match?(env) &&
184
- (body.to_s.size.zero? || request_body == body) &&
199
+ body_match?(request_body) &&
185
200
  headers_match?(request_headers), meta]
186
201
  end
187
202
 
@@ -222,6 +237,17 @@ module Faraday
222
237
  end
223
238
  end
224
239
 
240
+ def body_match?(request_body)
241
+ return true if body.to_s.size.zero?
242
+
243
+ case body
244
+ when Proc
245
+ body.call(request_body)
246
+ else
247
+ request_body == body
248
+ end
249
+ end
250
+
225
251
  def to_s
226
252
  "#{path} #{body}"
227
253
  end
@@ -246,7 +272,7 @@ module Faraday
246
272
  stub, meta = stubs.match(env)
247
273
 
248
274
  unless stub
249
- raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
275
+ raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
250
276
  "#{env[:url]} #{env[:body]}"
251
277
  end
252
278
 
@@ -257,7 +283,11 @@ module Faraday
257
283
  else
258
284
  stub.block.call(env, meta)
259
285
  end
260
- save_response(env, status, body, headers)
286
+
287
+ # We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
288
+ # See https://github.com/lostisland/faraday/issues/1444
289
+ # TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version
290
+ save_response(env, status, body, headers, nil)
261
291
 
262
292
  @app.call(env)
263
293
  end
@@ -59,7 +59,7 @@ module Faraday
59
59
 
60
60
  private
61
61
 
62
- def save_response(env, status, body, headers = nil, reason_phrase = nil)
62
+ def save_response(env, status, body, headers = nil, reason_phrase = nil, finished: true)
63
63
  env.status = status
64
64
  env.body = body
65
65
  env.reason_phrase = reason_phrase&.to_s&.strip
@@ -68,7 +68,7 @@ module Faraday
68
68
  yield(response_headers) if block_given?
69
69
  end
70
70
 
71
- env.response.finish(env) unless env.parallel?
71
+ env.response.finish(env) unless env.parallel? || !finished
72
72
  env.response
73
73
  end
74
74
 
@@ -130,10 +130,10 @@ module Faraday
130
130
  # Makes a GET HTTP request without a body.
131
131
  # @!scope class
132
132
  #
133
- # @param url [String] The optional String base URL to use as a prefix for
133
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
134
134
  # all requests. Can also be the options Hash.
135
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
136
- # @param headers [Hash] unencoded HTTP header key/value pairs.
135
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
136
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
137
137
  #
138
138
  # @example
139
139
  # conn.get '/items', { page: 1 }, :accept => 'application/json'
@@ -152,10 +152,10 @@ module Faraday
152
152
  # Makes a HEAD HTTP request without a body.
153
153
  # @!scope class
154
154
  #
155
- # @param url [String] The optional String base URL to use as a prefix for
155
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
156
156
  # all requests. Can also be the options Hash.
157
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
158
- # @param headers [Hash] unencoded HTTP header key/value pairs.
157
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
158
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
159
159
  #
160
160
  # @example
161
161
  # conn.head '/items/1'
@@ -167,10 +167,10 @@ module Faraday
167
167
  # Makes a DELETE HTTP request without a body.
168
168
  # @!scope class
169
169
  #
170
- # @param url [String] The optional String base URL to use as a prefix for
170
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
171
171
  # all requests. Can also be the options Hash.
172
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
173
- # @param headers [Hash] unencoded HTTP header key/value pairs.
172
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
173
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
174
174
  #
175
175
  # @example
176
176
  # conn.delete '/items/1'
@@ -182,10 +182,10 @@ module Faraday
182
182
  # Makes a TRACE HTTP request without a body.
183
183
  # @!scope class
184
184
  #
185
- # @param url [String] The optional String base URL to use as a prefix for
185
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
186
186
  # all requests. Can also be the options Hash.
187
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
188
- # @param headers [Hash] unencoded HTTP header key/value pairs.
187
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
188
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
189
189
  #
190
190
  # @example
191
191
  # conn.connect '/items/1'
@@ -210,9 +210,9 @@ module Faraday
210
210
  #
211
211
  # @overload options(url, params = nil, headers = nil)
212
212
  # Makes an OPTIONS HTTP request to the given URL.
213
- # @param url [String] String base URL to sue as a prefix for all requests.
214
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
215
- # @param headers [Hash] unencoded HTTP header key/value pairs.
213
+ # @param url [String, URI, nil] String base URL to sue as a prefix for all requests.
214
+ # @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
215
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
216
216
  #
217
217
  # @example
218
218
  # conn.options '/items/1'
@@ -233,10 +233,10 @@ module Faraday
233
233
  # Makes a POST HTTP request with a body.
234
234
  # @!scope class
235
235
  #
236
- # @param url [String] The optional String base URL to use as a prefix for
236
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
237
237
  # all requests. Can also be the options Hash.
238
- # @param body [String] body for the request.
239
- # @param headers [Hash] unencoded HTTP header key/value pairs.
238
+ # @param body [String, nil] body for the request.
239
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
240
240
  #
241
241
  # @example
242
242
  # conn.post '/items', data, content_type: 'application/json'
@@ -255,10 +255,10 @@ module Faraday
255
255
  # Makes a PUT HTTP request with a body.
256
256
  # @!scope class
257
257
  #
258
- # @param url [String] The optional String base URL to use as a prefix for
258
+ # @param url [String, URI, nil] The optional String base URL to use as a prefix for
259
259
  # all requests. Can also be the options Hash.
260
- # @param body [String] body for the request.
261
- # @param headers [Hash] unencoded HTTP header key/value pairs.
260
+ # @param body [String, nil] body for the request.
261
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
262
262
  #
263
263
  # @example
264
264
  # # TODO: Make it a PUT example
@@ -390,7 +390,7 @@ module Faraday
390
390
  # Takes a relative url for a request and combines it with the defaults
391
391
  # set on the connection instance.
392
392
  #
393
- # @param url [String]
393
+ # @param url [String, URI, nil]
394
394
  # @param extra_params [Hash]
395
395
  #
396
396
  # @example
@@ -423,10 +423,10 @@ module Faraday
423
423
  # Builds and runs the Faraday::Request.
424
424
  #
425
425
  # @param method [Symbol] HTTP method.
426
- # @param url [String, URI] String or URI to access.
427
- # @param body [Object] The request body that will eventually be converted to
426
+ # @param url [String, URI, nil] String or URI to access.
427
+ # @param body [String, nil] The request body that will eventually be converted to
428
428
  # a string.
429
- # @param headers [Hash] unencoded HTTP header key/value pairs.
429
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
430
430
  #
431
431
  # @return [Faraday::Response]
432
432
  def run_request(method, url, body, headers)
@@ -462,7 +462,7 @@ module Faraday
462
462
 
463
463
  # Build an absolute URL based on url_prefix.
464
464
  #
465
- # @param url [String, URI]
465
+ # @param url [String, URI, nil]
466
466
  # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
467
467
  # replace the query values
468
468
  # of the resulting url (default: nil).
@@ -537,7 +537,7 @@ module Faraday
537
537
  end
538
538
 
539
539
  def find_default_proxy
540
- uri = ENV['http_proxy']
540
+ uri = ENV.fetch('http_proxy', nil)
541
541
  return unless uri && !uri.empty?
542
542
 
543
543
  uri = "http://#{uri}" unless uri.match?(/^http/i)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp'
3
+ require 'pp' # rubocop:disable Lint/RedundantRequireStatement
4
4
 
5
5
  module Faraday
6
6
  module Logging
@@ -8,7 +8,7 @@ module Faraday
8
8
  class Formatter
9
9
  extend Forwardable
10
10
 
11
- DEFAULT_OPTIONS = { headers: true, bodies: false,
11
+ DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false,
12
12
  log_level: :info }.freeze
13
13
 
14
14
  def initialize(logger:, options:)
@@ -37,6 +37,18 @@ module Faraday
37
37
  log_body('response', env[:body]) if env[:body] && log_body?(:response)
38
38
  end
39
39
 
40
+ def error(error)
41
+ return unless log_errors?
42
+
43
+ error_log = proc { error.full_message }
44
+ public_send(log_level, 'error', &error_log)
45
+
46
+ log_headers('error', error.response_headers) if error.respond_to?(:response_headers) && log_headers?(:error)
47
+ return unless error.respond_to?(:response_body) && error.response_body && log_body?(:error)
48
+
49
+ log_body('error', error.response_body)
50
+ end
51
+
40
52
  def filter(filter_word, filter_replacement)
41
53
  @filter.push([filter_word, filter_replacement])
42
54
  end
@@ -77,6 +89,10 @@ module Faraday
77
89
  end
78
90
  end
79
91
 
92
+ def log_errors?
93
+ @options[:errors]
94
+ end
95
+
80
96
  def apply_filters(output)
81
97
  @filter.each do |pattern, replacement|
82
98
  output = output.to_s.gsub(pattern, replacement)
@@ -17,6 +17,9 @@ module Faraday
17
17
  app.call(env).on_complete do |environment|
18
18
  on_complete(environment) if respond_to?(:on_complete)
19
19
  end
20
+ rescue StandardError => e
21
+ on_error(e) if respond_to?(:on_error)
22
+ raise
20
23
  end
21
24
 
22
25
  def close
@@ -157,6 +157,24 @@ module Faraday
157
157
  %(#<#{self.class}#{attrs.join(' ')}>)
158
158
  end
159
159
 
160
+ def stream_response?
161
+ request.stream_response?
162
+ end
163
+
164
+ def stream_response(&block)
165
+ size = 0
166
+ yielded = false
167
+ block_result = block.call do |chunk| # rubocop:disable Performance/RedundantBlockCall
168
+ if chunk.bytesize.positive? || size.positive?
169
+ yielded = true
170
+ size += chunk.bytesize
171
+ request.on_data.call(chunk, size, self)
172
+ end
173
+ end
174
+ request.on_data.call(+'', 0, self) unless yielded
175
+ block_result
176
+ end
177
+
160
178
  # @private
161
179
  def custom_members
162
180
  @custom_members ||= {}
@@ -6,6 +6,10 @@ module Faraday
6
6
  # @!attribute verify
7
7
  # @return [Boolean] whether to verify SSL certificates or not
8
8
  #
9
+ # @!attribute verify_hostname
10
+ # @return [Boolean] whether to enable hostname verification on server certificates
11
+ # during the handshake or not (see https://github.com/ruby/openssl/pull/60)
12
+ #
9
13
  # @!attribute ca_file
10
14
  # @return [String] CA file
11
15
  #
@@ -41,7 +45,8 @@ module Faraday
41
45
  #
42
46
  # @!attribute max_version
43
47
  # @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)
44
- class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
48
+ class SSLOptions < Options.new(:verify, :verify_hostname,
49
+ :ca_file, :ca_path, :verify_mode,
45
50
  :cert_store, :client_cert, :client_key,
46
51
  :certificate, :private_key, :verify_depth,
47
52
  :version, :min_version, :max_version)
@@ -55,5 +60,10 @@ module Faraday
55
60
  def disable?
56
61
  !verify?
57
62
  end
63
+
64
+ # @return [Boolean] true if should verify_hostname
65
+ def verify_hostname?
66
+ verify_hostname != false
67
+ end
58
68
  end
59
69
  end
@@ -23,22 +23,27 @@ module Faraday
23
23
  def on_request(env)
24
24
  return if env.request_headers[KEY]
25
25
 
26
- env.request_headers[KEY] = header_from(@type, *@params)
26
+ env.request_headers[KEY] = header_from(@type, env, *@params)
27
27
  end
28
28
 
29
29
  private
30
30
 
31
31
  # @param type [String, Symbol]
32
+ # @param env [Faraday::Env]
32
33
  # @param params [Array]
33
34
  # @return [String] a header value
34
- def header_from(type, *params)
35
+ def header_from(type, env, *params)
35
36
  if type.to_s.casecmp('basic').zero? && params.size == 2
36
37
  Utils.basic_header_from(*params)
37
38
  elsif params.size != 1
38
39
  raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
39
40
  else
40
41
  value = params.first
41
- value = value.call if value.is_a?(Proc) || value.respond_to?(:call)
42
+ if (value.is_a?(Proc) && value.arity == 1) || (value.respond_to?(:call) && value.method(:call).arity == 1)
43
+ value = value.call(env)
44
+ elsif value.is_a?(Proc) || value.respond_to?(:call)
45
+ value = value.call
46
+ end
42
47
  "#{type} #{value}"
43
48
  end
44
49
  end
@@ -21,7 +21,7 @@ module Faraday
21
21
  # @!attribute headers
22
22
  # @return [Faraday::Utils::Headers] headers
23
23
  # @!attribute body
24
- # @return [Hash] body
24
+ # @return [String] body
25
25
  # @!attribute options
26
26
  # @return [RequestOptions] options
27
27
  #
@@ -26,6 +26,10 @@ module Faraday
26
26
  def on_complete(env)
27
27
  @formatter.response(env)
28
28
  end
29
+
30
+ def on_error(error)
31
+ @formatter.error(error) if @formatter.respond_to?(:error)
32
+ end
29
33
  end
30
34
  end
31
35
  end
@@ -132,7 +132,12 @@ module Faraday
132
132
 
133
133
  # Join multiple values with a comma.
134
134
  def add_parsed(key, value)
135
- self[key] ? self[key] << ', ' << value : self[key] = value
135
+ if key?(key)
136
+ self[key] = self[key].to_s
137
+ self[key] << ', ' << value
138
+ else
139
+ self[key] = value
140
+ end
136
141
  end
137
142
  end
138
143
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.3.0'
4
+ VERSION = '2.7.1'
5
5
  end
@@ -373,5 +373,41 @@ RSpec.describe Faraday::Adapter::Test do
373
373
  it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent' }
374
374
  it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' }
375
375
  end
376
+
377
+ describe 'body_match?' do
378
+ let(:stubs) do
379
+ described_class::Stubs.new do |stubs|
380
+ stubs.post('/no_check') { [200, {}, 'ok'] }
381
+ stubs.post('/with_string', 'abc') { [200, {}, 'ok'] }
382
+ stubs.post(
383
+ '/with_proc',
384
+ ->(request_body) { JSON.parse(request_body, symbolize_names: true) == { x: '!', a: [{ m: [{ a: true }], n: 123 }] } },
385
+ { content_type: 'application/json' }
386
+ ) do
387
+ [200, {}, 'ok']
388
+ end
389
+ end
390
+ end
391
+
392
+ context 'when trying without any args for body' do
393
+ subject(:without_body) { connection.post('/no_check') }
394
+
395
+ it { expect(without_body.status).to eq 200 }
396
+ end
397
+
398
+ context 'when trying with string body stubs' do
399
+ subject(:with_string) { connection.post('/with_string', 'abc') }
400
+
401
+ it { expect(with_string.status).to eq 200 }
402
+ end
403
+
404
+ context 'when trying with proc body stubs' do
405
+ subject(:with_proc) do
406
+ connection.post('/with_proc', JSON.dump(a: [{ n: 123, m: [{ a: true }] }], x: '!'), { 'Content-Type' => 'application/json' })
407
+ end
408
+
409
+ it { expect(with_proc.status).to eq 200 }
410
+ end
411
+ end
376
412
  end
377
413
  end
@@ -6,7 +6,7 @@ class CustomEncoder
6
6
  end
7
7
 
8
8
  def decode(params)
9
- params.split(',').map { |pair| pair.split('-') }.to_h
9
+ params.split(',').to_h { |pair| pair.split('-') }
10
10
  end
11
11
  end
12
12
 
@@ -131,6 +131,12 @@ RSpec.describe Faraday::Connection do
131
131
  it { expect(subject.ssl.verify?).to be_falsey }
132
132
  end
133
133
 
134
+ context 'with verify_hostname false' do
135
+ let(:options) { { ssl: { verify_hostname: false } } }
136
+
137
+ it { expect(subject.ssl.verify_hostname?).to be_falsey }
138
+ end
139
+
134
140
  context 'with empty block' do
135
141
  let(:conn) { Faraday::Connection.new {} }
136
142
 
@@ -505,7 +511,7 @@ RSpec.describe Faraday::Connection do
505
511
  it 'uses env http_proxy' do
506
512
  with_env 'http_proxy' => 'http://proxy.com' do
507
513
  conn = Faraday.new
508
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
514
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
509
515
  expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com')
510
516
  end
511
517
  end
@@ -513,7 +519,7 @@ RSpec.describe Faraday::Connection do
513
519
  it 'uses processes no_proxy before http_proxy' do
514
520
  with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do
515
521
  conn = Faraday.new
516
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
522
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
517
523
  expect(conn.proxy_for_request('http://google.co.uk')).to be_nil
518
524
  end
519
525
  end
@@ -521,7 +527,7 @@ RSpec.describe Faraday::Connection do
521
527
  it 'uses env https_proxy' do
522
528
  with_env 'https_proxy' => 'https://proxy.com' do
523
529
  conn = Faraday.new
524
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
530
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
525
531
  expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com')
526
532
  end
527
533
  end
@@ -529,7 +535,7 @@ RSpec.describe Faraday::Connection do
529
535
  it 'uses processes no_proxy before https_proxy' do
530
536
  with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
531
537
  conn = Faraday.new
532
- expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
538
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
533
539
  expect(conn.proxy_for_request('https://google.co.uk')).to be_nil
534
540
  end
535
541
  end
@@ -539,7 +545,7 @@ RSpec.describe Faraday::Connection do
539
545
  conn = Faraday.new
540
546
  conn.proxy = 'http://proxy2.com'
541
547
 
542
- expect(conn.instance_variable_get('@manual_proxy')).to be_truthy
548
+ expect(conn.instance_variable_get(:@manual_proxy)).to be_truthy
543
549
  expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com')
544
550
  end
545
551
  end
@@ -574,7 +580,7 @@ RSpec.describe Faraday::Connection do
574
580
  end
575
581
 
576
582
  conn.get(url)
577
- expect(conn.instance_variable_get('@temp_proxy')).to be_nil
583
+ expect(conn.instance_variable_get(:@temp_proxy)).to be_nil
578
584
  end
579
585
 
580
586
  it 'dynamically check no proxy' do
@@ -33,6 +33,24 @@ RSpec.describe Faraday::Middleware do
33
33
  end
34
34
  end
35
35
 
36
+ describe '#on_error' do
37
+ subject do
38
+ Class.new(described_class) do
39
+ def on_error(error)
40
+ # do nothing
41
+ end
42
+ end.new(app)
43
+ end
44
+
45
+ it 'is called by #call' do
46
+ expect(app).to receive(:call).and_raise(Faraday::ConnectionFailed)
47
+ is_expected.to receive(:call).and_call_original
48
+ is_expected.to receive(:on_error)
49
+
50
+ expect { subject.call(double) }.to raise_error(Faraday::ConnectionFailed)
51
+ end
52
+ end
53
+
36
54
  describe '#close' do
37
55
  context "with app that doesn't support \#close" do
38
56
  it 'should issue warning' do
@@ -27,6 +27,12 @@ RSpec.describe Faraday::Env do
27
27
  expect(ssl.fetch(:verify, true)).to be_falsey
28
28
  end
29
29
 
30
+ it 'handle verify_hostname when fetching' do
31
+ ssl = Faraday::SSLOptions.new
32
+ ssl.verify_hostname = true
33
+ expect(ssl.fetch(:verify_hostname, false)).to be_truthy
34
+ end
35
+
30
36
  it 'retains custom members' do
31
37
  env[:foo] = 'custom 1'
32
38
  env[:bar] = :custom2
@@ -72,6 +72,41 @@ RSpec.describe Faraday::Request::Authorization do
72
72
  include_examples 'does not interfere with existing authentication'
73
73
  end
74
74
 
75
+ context 'with an argument' do
76
+ let(:response) { conn.get('/auth-echo', nil, 'middle' => 'crunchy surprise') }
77
+
78
+ context 'when passed a proc' do
79
+ let(:auth_config) { [proc { |env| "proc #{env.request_headers['middle']}" }] }
80
+
81
+ it { expect(response.body).to eq('Bearer proc crunchy surprise') }
82
+
83
+ include_examples 'does not interfere with existing authentication'
84
+ end
85
+
86
+ context 'when passed a lambda' do
87
+ let(:auth_config) { [->(env) { "lambda #{env.request_headers['middle']}" }] }
88
+
89
+ it { expect(response.body).to eq('Bearer lambda crunchy surprise') }
90
+
91
+ include_examples 'does not interfere with existing authentication'
92
+ end
93
+
94
+ context 'when passed a callable with an argument' do
95
+ let(:callable) do
96
+ Class.new do
97
+ def call(env)
98
+ "callable #{env.request_headers['middle']}"
99
+ end
100
+ end.new
101
+ end
102
+ let(:auth_config) { [callable] }
103
+
104
+ it { expect(response.body).to eq('Bearer callable crunchy surprise') }
105
+
106
+ include_examples 'does not interfere with existing authentication'
107
+ end
108
+ end
109
+
75
110
  context 'when passed too many arguments' do
76
111
  let(:auth_config) { %w[baz foo] }
77
112
 
@@ -14,6 +14,7 @@ RSpec.describe Faraday::Request do
14
14
  context 'when nothing particular is configured' do
15
15
  it { expect(subject.http_method).to eq(:get) }
16
16
  it { expect(subject.to_env(conn).ssl.verify).to be_falsey }
17
+ it { expect(subject.to_env(conn).ssl.verify_hostname).to be_falsey }
17
18
  end
18
19
 
19
20
  context 'when HTTP method is post' do
@@ -64,6 +64,15 @@ RSpec.describe Faraday::Response::Logger do
64
64
  expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
65
65
  conn.get '/hello'
66
66
  end
67
+
68
+ context 'when no route' do
69
+ it 'delegates logging to the formatter' do
70
+ expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
71
+ expect(formatter).to receive(:error).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
72
+
73
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
74
+ end
75
+ end
67
76
  end
68
77
 
69
78
  context 'with custom formatter' do
@@ -94,6 +103,16 @@ RSpec.describe Faraday::Response::Logger do
94
103
  expect(string_io.string).to match('GET http:/hello')
95
104
  end
96
105
 
106
+ it 'logs status' do
107
+ conn.get '/hello', nil, accept: 'text/html'
108
+ expect(string_io.string).to match('Status 200')
109
+ end
110
+
111
+ it 'does not log error message by default' do
112
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
113
+ expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
114
+ end
115
+
97
116
  it 'logs request headers by default' do
98
117
  conn.get '/hello', nil, accept: 'text/html'
99
118
  expect(string_io.string).to match(%(Accept: "text/html))
@@ -188,6 +207,15 @@ RSpec.describe Faraday::Response::Logger do
188
207
  end
189
208
  end
190
209
 
210
+ context 'when logging errors' do
211
+ let(:logger_options) { { errors: true } }
212
+
213
+ it 'logs error message' do
214
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
215
+ expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
216
+ end
217
+ end
218
+
191
219
  context 'when using log_level' do
192
220
  let(:logger_options) { { bodies: true, log_level: :debug } }
193
221
 
@@ -57,11 +57,11 @@ RSpec.describe Faraday::Utils::Headers do
57
57
  end
58
58
 
59
59
  describe '#parse' do
60
- before { subject.parse(headers) }
61
-
62
60
  context 'when response headers leave http status line out' do
63
61
  let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" }
64
62
 
63
+ before { subject.parse(headers) }
64
+
65
65
  it { expect(subject.keys).to eq(%w[Content-Type]) }
66
66
  it { expect(subject['Content-Type']).to eq('text/html') }
67
67
  it { expect(subject['content-type']).to eq('text/html') }
@@ -70,13 +70,31 @@ RSpec.describe Faraday::Utils::Headers do
70
70
  context 'when response headers values include a colon' do
71
71
  let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" }
72
72
 
73
+ before { subject.parse(headers) }
74
+
73
75
  it { expect(subject['location']).to eq('http://httpbingo.org/') }
74
76
  end
75
77
 
76
78
  context 'when response headers include a blank line' do
77
79
  let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" }
78
80
 
81
+ before { subject.parse(headers) }
82
+
79
83
  it { expect(subject['content-type']).to eq('text/html') }
80
84
  end
85
+
86
+ context 'when response headers include already stored keys' do
87
+ let(:headers) { "HTTP/1.1 200 OK\r\nX-Numbers: 123\r\n\r\n" }
88
+
89
+ before do
90
+ h = subject
91
+ h[:x_numbers] = 8
92
+ h.parse(headers)
93
+ end
94
+
95
+ it do
96
+ expect(subject[:x_numbers]).to eq('8, 123')
97
+ end
98
+ end
81
99
  end
82
100
  end
@@ -102,7 +102,8 @@ RSpec.describe Faraday::Utils do
102
102
  verify_depth: nil,
103
103
  version: '2',
104
104
  min_version: nil,
105
- max_version: nil
105
+ max_version: nil,
106
+ verify_hostname: nil
106
107
  }
107
108
  end
108
109
 
@@ -37,7 +37,8 @@ shared_examples 'adapter examples' do |**options|
37
37
 
38
38
  let(:conn) do
39
39
  conn_options[:ssl] ||= {}
40
- conn_options[:ssl][:ca_file] ||= ENV['SSL_FILE']
40
+ conn_options[:ssl][:ca_file] ||= ENV.fetch('SSL_FILE', nil)
41
+ conn_options[:ssl][:verify_hostname] ||= ENV['SSL_VERIFY_HOSTNAME'] == 'yes'
41
42
 
42
43
  Faraday.new(remote, conn_options) do |conn|
43
44
  conn.request :url_encoded
@@ -153,12 +153,19 @@ shared_examples 'a request method' do |http_method|
153
153
  let(:streamed) { [] }
154
154
 
155
155
  context 'when response is empty' do
156
- it do
156
+ it 'handles streaming' do
157
+ env = nil
157
158
  conn.public_send(http_method, '/') do |req|
158
- req.options.on_data = proc { |*args| streamed << args }
159
+ req.options.on_data = proc do |chunk, size, block_env|
160
+ streamed << [chunk, size]
161
+ env ||= block_env
162
+ end
159
163
  end
160
164
 
161
165
  expect(streamed).to eq([['', 0]])
166
+ # TODO: enable this after updating all existing adapters to the new streaming API
167
+ # expect(env).to be_a(Faraday::Env)
168
+ # expect(env.status).to eq(200)
162
169
  end
163
170
  end
164
171
 
@@ -166,12 +173,19 @@ shared_examples 'a request method' do |http_method|
166
173
  before { request_stub.to_return(body: big_string) }
167
174
 
168
175
  it 'handles streaming' do
176
+ env = nil
169
177
  response = conn.public_send(http_method, '/') do |req|
170
- req.options.on_data = proc { |*args| streamed << args }
178
+ req.options.on_data = proc do |chunk, size, block_env|
179
+ streamed << [chunk, size]
180
+ env ||= block_env
181
+ end
171
182
  end
172
183
 
173
184
  expect(response.body).to eq('')
174
185
  check_streaming_response(streamed, chunk_size: 16 * 1024)
186
+ # TODO: enable this after updating all existing adapters to the new streaming API
187
+ # expect(env).to be_a(Faraday::Env)
188
+ # expect(env.status).to eq(200)
175
189
  end
176
190
  end
177
191
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,22 +10,28 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-05-06 00:00:00.000000000 Z
13
+ date: 2022-11-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday-net_http
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.0'
22
+ - - "<"
23
+ - !ruby/object:Gem::Version
24
+ version: '3.1'
22
25
  type: :runtime
23
26
  prerelease: false
24
27
  version_requirements: !ruby/object:Gem::Requirement
25
28
  requirements:
26
- - - "~>"
29
+ - - ">="
27
30
  - !ruby/object:Gem::Version
28
31
  version: '2.0'
32
+ - - "<"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.1'
29
35
  - !ruby/object:Gem::Dependency
30
36
  name: ruby2_keywords
31
37
  requirement: !ruby/object:Gem::Requirement
@@ -125,7 +131,7 @@ licenses:
125
131
  - MIT
126
132
  metadata:
127
133
  homepage_uri: https://lostisland.github.io/faraday
128
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.3.0
134
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.1
129
135
  source_code_uri: https://github.com/lostisland/faraday
130
136
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
131
137
  post_install_message: