faraday 2.7.4 → 2.7.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acdabcdd0a13d304292f17cd6764fba01d12f552cf78bdae3006ee38a3921ad0
4
- data.tar.gz: 13300a1971d6557a4c62f01c4b0c96d1aecb4372b4c8a1ba734022109d9f2c0b
3
+ metadata.gz: e4aa57af93476ba31117b14ed37bea950bf9b677d4dcca13ca1296a3ac2c3ff7
4
+ data.tar.gz: 98b3cb7b7c5c08eba9f58ad96181757d6cd7fc7431ac47ae19e8c95a25de12f9
5
5
  SHA512:
6
- metadata.gz: 0151023e942ae76b69a6bb28e70c792501333bc4f67c670bb990e80917c6b4d63aaa9ee168bd333abff2dd2b1fb54f244568e7a54d5346034d311924b17eabfe
7
- data.tar.gz: 9598f16ed0c19cdfe01be90a1a29e6751b6848d44eac1d481224fbe576a33ff73f631a2bd398f70b5534d4126f8dba9ced68bb17dad5ea8efe93214bf7ce4e1b
6
+ metadata.gz: 28f98f568e844799353a00d5ff49511f7bdb759a50edd3de2d4194fbb348dc14d1ef0294d854016ccdcbec915546225ebb2cf6dec354d6e7fbbf707b00cfc170
7
+ data.tar.gz: 3506cebb9ad1fbd1dd38c1804e18cfd7d7352796d11fa564cde9ce0eee1b1a8ba6d07acda4b179662e5b6eb23baf6f70173240cf8a6b69834d2db9c740a80e25
data/README.md CHANGED
@@ -12,7 +12,8 @@ requests. Instead, you probably want to have a look at [Awesome Faraday][awesome
12
12
  ## Getting Started
13
13
 
14
14
  The best starting point is the [Faraday Website][website], with its introduction and explanation.
15
- Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally.
15
+
16
+ Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally, or take a look at [Advanced techniques for calling HTTP APIs in Ruby](https://mattbrictson.com/blog/advanced-http-techniques-in-ruby) blog post from @mattbrictson 🚀
16
17
 
17
18
  ## Supported Ruby versions
18
19
 
data/Rakefile CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'rspec/core/rake_task'
4
4
 
5
- RSpec::Core::RakeTask.new(:spec)
5
+ RSpec::Core::RakeTask.new(:spec) do |task|
6
+ task.ruby_opts = %w[-W]
7
+ end
6
8
 
7
9
  task default: :spec
@@ -184,7 +184,7 @@ module Faraday
184
184
  end
185
185
 
186
186
  # Stub request
187
- 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
188
188
  # @param env [Faraday::Env]
189
189
  def matches?(env)
190
190
  request_host = env[:url].host
@@ -275,7 +275,7 @@ module Faraday
275
275
 
276
276
  unless stub
277
277
  raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
278
- "#{env[:url]} #{env[:body]}"
278
+ "#{env[:url]} #{env[:body]} #{env[:headers]}"
279
279
  end
280
280
 
281
281
  block_arity = stub.block.arity
@@ -514,22 +514,17 @@ module Faraday
514
514
  return if Faraday.ignore_env_proxy
515
515
 
516
516
  uri = nil
517
- if URI.parse('').respond_to?(:find_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
529
- uri = find_default_proxy
530
- end
531
- else
532
- 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
533
528
  uri = find_default_proxy
534
529
  end
535
530
  ProxyOptions.from(uri) if uri
data/lib/faraday/error.rb CHANGED
@@ -29,15 +29,21 @@ module Faraday
29
29
  end
30
30
 
31
31
  def response_status
32
- @response[:status] if @response
32
+ return unless @response
33
+
34
+ @response.is_a?(Faraday::Response) ? @response.status : @response[:status]
33
35
  end
34
36
 
35
37
  def response_headers
36
- @response[:headers] if @response
38
+ return unless @response
39
+
40
+ @response.is_a?(Faraday::Response) ? @response.headers : @response[:headers]
37
41
  end
38
42
 
39
43
  def response_body
40
- @response[:body] if @response
44
+ return unless @response
45
+
46
+ @response.is_a?(Faraday::Response) ? @response.body : @response[:body]
41
47
  end
42
48
 
43
49
  protected
@@ -106,6 +112,10 @@ module Faraday
106
112
  class ProxyAuthError < ClientError
107
113
  end
108
114
 
115
+ # Raised by Faraday::Response::RaiseError in case of a 408 response.
116
+ class RequestTimeoutError < ClientError
117
+ end
118
+
109
119
  # Raised by Faraday::Response::RaiseError in case of a 409 response.
110
120
  class ConflictError < ClientError
111
121
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pp' # rubocop:disable Lint/RedundantRequireStatement
3
+ require 'pp'
4
4
 
5
5
  module Faraday
6
6
  module Logging
@@ -13,25 +13,26 @@ module Faraday
13
13
 
14
14
  def initialize(logger:, options:)
15
15
  @logger = logger
16
- @filter = []
17
16
  @options = DEFAULT_OPTIONS.merge(options)
17
+ unless %i[debug info warn error fatal].include?(@options[:log_level])
18
+ @options[:log_level] = :info
19
+ end
20
+ @filter = []
18
21
  end
19
22
 
20
23
  def_delegators :@logger, :debug, :info, :warn, :error, :fatal
21
24
 
22
25
  def request(env)
23
- request_log = proc do
26
+ public_send(log_level, 'request') do
24
27
  "#{env.method.upcase} #{apply_filters(env.url.to_s)}"
25
28
  end
26
- public_send(log_level, 'request', &request_log)
27
29
 
28
30
  log_headers('request', env.request_headers) if log_headers?(:request)
29
31
  log_body('request', env[:body]) if env[:body] && log_body?(:request)
30
32
  end
31
33
 
32
34
  def response(env)
33
- status = proc { "Status #{env.status}" }
34
- public_send(log_level, 'response', &status)
35
+ public_send(log_level, 'response') { "Status #{env.status}" }
35
36
 
36
37
  log_headers('response', env.response_headers) if log_headers?(:response)
37
38
  log_body('response', env[:body]) if env[:body] && log_body?(:response)
@@ -40,8 +41,7 @@ module Faraday
40
41
  def exception(exc)
41
42
  return unless log_errors?
42
43
 
43
- error_log = proc { exc.full_message }
44
- public_send(log_level, 'error', &error_log)
44
+ public_send(log_level, 'error') { exc.full_message }
45
45
 
46
46
  log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error)
47
47
  return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error)
@@ -56,6 +56,8 @@ module Faraday
56
56
  private
57
57
 
58
58
  def dump_headers(headers)
59
+ return if headers.nil?
60
+
59
61
  headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
60
62
  end
61
63
 
@@ -101,21 +103,15 @@ module Faraday
101
103
  end
102
104
 
103
105
  def log_level
104
- unless %i[debug info warn error fatal].include?(@options[:log_level])
105
- return :info
106
- end
107
-
108
106
  @options[:log_level]
109
107
  end
110
108
 
111
109
  def log_headers(type, headers)
112
- headers_log = proc { apply_filters(dump_headers(headers)) }
113
- public_send(log_level, type, &headers_log)
110
+ public_send(log_level, type) { apply_filters(dump_headers(headers)) }
114
111
  end
115
112
 
116
113
  def log_body(type, body)
117
- body_log = proc { apply_filters(dump_body(body)) }
118
- public_send(log_level, type, &body_log)
114
+ public_send(log_level, type) { apply_filters(dump_body(body)) }
119
115
  end
120
116
  end
121
117
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # ConnectionOptions contains the configurable properties for a Faraday
5
- # connection object.
6
- class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
7
- :parallel_manager, :params, :headers,
8
- :builder_class)
9
-
4
+ # @!parse
5
+ # # ConnectionOptions contains the configurable properties for a Faraday
6
+ # # connection object.
7
+ # class ConnectionOptions < Options; end
8
+ ConnectionOptions = Options.new(:request, :proxy, :ssl, :builder, :url,
9
+ :parallel_manager, :params, :headers,
10
+ :builder_class) do
10
11
  options request: RequestOptions, ssl: SSLOptions
11
12
 
12
13
  memoized(:request) { self.class.options_for(:request).new }
@@ -1,71 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- # @!attribute method
5
- # @return [Symbol] HTTP method (`:get`, `:post`)
6
- #
7
- # @!attribute body
8
- # @return [String] The request body that will eventually be converted to a
9
- # string.
10
- #
11
- # @!attribute url
12
- # @return [URI] URI instance for the current request.
13
- #
14
- # @!attribute request
15
- # @return [Hash] options for configuring the request.
16
- # Options for configuring the request.
17
- #
18
- # - `:timeout` - time limit for the entire request (Integer in
19
- # seconds)
20
- # - `:open_timeout` - time limit for just the connection phase (e.g.
21
- # handshake) (Integer in seconds)
22
- # - `:read_timeout` - time limit for the first response byte received from
23
- # the server (Integer in seconds)
24
- # - `:write_timeout` - time limit for the client to send the request to the
25
- # server (Integer in seconds)
26
- # - `:on_data` - Proc for streaming
27
- # - `:proxy` - Hash of proxy options
28
- # - `:uri` - Proxy server URI
29
- # - `:user` - Proxy server username
30
- # - `:password` - Proxy server password
31
- #
32
- # @!attribute request_headers
33
- # @return [Hash] HTTP Headers to be sent to the server.
34
- #
35
- # @!attribute ssl
36
- # @return [Hash] options for configuring SSL requests
37
- #
38
- # @!attribute parallel_manager
39
- # @return [Object] sent if the connection is in parallel mode
40
- #
41
- # @!attribute params
42
- # @return [Hash]
43
- #
44
- # @!attribute response
45
- # @return [Response]
46
- #
47
- # @!attribute response_headers
48
- # @return [Hash] HTTP headers from the server
49
- #
50
- # @!attribute status
51
- # @return [Integer] HTTP response status code
52
- #
53
- # @!attribute reason_phrase
54
- # @return [String]
55
- class Env < Options.new(:method, :request_body, :url, :request,
56
- :request_headers, :ssl, :parallel_manager, :params,
57
- :response, :response_headers, :status,
58
- :reason_phrase, :response_body)
59
-
60
- # rubocop:disable Naming/ConstantName
61
- ContentLength = 'Content-Length'
62
- StatusesWithoutBody = Set.new [204, 304]
63
- SuccessfulStatuses = (200..299).freeze
64
- # rubocop:enable Naming/ConstantName
4
+ # @!parse
5
+ # # @!attribute method
6
+ # # @return [Symbol] HTTP method (`:get`, `:post`)
7
+ # #
8
+ # # @!attribute body
9
+ # # @return [String] The request body that will eventually be converted to a
10
+ # # string.
11
+ # #
12
+ # # @!attribute url
13
+ # # @return [URI] URI instance for the current request.
14
+ # #
15
+ # # @!attribute request
16
+ # # @return [Hash] options for configuring the request.
17
+ # # Options for configuring the request.
18
+ # #
19
+ # # - `:timeout` - time limit for the entire request (Integer in
20
+ # # seconds)
21
+ # # - `:open_timeout` - time limit for just the connection phase (e.g.
22
+ # # handshake) (Integer in seconds)
23
+ # # - `:read_timeout` - time limit for the first response byte received from
24
+ # # the server (Integer in seconds)
25
+ # # - `:write_timeout` - time limit for the client to send the request to the
26
+ # # server (Integer in seconds)
27
+ # # - `:on_data` - Proc for streaming
28
+ # # - `:proxy` - Hash of proxy options
29
+ # # - `:uri` - Proxy server URI
30
+ # # - `:user` - Proxy server username
31
+ # # - `:password` - Proxy server password
32
+ # #
33
+ # # @!attribute request_headers
34
+ # # @return [Hash] HTTP Headers to be sent to the server.
35
+ # #
36
+ # # @!attribute ssl
37
+ # # @return [Hash] options for configuring SSL requests
38
+ # #
39
+ # # @!attribute parallel_manager
40
+ # # @return [Object] sent if the connection is in parallel mode
41
+ # #
42
+ # # @!attribute params
43
+ # # @return [Hash]
44
+ # #
45
+ # # @!attribute response
46
+ # # @return [Response]
47
+ # #
48
+ # # @!attribute response_headers
49
+ # # @return [Hash] HTTP headers from the server
50
+ # #
51
+ # # @!attribute status
52
+ # # @return [Integer] HTTP response status code
53
+ # #
54
+ # # @!attribute reason_phrase
55
+ # # @return [String]
56
+ # class Env < Options; end
57
+ Env = Options.new(:method, :request_body, :url, :request,
58
+ :request_headers, :ssl, :parallel_manager, :params,
59
+ :response, :response_headers, :status,
60
+ :reason_phrase, :response_body) do
61
+ const_set(:ContentLength, 'Content-Length')
62
+ const_set(:StatusesWithoutBody, Set.new([204, 304]))
63
+ const_set(:SuccessfulStatuses, (200..299).freeze)
65
64
 
66
65
  # A Set of HTTP verbs that typically send a body. If no body is set for
67
66
  # these requests, the Content-Length header is set to 0.
68
- MethodsWithBodies = Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym))
67
+ const_set(:MethodsWithBodies, Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym)))
69
68
 
70
69
  options request: RequestOptions,
71
70
  request_headers: Utils::Headers, response_headers: Utils::Headers
@@ -126,25 +125,25 @@ module Faraday
126
125
 
127
126
  # @return [Boolean] true if status is in the set of {SuccessfulStatuses}.
128
127
  def success?
129
- SuccessfulStatuses.include?(status)
128
+ Env::SuccessfulStatuses.include?(status)
130
129
  end
131
130
 
132
131
  # @return [Boolean] true if there's no body yet, and the method is in the
133
- # set of {MethodsWithBodies}.
132
+ # set of {Env::MethodsWithBodies}.
134
133
  def needs_body?
135
- !body && MethodsWithBodies.include?(method)
134
+ !body && Env::MethodsWithBodies.include?(method)
136
135
  end
137
136
 
138
137
  # Sets content length to zero and the body to the empty string.
139
138
  def clear_body
140
- request_headers[ContentLength] = '0'
139
+ request_headers[Env::ContentLength] = '0'
141
140
  self.body = +''
142
141
  end
143
142
 
144
143
  # @return [Boolean] true if the status isn't in the set of
145
- # {StatusesWithoutBody}.
144
+ # {Env::StatusesWithoutBody}.
146
145
  def parse_body?
147
- !StatusesWithoutBody.include?(status)
146
+ !Env::StatusesWithoutBody.include?(status)
148
147
  end
149
148
 
150
149
  # @return [Boolean] true if there is a parallel_manager
@@ -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.
@@ -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,57 @@
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 ca_file
15
+ # # @return [String] CA file
16
+ # #
17
+ # # @!attribute ca_path
18
+ # # @return [String] CA path
19
+ # #
20
+ # # @!attribute verify_mode
21
+ # # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
22
+ # #
23
+ # # @!attribute cert_store
24
+ # # @return [OpenSSL::X509::Store] certificate store
25
+ # #
26
+ # # @!attribute client_cert
27
+ # # @return [String, OpenSSL::X509::Certificate] client certificate
28
+ # #
29
+ # # @!attribute client_key
30
+ # # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
31
+ # #
32
+ # # @!attribute certificate
33
+ # # @return [OpenSSL::X509::Certificate] certificate (Excon only)
34
+ # #
35
+ # # @!attribute private_key
36
+ # # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
37
+ # #
38
+ # # @!attribute verify_depth
39
+ # # @return [Integer] maximum depth for the certificate chain verification
40
+ # #
41
+ # # @!attribute version
42
+ # # @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)
43
+ # #
44
+ # # @!attribute min_version
45
+ # # @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)
46
+ # #
47
+ # # @!attribute max_version
48
+ # # @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)
49
+ # class SSLOptions < Options; end
50
+ SSLOptions = Options.new(:verify, :verify_hostname,
51
+ :ca_file, :ca_path, :verify_mode,
52
+ :cert_store, :client_cert, :client_key,
53
+ :certificate, :private_key, :verify_depth,
54
+ :version, :min_version, :max_version) do
54
55
  # @return [Boolean] true if should verify
55
56
  def verify?
56
57
  verify != false
@@ -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
@@ -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
@@ -40,7 +40,16 @@ module Faraday
40
40
  end
41
41
 
42
42
  def body?(env)
43
- (body = env[:body]) && !(body.respond_to?(:to_str) && body.empty?)
43
+ body = env[:body]
44
+ case body
45
+ when true, false
46
+ true
47
+ when nil
48
+ # NOTE: nil can be converted to `"null"`, but this middleware doesn't process `nil` for the compatibility.
49
+ false
50
+ else
51
+ !(body.respond_to?(:to_str) && body.empty?)
52
+ end
44
53
  end
45
54
 
46
55
  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
 
@@ -24,6 +24,8 @@ module Faraday
24
24
  # mimic the behavior that we get with proxy requests with HTTPS
25
25
  msg = %(407 "Proxy Authentication Required")
26
26
  raise Faraday::ProxyAuthError.new(msg, response_values(env))
27
+ when 408
28
+ raise Faraday::RequestTimeoutError, response_values(env)
27
29
  when 409
28
30
  raise Faraday::ConflictError, response_values(env)
29
31
  when 422
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Faraday
4
- VERSION = '2.7.4'
4
+ VERSION = '2.7.10'
5
5
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe Faraday::ClientError do
3
+ RSpec.describe Faraday::Error do
4
4
  describe '.initialize' do
5
5
  subject { described_class.new(exception, response) }
6
6
  let(:response) { nil }
@@ -12,8 +12,10 @@ RSpec.describe Faraday::ClientError do
12
12
  it { expect(subject.response).to be_nil }
13
13
  it { expect(subject.message).to eq(exception.message) }
14
14
  it { expect(subject.backtrace).to eq(exception.backtrace) }
15
- it { expect(subject.inspect).to eq('#<Faraday::ClientError wrapped=#<RuntimeError: test>>') }
15
+ it { expect(subject.inspect).to eq('#<Faraday::Error wrapped=#<RuntimeError: test>>') }
16
16
  it { expect(subject.response_status).to be_nil }
17
+ it { expect(subject.response_headers).to be_nil }
18
+ it { expect(subject.response_body).to be_nil }
17
19
  end
18
20
 
19
21
  context 'with response hash' do
@@ -22,8 +24,10 @@ RSpec.describe Faraday::ClientError do
22
24
  it { expect(subject.wrapped_exception).to be_nil }
23
25
  it { expect(subject.response).to eq(exception) }
24
26
  it { expect(subject.message).to eq('the server responded with status 400') }
25
- it { expect(subject.inspect).to eq('#<Faraday::ClientError response={:status=>400}>') }
27
+ it { expect(subject.inspect).to eq('#<Faraday::Error response={:status=>400}>') }
26
28
  it { expect(subject.response_status).to eq(400) }
29
+ it { expect(subject.response_headers).to be_nil }
30
+ it { expect(subject.response_body).to be_nil }
27
31
  end
28
32
 
29
33
  context 'with string' do
@@ -32,8 +36,10 @@ RSpec.describe Faraday::ClientError do
32
36
  it { expect(subject.wrapped_exception).to be_nil }
33
37
  it { expect(subject.response).to be_nil }
34
38
  it { expect(subject.message).to eq('custom message') }
35
- it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: custom message>>') }
39
+ it { expect(subject.inspect).to eq('#<Faraday::Error #<Faraday::Error: custom message>>') }
36
40
  it { expect(subject.response_status).to be_nil }
41
+ it { expect(subject.response_headers).to be_nil }
42
+ it { expect(subject.response_body).to be_nil }
37
43
  end
38
44
 
39
45
  context 'with anything else #to_s' do
@@ -42,8 +48,10 @@ RSpec.describe Faraday::ClientError do
42
48
  it { expect(subject.wrapped_exception).to be_nil }
43
49
  it { expect(subject.response).to be_nil }
44
50
  it { expect(subject.message).to eq('["error1", "error2"]') }
45
- it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: ["error1", "error2"]>>') }
51
+ it { expect(subject.inspect).to eq('#<Faraday::Error #<Faraday::Error: ["error1", "error2"]>>') }
46
52
  it { expect(subject.response_status).to be_nil }
53
+ it { expect(subject.response_headers).to be_nil }
54
+ it { expect(subject.response_body).to be_nil }
47
55
  end
48
56
 
49
57
  context 'with exception string and response hash' do
@@ -53,8 +61,25 @@ RSpec.describe Faraday::ClientError do
53
61
  it { expect(subject.wrapped_exception).to be_nil }
54
62
  it { expect(subject.response).to eq(response) }
55
63
  it { expect(subject.message).to eq('custom message') }
56
- it { expect(subject.inspect).to eq('#<Faraday::ClientError response={:status=>400}>') }
64
+ it { expect(subject.inspect).to eq('#<Faraday::Error response={:status=>400}>') }
57
65
  it { expect(subject.response_status).to eq(400) }
66
+ it { expect(subject.response_headers).to be_nil }
67
+ it { expect(subject.response_body).to be_nil }
68
+ end
69
+
70
+ context 'with exception and response object' do
71
+ let(:exception) { RuntimeError.new('test') }
72
+ let(:body) { { test: 'test' } }
73
+ let(:headers) { { 'Content-Type' => 'application/json' } }
74
+ let(:response) { Faraday::Response.new(status: 400, response_headers: headers, response_body: body) }
75
+
76
+ it { expect(subject.wrapped_exception).to eq(exception) }
77
+ it { expect(subject.response).to eq(response) }
78
+ it { expect(subject.message).to eq(exception.message) }
79
+ it { expect(subject.backtrace).to eq(exception.backtrace) }
80
+ it { expect(subject.response_status).to eq(400) }
81
+ it { expect(subject.response_headers).to eq(headers) }
82
+ it { expect(subject.response_body).to eq(body) }
58
83
  end
59
84
  end
60
85
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  RSpec.describe Faraday::Options do
4
4
  SubOptions = Class.new(Faraday::Options.new(:sub_a, :sub_b))
5
- class ParentOptions < Faraday::Options.new(:a, :b, :c)
5
+ ParentOptions = Faraday::Options.new(:a, :b, :c) do
6
6
  options c: SubOptions
7
7
  end
8
8
 
@@ -32,6 +32,14 @@ RSpec.describe Faraday::ProxyOptions do
32
32
  expect(proxy.user).to be_nil
33
33
  expect(proxy.password).to be_nil
34
34
  end
35
+
36
+ it 'treats empty string as nil' do
37
+ proxy = nil
38
+ proxy_string = proxy.to_s # => empty string
39
+ options = Faraday::ProxyOptions.from proxy_string
40
+ expect(options).to be_a_kind_of(Faraday::ProxyOptions)
41
+ expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
42
+ end
35
43
  end
36
44
 
37
45
  it 'allows hash access' do
@@ -73,6 +73,30 @@ RSpec.describe Faraday::Request::Json do
73
73
  end
74
74
  end
75
75
 
76
+ context 'true body' do
77
+ let(:result) { process(true) }
78
+
79
+ it 'encodes body' do
80
+ expect(result_body).to eq('true')
81
+ end
82
+
83
+ it 'adds content type' do
84
+ expect(result_type).to eq('application/json')
85
+ end
86
+ end
87
+
88
+ context 'false body' do
89
+ let(:result) { process(false) }
90
+
91
+ it 'encodes body' do
92
+ expect(result_body).to eq('false')
93
+ end
94
+
95
+ it 'adds content type' do
96
+ expect(result_type).to eq('application/json')
97
+ end
98
+ end
99
+
76
100
  context 'object body with json type' do
77
101
  let(:result) { process({ a: 1 }, 'application/json; charset=utf-8') }
78
102
 
@@ -25,6 +25,7 @@ RSpec.describe Faraday::Response::Logger do
25
25
  stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
26
26
  stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
27
27
  stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] }
28
+ stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' }
28
29
  end
29
30
  end
30
31
  end
@@ -216,6 +217,15 @@ RSpec.describe Faraday::Response::Logger do
216
217
  end
217
218
  end
218
219
 
220
+ context 'when logging headers and errors' do
221
+ let(:logger_options) { { headers: true, errors: true } }
222
+
223
+ it 'logs error message' do
224
+ expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed)
225
+ expect(string_io.string).to match(%(Failed to open TCP connection))
226
+ end
227
+ end
228
+
219
229
  context 'when using log_level' do
220
230
  let(:logger_options) { { bodies: true, log_level: :debug } }
221
231
 
@@ -11,6 +11,7 @@ RSpec.describe Faraday::Response::RaiseError do
11
11
  stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
12
12
  stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
13
13
  stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
14
+ stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
14
15
  stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
15
16
  stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
16
17
  stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
@@ -79,6 +80,17 @@ RSpec.describe Faraday::Response::RaiseError do
79
80
  end
80
81
  end
81
82
 
83
+ it 'raises Faraday::RequestTimeoutError for 408 responses' do
84
+ expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
85
+ expect(ex.message).to eq('the server responded with status 408')
86
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
87
+ expect(ex.response[:status]).to eq(408)
88
+ expect(ex.response_status).to eq(408)
89
+ expect(ex.response_body).to eq('keep looking')
90
+ expect(ex.response_headers['X-Reason']).to eq('because')
91
+ end
92
+ end
93
+
82
94
  it 'raises Faraday::ConflictError for 409 responses' do
83
95
  expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
84
96
  expect(ex.message).to eq('the server responded with status 409')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faraday
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.4
4
+ version: 2.7.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-01-20 00:00:00.000000000 Z
13
+ date: 2023-07-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday-net_http
@@ -131,7 +131,7 @@ licenses:
131
131
  - MIT
132
132
  metadata:
133
133
  homepage_uri: https://lostisland.github.io/faraday
134
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.4
134
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.10
135
135
  source_code_uri: https://github.com/lostisland/faraday
136
136
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
137
137
  post_install_message: