faraday 1.10.1 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +198 -4
  3. data/LICENSE.md +1 -1
  4. data/README.md +34 -20
  5. data/Rakefile +6 -1
  6. data/examples/client_spec.rb +41 -19
  7. data/examples/client_test.rb +48 -22
  8. data/lib/faraday/adapter/test.rb +62 -13
  9. data/lib/faraday/adapter.rb +6 -10
  10. data/lib/faraday/connection.rb +72 -150
  11. data/lib/faraday/encoders/nested_params_encoder.rb +14 -7
  12. data/lib/faraday/error.rb +24 -5
  13. data/lib/faraday/logging/formatter.rb +28 -15
  14. data/lib/faraday/middleware.rb +43 -2
  15. data/lib/faraday/middleware_registry.rb +17 -63
  16. data/lib/faraday/options/connection_options.rb +7 -6
  17. data/lib/faraday/options/env.rb +85 -62
  18. data/lib/faraday/options/proxy_options.rb +7 -3
  19. data/lib/faraday/options/request_options.rb +7 -6
  20. data/lib/faraday/options/ssl_options.rb +59 -45
  21. data/lib/faraday/options.rb +7 -6
  22. data/lib/faraday/rack_builder.rb +23 -21
  23. data/lib/faraday/request/authorization.rb +33 -41
  24. data/lib/faraday/request/instrumentation.rb +5 -1
  25. data/lib/faraday/request/json.rb +18 -3
  26. data/lib/faraday/request/url_encoded.rb +5 -1
  27. data/lib/faraday/request.rb +15 -31
  28. data/lib/faraday/response/json.rb +25 -5
  29. data/lib/faraday/response/logger.rb +6 -0
  30. data/lib/faraday/response/raise_error.rb +45 -18
  31. data/lib/faraday/response.rb +9 -21
  32. data/lib/faraday/utils/headers.rb +15 -4
  33. data/lib/faraday/utils.rb +11 -7
  34. data/lib/faraday/version.rb +1 -1
  35. data/lib/faraday.rb +8 -44
  36. data/spec/faraday/adapter/test_spec.rb +65 -0
  37. data/spec/faraday/connection_spec.rb +165 -93
  38. data/spec/faraday/error_spec.rb +31 -6
  39. data/spec/faraday/middleware_registry_spec.rb +31 -0
  40. data/spec/faraday/middleware_spec.rb +161 -0
  41. data/spec/faraday/options/env_spec.rb +8 -2
  42. data/spec/faraday/options/options_spec.rb +1 -1
  43. data/spec/faraday/options/proxy_options_spec.rb +8 -0
  44. data/spec/faraday/params_encoders/nested_spec.rb +10 -1
  45. data/spec/faraday/rack_builder_spec.rb +26 -54
  46. data/spec/faraday/request/authorization_spec.rb +50 -28
  47. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  48. data/spec/faraday/request/json_spec.rb +88 -0
  49. data/spec/faraday/request/url_encoded_spec.rb +12 -2
  50. data/spec/faraday/request_spec.rb +5 -15
  51. data/spec/faraday/response/json_spec.rb +93 -6
  52. data/spec/faraday/response/logger_spec.rb +38 -0
  53. data/spec/faraday/response/raise_error_spec.rb +111 -5
  54. data/spec/faraday/response_spec.rb +3 -1
  55. data/spec/faraday/utils/headers_spec.rb +31 -4
  56. data/spec/faraday/utils_spec.rb +64 -1
  57. data/spec/faraday_spec.rb +10 -4
  58. data/spec/spec_helper.rb +5 -6
  59. data/spec/support/fake_safe_buffer.rb +1 -1
  60. data/spec/support/faraday_middleware_subclasses.rb +18 -0
  61. data/spec/support/helper_methods.rb +0 -37
  62. data/spec/support/shared_examples/adapter.rb +2 -2
  63. data/spec/support/shared_examples/request_method.rb +22 -21
  64. metadata +24 -145
  65. data/lib/faraday/adapter/typhoeus.rb +0 -15
  66. data/lib/faraday/autoload.rb +0 -87
  67. data/lib/faraday/dependency_loader.rb +0 -37
  68. data/lib/faraday/deprecate.rb +0 -109
  69. data/lib/faraday/request/basic_authentication.rb +0 -20
  70. data/lib/faraday/request/token_authentication.rb +0 -20
  71. data/spec/faraday/adapter/em_http_spec.rb +0 -49
  72. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -18
  73. data/spec/faraday/adapter/excon_spec.rb +0 -49
  74. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  75. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  76. data/spec/faraday/adapter/patron_spec.rb +0 -18
  77. data/spec/faraday/adapter/rack_spec.rb +0 -8
  78. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  79. data/spec/faraday/composite_read_io_spec.rb +0 -80
  80. data/spec/faraday/deprecate_spec.rb +0 -147
  81. data/spec/faraday/response/middleware_spec.rb +0 -68
  82. data/spec/support/webmock_rack_app.rb +0 -68
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'timeout'
4
+
3
5
  module Faraday
4
6
  class Adapter
5
7
  # @example
@@ -26,6 +28,15 @@ module Faraday
26
28
  # ]
27
29
  # end
28
30
  #
31
+ # # Test the request body is the same as the stubbed body
32
+ # stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] }
33
+ #
34
+ # # You can pass a proc as a stubbed body and check the request body in your way.
35
+ # # In this case, the proc should return true or false.
36
+ # stub.post('/foo', ->(request_body) do
37
+ # JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, '']
38
+ # end
39
+ #
29
40
  # # You can set strict_mode to exactly match the stubbed requests.
30
41
  # stub.strict_mode = true
31
42
  # end
@@ -42,6 +53,12 @@ module Faraday
42
53
  #
43
54
  # resp = test.get '/items/2'
44
55
  # resp.body # => 'showing item: 2'
56
+ #
57
+ # resp = test.post '/bar', 'name=YK&word=call'
58
+ # resp.status # => 200
59
+ #
60
+ # resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now)
61
+ # resp.status # => 200
45
62
  class Test < Faraday::Adapter
46
63
  attr_accessor :stubs
47
64
 
@@ -55,6 +72,7 @@ module Faraday
55
72
  @stack = {}
56
73
  @consumed = {}
57
74
  @strict_mode = strict_mode
75
+ @stubs_mutex = Monitor.new
58
76
  yield(self) if block_given?
59
77
  end
60
78
 
@@ -70,10 +88,13 @@ module Faraday
70
88
  stack = @stack[request_method]
71
89
  consumed = (@consumed[request_method] ||= [])
72
90
 
73
- stub, meta = matches?(stack, env)
74
- if stub
75
- consumed << stack.delete(stub)
76
- return stub, meta
91
+ @stubs_mutex.synchronize do
92
+ stub, meta = matches?(stack, env)
93
+ if stub
94
+ removed = stack.delete(stub)
95
+ consumed << removed unless removed.nil?
96
+ return stub, meta
97
+ end
77
98
  end
78
99
  matches?(consumed, env)
79
100
  end
@@ -125,7 +146,7 @@ module Faraday
125
146
  # which means that all of a path, parameters, and headers must be the same as an actual request.
126
147
  def strict_mode=(value)
127
148
  @strict_mode = value
128
- @stack.each do |_method, stubs|
149
+ @stack.each_value do |stubs|
129
150
  stubs.each do |stub|
130
151
  stub.strict_mode = value
131
152
  end
@@ -163,7 +184,7 @@ module Faraday
163
184
  end
164
185
 
165
186
  # Stub request
166
- class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
187
+ Stub = Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) do
167
188
  # @param env [Faraday::Env]
168
189
  def matches?(env)
169
190
  request_host = env[:url].host
@@ -177,7 +198,7 @@ module Faraday
177
198
  [(host.nil? || host == request_host) &&
178
199
  path_match?(request_path, meta) &&
179
200
  params_match?(env) &&
180
- (body.to_s.size.zero? || request_body == body) &&
201
+ body_match?(request_body) &&
181
202
  headers_match?(request_headers), meta]
182
203
  end
183
204
 
@@ -218,6 +239,17 @@ module Faraday
218
239
  end
219
240
  end
220
241
 
242
+ def body_match?(request_body)
243
+ return true if body.to_s.empty?
244
+
245
+ case body
246
+ when Proc
247
+ body.call(request_body)
248
+ else
249
+ request_body == body
250
+ end
251
+ end
252
+
221
253
  def to_s
222
254
  "#{path} #{body}"
223
255
  end
@@ -242,21 +274,38 @@ module Faraday
242
274
  stub, meta = stubs.match(env)
243
275
 
244
276
  unless stub
245
- raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
246
- "#{env[:url]} #{env[:body]}"
277
+ raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
278
+ "#{env[:url]} #{env[:body]} #{env[:headers]}"
247
279
  end
248
280
 
249
281
  block_arity = stub.block.arity
282
+ params = if block_arity >= 0
283
+ [env, meta].take(block_arity)
284
+ else
285
+ [env, meta]
286
+ end
287
+
288
+ timeout = request_timeout(:open, env[:request])
289
+ timeout ||= request_timeout(:read, env[:request])
290
+
250
291
  status, headers, body =
251
- if block_arity >= 0
252
- stub.block.call(*[env, meta].take(block_arity))
292
+ if timeout
293
+ ::Timeout.timeout(timeout, Faraday::TimeoutError) do
294
+ stub.block.call(*params)
295
+ end
253
296
  else
254
- stub.block.call(env, meta)
297
+ stub.block.call(*params)
255
298
  end
256
- save_response(env, status, body, headers)
299
+
300
+ # We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
301
+ # See https://github.com/lostisland/faraday/issues/1444
302
+ # TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version
303
+ save_response(env, status, body, headers, nil)
257
304
 
258
305
  @app.call(env)
259
306
  end
260
307
  end
261
308
  end
262
309
  end
310
+
311
+ Faraday::Adapter.register_middleware(test: Faraday::Adapter::Test)
@@ -5,14 +5,9 @@ module Faraday
5
5
  # responsible for fulfilling a Faraday request.
6
6
  class Adapter
7
7
  extend MiddlewareRegistry
8
- extend DependencyLoader
9
8
 
10
9
  CONTENT_LENGTH = 'Content-Length'
11
10
 
12
- register_middleware File.expand_path('adapter', __dir__),
13
- test: [:Test, 'test'],
14
- typhoeus: [:Typhoeus, 'typhoeus']
15
-
16
11
  # This module marks an Adapter as supporting parallel requests.
17
12
  module Parallelism
18
13
  attr_writer :supports_parallel
@@ -31,7 +26,7 @@ module Faraday
31
26
  self.supports_parallel = false
32
27
 
33
28
  def initialize(_app = nil, opts = {}, &block)
34
- @app = ->(env) { env.response }
29
+ @app = lambda(&:response)
35
30
  @connection_options = opts
36
31
  @config_block = block
37
32
  end
@@ -64,7 +59,7 @@ module Faraday
64
59
 
65
60
  private
66
61
 
67
- 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)
68
63
  env.status = status
69
64
  env.body = body
70
65
  env.reason_phrase = reason_phrase&.to_s&.strip
@@ -73,7 +68,7 @@ module Faraday
73
68
  yield(response_headers) if block_given?
74
69
  end
75
70
 
76
- env.response.finish(env) unless env.parallel?
71
+ env.response.finish(env) unless env.parallel? || !finished
77
72
  env.response
78
73
  end
79
74
 
@@ -83,8 +78,7 @@ module Faraday
83
78
  # @param type [Symbol] Describes which timeout setting to get: :read,
84
79
  # :write, or :open.
85
80
  # @param options [Hash] Hash containing Symbol keys like :timeout,
86
- # :read_timeout, :write_timeout, :open_timeout, or
87
- # :timeout
81
+ # :read_timeout, :write_timeout, or :open_timeout
88
82
  #
89
83
  # @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
90
84
  # has been set.
@@ -103,3 +97,5 @@ module Faraday
103
97
  }.freeze
104
98
  end
105
99
  end
100
+
101
+ require 'faraday/adapter/test'
@@ -1,23 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday/deprecate'
4
-
5
3
  module Faraday
6
4
  # Connection objects manage the default properties and the middleware
7
5
  # stack for fulfilling an HTTP request.
8
6
  #
9
7
  # @example
10
8
  #
11
- # conn = Faraday::Connection.new 'http://sushi.com'
9
+ # conn = Faraday::Connection.new 'http://httpbingo.org'
12
10
  #
13
- # # GET http://sushi.com/nigiri
11
+ # # GET http://httpbingo.org/nigiri
14
12
  # conn.get 'nigiri'
15
13
  # # => #<Faraday::Response>
16
14
  #
17
15
  class Connection
18
16
  # A Set of allowed HTTP verbs.
19
17
  METHODS = Set.new %i[get post put delete head patch options trace]
20
- USER_AGENT = "Faraday v#{VERSION}"
18
+ USER_AGENT = "Faraday v#{VERSION}".freeze
21
19
 
22
20
  # @return [Hash] URI query unencoded key/value pairs.
23
21
  attr_reader :params
@@ -66,7 +64,7 @@ module Faraday
66
64
  options = ConnectionOptions.from(options)
67
65
 
68
66
  if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
69
- options = options.merge(url)
67
+ options = Utils.deep_merge(options, url)
70
68
  url = options.url
71
69
  end
72
70
 
@@ -119,7 +117,7 @@ module Faraday
119
117
 
120
118
  extend Forwardable
121
119
 
122
- def_delegators :builder, :build, :use, :request, :response, :adapter, :app
120
+ def_delegators :builder, :use, :request, :response, :adapter, :app
123
121
 
124
122
  # Closes the underlying resources and/or connections. In the case of
125
123
  # persistent connections, this closes all currently open connections
@@ -132,10 +130,10 @@ module Faraday
132
130
  # Makes a GET HTTP request without a body.
133
131
  # @!scope class
134
132
  #
135
- # @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
136
134
  # all requests. Can also be the options Hash.
137
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
138
- # @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.
139
137
  #
140
138
  # @example
141
139
  # conn.get '/items', { page: 1 }, :accept => 'application/json'
@@ -154,10 +152,10 @@ module Faraday
154
152
  # Makes a HEAD HTTP request without a body.
155
153
  # @!scope class
156
154
  #
157
- # @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
158
156
  # all requests. Can also be the options Hash.
159
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
160
- # @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.
161
159
  #
162
160
  # @example
163
161
  # conn.head '/items/1'
@@ -169,10 +167,10 @@ module Faraday
169
167
  # Makes a DELETE HTTP request without a body.
170
168
  # @!scope class
171
169
  #
172
- # @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
173
171
  # all requests. Can also be the options Hash.
174
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
175
- # @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.
176
174
  #
177
175
  # @example
178
176
  # conn.delete '/items/1'
@@ -184,10 +182,10 @@ module Faraday
184
182
  # Makes a TRACE HTTP request without a body.
185
183
  # @!scope class
186
184
  #
187
- # @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
188
186
  # all requests. Can also be the options Hash.
189
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
190
- # @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.
191
189
  #
192
190
  # @example
193
191
  # conn.connect '/items/1'
@@ -212,9 +210,9 @@ module Faraday
212
210
  #
213
211
  # @overload options(url, params = nil, headers = nil)
214
212
  # Makes an OPTIONS HTTP request to the given URL.
215
- # @param url [String] String base URL to sue as a prefix for all requests.
216
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
217
- # @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.
218
216
  #
219
217
  # @example
220
218
  # conn.options '/items/1'
@@ -222,7 +220,7 @@ module Faraday
222
220
  # @yield [Faraday::Request] for further request customizations
223
221
  # @return [Faraday::Response]
224
222
  def options(*args)
225
- return @options if args.size.zero?
223
+ return @options if args.empty?
226
224
 
227
225
  url, params, headers = *args
228
226
  run_request(:options, url, nil, headers) do |request|
@@ -235,10 +233,10 @@ module Faraday
235
233
  # Makes a POST HTTP request with a body.
236
234
  # @!scope class
237
235
  #
238
- # @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
239
237
  # all requests. Can also be the options Hash.
240
- # @param body [String] body for the request.
241
- # @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.
242
240
  #
243
241
  # @example
244
242
  # conn.post '/items', data, content_type: 'application/json'
@@ -257,20 +255,19 @@ module Faraday
257
255
  # Makes a PUT HTTP request with a body.
258
256
  # @!scope class
259
257
  #
260
- # @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
261
259
  # all requests. Can also be the options Hash.
262
- # @param body [String] body for the request.
263
- # @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.
264
262
  #
265
263
  # @example
266
- # # TODO: Make it a PUT example
267
- # conn.post '/items', data, content_type: 'application/json'
264
+ # conn.put '/products/123', data, content_type: 'application/json'
268
265
  #
269
- # # Simple ElasticSearch indexing sample.
270
- # conn.post '/twitter/tweet' do |req|
271
- # req.headers[:content_type] = 'application/json'
272
- # req.params[:routing] = 'kimchy'
273
- # req.body = JSON.generate(user: 'kimchy', ...)
266
+ # # Star a gist.
267
+ # conn.put 'https://api.github.com/gists/GIST_ID/star' do |req|
268
+ # req.headers['Accept'] = 'application/vnd.github+json'
269
+ # req.headers['Authorization'] = 'Bearer <YOUR-TOKEN>'
270
+ # req.headers['X-GitHub-Api-Version'] = '2022-11-28'
274
271
  # end
275
272
  #
276
273
  # @yield [Faraday::Request] for further request customizations
@@ -285,75 +282,6 @@ module Faraday
285
282
  RUBY
286
283
  end
287
284
 
288
- # Sets up the Authorization header with these credentials, encoded
289
- # with base64.
290
- #
291
- # @param login [String] The authentication login.
292
- # @param pass [String] The authentication password.
293
- #
294
- # @example
295
- #
296
- # conn.basic_auth 'Aladdin', 'open sesame'
297
- # conn.headers['Authorization']
298
- # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
299
- #
300
- # @return [void]
301
- def basic_auth(login, pass)
302
- set_authorization_header(:basic_auth, login, pass)
303
- end
304
-
305
- extend Faraday::Deprecate
306
- deprecate :basic_auth, '#request(:basic_auth, ...)', '2.0'
307
-
308
- # Sets up the Authorization header with the given token.
309
- #
310
- # @param token [String]
311
- # @param options [Hash] extra token options.
312
- #
313
- # @example
314
- #
315
- # conn.token_auth 'abcdef', foo: 'bar'
316
- # conn.headers['Authorization']
317
- # # => "Token token=\"abcdef\",
318
- # foo=\"bar\""
319
- #
320
- # @return [void]
321
- def token_auth(token, options = nil)
322
- warn <<~TEXT
323
- WARNING: `Faraday::Connection#token_auth` is deprecated; it will be removed in version 2.0.
324
- While initializing your connection, use `#request(:token_auth, ...)` instead.
325
- See https://lostisland.github.io/faraday/middleware/authentication for more usage info.
326
- TEXT
327
- set_authorization_header(:token_auth, token, options)
328
- end
329
-
330
- # Sets up a custom Authorization header.
331
- #
332
- # @param type [String] authorization type
333
- # @param token [String, Hash] token. A String value is taken literally, and
334
- # a Hash is encoded into comma-separated key/value pairs.
335
- #
336
- # @example
337
- #
338
- # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
339
- # conn.headers['Authorization']
340
- # # => "Bearer mF_9.B5f-4.1JqM"
341
- #
342
- # conn.authorization :Token, token: 'abcdef', foo: 'bar'
343
- # conn.headers['Authorization']
344
- # # => "Token token=\"abcdef\",
345
- # foo=\"bar\""
346
- #
347
- # @return [void]
348
- def authorization(type, token)
349
- warn <<~TEXT
350
- WARNING: `Faraday::Connection#authorization` is deprecated; it will be removed in version 2.0.
351
- While initializing your connection, use `#request(:authorization, ...)` instead.
352
- See https://lostisland.github.io/faraday/middleware/authentication for more usage info.
353
- TEXT
354
- set_authorization_header(:authorization, type, token)
355
- end
356
-
357
285
  # Check if the adapter is parallel-capable.
358
286
  #
359
287
  # @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
@@ -386,15 +314,23 @@ module Faraday
386
314
  #
387
315
  # @yield a block to execute multiple requests.
388
316
  # @return [void]
389
- def in_parallel(manager = nil)
317
+ def in_parallel(manager = nil, &block)
390
318
  @parallel_manager = manager || default_parallel_manager do
391
319
  warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \
392
320
  'on Faraday stack'
393
321
  warn caller[2, 10].join("\n")
394
322
  nil
395
323
  end
396
- yield
397
- @parallel_manager&.run
324
+ return yield unless @parallel_manager
325
+
326
+ if @parallel_manager.respond_to?(:execute)
327
+ # Execute is the new method that is responsible for executing the block.
328
+ @parallel_manager.execute(&block)
329
+ else
330
+ # TODO: Old behaviour, deprecate and remove in 3.0
331
+ yield
332
+ @parallel_manager.run
333
+ end
398
334
  ensure
399
335
  @parallel_manager = nil
400
336
  end
@@ -420,11 +356,11 @@ module Faraday
420
356
  # @example
421
357
  #
422
358
  # conn = Faraday::Connection.new { ... }
423
- # conn.url_prefix = "https://sushi.com/api"
359
+ # conn.url_prefix = "https://httpbingo.org/api"
424
360
  # conn.scheme # => https
425
361
  # conn.path_prefix # => "/api"
426
362
  #
427
- # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
363
+ # conn.get("nigiri?page=2") # accesses https://httpbingo.org/api/nigiri
428
364
  def url_prefix=(url, encoder = nil)
429
365
  uri = @url_prefix = Utils.URI(url)
430
366
  self.path_prefix = uri.path
@@ -441,7 +377,7 @@ module Faraday
441
377
  end
442
378
 
443
379
  def set_basic_auth(user, password)
444
- header = Faraday::Request::BasicAuthentication.header(user, password)
380
+ header = Faraday::Utils.basic_header_from(user, password)
445
381
  headers[Faraday::Request::Authorization::KEY] = header
446
382
  end
447
383
 
@@ -461,20 +397,20 @@ module Faraday
461
397
  # Takes a relative url for a request and combines it with the defaults
462
398
  # set on the connection instance.
463
399
  #
464
- # @param url [String]
400
+ # @param url [String, URI, nil]
465
401
  # @param extra_params [Hash]
466
402
  #
467
403
  # @example
468
404
  # conn = Faraday::Connection.new { ... }
469
- # conn.url_prefix = "https://sushi.com/api?token=abc"
405
+ # conn.url_prefix = "https://httpbingo.org/api?token=abc"
470
406
  # conn.scheme # => https
471
407
  # conn.path_prefix # => "/api"
472
408
  #
473
409
  # conn.build_url("nigiri?page=2")
474
- # # => https://sushi.com/api/nigiri?token=abc&page=2
410
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
475
411
  #
476
412
  # conn.build_url("nigiri", page: 2)
477
- # # => https://sushi.com/api/nigiri?token=abc&page=2
413
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
478
414
  #
479
415
  def build_url(url = nil, extra_params = nil)
480
416
  uri = build_exclusive_url(url)
@@ -494,10 +430,10 @@ module Faraday
494
430
  # Builds and runs the Faraday::Request.
495
431
  #
496
432
  # @param method [Symbol] HTTP method.
497
- # @param url [String, URI] String or URI to access.
498
- # @param body [Object] The request body that will eventually be converted to
499
- # a string.
500
- # @param headers [Hash] unencoded HTTP header key/value pairs.
433
+ # @param url [String, URI, nil] String or URI to access.
434
+ # @param body [String, Hash, Array, nil] The request body that will eventually be converted to
435
+ # a string; middlewares can be used to support more complex types.
436
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
501
437
  #
502
438
  # @return [Faraday::Response]
503
439
  def run_request(method, url, body, headers)
@@ -533,7 +469,7 @@ module Faraday
533
469
 
534
470
  # Build an absolute URL based on url_prefix.
535
471
  #
536
- # @param url [String, URI]
472
+ # @param url [String, URI, nil]
537
473
  # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
538
474
  # replace the query values
539
475
  # of the resulting url (default: nil).
@@ -542,17 +478,16 @@ module Faraday
542
478
  def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
543
479
  url = nil if url.respond_to?(:empty?) && url.empty?
544
480
  base = url_prefix.dup
545
- if url && base.path && base.path !~ %r{/$}
481
+ if url && !base.path.end_with?('/')
546
482
  base.path = "#{base.path}/" # ensure trailing slash
547
483
  end
548
- url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
484
+ # Ensure relative url will be parsed correctly (such as `service:search` )
485
+ url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?('http://', 'https://', '/', './', '../')
549
486
  uri = url ? base + url : base
550
487
  if params
551
488
  uri.query = params.to_query(params_encoder || options.params_encoder)
552
489
  end
553
- # rubocop:disable Style/SafeNavigation
554
490
  uri.query = nil if uri.query && uri.query.empty?
555
- # rubocop:enable Style/SafeNavigation
556
491
  uri
557
492
  end
558
493
 
@@ -584,41 +519,28 @@ module Faraday
584
519
  yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
585
520
  end
586
521
 
587
- def set_authorization_header(header_type, *args)
588
- header = Faraday::Request
589
- .lookup_middleware(header_type)
590
- .header(*args)
591
-
592
- headers[Faraday::Request::Authorization::KEY] = header
593
- end
594
-
595
522
  def proxy_from_env(url)
596
523
  return if Faraday.ignore_env_proxy
597
524
 
598
525
  uri = nil
599
- if URI.parse('').respond_to?(:find_proxy)
600
- case url
601
- when String
602
- uri = Utils.URI(url)
603
- uri = if uri.host.nil?
604
- find_default_proxy
605
- else
606
- URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
607
- end
608
- when URI
609
- uri = url.find_proxy
610
- when nil
611
- uri = find_default_proxy
612
- end
613
- else
614
- warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
526
+ case url
527
+ when String
528
+ uri = Utils.URI(url)
529
+ uri = if uri.host.nil?
530
+ find_default_proxy
531
+ else
532
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
533
+ end
534
+ when URI
535
+ uri = url.find_proxy
536
+ when nil
615
537
  uri = find_default_proxy
616
538
  end
617
539
  ProxyOptions.from(uri) if uri
618
540
  end
619
541
 
620
542
  def find_default_proxy
621
- uri = ENV['http_proxy']
543
+ uri = ENV.fetch('http_proxy', nil)
622
544
  return unless uri && !uri.empty?
623
545
 
624
546
  uri = "http://#{uri}" unless uri.match?(/^http/i)
@@ -636,7 +558,7 @@ module Faraday
636
558
  end
637
559
 
638
560
  def support_parallel?(adapter)
639
- adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
561
+ adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
640
562
  end
641
563
  end
642
564
  end