faraday 2.14.1 → 2.14.3

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: 8d5ef64533c80aaabadd55b5ea342b102fd652f5918039c7deff3b26c4ad4a67
4
- data.tar.gz: 81ebbac6eb08b7f85ee7d8673e3274bbe110c0a865604a3df7294814ba469eb8
3
+ metadata.gz: ecc5e9592d7434d7e39bc5cc827be5b62af99e258582468c8b6fd78e0122bf7e
4
+ data.tar.gz: 4f5728ac524a3456a800c8d0159b4569173b1c841f80fae7d0d2704e261b6588
5
5
  SHA512:
6
- metadata.gz: 50080c6a64a9c7b0775da8c3d63ece38a3e0946f36500665ee9be6fc547fc1a5313897ffe87fb1f08f802b6a69b8b11f46fb3a2a751ba8c00aab6910cebadbb4
7
- data.tar.gz: '093b793d6b3f0ca6951a4c71ffd1f4b2603a1ea7d6efce304b165ae8124dd7cb64f7aa46b455a0ee5c9ba8e0f91ec931484dcdd7d2082dbae64448ee7aa6b2d7'
6
+ metadata.gz: 12567175cd7d08a95ccf8203bffcb9bebf8d1b52f279ce034c3f3e17dc5efc81e08259c2992ff792560ed626dd59ae305c163cb43018860b3c0ae833c3f68855
7
+ data.tar.gz: bb786c688b4629c6bc43e4715715fcd42de120eee3802a3614eca60e17627ff77f40298af500a431158b1f1de8bd0d0bd58817a8793bab92e11bac9aa9b482f2
@@ -26,7 +26,7 @@ class Client
26
26
  end
27
27
 
28
28
  # Example API client test
29
- class ClientTest < Test::Unit::TestCase
29
+ class ClientTest < Test::Unit::TestCase # rubocop:disable Style/OneClassPerFile
30
30
  def test_httpbingo_name
31
31
  stubs = Faraday::Adapter::Test::Stubs.new
32
32
  stubs.get('/api') do |env|
@@ -127,6 +127,14 @@ module Faraday
127
127
  new_stub(:options, path, headers, &block)
128
128
  end
129
129
 
130
+ # Removes all stubs, including the ones that have already been consumed.
131
+ def clear
132
+ @stubs_mutex.synchronize do
133
+ @stack.clear
134
+ @consumed.clear
135
+ end
136
+ end
137
+
130
138
  # Raises an error if any of the stubbed calls have not been made.
131
139
  def verify_stubbed_calls
132
140
  failed_stubs = []
@@ -8,6 +8,12 @@ module Faraday
8
8
 
9
9
  CONTENT_LENGTH = 'Content-Length'
10
10
 
11
+ TIMEOUT_KEYS = {
12
+ read: :read_timeout,
13
+ open: :open_timeout,
14
+ write: :write_timeout
15
+ }.freeze
16
+
11
17
  # This module marks an Adapter as supporting parallel requests.
12
18
  module Parallelism
13
19
  attr_writer :supports_parallel
@@ -23,6 +29,7 @@ module Faraday
23
29
  end
24
30
 
25
31
  extend Parallelism
32
+
26
33
  self.supports_parallel = false
27
34
 
28
35
  def initialize(_app = nil, opts = {}, &block)
@@ -89,12 +96,6 @@ module Faraday
89
96
  end
90
97
  options[key] || options[:timeout]
91
98
  end
92
-
93
- TIMEOUT_KEYS = {
94
- read: :read_timeout,
95
- open: :open_timeout,
96
- write: :write_timeout
97
- }.freeze
98
99
  end
99
100
  end
100
101
 
@@ -481,9 +481,11 @@ module Faraday
481
481
  if url && !base.path.end_with?('/')
482
482
  base.path = "#{base.path}/" # ensure trailing slash
483
483
  end
484
+ url = url.to_s if url.respond_to?(:host)
484
485
  # Ensure relative url will be parsed correctly (such as `service:search` or `//evil.com`)
485
486
  url = "./#{url}" if url.respond_to?(:start_with?) &&
486
- (!url.start_with?('http://', 'https://', '/', './', '../') || url.start_with?('//'))
487
+ (url.start_with?('//') ||
488
+ !url.start_with?('http://', 'https://', '/', './', '../'))
487
489
  uri = url ? base + url : base
488
490
  if params
489
491
  uri.query = params.to_query(params_encoder || options.params_encoder)
@@ -6,6 +6,7 @@ module Faraday
6
6
  module FlatParamsEncoder
7
7
  class << self
8
8
  extend Forwardable
9
+
9
10
  def_delegators :'Faraday::Utils', :escape, :unescape
10
11
  end
11
12
 
@@ -106,6 +106,8 @@ module Faraday
106
106
 
107
107
  def decode_pair(key, value, context)
108
108
  subkeys = key.scan(SUBKEYS_REGEX)
109
+ validate_params_depth!(subkeys.length)
110
+
109
111
  subkeys.each_with_index do |subkey, i|
110
112
  is_array = subkey =~ /[\[\]]+\Z/
111
113
  subkey = Regexp.last_match.pre_match if is_array
@@ -145,6 +147,12 @@ module Faraday
145
147
  is_array ? context << value : context[subkey] = value
146
148
  end
147
149
 
150
+ def validate_params_depth!(depth)
151
+ return unless @param_depth_limit && depth > @param_depth_limit
152
+
153
+ raise Faraday::Error, "exceeded nested parameter depth limit of #{@param_depth_limit}"
154
+ end
155
+
148
156
  # Internal: convert a nested hash with purely numeric keys into an array.
149
157
  # FIXME: this is not compatible with Rack::Utils.parse_nested_query
150
158
  # @!visibility private
@@ -167,15 +175,17 @@ module Faraday
167
175
  # for your requests.
168
176
  module NestedParamsEncoder
169
177
  class << self
170
- attr_accessor :sort_params, :array_indices
178
+ attr_accessor :sort_params, :array_indices, :param_depth_limit
171
179
 
172
180
  extend Forwardable
181
+
173
182
  def_delegators :'Faraday::Utils', :escape, :unescape
174
183
  end
175
184
 
176
185
  # Useful default for OAuth and caching.
177
186
  @sort_params = true
178
187
  @array_indices = false
188
+ @param_depth_limit = 100
179
189
 
180
190
  extend EncodeMethods
181
191
  extend DecodeMethods
data/lib/faraday/error.rb CHANGED
@@ -172,7 +172,7 @@ module Faraday
172
172
  # A unified client error for timeouts.
173
173
  class TimeoutError < ServerError
174
174
  def initialize(exc = 'timeout', response = nil)
175
- super(exc, response)
175
+ super
176
176
  end
177
177
  end
178
178
 
@@ -65,7 +65,7 @@ module Faraday
65
65
  if app.respond_to?(:close)
66
66
  app.close
67
67
  else
68
- warn "#{app} does not implement \#close!"
68
+ warn "#{app} does not implement #close!"
69
69
  end
70
70
  end
71
71
  end
@@ -78,7 +78,7 @@ module Faraday
78
78
  # @param value [Object] a value fitting Option.from(v).
79
79
  # @return [Env] from given value
80
80
  def self.from(value)
81
- env = super(value)
81
+ env = super
82
82
  if value.respond_to?(:custom_members)
83
83
  env.custom_members.update(value.custom_members)
84
84
  end
@@ -90,7 +90,7 @@ module Faraday
90
90
  return self[current_body] if key == :body
91
91
 
92
92
  if in_member_set?(key)
93
- super(key)
93
+ super
94
94
  else
95
95
  custom_members[key]
96
96
  end
@@ -105,7 +105,7 @@ module Faraday
105
105
  end
106
106
 
107
107
  if in_member_set?(key)
108
- super(key, value)
108
+ super
109
109
  else
110
110
  custom_members[key] = value
111
111
  end
@@ -7,6 +7,7 @@ module Faraday
7
7
  # class ProxyOptions < Options; end
8
8
  ProxyOptions = Options.new(:uri, :user, :password) do
9
9
  extend Forwardable
10
+
10
11
  def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
11
12
  :path, :path=
12
13
 
@@ -29,7 +30,7 @@ module Faraday
29
30
  end
30
31
  end
31
32
 
32
- super(value)
33
+ super
33
34
  end
34
35
 
35
36
  memoized(:user) { uri&.user && Utils.unescape(uri.user) }
@@ -12,7 +12,7 @@ module Faraday
12
12
  if key && key.to_sym == :proxy
13
13
  super(key, value ? ProxyOptions.from(value) : nil)
14
14
  else
15
- super(key, value)
15
+ super
16
16
  end
17
17
  end
18
18
 
@@ -186,7 +186,7 @@ module Faraday
186
186
  def [](key)
187
187
  key = key.to_sym
188
188
  if (method = self.class.memoized_attributes[key])
189
- super(key) || (self[key] = instance_eval(&method))
189
+ super || (self[key] = instance_eval(&method))
190
190
  else
191
191
  super
192
192
  end
@@ -15,6 +15,11 @@ module Faraday
15
15
  # Used to detect missing arguments
16
16
  NO_ARGUMENT = Object.new
17
17
 
18
+ LOCK_ERR = "can't modify middleware stack after making a request"
19
+ MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
20
+ "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
21
+ 'For more info, check https://lostisland.github.io/faraday/usage/.'
22
+
18
23
  attr_accessor :handlers
19
24
 
20
25
  # Error raised when trying to modify the stack after calling `lock!`
@@ -211,11 +216,6 @@ module Faraday
211
216
 
212
217
  private
213
218
 
214
- LOCK_ERR = "can't modify middleware stack after making a request"
215
- MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
216
- "Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
217
- 'For more info, check https://lostisland.github.io/faraday/usage/.'
218
-
219
219
  def raise_if_locked
220
220
  raise StackLocked, LOCK_ERR if locked?
221
221
  end
@@ -51,7 +51,7 @@ module Faraday
51
51
 
52
52
  def [](key)
53
53
  key = KeyMap[key]
54
- super(key) || super(@names[key.downcase])
54
+ super || super(@names[key.downcase])
55
55
  end
56
56
 
57
57
  def []=(key, val)
@@ -59,13 +59,13 @@ module Faraday
59
59
  key = (@names[key.downcase] ||= key)
60
60
  # join multiple values with a comma
61
61
  val = val.to_ary.join(', ') if val.respond_to?(:to_ary)
62
- super(key, val)
62
+ super
63
63
  end
64
64
 
65
65
  def fetch(key, ...)
66
66
  key = KeyMap[key]
67
67
  key = @names.fetch(key.downcase, key)
68
- super(key, ...)
68
+ super
69
69
  end
70
70
 
71
71
  def delete(key)
@@ -74,13 +74,13 @@ module Faraday
74
74
  return unless key
75
75
 
76
76
  @names.delete key.downcase
77
- super(key)
77
+ super
78
78
  end
79
79
 
80
80
  def dig(key, *rest)
81
81
  key = KeyMap[key]
82
82
  key = @names.fetch(key.downcase, key)
83
- super(key, *rest)
83
+ super
84
84
  end
85
85
 
86
86
  def include?(key)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.14.1'
4
+ VERSION = '2.14.3'
5
5
  end
@@ -439,4 +439,22 @@ RSpec.describe Faraday::Adapter::Test do
439
439
  end
440
440
  end
441
441
  end
442
+
443
+ describe '#clear' do
444
+ it 'removes pending stubs' do
445
+ stubs.clear
446
+ expect { connection.get('/hello') }.to raise_error(described_class::Stubs::NotFound)
447
+ end
448
+
449
+ it 'removes already consumed stubs' do
450
+ expect(connection.get('/hello').body).to eq('hello')
451
+ stubs.clear
452
+ expect { connection.get('/hello') }.to raise_error(described_class::Stubs::NotFound)
453
+ end
454
+
455
+ it 'leaves the stubs empty' do
456
+ stubs.clear
457
+ expect(stubs).to be_empty
458
+ end
459
+ end
442
460
  end
@@ -318,6 +318,13 @@ RSpec.describe Faraday::Connection do
318
318
  expect(uri.host).to eq('httpbingo.org')
319
319
  end
320
320
 
321
+ it 'does not allow host override with URI("//evil.com/path")' do
322
+ conn.url_prefix = 'http://httpbingo.org/api'
323
+ uri = conn.build_exclusive_url(URI('//evil.com/path?token=1'))
324
+ expect(uri.host).to eq('httpbingo.org')
325
+ expect(uri.query).to eq('token=1')
326
+ end
327
+
321
328
  it 'does not allow host override with //evil.com:8080/path' do
322
329
  conn.url_prefix = 'http://httpbingo.org/api'
323
330
  uri = conn.build_exclusive_url('//evil.com:8080/path')
@@ -373,6 +380,18 @@ RSpec.describe Faraday::Connection do
373
380
  url = conn.build_url(nil, b: 2, c: 3)
374
381
  expect(url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=2&c=3')
375
382
  end
383
+
384
+ it 'raises a controlled error when URL query params exceed the nested depth limit' do
385
+ original_param_depth_limit = Faraday::NestedParamsEncoder.param_depth_limit
386
+ Faraday::NestedParamsEncoder.param_depth_limit = 2
387
+
388
+ expect { conn.build_url('/nigiri?a[b][c]=1') }.to raise_error(
389
+ Faraday::Error,
390
+ 'exceeded nested parameter depth limit of 2'
391
+ )
392
+ ensure
393
+ Faraday::NestedParamsEncoder.param_depth_limit = original_param_depth_limit
394
+ end
376
395
  end
377
396
 
378
397
  describe '#build_request' do
@@ -52,14 +52,14 @@ RSpec.describe Faraday::Middleware do
52
52
  end
53
53
 
54
54
  describe '#close' do
55
- context "with app that doesn't support \#close" do
55
+ context "with app that doesn't support #close" do
56
56
  it 'should issue warning' do
57
57
  is_expected.to receive(:warn)
58
58
  subject.close
59
59
  end
60
60
  end
61
61
 
62
- context "with app that supports \#close" do
62
+ context 'with app that supports #close' do
63
63
  it 'should issue warning' do
64
64
  expect(app).to receive(:close)
65
65
  is_expected.to_not receive(:warn)
@@ -5,6 +5,13 @@ require 'rack/utils'
5
5
  RSpec.describe Faraday::NestedParamsEncoder do
6
6
  it_behaves_like 'a params encoder'
7
7
 
8
+ around do |example|
9
+ original_param_depth_limit = described_class.param_depth_limit
10
+ example.run
11
+ ensure
12
+ described_class.param_depth_limit = original_param_depth_limit
13
+ end
14
+
8
15
  it 'decodes arrays' do
9
16
  query = 'a[1]=one&a[2]=two&a[3]=three'
10
17
  expected = { 'a' => %w[one two three] }
@@ -53,6 +60,27 @@ RSpec.describe Faraday::NestedParamsEncoder do
53
60
  expect(subject.decode(query)).to eq(expected)
54
61
  end
55
62
 
63
+ it 'allows nested params within the configured depth limit' do
64
+ described_class.param_depth_limit = 3
65
+
66
+ expect(subject.decode('a[b][c]=1')).to eq({ 'a' => { 'b' => { 'c' => '1' } } })
67
+ end
68
+
69
+ it 'raises a controlled error when nested params exceed the depth limit' do
70
+ described_class.param_depth_limit = 2
71
+
72
+ expect { subject.decode('a[b][c]=1') }.to raise_error(
73
+ Faraday::Error,
74
+ 'exceeded nested parameter depth limit of 2'
75
+ )
76
+ end
77
+
78
+ it 'allows disabling the nested params depth limit' do
79
+ described_class.param_depth_limit = nil
80
+
81
+ expect(subject.decode('a[b][c][d]=1')).to eq({ 'a' => { 'b' => { 'c' => { 'd' => '1' } } } })
82
+ end
83
+
56
84
  it 'decodes nested final value overrides any type' do
57
85
  query = 'a[b][c]=1&a[b]=2'
58
86
  expected = { 'a' => { 'b' => '2' } }
@@ -31,6 +31,15 @@ RSpec.describe Faraday::Request do
31
31
  it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
32
32
  end
33
33
 
34
+ context 'when setting the url on setup with a protocol-relative URI' do
35
+ let(:block) { proc { |req| req.url URI.parse('//evil.com/path?token=1') } }
36
+ let(:url) { subject.to_env(conn).url }
37
+
38
+ it { expect(url.host).to eq('httpbingo.org') }
39
+ it { expect(url.path).to eq('/api///evil.com/path') }
40
+ it { expect(url.query).to eq('token=1') }
41
+ end
42
+
34
43
  context 'when setting the url on setup with a string path and params' do
35
44
  let(:block) { proc { |req| req.url 'foo.json', 'a' => 1 } }
36
45
 
@@ -106,7 +106,7 @@ RSpec.describe Faraday::Response::Json, type: :response do
106
106
  end
107
107
 
108
108
  it 'passes relevant options to JSON parse' do
109
- expect(::JSON).to receive(:parse)
109
+ expect(JSON).to receive(:parse)
110
110
  .with(body, options[:parser_options])
111
111
  .and_return(result)
112
112
 
@@ -218,7 +218,7 @@ RSpec.describe Faraday::Response::Logger do
218
218
 
219
219
  it 'logs response body object' do
220
220
  conn.get '/rubbles', nil, accept: 'text/html'
221
- expect(string_io.string).to match(%([\"Barney\", \"Betty\", \"Bam Bam\"]\n))
221
+ expect(string_io.string).to match(%(["Barney", "Betty", "Bam Bam"]\n))
222
222
  end
223
223
 
224
224
  it 'logs filter body' do
@@ -33,7 +33,7 @@ RSpec.describe Faraday::Utils do
33
33
  end
34
34
 
35
35
  it 'parses with URI' do
36
- with_default_uri_parser(::URI) do
36
+ with_default_uri_parser(URI) do
37
37
  uri = normalize(url)
38
38
  expect(uri.host).to eq('example.com')
39
39
  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.14.1
4
+ version: 2.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -144,7 +144,7 @@ licenses:
144
144
  - MIT
145
145
  metadata:
146
146
  homepage_uri: https://lostisland.github.io/faraday
147
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.14.1
147
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.14.3
148
148
  source_code_uri: https://github.com/lostisland/faraday
149
149
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
150
150
  rubygems_mfa_required: 'true'