faraday 2.12.2 → 2.14.3
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/examples/client_test.rb +1 -1
- data/lib/faraday/adapter/test.rb +8 -0
- data/lib/faraday/adapter.rb +7 -6
- data/lib/faraday/connection.rb +5 -2
- data/lib/faraday/encoders/flat_params_encoder.rb +3 -2
- data/lib/faraday/encoders/nested_params_encoder.rb +11 -1
- data/lib/faraday/error.rb +43 -6
- data/lib/faraday/logging/formatter.rb +1 -1
- data/lib/faraday/middleware.rb +1 -1
- data/lib/faraday/options/env.rb +4 -4
- data/lib/faraday/options/proxy_options.rb +6 -3
- data/lib/faraday/options/request_options.rb +1 -1
- data/lib/faraday/options/ssl_options.rb +4 -1
- data/lib/faraday/options.rb +1 -1
- data/lib/faraday/rack_builder.rb +11 -14
- data/lib/faraday/response/logger.rb +5 -3
- data/lib/faraday/response/raise_error.rb +1 -1
- data/lib/faraday/response.rb +7 -3
- data/lib/faraday/utils/headers.rb +5 -5
- data/lib/faraday/version.rb +1 -1
- data/lib/faraday.rb +2 -1
- data/spec/faraday/adapter/test_spec.rb +18 -0
- data/spec/faraday/connection_spec.rb +52 -0
- data/spec/faraday/error_spec.rb +83 -1
- data/spec/faraday/middleware_spec.rb +2 -2
- data/spec/faraday/options/proxy_options_spec.rb +27 -0
- data/spec/faraday/params_encoders/nested_spec.rb +28 -0
- data/spec/faraday/request_spec.rb +9 -0
- data/spec/faraday/response/json_spec.rb +1 -1
- data/spec/faraday/response/logger_spec.rb +26 -5
- data/spec/faraday/response/raise_error_spec.rb +24 -13
- data/spec/faraday/response_spec.rb +7 -0
- data/spec/faraday/utils_spec.rb +2 -1
- metadata +4 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ecc5e9592d7434d7e39bc5cc827be5b62af99e258582468c8b6fd78e0122bf7e
|
|
4
|
+
data.tar.gz: 4f5728ac524a3456a800c8d0159b4569173b1c841f80fae7d0d2704e261b6588
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12567175cd7d08a95ccf8203bffcb9bebf8d1b52f279ce034c3f3e17dc5efc81e08259c2992ff792560ed626dd59ae305c163cb43018860b3c0ae833c3f68855
|
|
7
|
+
data.tar.gz: bb786c688b4629c6bc43e4715715fcd42de120eee3802a3614eca60e17627ff77f40298af500a431158b1f1de8bd0d0bd58817a8793bab92e11bac9aa9b482f2
|
data/examples/client_test.rb
CHANGED
|
@@ -26,7 +26,7 @@ class Client
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Example API client test
|
|
29
|
-
class ClientTest < Test::Unit::TestCase
|
|
29
|
+
class ClientTest < Test::Unit::TestCase # rubocop:disable Style/OneClassPerFile
|
|
30
30
|
def test_httpbingo_name
|
|
31
31
|
stubs = Faraday::Adapter::Test::Stubs.new
|
|
32
32
|
stubs.get('/api') do |env|
|
data/lib/faraday/adapter/test.rb
CHANGED
|
@@ -127,6 +127,14 @@ module Faraday
|
|
|
127
127
|
new_stub(:options, path, headers, &block)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
# Removes all stubs, including the ones that have already been consumed.
|
|
131
|
+
def clear
|
|
132
|
+
@stubs_mutex.synchronize do
|
|
133
|
+
@stack.clear
|
|
134
|
+
@consumed.clear
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
130
138
|
# Raises an error if any of the stubbed calls have not been made.
|
|
131
139
|
def verify_stubbed_calls
|
|
132
140
|
failed_stubs = []
|
data/lib/faraday/adapter.rb
CHANGED
|
@@ -8,6 +8,12 @@ module Faraday
|
|
|
8
8
|
|
|
9
9
|
CONTENT_LENGTH = 'Content-Length'
|
|
10
10
|
|
|
11
|
+
TIMEOUT_KEYS = {
|
|
12
|
+
read: :read_timeout,
|
|
13
|
+
open: :open_timeout,
|
|
14
|
+
write: :write_timeout
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
11
17
|
# This module marks an Adapter as supporting parallel requests.
|
|
12
18
|
module Parallelism
|
|
13
19
|
attr_writer :supports_parallel
|
|
@@ -23,6 +29,7 @@ module Faraday
|
|
|
23
29
|
end
|
|
24
30
|
|
|
25
31
|
extend Parallelism
|
|
32
|
+
|
|
26
33
|
self.supports_parallel = false
|
|
27
34
|
|
|
28
35
|
def initialize(_app = nil, opts = {}, &block)
|
|
@@ -89,12 +96,6 @@ module Faraday
|
|
|
89
96
|
end
|
|
90
97
|
options[key] || options[:timeout]
|
|
91
98
|
end
|
|
92
|
-
|
|
93
|
-
TIMEOUT_KEYS = {
|
|
94
|
-
read: :read_timeout,
|
|
95
|
-
open: :open_timeout,
|
|
96
|
-
write: :write_timeout
|
|
97
|
-
}.freeze
|
|
98
99
|
end
|
|
99
100
|
end
|
|
100
101
|
|
data/lib/faraday/connection.rb
CHANGED
|
@@ -481,8 +481,11 @@ module Faraday
|
|
|
481
481
|
if url && !base.path.end_with?('/')
|
|
482
482
|
base.path = "#{base.path}/" # ensure trailing slash
|
|
483
483
|
end
|
|
484
|
-
|
|
485
|
-
|
|
484
|
+
url = url.to_s if url.respond_to?(:host)
|
|
485
|
+
# Ensure relative url will be parsed correctly (such as `service:search` or `//evil.com`)
|
|
486
|
+
url = "./#{url}" if url.respond_to?(:start_with?) &&
|
|
487
|
+
(url.start_with?('//') ||
|
|
488
|
+
!url.start_with?('http://', 'https://', '/', './', '../'))
|
|
486
489
|
uri = url ? base + url : base
|
|
487
490
|
if params
|
|
488
491
|
uri.query = params.to_query(params_encoder || options.params_encoder)
|
|
@@ -6,6 +6,7 @@ module Faraday
|
|
|
6
6
|
module FlatParamsEncoder
|
|
7
7
|
class << self
|
|
8
8
|
extend Forwardable
|
|
9
|
+
|
|
9
10
|
def_delegators :'Faraday::Utils', :escape, :unescape
|
|
10
11
|
end
|
|
11
12
|
|
|
@@ -76,9 +77,9 @@ module Faraday
|
|
|
76
77
|
|
|
77
78
|
empty_accumulator = {}
|
|
78
79
|
|
|
79
|
-
split_query =
|
|
80
|
+
split_query = query.split('&').filter_map do |pair|
|
|
80
81
|
pair.split('=', 2) if pair && !pair.empty?
|
|
81
|
-
end
|
|
82
|
+
end
|
|
82
83
|
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
|
|
83
84
|
pair[0] = unescape(pair[0])
|
|
84
85
|
pair[1] = true if pair[1].nil?
|
|
@@ -106,6 +106,8 @@ module Faraday
|
|
|
106
106
|
|
|
107
107
|
def decode_pair(key, value, context)
|
|
108
108
|
subkeys = key.scan(SUBKEYS_REGEX)
|
|
109
|
+
validate_params_depth!(subkeys.length)
|
|
110
|
+
|
|
109
111
|
subkeys.each_with_index do |subkey, i|
|
|
110
112
|
is_array = subkey =~ /[\[\]]+\Z/
|
|
111
113
|
subkey = Regexp.last_match.pre_match if is_array
|
|
@@ -145,6 +147,12 @@ module Faraday
|
|
|
145
147
|
is_array ? context << value : context[subkey] = value
|
|
146
148
|
end
|
|
147
149
|
|
|
150
|
+
def validate_params_depth!(depth)
|
|
151
|
+
return unless @param_depth_limit && depth > @param_depth_limit
|
|
152
|
+
|
|
153
|
+
raise Faraday::Error, "exceeded nested parameter depth limit of #{@param_depth_limit}"
|
|
154
|
+
end
|
|
155
|
+
|
|
148
156
|
# Internal: convert a nested hash with purely numeric keys into an array.
|
|
149
157
|
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
|
|
150
158
|
# @!visibility private
|
|
@@ -167,15 +175,17 @@ module Faraday
|
|
|
167
175
|
# for your requests.
|
|
168
176
|
module NestedParamsEncoder
|
|
169
177
|
class << self
|
|
170
|
-
attr_accessor :sort_params, :array_indices
|
|
178
|
+
attr_accessor :sort_params, :array_indices, :param_depth_limit
|
|
171
179
|
|
|
172
180
|
extend Forwardable
|
|
181
|
+
|
|
173
182
|
def_delegators :'Faraday::Utils', :escape, :unescape
|
|
174
183
|
end
|
|
175
184
|
|
|
176
185
|
# Useful default for OAuth and caching.
|
|
177
186
|
@sort_params = true
|
|
178
187
|
@array_indices = false
|
|
188
|
+
@param_depth_limit = 100
|
|
179
189
|
|
|
180
190
|
extend EncodeMethods
|
|
181
191
|
extend DecodeMethods
|
data/lib/faraday/error.rb
CHANGED
|
@@ -79,12 +79,46 @@ module Faraday
|
|
|
79
79
|
|
|
80
80
|
# Pulls out potential parent exception and response hash.
|
|
81
81
|
def exc_msg_and_response(exc, response = nil)
|
|
82
|
-
|
|
82
|
+
case exc
|
|
83
|
+
when Exception
|
|
84
|
+
[exc, exc.message, response]
|
|
85
|
+
when Hash
|
|
86
|
+
[nil, build_error_message_from_hash(exc), exc]
|
|
87
|
+
when Faraday::Env
|
|
88
|
+
[nil, build_error_message_from_env(exc), exc]
|
|
89
|
+
else
|
|
90
|
+
[nil, exc.to_s, response]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def build_error_message_from_hash(hash)
|
|
97
|
+
# Be defensive with external Hash objects - they might be missing keys
|
|
98
|
+
status = hash.fetch(:status, nil)
|
|
99
|
+
request = hash.fetch(:request, nil)
|
|
100
|
+
|
|
101
|
+
return fallback_error_message(status) if request.nil?
|
|
83
102
|
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
method = request.fetch(:method, nil)
|
|
104
|
+
url = request.fetch(:url, nil)
|
|
105
|
+
build_status_error_message(status, method, url)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_error_message_from_env(env)
|
|
109
|
+
# Faraday::Env is internal - we can make reasonable assumptions about its structure
|
|
110
|
+
build_status_error_message(env.status, env.method, env.url)
|
|
111
|
+
end
|
|
86
112
|
|
|
87
|
-
|
|
113
|
+
def build_status_error_message(status, method, url)
|
|
114
|
+
method_str = method ? method.to_s.upcase : ''
|
|
115
|
+
url_str = url ? url.to_s : ''
|
|
116
|
+
"the server responded with status #{status} for #{method_str} #{url_str}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def fallback_error_message(status)
|
|
120
|
+
"the server responded with status #{status} - method and url are not available " \
|
|
121
|
+
'due to include_request: false on Faraday::Response::RaiseError middleware'
|
|
88
122
|
end
|
|
89
123
|
end
|
|
90
124
|
|
|
@@ -121,9 +155,12 @@ module Faraday
|
|
|
121
155
|
end
|
|
122
156
|
|
|
123
157
|
# Raised by Faraday::Response::RaiseError in case of a 422 response.
|
|
124
|
-
class
|
|
158
|
+
class UnprocessableContentError < ClientError
|
|
125
159
|
end
|
|
126
160
|
|
|
161
|
+
# Used to provide compatibility with legacy error name.
|
|
162
|
+
UnprocessableEntityError = UnprocessableContentError
|
|
163
|
+
|
|
127
164
|
# Raised by Faraday::Response::RaiseError in case of a 429 response.
|
|
128
165
|
class TooManyRequestsError < ClientError
|
|
129
166
|
end
|
|
@@ -135,7 +172,7 @@ module Faraday
|
|
|
135
172
|
# A unified client error for timeouts.
|
|
136
173
|
class TimeoutError < ServerError
|
|
137
174
|
def initialize(exc = 'timeout', response = nil)
|
|
138
|
-
super
|
|
175
|
+
super
|
|
139
176
|
end
|
|
140
177
|
end
|
|
141
178
|
|
data/lib/faraday/middleware.rb
CHANGED
data/lib/faraday/options/env.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Faraday
|
|
|
60
60
|
:reason_phrase, :response_body) do
|
|
61
61
|
const_set(:ContentLength, 'Content-Length')
|
|
62
62
|
const_set(:StatusesWithoutBody, Set.new([204, 304]))
|
|
63
|
-
const_set(:SuccessfulStatuses,
|
|
63
|
+
const_set(:SuccessfulStatuses, 200..299)
|
|
64
64
|
|
|
65
65
|
# A Set of HTTP verbs that typically send a body. If no body is set for
|
|
66
66
|
# these requests, the Content-Length header is set to 0.
|
|
@@ -78,7 +78,7 @@ module Faraday
|
|
|
78
78
|
# @param value [Object] a value fitting Option.from(v).
|
|
79
79
|
# @return [Env] from given value
|
|
80
80
|
def self.from(value)
|
|
81
|
-
env = super
|
|
81
|
+
env = super
|
|
82
82
|
if value.respond_to?(:custom_members)
|
|
83
83
|
env.custom_members.update(value.custom_members)
|
|
84
84
|
end
|
|
@@ -90,7 +90,7 @@ module Faraday
|
|
|
90
90
|
return self[current_body] if key == :body
|
|
91
91
|
|
|
92
92
|
if in_member_set?(key)
|
|
93
|
-
super
|
|
93
|
+
super
|
|
94
94
|
else
|
|
95
95
|
custom_members[key]
|
|
96
96
|
end
|
|
@@ -105,7 +105,7 @@ module Faraday
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
if in_member_set?(key)
|
|
108
|
-
super
|
|
108
|
+
super
|
|
109
109
|
else
|
|
110
110
|
custom_members[key] = value
|
|
111
111
|
end
|
|
@@ -7,6 +7,7 @@ module Faraday
|
|
|
7
7
|
# class ProxyOptions < Options; end
|
|
8
8
|
ProxyOptions = Options.new(:uri, :user, :password) do
|
|
9
9
|
extend Forwardable
|
|
10
|
+
|
|
10
11
|
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
|
|
11
12
|
:path, :path=
|
|
12
13
|
|
|
@@ -22,12 +23,14 @@ module Faraday
|
|
|
22
23
|
when URI
|
|
23
24
|
value = { uri: value }
|
|
24
25
|
when Hash, Options
|
|
25
|
-
if
|
|
26
|
-
value
|
|
26
|
+
if value[:uri]
|
|
27
|
+
value = value.dup.tap do |duped|
|
|
28
|
+
duped[:uri] = Utils.URI(duped[:uri])
|
|
29
|
+
end
|
|
27
30
|
end
|
|
28
31
|
end
|
|
29
32
|
|
|
30
|
-
super
|
|
33
|
+
super
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
memoized(:user) { uri&.user && Utils.unescape(uri.user) }
|
|
@@ -11,6 +11,9 @@ module Faraday
|
|
|
11
11
|
# # @return [Boolean] whether to enable hostname verification on server certificates
|
|
12
12
|
# # during the handshake or not (see https://github.com/ruby/openssl/pull/60)
|
|
13
13
|
# #
|
|
14
|
+
# # @!attribute hostname
|
|
15
|
+
# # @return [String] Server hostname used for SNI (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLSocket.html#method-i-hostname-3D)
|
|
16
|
+
# #
|
|
14
17
|
# # @!attribute ca_file
|
|
15
18
|
# # @return [String] CA file
|
|
16
19
|
# #
|
|
@@ -50,7 +53,7 @@ module Faraday
|
|
|
50
53
|
# # @!attribute ciphers
|
|
51
54
|
# # @return [String] cipher list in OpenSSL format (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D)
|
|
52
55
|
# class SSLOptions < Options; end
|
|
53
|
-
SSLOptions = Options.new(:verify, :verify_hostname,
|
|
56
|
+
SSLOptions = Options.new(:verify, :verify_hostname, :hostname,
|
|
54
57
|
:ca_file, :ca_path, :verify_mode,
|
|
55
58
|
:cert_store, :client_cert, :client_key,
|
|
56
59
|
:certificate, :private_key, :verify_depth,
|
data/lib/faraday/options.rb
CHANGED
data/lib/faraday/rack_builder.rb
CHANGED
|
@@ -15,6 +15,11 @@ module Faraday
|
|
|
15
15
|
# Used to detect missing arguments
|
|
16
16
|
NO_ARGUMENT = Object.new
|
|
17
17
|
|
|
18
|
+
LOCK_ERR = "can't modify middleware stack after making a request"
|
|
19
|
+
MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
|
|
20
|
+
"Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
|
|
21
|
+
'For more info, check https://lostisland.github.io/faraday/usage/.'
|
|
22
|
+
|
|
18
23
|
attr_accessor :handlers
|
|
19
24
|
|
|
20
25
|
# Error raised when trying to modify the stack after calling `lock!`
|
|
@@ -27,10 +32,11 @@ module Faraday
|
|
|
27
32
|
|
|
28
33
|
attr_reader :name
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
def initialize(klass, *args, **kwargs, &block)
|
|
31
36
|
@name = klass.to_s
|
|
32
37
|
REGISTRY.set(klass) if klass.respond_to?(:name)
|
|
33
38
|
@args = args
|
|
39
|
+
@kwargs = kwargs
|
|
34
40
|
@block = block
|
|
35
41
|
end
|
|
36
42
|
|
|
@@ -53,7 +59,7 @@ module Faraday
|
|
|
53
59
|
end
|
|
54
60
|
|
|
55
61
|
def build(app = nil)
|
|
56
|
-
klass.new(app, *@args, &@block)
|
|
62
|
+
klass.new(app, *@args, **@kwargs, &@block)
|
|
57
63
|
end
|
|
58
64
|
end
|
|
59
65
|
|
|
@@ -106,11 +112,11 @@ module Faraday
|
|
|
106
112
|
use_symbol(Faraday::Response, ...)
|
|
107
113
|
end
|
|
108
114
|
|
|
109
|
-
|
|
115
|
+
def adapter(klass = NO_ARGUMENT, *args, **kwargs, &block)
|
|
110
116
|
return @adapter if klass == NO_ARGUMENT || klass.nil?
|
|
111
117
|
|
|
112
118
|
klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
|
|
113
|
-
@adapter = self.class::Handler.new(klass, *args, &block)
|
|
119
|
+
@adapter = self.class::Handler.new(klass, *args, **kwargs, &block)
|
|
114
120
|
end
|
|
115
121
|
|
|
116
122
|
## methods to push onto the various positions in the stack:
|
|
@@ -210,17 +216,12 @@ module Faraday
|
|
|
210
216
|
|
|
211
217
|
private
|
|
212
218
|
|
|
213
|
-
LOCK_ERR = "can't modify middleware stack after making a request"
|
|
214
|
-
MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
|
|
215
|
-
"Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
|
|
216
|
-
'For more info, check https://lostisland.github.io/faraday/usage/.'
|
|
217
|
-
|
|
218
219
|
def raise_if_locked
|
|
219
220
|
raise StackLocked, LOCK_ERR if locked?
|
|
220
221
|
end
|
|
221
222
|
|
|
222
223
|
def raise_if_adapter(klass)
|
|
223
|
-
return unless
|
|
224
|
+
return unless klass <= Faraday::Adapter
|
|
224
225
|
|
|
225
226
|
raise 'Adapter should be set using the `adapter` method, not `use`'
|
|
226
227
|
end
|
|
@@ -233,10 +234,6 @@ module Faraday
|
|
|
233
234
|
!@adapter.nil?
|
|
234
235
|
end
|
|
235
236
|
|
|
236
|
-
def is_adapter?(klass) # rubocop:disable Naming/PredicateName
|
|
237
|
-
klass <= Faraday::Adapter
|
|
238
|
-
end
|
|
239
|
-
|
|
240
237
|
def use_symbol(mod, key, ...)
|
|
241
238
|
use(mod.lookup_middleware(key), ...)
|
|
242
239
|
end
|
|
@@ -10,11 +10,13 @@ module Faraday
|
|
|
10
10
|
# lifecycle to a given Logger object. By default, this logs to STDOUT. See
|
|
11
11
|
# Faraday::Logging::Formatter to see specifically what is logged.
|
|
12
12
|
class Logger < Middleware
|
|
13
|
+
DEFAULT_OPTIONS = { formatter: Logging::Formatter }.merge(Logging::Formatter::DEFAULT_OPTIONS).freeze
|
|
14
|
+
|
|
13
15
|
def initialize(app, logger = nil, options = {})
|
|
14
|
-
super(app)
|
|
16
|
+
super(app, options)
|
|
15
17
|
logger ||= ::Logger.new($stdout)
|
|
16
|
-
formatter_class = options.delete(:formatter)
|
|
17
|
-
@formatter = formatter_class.new(logger: logger, options: options)
|
|
18
|
+
formatter_class = @options.delete(:formatter)
|
|
19
|
+
@formatter = formatter_class.new(logger: logger, options: @options)
|
|
18
20
|
yield @formatter if block_given?
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -15,7 +15,7 @@ module Faraday
|
|
|
15
15
|
404 => Faraday::ResourceNotFound,
|
|
16
16
|
408 => Faraday::RequestTimeoutError,
|
|
17
17
|
409 => Faraday::ConflictError,
|
|
18
|
-
422 => Faraday::
|
|
18
|
+
422 => Faraday::UnprocessableContentError,
|
|
19
19
|
429 => Faraday::TooManyRequestsError
|
|
20
20
|
}.freeze
|
|
21
21
|
# rubocop:enable Naming/ConstantName
|
data/lib/faraday/response.rb
CHANGED
|
@@ -33,6 +33,10 @@ module Faraday
|
|
|
33
33
|
finished? ? env.body : nil
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def url
|
|
37
|
+
finished? ? env.url : nil
|
|
38
|
+
end
|
|
39
|
+
|
|
36
40
|
def finished?
|
|
37
41
|
!!env
|
|
38
42
|
end
|
|
@@ -60,9 +64,9 @@ module Faraday
|
|
|
60
64
|
|
|
61
65
|
def to_hash
|
|
62
66
|
{
|
|
63
|
-
status:
|
|
64
|
-
response_headers:
|
|
65
|
-
url:
|
|
67
|
+
status: status, body: body,
|
|
68
|
+
response_headers: headers,
|
|
69
|
+
url: url
|
|
66
70
|
}
|
|
67
71
|
end
|
|
68
72
|
|
|
@@ -51,7 +51,7 @@ module Faraday
|
|
|
51
51
|
|
|
52
52
|
def [](key)
|
|
53
53
|
key = KeyMap[key]
|
|
54
|
-
super
|
|
54
|
+
super || super(@names[key.downcase])
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def []=(key, val)
|
|
@@ -59,13 +59,13 @@ module Faraday
|
|
|
59
59
|
key = (@names[key.downcase] ||= key)
|
|
60
60
|
# join multiple values with a comma
|
|
61
61
|
val = val.to_ary.join(', ') if val.respond_to?(:to_ary)
|
|
62
|
-
super
|
|
62
|
+
super
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def fetch(key, ...)
|
|
66
66
|
key = KeyMap[key]
|
|
67
67
|
key = @names.fetch(key.downcase, key)
|
|
68
|
-
super
|
|
68
|
+
super
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def delete(key)
|
|
@@ -74,13 +74,13 @@ module Faraday
|
|
|
74
74
|
return unless key
|
|
75
75
|
|
|
76
76
|
@names.delete key.downcase
|
|
77
|
-
super
|
|
77
|
+
super
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def dig(key, *rest)
|
|
81
81
|
key = KeyMap[key]
|
|
82
82
|
key = @names.fetch(key.downcase, key)
|
|
83
|
-
super
|
|
83
|
+
super
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def include?(key)
|
data/lib/faraday/version.rb
CHANGED
data/lib/faraday.rb
CHANGED
|
@@ -439,4 +439,22 @@ RSpec.describe Faraday::Adapter::Test do
|
|
|
439
439
|
end
|
|
440
440
|
end
|
|
441
441
|
end
|
|
442
|
+
|
|
443
|
+
describe '#clear' do
|
|
444
|
+
it 'removes pending stubs' do
|
|
445
|
+
stubs.clear
|
|
446
|
+
expect { connection.get('/hello') }.to raise_error(described_class::Stubs::NotFound)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
it 'removes already consumed stubs' do
|
|
450
|
+
expect(connection.get('/hello').body).to eq('hello')
|
|
451
|
+
stubs.clear
|
|
452
|
+
expect { connection.get('/hello') }.to raise_error(described_class::Stubs::NotFound)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it 'leaves the stubs empty' do
|
|
456
|
+
stubs.clear
|
|
457
|
+
expect(stubs).to be_empty
|
|
458
|
+
end
|
|
459
|
+
end
|
|
442
460
|
end
|
|
@@ -311,6 +311,46 @@ RSpec.describe Faraday::Connection do
|
|
|
311
311
|
end
|
|
312
312
|
end
|
|
313
313
|
|
|
314
|
+
context 'with protocol-relative URL (GHSA-33mh-2634-fwr2)' do
|
|
315
|
+
it 'does not allow host override with //evil.com/path' do
|
|
316
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
317
|
+
uri = conn.build_exclusive_url('//evil.com/path')
|
|
318
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it 'does not allow host override with URI("//evil.com/path")' do
|
|
322
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
323
|
+
uri = conn.build_exclusive_url(URI('//evil.com/path?token=1'))
|
|
324
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
325
|
+
expect(uri.query).to eq('token=1')
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it 'does not allow host override with //evil.com:8080/path' do
|
|
329
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
330
|
+
uri = conn.build_exclusive_url('//evil.com:8080/path')
|
|
331
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
it 'does not allow host override with //user:pass@evil.com/path' do
|
|
335
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
336
|
+
uri = conn.build_exclusive_url('//user:pass@evil.com/path')
|
|
337
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it 'does not allow host override with ///evil.com' do
|
|
341
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
342
|
+
uri = conn.build_exclusive_url('///evil.com')
|
|
343
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
it 'still allows single-slash absolute paths' do
|
|
347
|
+
conn.url_prefix = 'http://httpbingo.org/api'
|
|
348
|
+
uri = conn.build_exclusive_url('/safe/path')
|
|
349
|
+
expect(uri.host).to eq('httpbingo.org')
|
|
350
|
+
expect(uri.path).to eq('/safe/path')
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
314
354
|
context 'with a custom `default_uri_parser`' do
|
|
315
355
|
let(:url) { 'http://httpbingo.org' }
|
|
316
356
|
let(:parser) { Addressable::URI }
|
|
@@ -340,6 +380,18 @@ RSpec.describe Faraday::Connection do
|
|
|
340
380
|
url = conn.build_url(nil, b: 2, c: 3)
|
|
341
381
|
expect(url.to_s).to eq('http://httpbingo.org/nigiri?a=1&b=2&c=3')
|
|
342
382
|
end
|
|
383
|
+
|
|
384
|
+
it 'raises a controlled error when URL query params exceed the nested depth limit' do
|
|
385
|
+
original_param_depth_limit = Faraday::NestedParamsEncoder.param_depth_limit
|
|
386
|
+
Faraday::NestedParamsEncoder.param_depth_limit = 2
|
|
387
|
+
|
|
388
|
+
expect { conn.build_url('/nigiri?a[b][c]=1') }.to raise_error(
|
|
389
|
+
Faraday::Error,
|
|
390
|
+
'exceeded nested parameter depth limit of 2'
|
|
391
|
+
)
|
|
392
|
+
ensure
|
|
393
|
+
Faraday::NestedParamsEncoder.param_depth_limit = original_param_depth_limit
|
|
394
|
+
end
|
|
343
395
|
end
|
|
344
396
|
|
|
345
397
|
describe '#build_request' do
|
data/spec/faraday/error_spec.rb
CHANGED
|
@@ -23,7 +23,7 @@ RSpec.describe Faraday::Error do
|
|
|
23
23
|
|
|
24
24
|
it { expect(subject.wrapped_exception).to be_nil }
|
|
25
25
|
it { expect(subject.response).to eq(exception) }
|
|
26
|
-
it { expect(subject.message).to eq('the server responded with status 400') }
|
|
26
|
+
it { expect(subject.message).to eq('the server responded with status 400 - method and url are not available due to include_request: false on Faraday::Response::RaiseError middleware') }
|
|
27
27
|
if RUBY_VERSION >= '3.4'
|
|
28
28
|
it { expect(subject.inspect).to eq('#<Faraday::Error response={status: 400}>') }
|
|
29
29
|
else
|
|
@@ -89,5 +89,87 @@ RSpec.describe Faraday::Error do
|
|
|
89
89
|
it { expect(subject.response_headers).to eq(headers) }
|
|
90
90
|
it { expect(subject.response_body).to eq(body) }
|
|
91
91
|
end
|
|
92
|
+
|
|
93
|
+
context 'with hash missing status key' do
|
|
94
|
+
let(:exception) { { body: 'error body' } }
|
|
95
|
+
|
|
96
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
97
|
+
it { expect(subject.response).to eq(exception) }
|
|
98
|
+
it { expect(subject.message).to eq('the server responded with status - method and url are not available due to include_request: false on Faraday::Response::RaiseError middleware') }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'with hash with status but missing request data' do
|
|
102
|
+
let(:exception) { { status: 404, body: 'not found' } } # missing request key
|
|
103
|
+
|
|
104
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
105
|
+
it { expect(subject.response).to eq(exception) }
|
|
106
|
+
it { expect(subject.message).to eq('the server responded with status 404 - method and url are not available due to include_request: false on Faraday::Response::RaiseError middleware') }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'with hash with status and request but missing method in request' do
|
|
110
|
+
let(:exception) { { status: 404, body: 'not found', request: { url: 'http://example.com/test' } } } # missing method
|
|
111
|
+
|
|
112
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
113
|
+
it { expect(subject.response).to eq(exception) }
|
|
114
|
+
it { expect(subject.message).to eq('the server responded with status 404 for http://example.com/test') }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context 'with hash with status and request but missing url in request' do
|
|
118
|
+
let(:exception) { { status: 404, body: 'not found', request: { method: :get } } } # missing url
|
|
119
|
+
|
|
120
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
121
|
+
it { expect(subject.response).to eq(exception) }
|
|
122
|
+
it { expect(subject.message).to eq('the server responded with status 404 for GET ') }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context 'with properly formed Faraday::Env' do
|
|
126
|
+
# This represents the normal case - a well-formed Faraday::Env object
|
|
127
|
+
# with all the standard properties populated as they would be during
|
|
128
|
+
# a typical HTTP request/response cycle
|
|
129
|
+
let(:exception) { Faraday::Env.new }
|
|
130
|
+
|
|
131
|
+
before do
|
|
132
|
+
exception.status = 500
|
|
133
|
+
exception.method = :post
|
|
134
|
+
exception.url = URI('https://api.example.com/users')
|
|
135
|
+
exception.request = Faraday::RequestOptions.new
|
|
136
|
+
exception.response_headers = { 'content-type' => 'application/json' }
|
|
137
|
+
exception.response_body = '{"error": "Internal server error"}'
|
|
138
|
+
exception.request_headers = { 'authorization' => 'Bearer token123' }
|
|
139
|
+
exception.request_body = '{"name": "John"}'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
143
|
+
it { expect(subject.response).to eq(exception) }
|
|
144
|
+
it { expect(subject.message).to eq('the server responded with status 500 for POST https://api.example.com/users') }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'with Faraday::Env missing status key' do
|
|
148
|
+
let(:exception) { Faraday::Env.new }
|
|
149
|
+
|
|
150
|
+
before do
|
|
151
|
+
exception[:body] = 'error body'
|
|
152
|
+
# Intentionally not setting status
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
156
|
+
it { expect(subject.response).to eq(exception) }
|
|
157
|
+
it { expect(subject.message).to eq('the server responded with status for ') }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
context 'with Faraday::Env with direct method and url properties' do
|
|
161
|
+
let(:exception) { Faraday::Env.new }
|
|
162
|
+
|
|
163
|
+
before do
|
|
164
|
+
exception.status = 404
|
|
165
|
+
exception.method = :get
|
|
166
|
+
exception.url = URI('http://example.com/test')
|
|
167
|
+
exception[:body] = 'not found'
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it { expect(subject.wrapped_exception).to be_nil }
|
|
171
|
+
it { expect(subject.response).to eq(exception) }
|
|
172
|
+
it { expect(subject.message).to eq('the server responded with status 404 for GET http://example.com/test') }
|
|
173
|
+
end
|
|
92
174
|
end
|
|
93
175
|
end
|
|
@@ -52,14 +52,14 @@ RSpec.describe Faraday::Middleware do
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
describe '#close' do
|
|
55
|
-
context "with app that doesn't support
|
|
55
|
+
context "with app that doesn't support #close" do
|
|
56
56
|
it 'should issue warning' do
|
|
57
57
|
is_expected.to receive(:warn)
|
|
58
58
|
subject.close
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
context
|
|
62
|
+
context 'with app that supports #close' do
|
|
63
63
|
it 'should issue warning' do
|
|
64
64
|
expect(app).to receive(:close)
|
|
65
65
|
is_expected.to_not receive(:warn)
|
|
@@ -27,6 +27,33 @@ RSpec.describe Faraday::ProxyOptions do
|
|
|
27
27
|
expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
it 'works with hash' do
|
|
31
|
+
hash = { user: 'user', password: 'pass', uri: 'http://@example.org' }
|
|
32
|
+
options = Faraday::ProxyOptions.from(hash)
|
|
33
|
+
expect(options.user).to eq('user')
|
|
34
|
+
expect(options.password).to eq('pass')
|
|
35
|
+
expect(options.uri).to be_a_kind_of(URI)
|
|
36
|
+
expect(options.path).to eq('')
|
|
37
|
+
expect(options.port).to eq(80)
|
|
38
|
+
expect(options.host).to eq('example.org')
|
|
39
|
+
expect(options.scheme).to eq('http')
|
|
40
|
+
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'works with option' do
|
|
44
|
+
opt_arg = { user: 'user', password: 'pass', uri: 'http://@example.org' }
|
|
45
|
+
option = Faraday::ConnectionOptions.from(proxy: opt_arg)
|
|
46
|
+
options = Faraday::ProxyOptions.from(option.proxy)
|
|
47
|
+
expect(options.user).to eq('user')
|
|
48
|
+
expect(options.password).to eq('pass')
|
|
49
|
+
expect(options.uri).to be_a_kind_of(URI)
|
|
50
|
+
expect(options.path).to eq('')
|
|
51
|
+
expect(options.port).to eq(80)
|
|
52
|
+
expect(options.host).to eq('example.org')
|
|
53
|
+
expect(options.scheme).to eq('http')
|
|
54
|
+
expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
|
|
55
|
+
end
|
|
56
|
+
|
|
30
57
|
it 'works with no auth' do
|
|
31
58
|
proxy = Faraday::ProxyOptions.from 'http://example.org'
|
|
32
59
|
expect(proxy.user).to be_nil
|
|
@@ -5,6 +5,13 @@ require 'rack/utils'
|
|
|
5
5
|
RSpec.describe Faraday::NestedParamsEncoder do
|
|
6
6
|
it_behaves_like 'a params encoder'
|
|
7
7
|
|
|
8
|
+
around do |example|
|
|
9
|
+
original_param_depth_limit = described_class.param_depth_limit
|
|
10
|
+
example.run
|
|
11
|
+
ensure
|
|
12
|
+
described_class.param_depth_limit = original_param_depth_limit
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
it 'decodes arrays' do
|
|
9
16
|
query = 'a[1]=one&a[2]=two&a[3]=three'
|
|
10
17
|
expected = { 'a' => %w[one two three] }
|
|
@@ -53,6 +60,27 @@ RSpec.describe Faraday::NestedParamsEncoder do
|
|
|
53
60
|
expect(subject.decode(query)).to eq(expected)
|
|
54
61
|
end
|
|
55
62
|
|
|
63
|
+
it 'allows nested params within the configured depth limit' do
|
|
64
|
+
described_class.param_depth_limit = 3
|
|
65
|
+
|
|
66
|
+
expect(subject.decode('a[b][c]=1')).to eq({ 'a' => { 'b' => { 'c' => '1' } } })
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'raises a controlled error when nested params exceed the depth limit' do
|
|
70
|
+
described_class.param_depth_limit = 2
|
|
71
|
+
|
|
72
|
+
expect { subject.decode('a[b][c]=1') }.to raise_error(
|
|
73
|
+
Faraday::Error,
|
|
74
|
+
'exceeded nested parameter depth limit of 2'
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'allows disabling the nested params depth limit' do
|
|
79
|
+
described_class.param_depth_limit = nil
|
|
80
|
+
|
|
81
|
+
expect(subject.decode('a[b][c][d]=1')).to eq({ 'a' => { 'b' => { 'c' => { 'd' => '1' } } } })
|
|
82
|
+
end
|
|
83
|
+
|
|
56
84
|
it 'decodes nested final value overrides any type' do
|
|
57
85
|
query = 'a[b][c]=1&a[b]=2'
|
|
58
86
|
expected = { 'a' => { 'b' => '2' } }
|
|
@@ -31,6 +31,15 @@ RSpec.describe Faraday::Request do
|
|
|
31
31
|
it { expect(subject.to_env(conn).url.to_s).to eq('http://httpbingo.org/api/foo.json?a=1') }
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
context 'when setting the url on setup with a protocol-relative URI' do
|
|
35
|
+
let(:block) { proc { |req| req.url URI.parse('//evil.com/path?token=1') } }
|
|
36
|
+
let(:url) { subject.to_env(conn).url }
|
|
37
|
+
|
|
38
|
+
it { expect(url.host).to eq('httpbingo.org') }
|
|
39
|
+
it { expect(url.path).to eq('/api///evil.com/path') }
|
|
40
|
+
it { expect(url.query).to eq('token=1') }
|
|
41
|
+
end
|
|
42
|
+
|
|
34
43
|
context 'when setting the url on setup with a string path and params' do
|
|
35
44
|
let(:block) { proc { |req| req.url 'foo.json', 'a' => 1 } }
|
|
36
45
|
|
|
@@ -106,7 +106,7 @@ RSpec.describe Faraday::Response::Json, type: :response do
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
it 'passes relevant options to JSON parse' do
|
|
109
|
-
expect(
|
|
109
|
+
expect(JSON).to receive(:parse)
|
|
110
110
|
.with(body, options[:parser_options])
|
|
111
111
|
.and_return(result)
|
|
112
112
|
|
|
@@ -21,6 +21,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
|
21
21
|
stubs.post('/ohai') { [200, { 'Content-Type' => 'text/html' }, 'fred'] }
|
|
22
22
|
stubs.post('/ohyes') { [200, { 'Content-Type' => 'text/html' }, 'pebbles'] }
|
|
23
23
|
stubs.get('/rubbles') { [200, { 'Content-Type' => 'application/json' }, rubbles] }
|
|
24
|
+
stubs.get('/8bit') { [200, { 'Content-Type' => 'text/html' }, (+'café!').force_encoding(Encoding::ASCII_8BIT)] }
|
|
24
25
|
stubs.get('/filtered_body') { [200, { 'Content-Type' => 'text/html' }, 'soylent green is people'] }
|
|
25
26
|
stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
|
|
26
27
|
stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
|
|
@@ -189,7 +190,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
|
189
190
|
context 'when logging request body' do
|
|
190
191
|
let(:logger_options) { { bodies: { request: true } } }
|
|
191
192
|
|
|
192
|
-
it '
|
|
193
|
+
it 'logs only request body' do
|
|
193
194
|
conn.post '/ohyes', 'name=Tamago', accept: 'text/html'
|
|
194
195
|
expect(string_io.string).to match(%(name=Tamago))
|
|
195
196
|
expect(string_io.string).not_to match(%(pebbles))
|
|
@@ -199,7 +200,7 @@ RSpec.describe Faraday::Response::Logger do
|
|
|
199
200
|
context 'when logging response body' do
|
|
200
201
|
let(:logger_options) { { bodies: { response: true } } }
|
|
201
202
|
|
|
202
|
-
it '
|
|
203
|
+
it 'logs only response body' do
|
|
203
204
|
conn.post '/ohyes', 'name=Hamachi', accept: 'text/html'
|
|
204
205
|
expect(string_io.string).to match(%(pebbles))
|
|
205
206
|
expect(string_io.string).not_to match(%(name=Hamachi))
|
|
@@ -209,15 +210,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
|
209
210
|
context 'when logging request and response bodies' do
|
|
210
211
|
let(:logger_options) { { bodies: true } }
|
|
211
212
|
|
|
212
|
-
it '
|
|
213
|
+
it 'logs request and response body' do
|
|
213
214
|
conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
|
|
214
215
|
expect(string_io.string).to match(%(name=Ebi))
|
|
215
216
|
expect(string_io.string).to match(%(pebbles))
|
|
216
217
|
end
|
|
217
218
|
|
|
218
|
-
it '
|
|
219
|
+
it 'logs response body object' do
|
|
219
220
|
conn.get '/rubbles', nil, accept: 'text/html'
|
|
220
|
-
expect(string_io.string).to match(%([
|
|
221
|
+
expect(string_io.string).to match(%(["Barney", "Betty", "Bam Bam"]\n))
|
|
221
222
|
end
|
|
222
223
|
|
|
223
224
|
it 'logs filter body' do
|
|
@@ -228,6 +229,26 @@ RSpec.describe Faraday::Response::Logger do
|
|
|
228
229
|
end
|
|
229
230
|
end
|
|
230
231
|
|
|
232
|
+
context 'when bodies are logged by default' do
|
|
233
|
+
before do
|
|
234
|
+
described_class.default_options = { bodies: true }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'logs response body' do
|
|
238
|
+
conn.post '/ohai'
|
|
239
|
+
expect(string_io.string).to match(%(fred))
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'converts to UTF-8' do
|
|
243
|
+
conn.get '/8bit'
|
|
244
|
+
expect(string_io.string).to match(%(caf��!))
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
after do
|
|
248
|
+
described_class.default_options = { bodies: false }
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
231
252
|
context 'when logging errors' do
|
|
232
253
|
let(:logger_options) { { errors: true } }
|
|
233
254
|
|
|
@@ -13,7 +13,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
13
13
|
stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
14
14
|
stub.get('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
15
15
|
stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
16
|
-
stub.get('unprocessable-
|
|
16
|
+
stub.get('unprocessable-content') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
17
17
|
stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
18
18
|
stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
|
|
19
19
|
stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
|
|
@@ -28,7 +28,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
28
28
|
|
|
29
29
|
it 'raises Faraday::BadRequestError for 400 responses' do
|
|
30
30
|
expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) do |ex|
|
|
31
|
-
expect(ex.message).to eq('the server responded with status 400')
|
|
31
|
+
expect(ex.message).to eq('the server responded with status 400 for GET http:/bad-request')
|
|
32
32
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
33
33
|
expect(ex.response[:status]).to eq(400)
|
|
34
34
|
expect(ex.response_status).to eq(400)
|
|
@@ -39,7 +39,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
39
39
|
|
|
40
40
|
it 'raises Faraday::UnauthorizedError for 401 responses' do
|
|
41
41
|
expect { conn.get('unauthorized') }.to raise_error(Faraday::UnauthorizedError) do |ex|
|
|
42
|
-
expect(ex.message).to eq('the server responded with status 401')
|
|
42
|
+
expect(ex.message).to eq('the server responded with status 401 for GET http:/unauthorized')
|
|
43
43
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
44
44
|
expect(ex.response[:status]).to eq(401)
|
|
45
45
|
expect(ex.response_status).to eq(401)
|
|
@@ -50,7 +50,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
50
50
|
|
|
51
51
|
it 'raises Faraday::ForbiddenError for 403 responses' do
|
|
52
52
|
expect { conn.get('forbidden') }.to raise_error(Faraday::ForbiddenError) do |ex|
|
|
53
|
-
expect(ex.message).to eq('the server responded with status 403')
|
|
53
|
+
expect(ex.message).to eq('the server responded with status 403 for GET http:/forbidden')
|
|
54
54
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
55
55
|
expect(ex.response[:status]).to eq(403)
|
|
56
56
|
expect(ex.response_status).to eq(403)
|
|
@@ -61,7 +61,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
61
61
|
|
|
62
62
|
it 'raises Faraday::ResourceNotFound for 404 responses' do
|
|
63
63
|
expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex|
|
|
64
|
-
expect(ex.message).to eq('the server responded with status 404')
|
|
64
|
+
expect(ex.message).to eq('the server responded with status 404 for GET http:/not-found')
|
|
65
65
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
66
66
|
expect(ex.response[:status]).to eq(404)
|
|
67
67
|
expect(ex.response_status).to eq(404)
|
|
@@ -83,7 +83,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
83
83
|
|
|
84
84
|
it 'raises Faraday::RequestTimeoutError for 408 responses' do
|
|
85
85
|
expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
|
|
86
|
-
expect(ex.message).to eq('the server responded with status 408')
|
|
86
|
+
expect(ex.message).to eq('the server responded with status 408 for GET http:/request-timeout')
|
|
87
87
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
88
88
|
expect(ex.response[:status]).to eq(408)
|
|
89
89
|
expect(ex.response_status).to eq(408)
|
|
@@ -94,7 +94,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
94
94
|
|
|
95
95
|
it 'raises Faraday::ConflictError for 409 responses' do
|
|
96
96
|
expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
|
|
97
|
-
expect(ex.message).to eq('the server responded with status 409')
|
|
97
|
+
expect(ex.message).to eq('the server responded with status 409 for GET http:/conflict')
|
|
98
98
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
99
99
|
expect(ex.response[:status]).to eq(409)
|
|
100
100
|
expect(ex.response_status).to eq(409)
|
|
@@ -103,9 +103,20 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
it 'raises Faraday::UnprocessableEntityError for 422 responses' do
|
|
107
|
-
expect { conn.get('unprocessable-
|
|
108
|
-
expect(ex.message).to eq('the server responded with status 422')
|
|
106
|
+
it 'raises legacy Faraday::UnprocessableEntityError for 422 responses' do
|
|
107
|
+
expect { conn.get('unprocessable-content') }.to raise_error(Faraday::UnprocessableEntityError) do |ex|
|
|
108
|
+
expect(ex.message).to eq('the server responded with status 422 for GET http:/unprocessable-content')
|
|
109
|
+
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
110
|
+
expect(ex.response[:status]).to eq(422)
|
|
111
|
+
expect(ex.response_status).to eq(422)
|
|
112
|
+
expect(ex.response_body).to eq('keep looking')
|
|
113
|
+
expect(ex.response_headers['X-Reason']).to eq('because')
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'raises Faraday::UnprocessableContentError for 422 responses' do
|
|
118
|
+
expect { conn.get('unprocessable-content') }.to raise_error(Faraday::UnprocessableContentError) do |ex|
|
|
119
|
+
expect(ex.message).to eq('the server responded with status 422 for GET http:/unprocessable-content')
|
|
109
120
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
110
121
|
expect(ex.response[:status]).to eq(422)
|
|
111
122
|
expect(ex.response_status).to eq(422)
|
|
@@ -116,7 +127,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
116
127
|
|
|
117
128
|
it 'raises Faraday::TooManyRequestsError for 429 responses' do
|
|
118
129
|
expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex|
|
|
119
|
-
expect(ex.message).to eq('the server responded with status 429')
|
|
130
|
+
expect(ex.message).to eq('the server responded with status 429 for GET http:/too-many-requests')
|
|
120
131
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
121
132
|
expect(ex.response[:status]).to eq(429)
|
|
122
133
|
expect(ex.response_status).to eq(429)
|
|
@@ -138,7 +149,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
138
149
|
|
|
139
150
|
it 'raises Faraday::ClientError for other 4xx responses' do
|
|
140
151
|
expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex|
|
|
141
|
-
expect(ex.message).to eq('the server responded with status 499')
|
|
152
|
+
expect(ex.message).to eq('the server responded with status 499 for GET http:/4xx')
|
|
142
153
|
expect(ex.response[:headers]['X-Reason']).to eq('because')
|
|
143
154
|
expect(ex.response[:status]).to eq(499)
|
|
144
155
|
expect(ex.response_status).to eq(499)
|
|
@@ -149,7 +160,7 @@ RSpec.describe Faraday::Response::RaiseError do
|
|
|
149
160
|
|
|
150
161
|
it 'raises Faraday::ServerError for 500 responses' do
|
|
151
162
|
expect { conn.get('server-error') }.to raise_error(Faraday::ServerError) do |ex|
|
|
152
|
-
expect(ex.message).to eq('the server responded with status 500')
|
|
163
|
+
expect(ex.message).to eq('the server responded with status 500 for GET http:/server-error')
|
|
153
164
|
expect(ex.response[:headers]['X-Error']).to eq('bailout')
|
|
154
165
|
expect(ex.response[:status]).to eq(500)
|
|
155
166
|
expect(ex.response_status).to eq(500)
|
|
@@ -13,6 +13,7 @@ RSpec.describe Faraday::Response do
|
|
|
13
13
|
it { expect(subject.success?).to be_falsey }
|
|
14
14
|
it { expect(subject.status).to eq(404) }
|
|
15
15
|
it { expect(subject.body).to eq('yikes') }
|
|
16
|
+
it { expect(subject.url).to eq(URI('https://lostisland.github.io/faraday')) }
|
|
16
17
|
it { expect(subject.headers['Content-Type']).to eq('text/plain') }
|
|
17
18
|
it { expect(subject['content-type']).to eq('text/plain') }
|
|
18
19
|
|
|
@@ -31,6 +32,12 @@ RSpec.describe Faraday::Response do
|
|
|
31
32
|
it { expect(hash[:response_headers]).to eq(subject.headers) }
|
|
32
33
|
it { expect(hash[:body]).to eq(subject.body) }
|
|
33
34
|
it { expect(hash[:url]).to eq(subject.env.url) }
|
|
35
|
+
|
|
36
|
+
context 'when response is not finished' do
|
|
37
|
+
subject { Faraday::Response.new.to_hash }
|
|
38
|
+
|
|
39
|
+
it { is_expected.to eq({ status: nil, body: nil, response_headers: {}, url: nil }) }
|
|
40
|
+
end
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
describe 'marshal serialization support' do
|
data/spec/faraday/utils_spec.rb
CHANGED
|
@@ -33,7 +33,7 @@ RSpec.describe Faraday::Utils do
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it 'parses with URI' do
|
|
36
|
-
with_default_uri_parser(
|
|
36
|
+
with_default_uri_parser(URI) do
|
|
37
37
|
uri = normalize(url)
|
|
38
38
|
expect(uri.host).to eq('example.com')
|
|
39
39
|
end
|
|
@@ -104,6 +104,7 @@ RSpec.describe Faraday::Utils do
|
|
|
104
104
|
min_version: nil,
|
|
105
105
|
max_version: nil,
|
|
106
106
|
verify_hostname: nil,
|
|
107
|
+
hostname: nil,
|
|
107
108
|
ciphers: nil
|
|
108
109
|
}
|
|
109
110
|
end
|
metadata
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: faraday
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.14.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- "@technoweenie"
|
|
8
8
|
- "@iMacTia"
|
|
9
9
|
- "@olleolleolle"
|
|
10
|
-
autorequire:
|
|
11
10
|
bindir: bin
|
|
12
11
|
cert_chain: []
|
|
13
|
-
date:
|
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
14
13
|
dependencies:
|
|
15
14
|
- !ruby/object:Gem::Dependency
|
|
16
15
|
name: faraday-net_http
|
|
@@ -60,7 +59,6 @@ dependencies:
|
|
|
60
59
|
- - ">="
|
|
61
60
|
- !ruby/object:Gem::Version
|
|
62
61
|
version: '0'
|
|
63
|
-
description:
|
|
64
62
|
email: technoweenie@gmail.com
|
|
65
63
|
executables: []
|
|
66
64
|
extensions: []
|
|
@@ -146,11 +144,10 @@ licenses:
|
|
|
146
144
|
- MIT
|
|
147
145
|
metadata:
|
|
148
146
|
homepage_uri: https://lostisland.github.io/faraday
|
|
149
|
-
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.
|
|
147
|
+
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.14.3
|
|
150
148
|
source_code_uri: https://github.com/lostisland/faraday
|
|
151
149
|
bug_tracker_uri: https://github.com/lostisland/faraday/issues
|
|
152
150
|
rubygems_mfa_required: 'true'
|
|
153
|
-
post_install_message:
|
|
154
151
|
rdoc_options: []
|
|
155
152
|
require_paths:
|
|
156
153
|
- lib
|
|
@@ -166,8 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
166
163
|
- !ruby/object:Gem::Version
|
|
167
164
|
version: '0'
|
|
168
165
|
requirements: []
|
|
169
|
-
rubygems_version: 3.
|
|
170
|
-
signing_key:
|
|
166
|
+
rubygems_version: 3.6.9
|
|
171
167
|
specification_version: 4
|
|
172
168
|
summary: HTTP/REST API client library.
|
|
173
169
|
test_files: []
|