faraday 2.2.0 → 2.5.0

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: eaa5f5a3ea91b21a40ad7872a8eda558226e1d5f4d8f9875ecf9ece44e0181e4
4
- data.tar.gz: 51af319bffd649b4b828cfed91b2a419211b1c2b171a3016949388b1a749c1ac
3
+ metadata.gz: a991fd75b3b03d53636acde7819f2f2e4edd1ba9c43a2328083bfdc1a881e4b4
4
+ data.tar.gz: 7b30cf69876f689e09ae2128724a59f3e653d9e4a5963c5d77f4da2b4b200cac
5
5
  SHA512:
6
- metadata.gz: b68ff300b45dbe3a7f85ab40f7a23c86b2c373a1672841a96230179f415da3f3bcf2123251235c4399575826043f7221fe81615171fbfd3af4d33a21410f8670
7
- data.tar.gz: 41cd332afaf70ea6e306247b3f2ea9d9e38ed248e381aef798f914773b1dd7c7473ab9a6fcb5e03cb8e7163c0f81f26e813877bb5f7412964e55ddb9866ffe20
6
+ metadata.gz: f1f24cae3a79cc5db4d5ac1968d46904f32759b3a7dc00e4f920c648867631f53451c5ec30fbaf982d23c6a57b64169c966a35b7ffb3892df265ff626d67d870
7
+ data.tar.gz: d07ec4f994e8440b4f762ff0e6d058508d891bca0bddf63f6270cc367b7b23d24c965c1c585be9d27687ef79df26d7688b484204db2b1ae8f8e555f364e5da45
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  This file is not being updated anymore. Instead, please check the [Releases](https://github.com/lostisland/faraday/releases) page.
6
6
 
7
+ ## [2.2.0](https://github.com/lostisland/faraday/compare/v2.1.0...v2.2.0) (2022-02-03)
8
+
9
+ * Reintroduce the possibility to register middleware with symbols, strings or procs in [#1391](https://github.com/lostisland/faraday/pull/1391)
10
+
7
11
  ## [2.1.0](https://github.com/lostisland/faraday/compare/v2.0.1...v2.1.0) (2022-01-15)
8
12
 
9
13
  * Fix test adapter thread safety by @iMacTia in [#1380](https://github.com/lostisland/faraday/pull/1380)
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
@@ -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
 
@@ -62,11 +62,17 @@ module Faraday
62
62
  end
63
63
 
64
64
  def encode_array(parent, value)
65
- new_parent = "#{parent}%5B%5D"
66
- return new_parent if value.empty?
65
+ return "#{parent}%5B%5D" if value.empty?
67
66
 
68
67
  buffer = +''
69
- value.each { |val| buffer << "#{encode_pair(new_parent, val)}&" }
68
+ value.each_with_index do |val, index|
69
+ new_parent = if @array_indices
70
+ "#{parent}%5B#{index}%5D"
71
+ else
72
+ "#{parent}%5B%5D"
73
+ end
74
+ buffer << "#{encode_pair(new_parent, val)}&"
75
+ end
70
76
  buffer.chop
71
77
  end
72
78
  end
@@ -161,7 +167,7 @@ module Faraday
161
167
  # for your requests.
162
168
  module NestedParamsEncoder
163
169
  class << self
164
- attr_accessor :sort_params
170
+ attr_accessor :sort_params, :array_indices
165
171
 
166
172
  extend Forwardable
167
173
  def_delegators :'Faraday::Utils', :escape, :unescape
@@ -169,6 +175,7 @@ module Faraday
169
175
 
170
176
  # Useful default for OAuth and caching.
171
177
  @sort_params = true
178
+ @array_indices = false
172
179
 
173
180
  extend EncodeMethods
174
181
  extend DecodeMethods
@@ -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
@@ -31,7 +31,9 @@ module Faraday
31
31
  return unless process_request?(env)
32
32
 
33
33
  env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
34
- yield(env.body) unless env.body.respond_to?(:to_str)
34
+ return if env.body.respond_to?(:to_str) || env.body.respond_to?(:read)
35
+
36
+ yield(env.body)
35
37
  end
36
38
 
37
39
  # @param env [Faraday::Env]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.2.0'
4
+ VERSION = '2.5.0'
5
5
  end
data/lib/faraday.rb CHANGED
@@ -47,7 +47,7 @@ module Faraday
47
47
 
48
48
  # @overload default_adapter
49
49
  # Gets the Symbol key identifying a default Adapter to use
50
- # for the default {Faraday::Connection}. Defaults to `:test`.
50
+ # for the default {Faraday::Connection}. Defaults to `:net_http`.
51
51
  # @return [Symbol] the default adapter
52
52
  # @overload default_adapter=(adapter)
53
53
  # Updates default adapter while resetting {.default_connection}.
@@ -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
@@ -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
 
@@ -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
@@ -102,6 +102,14 @@ RSpec.describe Faraday::NestedParamsEncoder do
102
102
  Faraday::NestedParamsEncoder.sort_params = true
103
103
  end
104
104
 
105
+ it 'encodes arrays indices when asked' do
106
+ params = { a: [0, 1, 2] }
107
+ expect(subject.encode(params)).to eq('a%5B%5D=0&a%5B%5D=1&a%5B%5D=2')
108
+ Faraday::NestedParamsEncoder.array_indices = true
109
+ expect(subject.encode(params)).to eq('a%5B0%5D=0&a%5B1%5D=1&a%5B2%5D=2')
110
+ Faraday::NestedParamsEncoder.array_indices = false
111
+ end
112
+
105
113
  shared_examples 'a wrong decoding' do
106
114
  it do
107
115
  expect { subject.decode(query) }.to raise_error(TypeError) do |e|
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'stringio'
4
+
3
5
  RSpec.describe Faraday::Request::UrlEncoded do
4
6
  let(:conn) do
5
7
  Faraday.new do |b|
@@ -7,7 +9,11 @@ RSpec.describe Faraday::Request::UrlEncoded do
7
9
  b.adapter :test do |stub|
8
10
  stub.post('/echo') do |env|
9
11
  posted_as = env[:request_headers]['Content-Type']
10
- [200, { 'Content-Type' => posted_as }, env[:body]]
12
+ body = env[:body]
13
+ if body.respond_to?(:read)
14
+ body = body.read
15
+ end
16
+ [200, { 'Content-Type' => posted_as }, body]
11
17
  end
12
18
  end
13
19
  end
@@ -67,6 +73,11 @@ RSpec.describe Faraday::Request::UrlEncoded do
67
73
  expect(response.body).to eq('a%5Bb%5D%5Bc%5D%5B%5D=d')
68
74
  end
69
75
 
76
+ it 'works with files' do
77
+ response = conn.post('/echo', StringIO.new('str=apple'))
78
+ expect(response.body).to eq('str=apple')
79
+ end
80
+
70
81
  context 'customising default_space_encoding' do
71
82
  around do |example|
72
83
  Faraday::Utils.default_space_encoding = '%20'
@@ -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
@@ -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
 
@@ -38,6 +38,7 @@ shared_examples 'adapter examples' do |**options|
38
38
  let(:conn) do
39
39
  conn_options[:ssl] ||= {}
40
40
  conn_options[:ssl][:ca_file] ||= ENV['SSL_FILE']
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.2.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-02-03 00:00:00.000000000 Z
13
+ date: 2022-08-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday-net_http
@@ -125,7 +125,7 @@ licenses:
125
125
  - MIT
126
126
  metadata:
127
127
  homepage_uri: https://lostisland.github.io/faraday
128
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.2.0
128
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.5.0
129
129
  source_code_uri: https://github.com/lostisland/faraday
130
130
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
131
131
  post_install_message: