faraday 1.0.0 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) 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 +6 -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 +7 -21
  10. data/lib/faraday/adapter_registry.rb +3 -1
  11. data/lib/faraday/connection.rb +75 -133
  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 +39 -6
  15. data/lib/faraday/logging/formatter.rb +28 -15
  16. data/lib/faraday/methods.rb +6 -0
  17. data/lib/faraday/middleware.rb +59 -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 +74 -0
  32. data/lib/faraday/response/logger.rb +8 -4
  33. data/lib/faraday/response/raise_error.rb +43 -3
  34. data/lib/faraday/response.rb +10 -23
  35. data/lib/faraday/utils/headers.rb +17 -6
  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 +193 -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 +18 -1
  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 +206 -0
  56. data/spec/faraday/response/logger_spec.rb +38 -0
  57. data/spec/faraday/response/raise_error_spec.rb +149 -0
  58. data/spec/faraday/response_spec.rb +3 -1
  59. data/spec/faraday/utils/headers_spec.rb +31 -4
  60. data/spec/faraday/utils_spec.rb +63 -1
  61. data/spec/faraday_spec.rb +10 -4
  62. data/spec/spec_helper.rb +6 -5
  63. data/spec/support/fake_safe_buffer.rb +1 -1
  64. data/spec/support/faraday_middleware_subclasses.rb +18 -0
  65. data/spec/support/helper_methods.rb +0 -37
  66. data/spec/support/shared_examples/adapter.rb +4 -3
  67. data/spec/support/shared_examples/request_method.rb +60 -31
  68. metadata +34 -44
  69. data/UPGRADING.md +0 -55
  70. data/lib/faraday/adapter/em_http.rb +0 -285
  71. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -62
  72. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -69
  73. data/lib/faraday/adapter/em_synchrony.rb +0 -150
  74. data/lib/faraday/adapter/excon.rb +0 -124
  75. data/lib/faraday/adapter/httpclient.rb +0 -151
  76. data/lib/faraday/adapter/net_http.rb +0 -209
  77. data/lib/faraday/adapter/net_http_persistent.rb +0 -91
  78. data/lib/faraday/adapter/patron.rb +0 -132
  79. data/lib/faraday/adapter/rack.rb +0 -75
  80. data/lib/faraday/adapter/typhoeus.rb +0 -15
  81. data/lib/faraday/autoload.rb +0 -95
  82. data/lib/faraday/dependency_loader.rb +0 -37
  83. data/lib/faraday/file_part.rb +0 -128
  84. data/lib/faraday/param_part.rb +0 -53
  85. data/lib/faraday/request/basic_authentication.rb +0 -20
  86. data/lib/faraday/request/multipart.rb +0 -99
  87. data/lib/faraday/request/retry.rb +0 -239
  88. data/lib/faraday/request/token_authentication.rb +0 -20
  89. data/spec/faraday/adapter/em_http_spec.rb +0 -47
  90. data/spec/faraday/adapter/em_synchrony_spec.rb +0 -16
  91. data/spec/faraday/adapter/excon_spec.rb +0 -49
  92. data/spec/faraday/adapter/httpclient_spec.rb +0 -73
  93. data/spec/faraday/adapter/net_http_persistent_spec.rb +0 -57
  94. data/spec/faraday/adapter/net_http_spec.rb +0 -64
  95. data/spec/faraday/adapter/patron_spec.rb +0 -18
  96. data/spec/faraday/adapter/rack_spec.rb +0 -8
  97. data/spec/faraday/adapter/typhoeus_spec.rb +0 -7
  98. data/spec/faraday/composite_read_io_spec.rb +0 -80
  99. data/spec/faraday/request/multipart_spec.rb +0 -274
  100. data/spec/faraday/request/retry_spec.rb +0 -242
  101. data/spec/faraday/response/middleware_spec.rb +0 -52
  102. 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
475
- # a string.
476
- # @param headers [Hash] unencoded HTTP header key/value pairs.
425
+ # @param url [String, URI, nil] String or URI to access.
426
+ # @param body [String, Hash, Array, nil] The request body that will eventually be converted to
427
+ # a string; middlewares can be used to support more complex types.
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,17 @@ 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
+ # Ensure relative url will be parsed correctly (such as `service:search` )
477
+ url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?('http://', 'https://', '/', './', '../')
525
478
  uri = url ? base + url : base
526
479
  if params
527
480
  uri.query = params.to_query(params_encoder || options.params_encoder)
528
481
  end
529
- # rubocop:disable Style/SafeNavigation
530
482
  uri.query = nil if uri.query && uri.query.empty?
531
- # rubocop:enable Style/SafeNavigation
532
483
  uri
533
484
  end
534
485
 
@@ -560,40 +511,31 @@ module Faraday
560
511
  yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
561
512
  end
562
513
 
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
514
  def proxy_from_env(url)
572
515
  return if Faraday.ignore_env_proxy
573
516
 
574
517
  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']
518
+ case url
519
+ when String
520
+ uri = Utils.URI(url)
521
+ uri = if uri.host.nil?
522
+ find_default_proxy
523
+ else
524
+ URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
525
+ end
526
+ when URI
527
+ uri = url.find_proxy
528
+ when nil
587
529
  uri = find_default_proxy
588
530
  end
589
531
  ProxyOptions.from(uri) if uri
590
532
  end
591
533
 
592
534
  def find_default_proxy
593
- uri = ENV['http_proxy']
535
+ uri = ENV.fetch('http_proxy', nil)
594
536
  return unless uri && !uri.empty?
595
537
 
596
- uri = 'http://' + uri if uri !~ /^http/i
538
+ uri = "http://#{uri}" unless uri.match?(/^http/i)
597
539
  uri
598
540
  end
599
541
 
@@ -608,7 +550,7 @@ module Faraday
608
550
  end
609
551
 
610
552
  def support_parallel?(adapter)
611
- adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
553
+ adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
612
554
  end
613
555
  end
614
556
  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,11 @@ 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
161
 
127
- # Exception used to control the Retry middleware.
128
- #
129
- # @see Faraday::Request::Retry
130
- class RetriableResponse < Error
162
+ # Raised by Faraday::Middleware and subclasses when invalid default_options are used
163
+ class InitializationError < Error
131
164
  end
132
165
  end