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 +4 -4
- data/README.md +22 -10
- data/Rakefile +3 -1
- data/lib/faraday/adapter/test.rb +2 -2
- data/lib/faraday/connection.rb +11 -16
- data/lib/faraday/error.rb +13 -3
- data/lib/faraday/logging/formatter.rb +12 -16
- data/lib/faraday/options/connection_options.rb +7 -6
- data/lib/faraday/options/env.rb +67 -68
- data/lib/faraday/options/proxy_options.rb +7 -3
- data/lib/faraday/options/request_options.rb +7 -6
- data/lib/faraday/options/ssl_options.rb +51 -50
- data/lib/faraday/options.rb +1 -0
- data/lib/faraday/request/instrumentation.rb +3 -1
- data/lib/faraday/request/json.rb +10 -1
- data/lib/faraday/request.rb +10 -7
- data/lib/faraday/response/raise_error.rb +20 -3
- data/lib/faraday/version.rb +1 -1
- data/spec/faraday/error_spec.rb +31 -6
- data/spec/faraday/options/options_spec.rb +1 -1
- data/spec/faraday/options/proxy_options_spec.rb +8 -0
- data/spec/faraday/request/json_spec.rb +24 -0
- data/spec/faraday/response/logger_spec.rb +10 -0
- data/spec/faraday/response/raise_error_spec.rb +28 -1
- data/spec/faraday_spec.rb +8 -4
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72fbb1db4fce28541cd53b5908e1fc18539ead8322d0b642069bd2e63d2a6543
|
4
|
+
data.tar.gz: a5e4f596d8f23e00f064c9789f85fa1cb194cac85168177750b76b3a3e9c7f4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f880cdd4a42f22ac4eafeab1ddfcfb9e7a8ff0299956a279b207e4ed50d9b86fa09e44e74c4810b9ace3748db5edf6a9f62c73310d09ec1bbf73ec981356d921
|
7
|
+
data.tar.gz: 159e971ec7168017e0053511217a8b89314cd25aaf626a3a409db800218e39b172741a1264616c7b770a3ce45e9ee9a0bd5f9dc6fd43511cc4b9f8ae5fa8304a
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [][website]
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/faraday)
|
4
4
|
[](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
|
-
|
10
|
-
|
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
|
-
|
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
|
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
|
-
[
|
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
data/lib/faraday/adapter/test.rb
CHANGED
@@ -184,7 +184,7 @@ module Faraday
|
|
184
184
|
end
|
185
185
|
|
186
186
|
# Stub request
|
187
|
-
|
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
|
data/lib/faraday/connection.rb
CHANGED
@@ -514,22 +514,17 @@ module Faraday
|
|
514
514
|
return if Faraday.ignore_env_proxy
|
515
515
|
|
516
516
|
uri = nil
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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'
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
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 }
|
data/lib/faraday/options/env.rb
CHANGED
@@ -1,71 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Faraday
|
4
|
-
# @!
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# - `:
|
28
|
-
#
|
29
|
-
# - `:
|
30
|
-
# - `:
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
ContentLength
|
62
|
-
StatusesWithoutBody
|
63
|
-
SuccessfulStatuses
|
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
|
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
|
-
#
|
5
|
-
#
|
6
|
-
|
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
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
data/lib/faraday/options.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/faraday/request/json.rb
CHANGED
@@ -40,7 +40,16 @@ module Faraday
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def body?(env)
|
43
|
-
|
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)
|
data/lib/faraday/request.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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)
|
data/lib/faraday/version.rb
CHANGED
data/spec/faraday/error_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe Faraday::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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
|
@@ -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
|
-
|
22
|
-
|
23
|
-
|
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
|
+
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-
|
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.
|
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:
|