faraday 2.7.4 → 2.13.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/README.md +23 -11
  4. data/Rakefile +6 -1
  5. data/lib/faraday/adapter/test.rb +3 -3
  6. data/lib/faraday/adapter.rb +1 -1
  7. data/lib/faraday/connection.rb +27 -23
  8. data/lib/faraday/encoders/nested_params_encoder.rb +1 -1
  9. data/lib/faraday/error.rb +21 -3
  10. data/lib/faraday/logging/formatter.rb +13 -17
  11. data/lib/faraday/middleware.rb +40 -1
  12. data/lib/faraday/options/connection_options.rb +7 -6
  13. data/lib/faraday/options/env.rb +68 -69
  14. data/lib/faraday/options/proxy_options.rb +11 -5
  15. data/lib/faraday/options/request_options.rb +7 -6
  16. data/lib/faraday/options/ssl_options.rb +57 -50
  17. data/lib/faraday/options.rb +4 -3
  18. data/lib/faraday/rack_builder.rb +20 -20
  19. data/lib/faraday/request/instrumentation.rb +3 -1
  20. data/lib/faraday/request/json.rb +18 -3
  21. data/lib/faraday/request.rb +10 -7
  22. data/lib/faraday/response/json.rb +21 -1
  23. data/lib/faraday/response/logger.rb +5 -3
  24. data/lib/faraday/response/raise_error.rb +36 -17
  25. data/lib/faraday/utils/headers.rb +8 -2
  26. data/lib/faraday/utils.rb +3 -4
  27. data/lib/faraday/version.rb +1 -1
  28. data/spec/faraday/connection_spec.rb +2 -2
  29. data/spec/faraday/error_spec.rb +39 -6
  30. data/spec/faraday/middleware_spec.rb +143 -0
  31. data/spec/faraday/options/options_spec.rb +1 -1
  32. data/spec/faraday/options/proxy_options_spec.rb +35 -0
  33. data/spec/faraday/params_encoders/nested_spec.rb +2 -1
  34. data/spec/faraday/request/json_spec.rb +88 -0
  35. data/spec/faraday/response/json_spec.rb +89 -0
  36. data/spec/faraday/response/logger_spec.rb +49 -4
  37. data/spec/faraday/response/raise_error_spec.rb +104 -1
  38. data/spec/faraday/utils/headers_spec.rb +9 -0
  39. data/spec/faraday/utils_spec.rb +3 -1
  40. data/spec/faraday_spec.rb +10 -4
  41. data/spec/spec_helper.rb +6 -5
  42. data/spec/support/faraday_middleware_subclasses.rb +18 -0
  43. metadata +26 -14
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # ProxyOptions contains the configurable properties for the proxy
5
- # configuration used when making an HTTP request.
6
- class ProxyOptions < Options.new(:uri, :user, :password)
4
+ # @!parse
5
+ # # ProxyOptions contains the configurable properties for the proxy
6
+ # # configuration used when making an HTTP request.
7
+ # class ProxyOptions < Options; end
8
+ ProxyOptions = Options.new(:uri, :user, :password) do
7
9
  extend Forwardable
8
10
  def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
9
11
  :path, :path=
10
12
 
11
13
  def self.from(value)
12
14
  case value
15
+ when ''
16
+ value = nil
13
17
  when String
14
18
  # URIs without a scheme should default to http (like 'example:123').
15
19
  # This fixes #1282 and prevents a silent failure in some adapters.
@@ -18,8 +22,10 @@ module Faraday
18
22
  when URI
19
23
  value = { uri: value }
20
24
  when Hash, Options
21
- if (uri = value.delete(:uri))
22
- value[:uri] = Utils.URI(uri)
25
+ if value[:uri]
26
+ value = value.dup.tap do |duped|
27
+ duped[:uri] = Utils.URI(duped[:uri])
28
+ end
23
29
  end
24
30
  end
25
31
 
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # RequestOptions contains the configurable properties for a Faraday request.
5
- class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
6
- :timeout, :open_timeout, :read_timeout,
7
- :write_timeout, :boundary, :oauth,
8
- :context, :on_data)
9
-
4
+ # @!parse
5
+ # # RequestOptions contains the configurable properties for a Faraday request.
6
+ # class RequestOptions < Options; end
7
+ RequestOptions = Options.new(:params_encoder, :proxy, :bind,
8
+ :timeout, :open_timeout, :read_timeout,
9
+ :write_timeout, :boundary, :oauth,
10
+ :context, :on_data) do
10
11
  def []=(key, value)
11
12
  if key && key.to_sym == :proxy
12
13
  super(key, value ? ProxyOptions.from(value) : nil)
@@ -1,56 +1,63 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # SSL-related options.
5
- #
6
- # @!attribute verify
7
- # @return [Boolean] whether to verify SSL certificates or not
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
- #
13
- # @!attribute ca_file
14
- # @return [String] CA file
15
- #
16
- # @!attribute ca_path
17
- # @return [String] CA path
18
- #
19
- # @!attribute verify_mode
20
- # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
21
- #
22
- # @!attribute cert_store
23
- # @return [OpenSSL::X509::Store] certificate store
24
- #
25
- # @!attribute client_cert
26
- # @return [String, OpenSSL::X509::Certificate] client certificate
27
- #
28
- # @!attribute client_key
29
- # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
30
- #
31
- # @!attribute certificate
32
- # @return [OpenSSL::X509::Certificate] certificate (Excon only)
33
- #
34
- # @!attribute private_key
35
- # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
36
- #
37
- # @!attribute verify_depth
38
- # @return [Integer] maximum depth for the certificate chain verification
39
- #
40
- # @!attribute version
41
- # @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)
42
- #
43
- # @!attribute min_version
44
- # @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)
45
- #
46
- # @!attribute max_version
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)
48
- class SSLOptions < Options.new(:verify, :verify_hostname,
49
- :ca_file, :ca_path, :verify_mode,
50
- :cert_store, :client_cert, :client_key,
51
- :certificate, :private_key, :verify_depth,
52
- :version, :min_version, :max_version)
53
-
4
+ # @!parse
5
+ # # SSL-related options.
6
+ # #
7
+ # # @!attribute verify
8
+ # # @return [Boolean] whether to verify SSL certificates or not
9
+ # #
10
+ # # @!attribute verify_hostname
11
+ # # @return [Boolean] whether to enable hostname verification on server certificates
12
+ # # during the handshake or not (see https://github.com/ruby/openssl/pull/60)
13
+ # #
14
+ # # @!attribute hostname
15
+ # # @return [String] Server hostname used for SNI (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLSocket.html#method-i-hostname-3D)
16
+ # #
17
+ # # @!attribute ca_file
18
+ # # @return [String] CA file
19
+ # #
20
+ # # @!attribute ca_path
21
+ # # @return [String] CA path
22
+ # #
23
+ # # @!attribute verify_mode
24
+ # # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
25
+ # #
26
+ # # @!attribute cert_store
27
+ # # @return [OpenSSL::X509::Store] certificate store
28
+ # #
29
+ # # @!attribute client_cert
30
+ # # @return [String, OpenSSL::X509::Certificate] client certificate
31
+ # #
32
+ # # @!attribute client_key
33
+ # # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
34
+ # #
35
+ # # @!attribute certificate
36
+ # # @return [OpenSSL::X509::Certificate] certificate (Excon only)
37
+ # #
38
+ # # @!attribute private_key
39
+ # # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
40
+ # #
41
+ # # @!attribute verify_depth
42
+ # # @return [Integer] maximum depth for the certificate chain verification
43
+ # #
44
+ # # @!attribute version
45
+ # # @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)
46
+ # #
47
+ # # @!attribute min_version
48
+ # # @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)
49
+ # #
50
+ # # @!attribute max_version
51
+ # # @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)
52
+ # #
53
+ # # @!attribute ciphers
54
+ # # @return [String] cipher list in OpenSSL format (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D)
55
+ # class SSLOptions < Options; end
56
+ SSLOptions = Options.new(:verify, :verify_hostname, :hostname,
57
+ :ca_file, :ca_path, :verify_mode,
58
+ :cert_store, :client_cert, :client_key,
59
+ :certificate, :private_key, :verify_depth,
60
+ :version, :min_version, :max_version, :ciphers) do
54
61
  # @return [Boolean] true if should verify
55
62
  def verify?
56
63
  verify != false
@@ -30,7 +30,7 @@ module Faraday
30
30
  new_value = value
31
31
  end
32
32
 
33
- send("#{key}=", new_value) unless new_value.nil?
33
+ send(:"#{key}=", new_value) unless new_value.nil?
34
34
  end
35
35
  self
36
36
  end
@@ -38,7 +38,7 @@ module Faraday
38
38
  # Public
39
39
  def delete(key)
40
40
  value = send(key)
41
- send("#{key}=", nil)
41
+ send(:"#{key}=", nil)
42
42
  value
43
43
  end
44
44
 
@@ -57,7 +57,7 @@ module Faraday
57
57
  else
58
58
  other_value
59
59
  end
60
- send("#{key}=", new_value) unless new_value.nil?
60
+ send(:"#{key}=", new_value) unless new_value.nil?
61
61
  end
62
62
  self
63
63
  end
@@ -174,6 +174,7 @@ module Faraday
174
174
 
175
175
  memoized_attributes[key.to_sym] = block
176
176
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
177
+ remove_method(key) if method_defined?(key, false)
177
178
  def #{key}() self[:#{key}]; end
178
179
  RUBY
179
180
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ruby2_keywords'
4
3
  require 'faraday/adapter_registry'
5
4
 
6
5
  module Faraday
@@ -28,10 +27,11 @@ module Faraday
28
27
 
29
28
  attr_reader :name
30
29
 
31
- ruby2_keywords def initialize(klass, *args, &block)
30
+ def initialize(klass, *args, **kwargs, &block)
32
31
  @name = klass.to_s
33
32
  REGISTRY.set(klass) if klass.respond_to?(:name)
34
33
  @args = args
34
+ @kwargs = kwargs
35
35
  @block = block
36
36
  end
37
37
 
@@ -54,7 +54,7 @@ module Faraday
54
54
  end
55
55
 
56
56
  def build(app = nil)
57
- klass.new(app, *@args, &@block)
57
+ klass.new(app, *@args, **@kwargs, &@block)
58
58
  end
59
59
  end
60
60
 
@@ -89,52 +89,52 @@ module Faraday
89
89
  @handlers.frozen?
90
90
  end
91
91
 
92
- ruby2_keywords def use(klass, *args, &block)
92
+ def use(klass, ...)
93
93
  if klass.is_a? Symbol
94
- use_symbol(Faraday::Middleware, klass, *args, &block)
94
+ use_symbol(Faraday::Middleware, klass, ...)
95
95
  else
96
96
  raise_if_locked
97
97
  raise_if_adapter(klass)
98
- @handlers << self.class::Handler.new(klass, *args, &block)
98
+ @handlers << self.class::Handler.new(klass, ...)
99
99
  end
100
100
  end
101
101
 
102
- ruby2_keywords def request(key, *args, &block)
103
- use_symbol(Faraday::Request, key, *args, &block)
102
+ def request(key, ...)
103
+ use_symbol(Faraday::Request, key, ...)
104
104
  end
105
105
 
106
- ruby2_keywords def response(key, *args, &block)
107
- use_symbol(Faraday::Response, key, *args, &block)
106
+ def response(...)
107
+ use_symbol(Faraday::Response, ...)
108
108
  end
109
109
 
110
- ruby2_keywords def adapter(klass = NO_ARGUMENT, *args, &block)
110
+ def adapter(klass = NO_ARGUMENT, *args, **kwargs, &block)
111
111
  return @adapter if klass == NO_ARGUMENT || klass.nil?
112
112
 
113
113
  klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
114
- @adapter = self.class::Handler.new(klass, *args, &block)
114
+ @adapter = self.class::Handler.new(klass, *args, **kwargs, &block)
115
115
  end
116
116
 
117
117
  ## methods to push onto the various positions in the stack:
118
118
 
119
- ruby2_keywords def insert(index, *args, &block)
119
+ def insert(index, ...)
120
120
  raise_if_locked
121
121
  index = assert_index(index)
122
- handler = self.class::Handler.new(*args, &block)
122
+ handler = self.class::Handler.new(...)
123
123
  @handlers.insert(index, handler)
124
124
  end
125
125
 
126
126
  alias insert_before insert
127
127
 
128
- ruby2_keywords def insert_after(index, *args, &block)
128
+ def insert_after(index, ...)
129
129
  index = assert_index(index)
130
- insert(index + 1, *args, &block)
130
+ insert(index + 1, ...)
131
131
  end
132
132
 
133
- ruby2_keywords def swap(index, *args, &block)
133
+ def swap(index, ...)
134
134
  raise_if_locked
135
135
  index = assert_index(index)
136
136
  @handlers.delete_at(index)
137
- insert(index, *args, &block)
137
+ insert(index, ...)
138
138
  end
139
139
 
140
140
  def delete(handler)
@@ -238,8 +238,8 @@ module Faraday
238
238
  klass <= Faraday::Adapter
239
239
  end
240
240
 
241
- ruby2_keywords def use_symbol(mod, key, *args, &block)
242
- use(mod.lookup_middleware(key), *args, &block)
241
+ def use_symbol(mod, key, ...)
242
+ use(mod.lookup_middleware(key), ...)
243
243
  end
244
244
 
245
245
  def assert_index(index)
@@ -5,12 +5,14 @@ module Faraday
5
5
  # Middleware for instrumenting Requests.
6
6
  class Instrumentation < Faraday::Middleware
7
7
  # Options class used in Request::Instrumentation class.
8
- class Options < Faraday::Options.new(:name, :instrumenter)
8
+ Options = Faraday::Options.new(:name, :instrumenter) do
9
+ remove_method :name
9
10
  # @return [String]
10
11
  def name
11
12
  self[:name] ||= 'request.faraday'
12
13
  end
13
14
 
15
+ remove_method :instrumenter
14
16
  # @return [Class]
15
17
  def instrumenter
16
18
  self[:instrumenter] ||= ActiveSupport::Notifications
@@ -13,7 +13,7 @@ module Faraday
13
13
  # Doesn't try to encode bodies that already are in string form.
14
14
  class Json < Middleware
15
15
  MIME_TYPE = 'application/json'
16
- MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?json$}.freeze
16
+ MIME_TYPE_REGEX = %r{^application/(vnd\..+\+)?json$}
17
17
 
18
18
  def on_request(env)
19
19
  match_content_type(env) do |data|
@@ -24,7 +24,13 @@ module Faraday
24
24
  private
25
25
 
26
26
  def encode(data)
27
- ::JSON.generate(data)
27
+ if options[:encoder].is_a?(Array) && options[:encoder].size >= 2
28
+ options[:encoder][0].public_send(options[:encoder][1], data)
29
+ elsif options[:encoder].respond_to?(:dump)
30
+ options[:encoder].dump(data)
31
+ else
32
+ ::JSON.generate(data)
33
+ end
28
34
  end
29
35
 
30
36
  def match_content_type(env)
@@ -40,7 +46,16 @@ module Faraday
40
46
  end
41
47
 
42
48
  def body?(env)
43
- (body = env[:body]) && !(body.respond_to?(:to_str) && body.empty?)
49
+ body = env[:body]
50
+ case body
51
+ when true, false
52
+ true
53
+ when nil
54
+ # NOTE: nil can be converted to `"null"`, but this middleware doesn't process `nil` for the compatibility.
55
+ false
56
+ else
57
+ !(body.respond_to?(:to_str) && body.empty?)
58
+ end
44
59
  end
45
60
 
46
61
  def request_type(env)
@@ -24,13 +24,14 @@ module Faraday
24
24
  # @return [String] body
25
25
  # @!attribute options
26
26
  # @return [RequestOptions] options
27
- #
28
- # rubocop:disable Style/StructInheritance
29
- class Request < Struct.new(:http_method, :path, :params, :headers, :body, :options)
30
- # rubocop:enable Style/StructInheritance
31
-
27
+ Request = Struct.new(:http_method, :path, :params, :headers, :body, :options) do
32
28
  extend MiddlewareRegistry
33
29
 
30
+ alias_method :member_get, :[]
31
+ private :member_get
32
+ alias_method :member_set, :[]=
33
+ private :member_set
34
+
34
35
  # @param request_method [String]
35
36
  # @yield [request] for block customization, if block given
36
37
  # @yieldparam request [Request]
@@ -41,6 +42,7 @@ module Faraday
41
42
  end
42
43
  end
43
44
 
45
+ remove_method :params=
44
46
  # Replace params, preserving the existing hash type.
45
47
  #
46
48
  # @param hash [Hash] new params
@@ -48,10 +50,11 @@ module Faraday
48
50
  if params
49
51
  params.replace hash
50
52
  else
51
- super
53
+ member_set(:params, hash)
52
54
  end
53
55
  end
54
56
 
57
+ remove_method :headers=
55
58
  # Replace request headers, preserving the existing hash type.
56
59
  #
57
60
  # @param hash [Hash] new headers
@@ -59,7 +62,7 @@ module Faraday
59
62
  if headers
60
63
  headers.replace hash
61
64
  else
62
- super
65
+ member_set(:headers, hash)
63
66
  end
64
67
  end
65
68
 
@@ -11,6 +11,8 @@ module Faraday
11
11
  @parser_options = parser_options
12
12
  @content_types = Array(content_type)
13
13
  @preserve_raw = preserve_raw
14
+
15
+ process_parser_options
14
16
  end
15
17
 
16
18
  def on_complete(env)
@@ -27,7 +29,11 @@ module Faraday
27
29
  end
28
30
 
29
31
  def parse(body)
30
- ::JSON.parse(body, @parser_options || {}) unless body.strip.empty?
32
+ return if body.strip.empty?
33
+
34
+ decoder, method_name = @decoder_options
35
+
36
+ decoder.public_send(method_name, body, @parser_options || {})
31
37
  end
32
38
 
33
39
  def parse_response?(env)
@@ -47,6 +53,20 @@ module Faraday
47
53
  type = type.split(';', 2).first if type.index(';')
48
54
  type
49
55
  end
56
+
57
+ def process_parser_options
58
+ @decoder_options = @parser_options&.delete(:decoder)
59
+
60
+ @decoder_options =
61
+ if @decoder_options.is_a?(Array) && @decoder_options.size >= 2
62
+ @decoder_options.slice(0, 2)
63
+ elsif @decoder_options&.respond_to?(:load) # rubocop:disable Lint/RedundantSafeNavigation
64
+ # In some versions of Rails, `nil` responds to `load` - hence the safe navigation check above
65
+ [@decoder_options, :load]
66
+ else
67
+ [::JSON, :parse]
68
+ end
69
+ end
50
70
  end
51
71
  end
52
72
  end
@@ -10,11 +10,13 @@ module Faraday
10
10
  # lifecycle to a given Logger object. By default, this logs to STDOUT. See
11
11
  # Faraday::Logging::Formatter to see specifically what is logged.
12
12
  class Logger < Middleware
13
+ DEFAULT_OPTIONS = { formatter: Logging::Formatter }.merge(Logging::Formatter::DEFAULT_OPTIONS).freeze
14
+
13
15
  def initialize(app, logger = nil, options = {})
14
- super(app)
16
+ super(app, options)
15
17
  logger ||= ::Logger.new($stdout)
16
- formatter_class = options.delete(:formatter) || Logging::Formatter
17
- @formatter = formatter_class.new(logger: logger, options: options)
18
+ formatter_class = @options.delete(:formatter)
19
+ @formatter = formatter_class.new(logger: logger, options: @options)
18
20
  yield @formatter if block_given?
19
21
  end
20
22
 
@@ -6,28 +6,32 @@ module Faraday
6
6
  # client or server error responses.
7
7
  class RaiseError < Middleware
8
8
  # rubocop:disable Naming/ConstantName
9
- ClientErrorStatuses = (400...500).freeze
10
- ServerErrorStatuses = (500...600).freeze
9
+ ClientErrorStatuses = (400...500)
10
+ ServerErrorStatuses = (500...600)
11
+ ClientErrorStatusesWithCustomExceptions = {
12
+ 400 => Faraday::BadRequestError,
13
+ 401 => Faraday::UnauthorizedError,
14
+ 403 => Faraday::ForbiddenError,
15
+ 404 => Faraday::ResourceNotFound,
16
+ 408 => Faraday::RequestTimeoutError,
17
+ 409 => Faraday::ConflictError,
18
+ 422 => Faraday::UnprocessableEntityError,
19
+ 429 => Faraday::TooManyRequestsError
20
+ }.freeze
11
21
  # rubocop:enable Naming/ConstantName
12
22
 
23
+ DEFAULT_OPTIONS = { include_request: true, allowed_statuses: [] }.freeze
24
+
13
25
  def on_complete(env)
26
+ return if Array(options[:allowed_statuses]).include?(env[:status])
27
+
14
28
  case env[:status]
15
- when 400
16
- raise Faraday::BadRequestError, response_values(env)
17
- when 401
18
- raise Faraday::UnauthorizedError, response_values(env)
19
- when 403
20
- raise Faraday::ForbiddenError, response_values(env)
21
- when 404
22
- raise Faraday::ResourceNotFound, response_values(env)
29
+ when *ClientErrorStatusesWithCustomExceptions.keys
30
+ raise ClientErrorStatusesWithCustomExceptions[env[:status]], response_values(env)
23
31
  when 407
24
32
  # mimic the behavior that we get with proxy requests with HTTPS
25
33
  msg = %(407 "Proxy Authentication Required")
26
34
  raise Faraday::ProxyAuthError.new(msg, response_values(env))
27
- when 409
28
- raise Faraday::ConflictError, response_values(env)
29
- when 422
30
- raise Faraday::UnprocessableEntityError, response_values(env)
31
35
  when ClientErrorStatuses
32
36
  raise Faraday::ClientError, response_values(env)
33
37
  when ServerErrorStatuses
@@ -37,11 +41,26 @@ module Faraday
37
41
  end
38
42
  end
39
43
 
44
+ # Returns a hash of response data with the following keys:
45
+ # - status
46
+ # - headers
47
+ # - body
48
+ # - request
49
+ #
50
+ # The `request` key is omitted when the middleware is explicitly
51
+ # configured with the option `include_request: false`.
40
52
  def response_values(env)
41
- {
53
+ response = {
42
54
  status: env.status,
43
55
  headers: env.response_headers,
44
- body: env.body,
56
+ body: env.body
57
+ }
58
+
59
+ # Include the request data by default. If the middleware was explicitly
60
+ # configured to _not_ include request data, then omit it.
61
+ return response unless options[:include_request]
62
+
63
+ response.merge(
45
64
  request: {
46
65
  method: env.method,
47
66
  url: env.url,
@@ -50,7 +69,7 @@ module Faraday
50
69
  headers: env.request_headers,
51
70
  body: env.request_body
52
71
  }
53
- }
72
+ )
54
73
  end
55
74
 
56
75
  def query_params(env)
@@ -62,10 +62,10 @@ module Faraday
62
62
  super(key, val)
63
63
  end
64
64
 
65
- def fetch(key, *args, &block)
65
+ def fetch(key, ...)
66
66
  key = KeyMap[key]
67
67
  key = @names.fetch(key.downcase, key)
68
- super(key, *args, &block)
68
+ super(key, ...)
69
69
  end
70
70
 
71
71
  def delete(key)
@@ -77,6 +77,12 @@ module Faraday
77
77
  super(key)
78
78
  end
79
79
 
80
+ def dig(key, *rest)
81
+ key = KeyMap[key]
82
+ key = @names.fetch(key.downcase, key)
83
+ super(key, *rest)
84
+ end
85
+
80
86
  def include?(key)
81
87
  @names.include? key.downcase
82
88
  end
data/lib/faraday/utils.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'base64'
4
3
  require 'uri'
5
4
  require 'faraday/utils/headers'
6
5
  require 'faraday/utils/params_hash'
@@ -26,7 +25,7 @@ module Faraday
26
25
  attr_writer :default_space_encoding
27
26
  end
28
27
 
29
- ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/.freeze
28
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
30
29
 
31
30
  def escape(str)
32
31
  str.to_s.gsub(ESCAPE_RE) do |match|
@@ -38,7 +37,7 @@ module Faraday
38
37
  CGI.unescape str.to_s
39
38
  end
40
39
 
41
- DEFAULT_SEP = /[&;] */n.freeze
40
+ DEFAULT_SEP = /[&;] */n
42
41
 
43
42
  # Adapted from Rack
44
43
  def parse_query(query)
@@ -54,7 +53,7 @@ module Faraday
54
53
  end
55
54
 
56
55
  def basic_header_from(login, pass)
57
- value = Base64.encode64("#{login}:#{pass}")
56
+ value = ["#{login}:#{pass}"].pack('m') # Base64 encoding
58
57
  value.delete!("\n")
59
58
  "Basic #{value}"
60
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.7.4'
4
+ VERSION = '2.13.1'
5
5
  end
@@ -300,14 +300,14 @@ RSpec.describe Faraday::Connection do
300
300
  it 'joins url to base when used relative path' do
301
301
  conn = Faraday.new(url: url)
302
302
  uri = conn.build_exclusive_url('service:search?limit=400')
303
- expect(uri.to_s).to eq('http://service.com/service%3Asearch?limit=400')
303
+ expect(uri.to_s).to eq('http://service.com/service:search?limit=400')
304
304
  end
305
305
 
306
306
  it 'joins url to base when used with path prefix' do
307
307
  conn = Faraday.new(url: url)
308
308
  conn.path_prefix = '/api'
309
309
  uri = conn.build_exclusive_url('service:search?limit=400')
310
- expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400')
310
+ expect(uri.to_s).to eq('http://service.com/api/service:search?limit=400')
311
311
  end
312
312
  end
313
313