faraday 1.0.0 → 2.9.0

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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +35 -23
  5. data/Rakefile +3 -1
  6. data/examples/client_spec.rb +68 -14
  7. data/examples/client_test.rb +80 -15
  8. data/lib/faraday/adapter/test.rb +117 -52
  9. data/lib/faraday/adapter.rb +6 -20
  10. data/lib/faraday/adapter_registry.rb +3 -1
  11. data/lib/faraday/connection.rb +73 -132
  12. data/lib/faraday/encoders/flat_params_encoder.rb +9 -2
  13. data/lib/faraday/encoders/nested_params_encoder.rb +20 -8
  14. data/lib/faraday/error.rb +37 -8
  15. data/lib/faraday/logging/formatter.rb +28 -15
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +17 -5
  18. data/lib/faraday/middleware_registry.rb +17 -63
  19. data/lib/faraday/options/connection_options.rb +7 -6
  20. data/lib/faraday/options/env.rb +85 -62
  21. data/lib/faraday/options/proxy_options.rb +11 -3
  22. data/lib/faraday/options/request_options.rb +7 -6
  23. data/lib/faraday/options/ssl_options.rb +56 -45
  24. data/lib/faraday/options.rb +11 -14
  25. data/lib/faraday/rack_builder.rb +35 -32
  26. data/lib/faraday/request/authorization.rb +37 -36
  27. data/lib/faraday/request/instrumentation.rb +5 -1
  28. data/lib/faraday/request/json.rb +70 -0
  29. data/lib/faraday/request/url_encoded.rb +8 -2
  30. data/lib/faraday/request.rb +22 -29
  31. data/lib/faraday/response/json.rb +73 -0
  32. data/lib/faraday/response/logger.rb +8 -4
  33. data/lib/faraday/response/raise_error.rb +41 -3
  34. data/lib/faraday/response.rb +10 -23
  35. data/lib/faraday/utils/headers.rb +9 -4
  36. data/lib/faraday/utils.rb +22 -10
  37. data/lib/faraday/version.rb +5 -0
  38. data/lib/faraday.rb +49 -58
  39. data/spec/faraday/adapter/test_spec.rb +442 -0
  40. data/spec/faraday/connection_spec.rb +207 -90
  41. data/spec/faraday/error_spec.rb +45 -5
  42. data/spec/faraday/middleware_registry_spec.rb +31 -0
  43. data/spec/faraday/middleware_spec.rb +50 -6
  44. data/spec/faraday/options/env_spec.rb +8 -2
  45. data/spec/faraday/options/options_spec.rb +1 -1
  46. data/spec/faraday/options/proxy_options_spec.rb +15 -0
  47. data/spec/faraday/params_encoders/flat_spec.rb +8 -0
  48. data/spec/faraday/params_encoders/nested_spec.rb +16 -0
  49. data/spec/faraday/rack_builder_spec.rb +171 -50
  50. data/spec/faraday/request/authorization_spec.rb +54 -24
  51. data/spec/faraday/request/instrumentation_spec.rb +5 -7
  52. data/spec/faraday/request/json_spec.rb +199 -0
  53. data/spec/faraday/request/url_encoded_spec.rb +25 -2
  54. data/spec/faraday/request_spec.rb +11 -10
  55. data/spec/faraday/response/json_spec.rb +189 -0
  56. data/spec/faraday/response/logger_spec.rb +38 -0
  57. data/spec/faraday/response/raise_error_spec.rb +105 -0
  58. data/spec/faraday/response_spec.rb +3 -1
  59. data/spec/faraday/utils/headers_spec.rb +22 -4
  60. data/spec/faraday/utils_spec.rb +63 -1
  61. data/spec/faraday_spec.rb +8 -4
  62. data/spec/spec_helper.rb +6 -5
  63. data/spec/support/fake_safe_buffer.rb +1 -1
  64. data/spec/support/helper_methods.rb +0 -37
  65. data/spec/support/shared_examples/adapter.rb +4 -3
  66. data/spec/support/shared_examples/request_method.rb +60 -31
  67. metadata +19 -44
  68. data/UPGRADING.md +0 -55
  69. data/lib/faraday/adapter/em_http.rb +0 -285
  70. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  71. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  72. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  73. data/lib/faraday/adapter/excon.rb +0 -124
  74. data/lib/faraday/adapter/httpclient.rb +0 -151
  75. data/lib/faraday/adapter/net_http.rb +0 -209
  76. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  77. data/lib/faraday/adapter/patron.rb +0 -132
  78. data/lib/faraday/adapter/rack.rb +0 -75
  79. data/lib/faraday/adapter/typhoeus.rb +0 -15
  80. data/lib/faraday/autoload.rb +0 -95
  81. data/lib/faraday/dependency_loader.rb +0 -37
  82. data/lib/faraday/file_part.rb +0 -128
  83. data/lib/faraday/param_part.rb +0 -53
  84. data/lib/faraday/request/basic_authentication.rb +0 -20
  85. data/lib/faraday/request/multipart.rb +0 -99
  86. data/lib/faraday/request/retry.rb +0 -239
  87. data/lib/faraday/request/token_authentication.rb +0 -20
  88. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  89. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  90. data/spec/faraday/adapter/excon_spec.rb +0 -49
  91. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  92. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  93. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  94. data/spec/faraday/adapter/patron_spec.rb +0 -18
  95. data/spec/faraday/adapter/rack_spec.rb +0 -8
  96. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  97. data/spec/faraday/composite_read_io_spec.rb +0 -80
  98. data/spec/faraday/request/multipart_spec.rb +0 -274
  99. data/spec/faraday/request/retry_spec.rb +0 -242
  100. data/spec/faraday/response/middleware_spec.rb +0 -52
  101. data/spec/support/webmock_rack_app.rb +0 -68
@@ -6,15 +6,16 @@ module Faraday
6
6
  #
7
7
  # @example
8
8
  #
9
- # conn = Faraday::Connection.new 'http://sushi.com'
9
+ # conn = Faraday::Connection.new 'http://httpbingo.org'
10
10
  #
11
- # # GET http://sushi.com/nigiri
11
+ # # GET http://httpbingo.org/nigiri
12
12
  # conn.get 'nigiri'
13
13
  # # => #<Faraday::Response>
14
14
  #
15
15
  class Connection
16
16
  # A Set of allowed HTTP verbs.
17
17
  METHODS = Set.new %i[get post put delete head patch options trace]
18
+ USER_AGENT = "Faraday v#{VERSION}".freeze
18
19
 
19
20
  # @return [Hash] URI query unencoded key/value pairs.
20
21
  attr_reader :params
@@ -26,7 +27,7 @@ module Faraday
26
27
  # Connection. This includes a default host name, scheme, port, and path.
27
28
  attr_reader :url_prefix
28
29
 
29
- # @return [Faraday::Builder] Builder for this Connection.
30
+ # @return [Faraday::RackBuilder] Builder for this Connection.
30
31
  attr_reader :builder
31
32
 
32
33
  # @return [Hash] SSL options.
@@ -63,7 +64,7 @@ module Faraday
63
64
  options = ConnectionOptions.from(options)
64
65
 
65
66
  if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
66
- options = options.merge(url)
67
+ options = Utils.deep_merge(options, url)
67
68
  url = options.url
68
69
  end
69
70
 
@@ -73,6 +74,7 @@ module Faraday
73
74
  @options = options.request
74
75
  @ssl = options.ssl
75
76
  @default_parallel_manager = options.parallel_manager
77
+ @manual_proxy = nil
76
78
 
77
79
  @builder = options.builder || begin
78
80
  # pass an empty block to Builder so it doesn't assume default middleware
@@ -88,7 +90,7 @@ module Faraday
88
90
 
89
91
  yield(self) if block_given?
90
92
 
91
- @headers[:user_agent] ||= "Faraday v#{VERSION}"
93
+ @headers[:user_agent] ||= USER_AGENT
92
94
  end
93
95
 
94
96
  def initialize_proxy(url, options)
@@ -115,7 +117,7 @@ module Faraday
115
117
 
116
118
  extend Forwardable
117
119
 
118
- def_delegators :builder, :build, :use, :request, :response, :adapter, :app
120
+ def_delegators :builder, :use, :request, :response, :adapter, :app
119
121
 
120
122
  # Closes the underlying resources and/or connections. In the case of
121
123
  # persistent connections, this closes all currently open connections
@@ -128,10 +130,10 @@ module Faraday
128
130
  # Makes a GET HTTP request without a body.
129
131
  # @!scope class
130
132
  #
131
- # @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
132
134
  # all requests. Can also be the options Hash.
133
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
134
- # @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.
135
137
  #
136
138
  # @example
137
139
  # conn.get '/items', { page: 1 }, :accept => 'application/json'
@@ -150,10 +152,10 @@ module Faraday
150
152
  # Makes a HEAD HTTP request without a body.
151
153
  # @!scope class
152
154
  #
153
- # @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
154
156
  # all requests. Can also be the options Hash.
155
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
156
- # @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.
157
159
  #
158
160
  # @example
159
161
  # conn.head '/items/1'
@@ -165,10 +167,10 @@ module Faraday
165
167
  # Makes a DELETE HTTP request without a body.
166
168
  # @!scope class
167
169
  #
168
- # @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
169
171
  # all requests. Can also be the options Hash.
170
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
171
- # @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.
172
174
  #
173
175
  # @example
174
176
  # conn.delete '/items/1'
@@ -180,10 +182,10 @@ module Faraday
180
182
  # Makes a TRACE HTTP request without a body.
181
183
  # @!scope class
182
184
  #
183
- # @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
184
186
  # all requests. Can also be the options Hash.
185
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
186
- # @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.
187
189
  #
188
190
  # @example
189
191
  # conn.connect '/items/1'
@@ -208,9 +210,9 @@ module Faraday
208
210
  #
209
211
  # @overload options(url, params = nil, headers = nil)
210
212
  # Makes an OPTIONS HTTP request to the given URL.
211
- # @param url [String] String base URL to sue as a prefix for all requests.
212
- # @param params [Hash] Hash of URI query unencoded key/value pairs.
213
- # @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.
214
216
  #
215
217
  # @example
216
218
  # conn.options '/items/1'
@@ -218,7 +220,7 @@ module Faraday
218
220
  # @yield [Faraday::Request] for further request customizations
219
221
  # @return [Faraday::Response]
220
222
  def options(*args)
221
- return @options if args.size.zero?
223
+ return @options if args.empty?
222
224
 
223
225
  url, params, headers = *args
224
226
  run_request(:options, url, nil, headers) do |request|
@@ -231,10 +233,10 @@ module Faraday
231
233
  # Makes a POST HTTP request with a body.
232
234
  # @!scope class
233
235
  #
234
- # @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
235
237
  # all requests. Can also be the options Hash.
236
- # @param body [String] body for the request.
237
- # @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.
238
240
  #
239
241
  # @example
240
242
  # conn.post '/items', data, content_type: 'application/json'
@@ -253,20 +255,19 @@ module Faraday
253
255
  # Makes a PUT HTTP request with a body.
254
256
  # @!scope class
255
257
  #
256
- # @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
257
259
  # all requests. Can also be the options Hash.
258
- # @param body [String] body for the request.
259
- # @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.
260
262
  #
261
263
  # @example
262
- # # TODO: Make it a PUT example
263
- # conn.post '/items', data, content_type: 'application/json'
264
+ # conn.put '/products/123', data, content_type: 'application/json'
264
265
  #
265
- # # Simple ElasticSearch indexing sample.
266
- # conn.post '/twitter/tweet' do |req|
267
- # req.headers[:content_type] = 'application/json'
268
- # req.params[:routing] = 'kimchy'
269
- # 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'
270
271
  # end
271
272
  #
272
273
  # @yield [Faraday::Request] for further request customizations
@@ -281,62 +282,6 @@ module Faraday
281
282
  RUBY
282
283
  end
283
284
 
284
- # Sets up the Authorization header with these credentials, encoded
285
- # with base64.
286
- #
287
- # @param login [String] The authentication login.
288
- # @param pass [String] The authentication password.
289
- #
290
- # @example
291
- #
292
- # conn.basic_auth 'Aladdin', 'open sesame'
293
- # conn.headers['Authorization']
294
- # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
295
- #
296
- # @return [void]
297
- def basic_auth(login, pass)
298
- set_authorization_header(:basic_auth, login, pass)
299
- end
300
-
301
- # Sets up the Authorization header with the given token.
302
- #
303
- # @param token [String]
304
- # @param options [Hash] extra token options.
305
- #
306
- # @example
307
- #
308
- # conn.token_auth 'abcdef', foo: 'bar'
309
- # conn.headers['Authorization']
310
- # # => "Token token=\"abcdef\",
311
- # foo=\"bar\""
312
- #
313
- # @return [void]
314
- def token_auth(token, options = nil)
315
- set_authorization_header(:token_auth, token, options)
316
- end
317
-
318
- # Sets up a custom Authorization header.
319
- #
320
- # @param type [String] authorization type
321
- # @param token [String, Hash] token. A String value is taken literally, and
322
- # a Hash is encoded into comma-separated key/value pairs.
323
- #
324
- # @example
325
- #
326
- # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
327
- # conn.headers['Authorization']
328
- # # => "Bearer mF_9.B5f-4.1JqM"
329
- #
330
- # conn.authorization :Token, token: 'abcdef', foo: 'bar'
331
- # conn.headers['Authorization']
332
- # # => "Token token=\"abcdef\",
333
- # foo=\"bar\""
334
- #
335
- # @return [void]
336
- def authorization(type, token)
337
- set_authorization_header(:authorization, type, token)
338
- end
339
-
340
285
  # Check if the adapter is parallel-capable.
341
286
  #
342
287
  # @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
@@ -403,11 +348,11 @@ module Faraday
403
348
  # @example
404
349
  #
405
350
  # conn = Faraday::Connection.new { ... }
406
- # conn.url_prefix = "https://sushi.com/api"
351
+ # conn.url_prefix = "https://httpbingo.org/api"
407
352
  # conn.scheme # => https
408
353
  # conn.path_prefix # => "/api"
409
354
  #
410
- # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
355
+ # conn.get("nigiri?page=2") # accesses https://httpbingo.org/api/nigiri
411
356
  def url_prefix=(url, encoder = nil)
412
357
  uri = @url_prefix = Utils.URI(url)
413
358
  self.path_prefix = uri.path
@@ -416,9 +361,16 @@ module Faraday
416
361
  uri.query = nil
417
362
 
418
363
  with_uri_credentials(uri) do |user, password|
419
- basic_auth user, password
364
+ set_basic_auth(user, password)
420
365
  uri.user = uri.password = nil
421
366
  end
367
+
368
+ @proxy = proxy_from_env(url) unless @manual_proxy
369
+ end
370
+
371
+ def set_basic_auth(user, password)
372
+ header = Faraday::Utils.basic_header_from(user, password)
373
+ headers[Faraday::Request::Authorization::KEY] = header
422
374
  end
423
375
 
424
376
  # Sets the path prefix and ensures that it always has a leading
@@ -429,7 +381,7 @@ module Faraday
429
381
  # @return [String] the new path prefix
430
382
  def path_prefix=(value)
431
383
  url_prefix.path = if value
432
- value = '/' + value unless value[0, 1] == '/'
384
+ value = "/#{value}" unless value[0, 1] == '/'
433
385
  value
434
386
  end
435
387
  end
@@ -437,20 +389,20 @@ module Faraday
437
389
  # Takes a relative url for a request and combines it with the defaults
438
390
  # set on the connection instance.
439
391
  #
440
- # @param url [String]
392
+ # @param url [String, URI, nil]
441
393
  # @param extra_params [Hash]
442
394
  #
443
395
  # @example
444
396
  # conn = Faraday::Connection.new { ... }
445
- # conn.url_prefix = "https://sushi.com/api?token=abc"
397
+ # conn.url_prefix = "https://httpbingo.org/api?token=abc"
446
398
  # conn.scheme # => https
447
399
  # conn.path_prefix # => "/api"
448
400
  #
449
401
  # conn.build_url("nigiri?page=2")
450
- # # => https://sushi.com/api/nigiri?token=abc&page=2
402
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
451
403
  #
452
404
  # conn.build_url("nigiri", page: 2)
453
- # # => https://sushi.com/api/nigiri?token=abc&page=2
405
+ # # => https://httpbingo.org/api/nigiri?token=abc&page=2
454
406
  #
455
407
  def build_url(url = nil, extra_params = nil)
456
408
  uri = build_exclusive_url(url)
@@ -470,10 +422,10 @@ module Faraday
470
422
  # Builds and runs the Faraday::Request.
471
423
  #
472
424
  # @param method [Symbol] HTTP method.
473
- # @param url [String, URI] String or URI to access.
474
- # @param body [Object] The request body that will eventually be converted to
425
+ # @param url [String, URI, nil] String or URI to access.
426
+ # @param body [String, nil] The request body that will eventually be converted to
475
427
  # a string.
476
- # @param headers [Hash] unencoded HTTP header key/value pairs.
428
+ # @param headers [Hash, nil] unencoded HTTP header key/value pairs.
477
429
  #
478
430
  # @return [Faraday::Response]
479
431
  def run_request(method, url, body, headers)
@@ -509,7 +461,7 @@ module Faraday
509
461
 
510
462
  # Build an absolute URL based on url_prefix.
511
463
  #
512
- # @param url [String, URI]
464
+ # @param url [String, URI, nil]
513
465
  # @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
514
466
  # replace the query values
515
467
  # of the resulting url (default: nil).
@@ -517,18 +469,16 @@ module Faraday
517
469
  # @return [URI]
518
470
  def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
519
471
  url = nil if url.respond_to?(:empty?) && url.empty?
520
- base = url_prefix
521
- if url && base.path && base.path !~ %r{/$}
522
- base = base.dup
523
- base.path = base.path + '/' # ensure trailing slash
472
+ base = url_prefix.dup
473
+ if url && !base.path.end_with?('/')
474
+ base.path = "#{base.path}/" # ensure trailing slash
524
475
  end
476
+ url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque
525
477
  uri = url ? base + url : base
526
478
  if params
527
479
  uri.query = params.to_query(params_encoder || options.params_encoder)
528
480
  end
529
- # rubocop:disable Style/SafeNavigation
530
481
  uri.query = nil if uri.query && uri.query.empty?
531
- # rubocop:enable Style/SafeNavigation
532
482
  uri
533
483
  end
534
484
 
@@ -560,40 +510,31 @@ module Faraday
560
510
  yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
561
511
  end
562
512
 
563
- def set_authorization_header(header_type, *args)
564
- header = Faraday::Request
565
- .lookup_middleware(header_type)
566
- .header(*args)
567
-
568
- headers[Faraday::Request::Authorization::KEY] = header
569
- end
570
-
571
513
  def proxy_from_env(url)
572
514
  return if Faraday.ignore_env_proxy
573
515
 
574
516
  uri = nil
575
- if URI.parse('').respond_to?(:find_proxy)
576
- case url
577
- when String
578
- uri = Utils.URI(url)
579
- uri = URI.parse("#{uri.scheme}://#{uri.hostname}").find_proxy
580
- when URI
581
- uri = url.find_proxy
582
- when nil
583
- uri = find_default_proxy
584
- end
585
- else
586
- warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
517
+ case url
518
+ when String
519
+ uri = Utils.URI(url)
520
+ uri = if uri.host.nil?
521
+ find_default_proxy
522
+ else
523
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
524
+ end
525
+ when URI
526
+ uri = url.find_proxy
527
+ when nil
587
528
  uri = find_default_proxy
588
529
  end
589
530
  ProxyOptions.from(uri) if uri
590
531
  end
591
532
 
592
533
  def find_default_proxy
593
- uri = ENV['http_proxy']
534
+ uri = ENV.fetch('http_proxy', nil)
594
535
  return unless uri && !uri.empty?
595
536
 
596
- uri = 'http://' + uri if uri !~ /^http/i
537
+ uri = "http://#{uri}" unless uri.match?(/^http/i)
597
538
  uri
598
539
  end
599
540
 
@@ -608,7 +549,7 @@ module Faraday
608
549
  end
609
550
 
610
551
  def support_parallel?(adapter)
611
- adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
552
+ adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
612
553
  end
613
554
  end
614
555
  end
@@ -33,9 +33,9 @@ module Faraday
33
33
  key = key.to_s if key.is_a?(Symbol)
34
34
  [key, value]
35
35
  end
36
- # Useful default for OAuth and caching.
36
+
37
37
  # Only to be used for non-Array inputs. Arrays should preserve order.
38
- params.sort!
38
+ params.sort! if @sort_params
39
39
  end
40
40
 
41
41
  # The params have form [['key1', 'value1'], ['key2', 'value2']].
@@ -94,5 +94,12 @@ module Faraday
94
94
  end
95
95
  end
96
96
  end
97
+
98
+ class << self
99
+ attr_accessor :sort_params
100
+ end
101
+
102
+ # Useful default for OAuth and caching.
103
+ @sort_params = true
97
104
  end
98
105
  end
@@ -21,9 +21,9 @@ module Faraday
21
21
  key = key.to_s if key.is_a?(Symbol)
22
22
  [key, value]
23
23
  end
24
- # Useful default for OAuth and caching.
24
+
25
25
  # Only to be used for non-Array inputs. Arrays should preserve order.
26
- params.sort!
26
+ params.sort! if @sort_params
27
27
  end
28
28
 
29
29
  # The params have form [['key1', 'value1'], ['key2', 'value2']].
@@ -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
@@ -96,13 +102,13 @@ module Faraday
96
102
 
97
103
  protected
98
104
 
99
- SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
105
+ SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/
100
106
 
101
107
  def decode_pair(key, value, context)
102
108
  subkeys = key.scan(SUBKEYS_REGEX)
103
109
  subkeys.each_with_index do |subkey, i|
104
110
  is_array = subkey =~ /[\[\]]+\Z/
105
- subkey = $` if is_array
111
+ subkey = Regexp.last_match.pre_match if is_array
106
112
  last_subkey = i == subkeys.length - 1
107
113
 
108
114
  context = prepare_context(context, subkey, is_array, last_subkey)
@@ -124,7 +130,7 @@ module Faraday
124
130
  value_type = is_array ? Array : Hash
125
131
  if context[subkey] && !context[subkey].is_a?(value_type)
126
132
  raise TypeError, "expected #{value_type.name} " \
127
- "(got #{context[subkey].class.name}) for param `#{subkey}'"
133
+ "(got #{context[subkey].class.name}) for param `#{subkey}'"
128
134
  end
129
135
 
130
136
  context[subkey] ||= value_type.new
@@ -161,10 +167,16 @@ module Faraday
161
167
  # for your requests.
162
168
  module NestedParamsEncoder
163
169
  class << self
170
+ attr_accessor :sort_params, :array_indices
171
+
164
172
  extend Forwardable
165
173
  def_delegators :'Faraday::Utils', :escape, :unescape
166
174
  end
167
175
 
176
+ # Useful default for OAuth and caching.
177
+ @sort_params = true
178
+ @array_indices = false
179
+
168
180
  extend EncodeMethods
169
181
  extend DecodeMethods
170
182
  end
data/lib/faraday/error.rb CHANGED
@@ -6,7 +6,7 @@ module Faraday
6
6
  class Error < StandardError
7
7
  attr_reader :response, :wrapped_exception
8
8
 
9
- def initialize(exc, response = nil)
9
+ def initialize(exc = nil, response = nil)
10
10
  @wrapped_exception = nil unless defined?(@wrapped_exception)
11
11
  @response = nil unless defined?(@response)
12
12
  super(exc_msg_and_response!(exc, response))
@@ -28,6 +28,24 @@ module Faraday
28
28
  %(#<#{self.class}#{inner}>)
29
29
  end
30
30
 
31
+ def response_status
32
+ return unless @response
33
+
34
+ @response.is_a?(Faraday::Response) ? @response.status : @response[:status]
35
+ end
36
+
37
+ def response_headers
38
+ return unless @response
39
+
40
+ @response.is_a?(Faraday::Response) ? @response.headers : @response[:headers]
41
+ end
42
+
43
+ def response_body
44
+ return unless @response
45
+
46
+ @response.is_a?(Faraday::Response) ? @response.body : @response[:body]
47
+ end
48
+
31
49
  protected
32
50
 
33
51
  # Pulls out potential parent exception and response hash, storing them in
@@ -38,6 +56,15 @@ module Faraday
38
56
  # :headers - String key/value hash of HTTP response header
39
57
  # values.
40
58
  # :body - Optional string HTTP response body.
59
+ # :request - Hash
60
+ # :method - Symbol with the request HTTP method.
61
+ # :url - URI object with the url requested.
62
+ # :url_path - String with the url path requested.
63
+ # :params - String key/value hash of query params
64
+ # present in the request.
65
+ # :headers - String key/value hash of HTTP request
66
+ # header values.
67
+ # :body - String HTTP request body.
41
68
  #
42
69
  # If a subclass has to call this, then it should pass a string message
43
70
  # to `super`. See NilStatusError.
@@ -85,6 +112,10 @@ module Faraday
85
112
  class ProxyAuthError < ClientError
86
113
  end
87
114
 
115
+ # Raised by Faraday::Response::RaiseError in case of a 408 response.
116
+ class RequestTimeoutError < ClientError
117
+ end
118
+
88
119
  # Raised by Faraday::Response::RaiseError in case of a 409 response.
89
120
  class ConflictError < ClientError
90
121
  end
@@ -93,6 +124,10 @@ module Faraday
93
124
  class UnprocessableEntityError < ClientError
94
125
  end
95
126
 
127
+ # Raised by Faraday::Response::RaiseError in case of a 429 response.
128
+ class TooManyRequestsError < ClientError
129
+ end
130
+
96
131
  # Faraday server error class. Represents 5xx status responses.
97
132
  class ServerError < Error
98
133
  end
@@ -120,13 +155,7 @@ module Faraday
120
155
  class SSLError < Error
121
156
  end
122
157
 
123
- # Raised by FaradayMiddleware::ResponseMiddleware
158
+ # Raised by middlewares that parse the response, like the JSON response middleware.
124
159
  class ParsingError < Error
125
160
  end
126
-
127
- # Exception used to control the Retry middleware.
128
- #
129
- # @see Faraday::Request::Retry
130
- class RetriableResponse < Error
131
- end
132
161
  end