faraday 2.7.4 → 2.7.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acdabcdd0a13d304292f17cd6764fba01d12f552cf78bdae3006ee38a3921ad0
4
- data.tar.gz: 13300a1971d6557a4c62f01c4b0c96d1aecb4372b4c8a1ba734022109d9f2c0b
3
+ metadata.gz: 72fbb1db4fce28541cd53b5908e1fc18539ead8322d0b642069bd2e63d2a6543
4
+ data.tar.gz: a5e4f596d8f23e00f064c9789f85fa1cb194cac85168177750b76b3a3e9c7f4d
5
5
  SHA512:
6
- metadata.gz: 0151023e942ae76b69a6bb28e70c792501333bc4f67c670bb990e80917c6b4d63aaa9ee168bd333abff2dd2b1fb54f244568e7a54d5346034d311924b17eabfe
7
- data.tar.gz: 9598f16ed0c19cdfe01be90a1a29e6751b6848d44eac1d481224fbe576a33ff73f631a2bd398f70b5534d4126f8dba9ced68bb17dad5ea8efe93214bf7ce4e1b
6
+ metadata.gz: f880cdd4a42f22ac4eafeab1ddfcfb9e7a8ff0299956a279b207e4ed50d9b86fa09e44e74c4810b9ace3748db5edf6a9f62c73310d09ec1bbf73ec981356d921
7
+ data.tar.gz: 159e971ec7168017e0053511217a8b89314cd25aaf626a3a409db800218e39b172741a1264616c7b770a3ce45e9ee9a0bd5f9dc6fd43511cc4b9f8ae5fa8304a
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [![Faraday](./docs/assets/img/repo-card-slim.png)][website]
1
+ # [![Faraday](./docs/_media/home-logo.svg)][website]
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
4
4
  [![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
@@ -6,13 +6,29 @@
6
6
 
7
7
  Faraday is an HTTP client library abstraction layer that provides a common interface over many
8
8
  adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
9
- You probably don't want to use Faraday directly in your project, as it will lack an actual client library to perform
10
- requests. Instead, you probably want to have a look at [Awesome Faraday][awesome] for a list of available adapters.
9
+ Take a look at [Awesome Faraday][awesome] for a list of available adapters and middleware.
10
+
11
+ ## Why use Faraday?
12
+
13
+ Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses,
14
+ making it easier to build sophisticated API clients or web service libraries that abstract away
15
+ the details of how HTTP requests are made.
16
+
17
+ Faraday comes with a lot of features out of the box, such as:
18
+ * Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
19
+ * Persistent connections (keep-alive)
20
+ * Parallel requests
21
+ * Automatic response parsing (JSON, XML, YAML)
22
+ * Customization of the request/response cycle with middleware
23
+ * Support for streaming responses
24
+ * Support for uploading files
25
+ * And much more!
11
26
 
12
27
  ## Getting Started
13
28
 
14
29
  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.
30
+
31
+ 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](https://github.com/mattbrictson) 🚀
16
32
 
17
33
  ## Supported Ruby versions
18
34
 
@@ -42,14 +58,10 @@ But before you start coding, please read our [Contributing Guide][contributing]
42
58
 
43
59
  ## Copyright
44
60
 
45
- © 2009 - 2023, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
61
+ © 2009 - 2023, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
46
62
 
47
63
  [awesome]: https://github.com/lostisland/awesome-faraday/#adapters
48
64
  [website]: https://lostisland.github.io/faraday
49
- [faraday_team]: https://lostisland.github.io/faraday/team
50
- [contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
65
+ [contributing]: https://github.com/lostisland/faraday/blob/main/.github/CONTRIBUTING.md
51
66
  [apidoc]: https://www.rubydoc.info/github/lostisland/faraday
52
67
  [actions]: https://github.com/lostisland/faraday/actions
53
- [jruby]: http://jruby.org/
54
- [rubinius]: http://rubini.us/
55
- [license]: LICENSE.md
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
@@ -37,11 +39,26 @@ module Faraday
37
39
  end
38
40
  end
39
41
 
42
+ # Returns a hash of response data with the following keys:
43
+ # - status
44
+ # - headers
45
+ # - body
46
+ # - request
47
+ #
48
+ # The `request` key is omitted when the middleware is explicitly
49
+ # configured with the option `include_request: false`.
40
50
  def response_values(env)
41
- {
51
+ response = {
42
52
  status: env.status,
43
53
  headers: env.response_headers,
44
- body: env.body,
54
+ body: env.body
55
+ }
56
+
57
+ # Include the request data by default. If the middleware was explicitly
58
+ # configured to _not_ include request data, then omit it.
59
+ return response unless options.fetch(:include_request, true)
60
+
61
+ response.merge(
45
62
  request: {
46
63
  method: env.method,
47
64
  url: env.url,
@@ -50,7 +67,7 @@ module Faraday
50
67
  headers: env.request_headers,
51
68
  body: env.request_body
52
69
  }
53
- }
70
+ )
54
71
  end
55
72
 
56
73
  def query_params(env)
@@ -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.11'
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')
@@ -137,7 +149,7 @@ RSpec.describe Faraday::Response::RaiseError do
137
149
  describe 'request info' do
138
150
  let(:conn) do
139
151
  Faraday.new do |b|
140
- b.response :raise_error
152
+ b.response :raise_error, **middleware_options
141
153
  b.adapter :test do |stub|
142
154
  stub.post(url, request_body, request_headers) do
143
155
  [400, { 'X-Reason' => 'because' }, 'keep looking']
@@ -145,6 +157,7 @@ RSpec.describe Faraday::Response::RaiseError do
145
157
  end
146
158
  end
147
159
  end
160
+ let(:middleware_options) { {} }
148
161
  let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
149
162
  let(:request_headers) { { 'Authorization' => 'Basic 123' } }
150
163
  let(:url_path) { 'request' }
@@ -168,5 +181,19 @@ RSpec.describe Faraday::Response::RaiseError do
168
181
  expect(ex.response[:request][:body]).to eq(request_body)
169
182
  end
170
183
  end
184
+
185
+ context 'when the include_request option is set to false' do
186
+ let(:middleware_options) { { include_request: false } }
187
+
188
+ it 'does not include request info in the exception' do
189
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
190
+ expect(ex.response.keys).to contain_exactly(
191
+ :status,
192
+ :headers,
193
+ :body
194
+ )
195
+ end
196
+ end
197
+ end
171
198
  end
172
199
  end
data/spec/faraday_spec.rb CHANGED
@@ -18,10 +18,14 @@ RSpec.describe Faraday do
18
18
  end
19
19
 
20
20
  it 'uses method_missing on Faraday if there is no proxyable method' do
21
- expect { Faraday.this_method_does_not_exist }.to raise_error(
22
- NoMethodError,
23
- "undefined method `this_method_does_not_exist' for Faraday:Module"
24
- )
21
+ expected_message =
22
+ if RUBY_VERSION >= '3.3'
23
+ "undefined method `this_method_does_not_exist' for module Faraday"
24
+ else
25
+ "undefined method `this_method_does_not_exist' for Faraday:Module"
26
+ end
27
+
28
+ expect { Faraday.this_method_does_not_exist }.to raise_error(NoMethodError, expected_message)
25
29
  end
26
30
 
27
31
  it 'proxied methods can be accessed' do
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.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - "@technoweenie"
@@ -10,8 +10,22 @@ 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-09-12 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: base64
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: faraday-net_http
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -131,7 +145,7 @@ licenses:
131
145
  - MIT
132
146
  metadata:
133
147
  homepage_uri: https://lostisland.github.io/faraday
134
- changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.4
148
+ changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.11
135
149
  source_code_uri: https://github.com/lostisland/faraday
136
150
  bug_tracker_uri: https://github.com/lostisland/faraday/issues
137
151
  post_install_message: