faraday 2.3.0 → 2.7.4
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/LICENSE.md +1 -1
- data/README.md +9 -9
- data/examples/client_spec.rb +22 -0
- data/examples/client_test.rb +26 -0
- data/lib/faraday/adapter/test.rb +49 -6
- data/lib/faraday/adapter.rb +3 -4
- data/lib/faraday/connection.rb +36 -37
- data/lib/faraday/logging/formatter.rb +18 -2
- data/lib/faraday/middleware.rb +3 -0
- data/lib/faraday/options/env.rb +31 -7
- data/lib/faraday/options/ssl_options.rb +11 -1
- data/lib/faraday/request/authorization.rb +8 -3
- data/lib/faraday/request.rb +1 -1
- data/lib/faraday/response/logger.rb +4 -0
- data/lib/faraday/response.rb +2 -1
- data/lib/faraday/utils/headers.rb +6 -1
- data/lib/faraday/version.rb +1 -1
- data/spec/faraday/adapter/test_spec.rb +65 -0
- data/spec/faraday/connection_spec.rb +28 -7
- data/spec/faraday/middleware_spec.rb +18 -0
- data/spec/faraday/options/env_spec.rb +6 -0
- data/spec/faraday/request/authorization_spec.rb +35 -0
- data/spec/faraday/request_spec.rb +1 -0
- data/spec/faraday/response/logger_spec.rb +28 -0
- data/spec/faraday/response_spec.rb +3 -1
- data/spec/faraday/utils/headers_spec.rb +20 -2
- data/spec/faraday/utils_spec.rb +2 -1
- data/spec/support/shared_examples/adapter.rb +2 -1
- data/spec/support/shared_examples/request_method.rb +17 -3
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acdabcdd0a13d304292f17cd6764fba01d12f552cf78bdae3006ee38a3921ad0
|
4
|
+
data.tar.gz: 13300a1971d6557a4c62f01c4b0c96d1aecb4372b4c8a1ba734022109d9f2c0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0151023e942ae76b69a6bb28e70c792501333bc4f67c670bb990e80917c6b4d63aaa9ee168bd333abff2dd2b1fb54f244568e7a54d5346034d311924b17eabfe
|
7
|
+
data.tar.gz: 9598f16ed0c19cdfe01be90a1a29e6751b6848d44eac1d481224fbe576a33ff73f631a2bd398f70b5534d4126f8dba9ced68bb17dad5ea8efe93214bf7ce4e1b
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
[](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
|
5
5
|
[](https://github.com/lostisland/faraday/discussions)
|
6
6
|
|
7
|
-
|
8
7
|
Faraday is an HTTP client library abstraction layer that provides a common interface over many
|
9
8
|
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
|
10
9
|
You probably don't want to use Faraday directly in your project, as it will lack an actual client library to perform
|
@@ -42,14 +41,15 @@ Open the issues page and check for the `help wanted` label!
|
|
42
41
|
But before you start coding, please read our [Contributing Guide][contributing]
|
43
42
|
|
44
43
|
## Copyright
|
45
|
-
© 2009 - 2021, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
|
46
44
|
|
47
|
-
[
|
48
|
-
|
45
|
+
© 2009 - 2023, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
|
46
|
+
|
47
|
+
[awesome]: https://github.com/lostisland/awesome-faraday/#adapters
|
48
|
+
[website]: https://lostisland.github.io/faraday
|
49
49
|
[faraday_team]: https://lostisland.github.io/faraday/team
|
50
50
|
[contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
|
51
|
-
[apidoc]:
|
52
|
-
[actions]:
|
53
|
-
[jruby]:
|
54
|
-
[rubinius]:
|
55
|
-
[license]:
|
51
|
+
[apidoc]: https://www.rubydoc.info/github/lostisland/faraday
|
52
|
+
[actions]: https://github.com/lostisland/faraday/actions
|
53
|
+
[jruby]: http://jruby.org/
|
54
|
+
[rubinius]: http://rubini.us/
|
55
|
+
[license]: LICENSE.md
|
data/examples/client_spec.rb
CHANGED
@@ -17,6 +17,11 @@ class Client
|
|
17
17
|
data = JSON.parse(res.body)
|
18
18
|
data['origin']
|
19
19
|
end
|
20
|
+
|
21
|
+
def foo(params)
|
22
|
+
res = @conn.post('/foo', JSON.dump(params))
|
23
|
+
res.status
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
27
|
RSpec.describe Client do
|
@@ -94,4 +99,21 @@ RSpec.describe Client do
|
|
94
99
|
stubs.verify_stubbed_calls
|
95
100
|
end
|
96
101
|
end
|
102
|
+
|
103
|
+
context 'When you want to test the body, you can use a proc as well as string' do
|
104
|
+
it 'tests with a string' do
|
105
|
+
stubs.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
|
106
|
+
|
107
|
+
expect(client.foo(name: 'YK')).to eq 200
|
108
|
+
stubs.verify_stubbed_calls
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'tests with a proc' do
|
112
|
+
check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
|
113
|
+
stubs.post('/foo', check) { [200, {}, ''] }
|
114
|
+
|
115
|
+
expect(client.foo(name: 'YK', created_at: Time.now)).to eq 200
|
116
|
+
stubs.verify_stubbed_calls
|
117
|
+
end
|
118
|
+
end
|
97
119
|
end
|
data/examples/client_test.rb
CHANGED
@@ -18,6 +18,11 @@ class Client
|
|
18
18
|
data = JSON.parse(res.body)
|
19
19
|
data['origin']
|
20
20
|
end
|
21
|
+
|
22
|
+
def foo(params)
|
23
|
+
res = @conn.post('/foo', JSON.dump(params))
|
24
|
+
res.status
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
28
|
# Example API client test
|
@@ -109,6 +114,27 @@ class ClientTest < Test::Unit::TestCase
|
|
109
114
|
stubs.verify_stubbed_calls
|
110
115
|
end
|
111
116
|
|
117
|
+
def test_with_string_body
|
118
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
119
|
+
stub.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
|
120
|
+
end
|
121
|
+
cli = client(stubs)
|
122
|
+
assert_equal 200, cli.foo(name: 'YK')
|
123
|
+
|
124
|
+
stubs.verify_stubbed_calls
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_with_proc_body
|
128
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
129
|
+
check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
|
130
|
+
stub.post('/foo', check) { [200, {}, ''] }
|
131
|
+
end
|
132
|
+
cli = client(stubs)
|
133
|
+
assert_equal 200, cli.foo(name: 'YK', created_at: Time.now)
|
134
|
+
|
135
|
+
stubs.verify_stubbed_calls
|
136
|
+
end
|
137
|
+
|
112
138
|
def client(stubs)
|
113
139
|
conn = Faraday.new do |builder|
|
114
140
|
builder.adapter :test, stubs
|
data/lib/faraday/adapter/test.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'timeout'
|
4
|
+
|
3
5
|
module Faraday
|
4
6
|
class Adapter
|
5
7
|
# @example
|
@@ -26,6 +28,15 @@ module Faraday
|
|
26
28
|
# ]
|
27
29
|
# end
|
28
30
|
#
|
31
|
+
# # Test the request body is the same as the stubbed body
|
32
|
+
# stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] }
|
33
|
+
#
|
34
|
+
# # You can pass a proc as a stubbed body and check the request body in your way.
|
35
|
+
# # In this case, the proc should return true or false.
|
36
|
+
# stub.post('/foo', ->(request_body) do
|
37
|
+
# JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, '']
|
38
|
+
# end
|
39
|
+
#
|
29
40
|
# # You can set strict_mode to exactly match the stubbed requests.
|
30
41
|
# stub.strict_mode = true
|
31
42
|
# end
|
@@ -42,6 +53,12 @@ module Faraday
|
|
42
53
|
#
|
43
54
|
# resp = test.get '/items/2'
|
44
55
|
# resp.body # => 'showing item: 2'
|
56
|
+
#
|
57
|
+
# resp = test.post '/bar', 'name=YK&word=call'
|
58
|
+
# resp.status # => 200
|
59
|
+
#
|
60
|
+
# resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now)
|
61
|
+
# resp.status # => 200
|
45
62
|
class Test < Faraday::Adapter
|
46
63
|
attr_accessor :stubs
|
47
64
|
|
@@ -181,7 +198,7 @@ module Faraday
|
|
181
198
|
[(host.nil? || host == request_host) &&
|
182
199
|
path_match?(request_path, meta) &&
|
183
200
|
params_match?(env) &&
|
184
|
-
(
|
201
|
+
body_match?(request_body) &&
|
185
202
|
headers_match?(request_headers), meta]
|
186
203
|
end
|
187
204
|
|
@@ -222,6 +239,17 @@ module Faraday
|
|
222
239
|
end
|
223
240
|
end
|
224
241
|
|
242
|
+
def body_match?(request_body)
|
243
|
+
return true if body.to_s.empty?
|
244
|
+
|
245
|
+
case body
|
246
|
+
when Proc
|
247
|
+
body.call(request_body)
|
248
|
+
else
|
249
|
+
request_body == body
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
225
253
|
def to_s
|
226
254
|
"#{path} #{body}"
|
227
255
|
end
|
@@ -246,18 +274,33 @@ module Faraday
|
|
246
274
|
stub, meta = stubs.match(env)
|
247
275
|
|
248
276
|
unless stub
|
249
|
-
raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
|
277
|
+
raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
|
250
278
|
"#{env[:url]} #{env[:body]}"
|
251
279
|
end
|
252
280
|
|
253
281
|
block_arity = stub.block.arity
|
282
|
+
params = if block_arity >= 0
|
283
|
+
[env, meta].take(block_arity)
|
284
|
+
else
|
285
|
+
[env, meta]
|
286
|
+
end
|
287
|
+
|
288
|
+
timeout = request_timeout(:open, env[:request])
|
289
|
+
timeout ||= request_timeout(:read, env[:request])
|
290
|
+
|
254
291
|
status, headers, body =
|
255
|
-
if
|
256
|
-
|
292
|
+
if timeout
|
293
|
+
::Timeout.timeout(timeout, Faraday::TimeoutError) do
|
294
|
+
stub.block.call(*params)
|
295
|
+
end
|
257
296
|
else
|
258
|
-
stub.block.call(
|
297
|
+
stub.block.call(*params)
|
259
298
|
end
|
260
|
-
|
299
|
+
|
300
|
+
# We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
|
301
|
+
# See https://github.com/lostisland/faraday/issues/1444
|
302
|
+
# TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version
|
303
|
+
save_response(env, status, body, headers, nil)
|
261
304
|
|
262
305
|
@app.call(env)
|
263
306
|
end
|
data/lib/faraday/adapter.rb
CHANGED
@@ -59,7 +59,7 @@ module Faraday
|
|
59
59
|
|
60
60
|
private
|
61
61
|
|
62
|
-
def save_response(env, status, body, headers = nil, reason_phrase = nil)
|
62
|
+
def save_response(env, status, body, headers = nil, reason_phrase = nil, finished: true)
|
63
63
|
env.status = status
|
64
64
|
env.body = body
|
65
65
|
env.reason_phrase = reason_phrase&.to_s&.strip
|
@@ -68,7 +68,7 @@ module Faraday
|
|
68
68
|
yield(response_headers) if block_given?
|
69
69
|
end
|
70
70
|
|
71
|
-
env.response.finish(env) unless env.parallel?
|
71
|
+
env.response.finish(env) unless env.parallel? || !finished
|
72
72
|
env.response
|
73
73
|
end
|
74
74
|
|
@@ -78,8 +78,7 @@ module Faraday
|
|
78
78
|
# @param type [Symbol] Describes which timeout setting to get: :read,
|
79
79
|
# :write, or :open.
|
80
80
|
# @param options [Hash] Hash containing Symbol keys like :timeout,
|
81
|
-
# :read_timeout, :write_timeout, :open_timeout
|
82
|
-
# :timeout
|
81
|
+
# :read_timeout, :write_timeout, or :open_timeout
|
83
82
|
#
|
84
83
|
# @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
|
85
84
|
# has been set.
|
data/lib/faraday/connection.rb
CHANGED
@@ -130,10 +130,10 @@ module Faraday
|
|
130
130
|
# Makes a GET HTTP request without a body.
|
131
131
|
# @!scope class
|
132
132
|
#
|
133
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
133
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
134
134
|
# all requests. Can also be the options Hash.
|
135
|
-
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
136
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
135
|
+
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
|
136
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
137
137
|
#
|
138
138
|
# @example
|
139
139
|
# conn.get '/items', { page: 1 }, :accept => 'application/json'
|
@@ -152,10 +152,10 @@ module Faraday
|
|
152
152
|
# Makes a HEAD HTTP request without a body.
|
153
153
|
# @!scope class
|
154
154
|
#
|
155
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
155
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
156
156
|
# all requests. Can also be the options Hash.
|
157
|
-
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
158
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
157
|
+
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
|
158
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
159
159
|
#
|
160
160
|
# @example
|
161
161
|
# conn.head '/items/1'
|
@@ -167,10 +167,10 @@ module Faraday
|
|
167
167
|
# Makes a DELETE HTTP request without a body.
|
168
168
|
# @!scope class
|
169
169
|
#
|
170
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
170
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
171
171
|
# all requests. Can also be the options Hash.
|
172
|
-
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
173
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
172
|
+
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
|
173
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
174
174
|
#
|
175
175
|
# @example
|
176
176
|
# conn.delete '/items/1'
|
@@ -182,10 +182,10 @@ module Faraday
|
|
182
182
|
# Makes a TRACE HTTP request without a body.
|
183
183
|
# @!scope class
|
184
184
|
#
|
185
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
185
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
186
186
|
# all requests. Can also be the options Hash.
|
187
|
-
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
188
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
187
|
+
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
|
188
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
189
189
|
#
|
190
190
|
# @example
|
191
191
|
# conn.connect '/items/1'
|
@@ -210,9 +210,9 @@ module Faraday
|
|
210
210
|
#
|
211
211
|
# @overload options(url, params = nil, headers = nil)
|
212
212
|
# Makes an OPTIONS HTTP request to the given URL.
|
213
|
-
# @param url [String] String base URL to sue as a prefix for all requests.
|
214
|
-
# @param params [Hash] Hash of URI query unencoded key/value pairs.
|
215
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
213
|
+
# @param url [String, URI, nil] String base URL to sue as a prefix for all requests.
|
214
|
+
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
|
215
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
216
216
|
#
|
217
217
|
# @example
|
218
218
|
# conn.options '/items/1'
|
@@ -220,7 +220,7 @@ module Faraday
|
|
220
220
|
# @yield [Faraday::Request] for further request customizations
|
221
221
|
# @return [Faraday::Response]
|
222
222
|
def options(*args)
|
223
|
-
return @options if args.
|
223
|
+
return @options if args.empty?
|
224
224
|
|
225
225
|
url, params, headers = *args
|
226
226
|
run_request(:options, url, nil, headers) do |request|
|
@@ -233,10 +233,10 @@ module Faraday
|
|
233
233
|
# Makes a POST HTTP request with a body.
|
234
234
|
# @!scope class
|
235
235
|
#
|
236
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
236
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
237
237
|
# all requests. Can also be the options Hash.
|
238
|
-
# @param body [String] body for the request.
|
239
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
238
|
+
# @param body [String, nil] body for the request.
|
239
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
240
240
|
#
|
241
241
|
# @example
|
242
242
|
# conn.post '/items', data, content_type: 'application/json'
|
@@ -255,20 +255,19 @@ module Faraday
|
|
255
255
|
# Makes a PUT HTTP request with a body.
|
256
256
|
# @!scope class
|
257
257
|
#
|
258
|
-
# @param url [String] The optional String base URL to use as a prefix for
|
258
|
+
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
|
259
259
|
# all requests. Can also be the options Hash.
|
260
|
-
# @param body [String] body for the request.
|
261
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
260
|
+
# @param body [String, nil] body for the request.
|
261
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
262
262
|
#
|
263
263
|
# @example
|
264
|
-
#
|
265
|
-
# conn.post '/items', data, content_type: 'application/json'
|
264
|
+
# conn.put '/products/123', data, content_type: 'application/json'
|
266
265
|
#
|
267
|
-
# #
|
268
|
-
# conn.
|
269
|
-
# req.headers[
|
270
|
-
# req.
|
271
|
-
# req.
|
266
|
+
# # Star a gist.
|
267
|
+
# conn.put 'https://api.github.com/gists/GIST_ID/star' do |req|
|
268
|
+
# req.headers['Accept'] = 'application/vnd.github+json'
|
269
|
+
# req.headers['Authorization'] = 'Bearer <YOUR-TOKEN>'
|
270
|
+
# req.headers['X-GitHub-Api-Version'] = '2022-11-28'
|
272
271
|
# end
|
273
272
|
#
|
274
273
|
# @yield [Faraday::Request] for further request customizations
|
@@ -390,7 +389,7 @@ module Faraday
|
|
390
389
|
# Takes a relative url for a request and combines it with the defaults
|
391
390
|
# set on the connection instance.
|
392
391
|
#
|
393
|
-
# @param url [String]
|
392
|
+
# @param url [String, URI, nil]
|
394
393
|
# @param extra_params [Hash]
|
395
394
|
#
|
396
395
|
# @example
|
@@ -423,10 +422,10 @@ module Faraday
|
|
423
422
|
# Builds and runs the Faraday::Request.
|
424
423
|
#
|
425
424
|
# @param method [Symbol] HTTP method.
|
426
|
-
# @param url [String, URI] String or URI to access.
|
427
|
-
# @param body [
|
425
|
+
# @param url [String, URI, nil] String or URI to access.
|
426
|
+
# @param body [String, nil] The request body that will eventually be converted to
|
428
427
|
# a string.
|
429
|
-
# @param headers [Hash] unencoded HTTP header key/value pairs.
|
428
|
+
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
|
430
429
|
#
|
431
430
|
# @return [Faraday::Response]
|
432
431
|
def run_request(method, url, body, headers)
|
@@ -462,7 +461,7 @@ module Faraday
|
|
462
461
|
|
463
462
|
# Build an absolute URL based on url_prefix.
|
464
463
|
#
|
465
|
-
# @param url [String, URI]
|
464
|
+
# @param url [String, URI, nil]
|
466
465
|
# @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
|
467
466
|
# replace the query values
|
468
467
|
# of the resulting url (default: nil).
|
@@ -471,10 +470,10 @@ module Faraday
|
|
471
470
|
def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
|
472
471
|
url = nil if url.respond_to?(:empty?) && url.empty?
|
473
472
|
base = url_prefix.dup
|
474
|
-
if url && base.path
|
473
|
+
if url && !base.path.end_with?('/')
|
475
474
|
base.path = "#{base.path}/" # ensure trailing slash
|
476
475
|
end
|
477
|
-
url = url.to_s.gsub(':', '%3A') if
|
476
|
+
url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque
|
478
477
|
uri = url ? base + url : base
|
479
478
|
if params
|
480
479
|
uri.query = params.to_query(params_encoder || options.params_encoder)
|
@@ -537,7 +536,7 @@ module Faraday
|
|
537
536
|
end
|
538
537
|
|
539
538
|
def find_default_proxy
|
540
|
-
uri = ENV
|
539
|
+
uri = ENV.fetch('http_proxy', nil)
|
541
540
|
return unless uri && !uri.empty?
|
542
541
|
|
543
542
|
uri = "http://#{uri}" unless uri.match?(/^http/i)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pp'
|
3
|
+
require 'pp' # rubocop:disable Lint/RedundantRequireStatement
|
4
4
|
|
5
5
|
module Faraday
|
6
6
|
module Logging
|
@@ -8,7 +8,7 @@ module Faraday
|
|
8
8
|
class Formatter
|
9
9
|
extend Forwardable
|
10
10
|
|
11
|
-
DEFAULT_OPTIONS = { headers: true, bodies: false,
|
11
|
+
DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false,
|
12
12
|
log_level: :info }.freeze
|
13
13
|
|
14
14
|
def initialize(logger:, options:)
|
@@ -37,6 +37,18 @@ module Faraday
|
|
37
37
|
log_body('response', env[:body]) if env[:body] && log_body?(:response)
|
38
38
|
end
|
39
39
|
|
40
|
+
def exception(exc)
|
41
|
+
return unless log_errors?
|
42
|
+
|
43
|
+
error_log = proc { exc.full_message }
|
44
|
+
public_send(log_level, 'error', &error_log)
|
45
|
+
|
46
|
+
log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error)
|
47
|
+
return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error)
|
48
|
+
|
49
|
+
log_body('error', exc.response_body)
|
50
|
+
end
|
51
|
+
|
40
52
|
def filter(filter_word, filter_replacement)
|
41
53
|
@filter.push([filter_word, filter_replacement])
|
42
54
|
end
|
@@ -77,6 +89,10 @@ module Faraday
|
|
77
89
|
end
|
78
90
|
end
|
79
91
|
|
92
|
+
def log_errors?
|
93
|
+
@options[:errors]
|
94
|
+
end
|
95
|
+
|
80
96
|
def apply_filters(output)
|
81
97
|
@filter.each do |pattern, replacement|
|
82
98
|
output = output.to_s.gsub(pattern, replacement)
|
data/lib/faraday/middleware.rb
CHANGED
data/lib/faraday/options/env.rb
CHANGED
@@ -15,13 +15,19 @@ module Faraday
|
|
15
15
|
# @return [Hash] options for configuring the request.
|
16
16
|
# Options for configuring the request.
|
17
17
|
#
|
18
|
-
# - `:timeout`
|
19
|
-
#
|
20
|
-
# - `:
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
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
|
25
31
|
#
|
26
32
|
# @!attribute request_headers
|
27
33
|
# @return [Hash] HTTP Headers to be sent to the server.
|
@@ -157,6 +163,24 @@ module Faraday
|
|
157
163
|
%(#<#{self.class}#{attrs.join(' ')}>)
|
158
164
|
end
|
159
165
|
|
166
|
+
def stream_response?
|
167
|
+
request.stream_response?
|
168
|
+
end
|
169
|
+
|
170
|
+
def stream_response(&block)
|
171
|
+
size = 0
|
172
|
+
yielded = false
|
173
|
+
block_result = block.call do |chunk| # rubocop:disable Performance/RedundantBlockCall
|
174
|
+
if chunk.bytesize.positive? || size.positive?
|
175
|
+
yielded = true
|
176
|
+
size += chunk.bytesize
|
177
|
+
request.on_data.call(chunk, size, self)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
request.on_data.call(+'', 0, self) unless yielded
|
181
|
+
block_result
|
182
|
+
end
|
183
|
+
|
160
184
|
# @private
|
161
185
|
def custom_members
|
162
186
|
@custom_members ||= {}
|
@@ -6,6 +6,10 @@ module Faraday
|
|
6
6
|
# @!attribute verify
|
7
7
|
# @return [Boolean] whether to verify SSL certificates or not
|
8
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
|
+
#
|
9
13
|
# @!attribute ca_file
|
10
14
|
# @return [String] CA file
|
11
15
|
#
|
@@ -41,7 +45,8 @@ module Faraday
|
|
41
45
|
#
|
42
46
|
# @!attribute max_version
|
43
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)
|
44
|
-
class SSLOptions < Options.new(:verify, :
|
48
|
+
class SSLOptions < Options.new(:verify, :verify_hostname,
|
49
|
+
:ca_file, :ca_path, :verify_mode,
|
45
50
|
:cert_store, :client_cert, :client_key,
|
46
51
|
:certificate, :private_key, :verify_depth,
|
47
52
|
:version, :min_version, :max_version)
|
@@ -55,5 +60,10 @@ module Faraday
|
|
55
60
|
def disable?
|
56
61
|
!verify?
|
57
62
|
end
|
63
|
+
|
64
|
+
# @return [Boolean] true if should verify_hostname
|
65
|
+
def verify_hostname?
|
66
|
+
verify_hostname != false
|
67
|
+
end
|
58
68
|
end
|
59
69
|
end
|
@@ -23,22 +23,27 @@ module Faraday
|
|
23
23
|
def on_request(env)
|
24
24
|
return if env.request_headers[KEY]
|
25
25
|
|
26
|
-
env.request_headers[KEY] = header_from(@type, *@params)
|
26
|
+
env.request_headers[KEY] = header_from(@type, env, *@params)
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
31
|
# @param type [String, Symbol]
|
32
|
+
# @param env [Faraday::Env]
|
32
33
|
# @param params [Array]
|
33
34
|
# @return [String] a header value
|
34
|
-
def header_from(type, *params)
|
35
|
+
def header_from(type, env, *params)
|
35
36
|
if type.to_s.casecmp('basic').zero? && params.size == 2
|
36
37
|
Utils.basic_header_from(*params)
|
37
38
|
elsif params.size != 1
|
38
39
|
raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
|
39
40
|
else
|
40
41
|
value = params.first
|
41
|
-
|
42
|
+
if (value.is_a?(Proc) && value.arity == 1) || (value.respond_to?(:call) && value.method(:call).arity == 1)
|
43
|
+
value = value.call(env)
|
44
|
+
elsif value.is_a?(Proc) || value.respond_to?(:call)
|
45
|
+
value = value.call
|
46
|
+
end
|
42
47
|
"#{type} #{value}"
|
43
48
|
end
|
44
49
|
end
|
data/lib/faraday/request.rb
CHANGED
data/lib/faraday/response.rb
CHANGED
@@ -132,7 +132,12 @@ module Faraday
|
|
132
132
|
|
133
133
|
# Join multiple values with a comma.
|
134
134
|
def add_parsed(key, value)
|
135
|
-
|
135
|
+
if key?(key)
|
136
|
+
self[key] = self[key].to_s
|
137
|
+
self[key] << ', ' << value
|
138
|
+
else
|
139
|
+
self[key] = value
|
140
|
+
end
|
136
141
|
end
|
137
142
|
end
|
138
143
|
end
|
data/lib/faraday/version.rb
CHANGED
@@ -373,5 +373,70 @@ RSpec.describe Faraday::Adapter::Test do
|
|
373
373
|
it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent' }
|
374
374
|
it_behaves_like 'does not raise NotFound even when headers do not satisfy the strict check', '/with_user_agent', { authorization: 'Bearer m_ck', user_agent: 'My Agent', x_special: 'special' }
|
375
375
|
end
|
376
|
+
|
377
|
+
describe 'body_match?' do
|
378
|
+
let(:stubs) do
|
379
|
+
described_class::Stubs.new do |stubs|
|
380
|
+
stubs.post('/no_check') { [200, {}, 'ok'] }
|
381
|
+
stubs.post('/with_string', 'abc') { [200, {}, 'ok'] }
|
382
|
+
stubs.post(
|
383
|
+
'/with_proc',
|
384
|
+
->(request_body) { JSON.parse(request_body, symbolize_names: true) == { x: '!', a: [{ m: [{ a: true }], n: 123 }] } },
|
385
|
+
{ content_type: 'application/json' }
|
386
|
+
) do
|
387
|
+
[200, {}, 'ok']
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
context 'when trying without any args for body' do
|
393
|
+
subject(:without_body) { connection.post('/no_check') }
|
394
|
+
|
395
|
+
it { expect(without_body.status).to eq 200 }
|
396
|
+
end
|
397
|
+
|
398
|
+
context 'when trying with string body stubs' do
|
399
|
+
subject(:with_string) { connection.post('/with_string', 'abc') }
|
400
|
+
|
401
|
+
it { expect(with_string.status).to eq 200 }
|
402
|
+
end
|
403
|
+
|
404
|
+
context 'when trying with proc body stubs' do
|
405
|
+
subject(:with_proc) do
|
406
|
+
connection.post('/with_proc', JSON.dump(a: [{ n: 123, m: [{ a: true }] }], x: '!'), { 'Content-Type' => 'application/json' })
|
407
|
+
end
|
408
|
+
|
409
|
+
it { expect(with_proc.status).to eq 200 }
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
describe 'request timeout' do
|
415
|
+
subject(:request) do
|
416
|
+
connection.get('/sleep') do |req|
|
417
|
+
req.options.timeout = timeout
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
before do
|
422
|
+
stubs.get('/sleep') do
|
423
|
+
sleep(0.01)
|
424
|
+
[200, {}, '']
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
context 'when request is within timeout' do
|
429
|
+
let(:timeout) { 1 }
|
430
|
+
|
431
|
+
it { expect(request.status).to eq 200 }
|
432
|
+
end
|
433
|
+
|
434
|
+
context 'when request is too slow' do
|
435
|
+
let(:timeout) { 0.001 }
|
436
|
+
|
437
|
+
it 'raises an exception' do
|
438
|
+
expect { request }.to raise_error(Faraday::TimeoutError)
|
439
|
+
end
|
440
|
+
end
|
376
441
|
end
|
377
442
|
end
|
@@ -6,7 +6,7 @@ class CustomEncoder
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def decode(params)
|
9
|
-
params.split(',').
|
9
|
+
params.split(',').to_h { |pair| pair.split('-') }
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -131,6 +131,12 @@ RSpec.describe Faraday::Connection do
|
|
131
131
|
it { expect(subject.ssl.verify?).to be_falsey }
|
132
132
|
end
|
133
133
|
|
134
|
+
context 'with verify_hostname false' do
|
135
|
+
let(:options) { { ssl: { verify_hostname: false } } }
|
136
|
+
|
137
|
+
it { expect(subject.ssl.verify_hostname?).to be_falsey }
|
138
|
+
end
|
139
|
+
|
134
140
|
context 'with empty block' do
|
135
141
|
let(:conn) { Faraday::Connection.new {} }
|
136
142
|
|
@@ -304,6 +310,21 @@ RSpec.describe Faraday::Connection do
|
|
304
310
|
expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400')
|
305
311
|
end
|
306
312
|
end
|
313
|
+
|
314
|
+
context 'with a custom `default_uri_parser`' do
|
315
|
+
let(:url) { 'http://httpbingo.org' }
|
316
|
+
let(:parser) { Addressable::URI }
|
317
|
+
|
318
|
+
around do |example|
|
319
|
+
with_default_uri_parser(parser) do
|
320
|
+
example.run
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'does not raise error' do
|
325
|
+
expect { conn.build_exclusive_url('/nigiri') }.not_to raise_error
|
326
|
+
end
|
327
|
+
end
|
307
328
|
end
|
308
329
|
|
309
330
|
describe '#build_url' do
|
@@ -505,7 +526,7 @@ RSpec.describe Faraday::Connection do
|
|
505
526
|
it 'uses env http_proxy' do
|
506
527
|
with_env 'http_proxy' => 'http://proxy.com' do
|
507
528
|
conn = Faraday.new
|
508
|
-
expect(conn.instance_variable_get(
|
529
|
+
expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
|
509
530
|
expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com')
|
510
531
|
end
|
511
532
|
end
|
@@ -513,7 +534,7 @@ RSpec.describe Faraday::Connection do
|
|
513
534
|
it 'uses processes no_proxy before http_proxy' do
|
514
535
|
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do
|
515
536
|
conn = Faraday.new
|
516
|
-
expect(conn.instance_variable_get(
|
537
|
+
expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
|
517
538
|
expect(conn.proxy_for_request('http://google.co.uk')).to be_nil
|
518
539
|
end
|
519
540
|
end
|
@@ -521,7 +542,7 @@ RSpec.describe Faraday::Connection do
|
|
521
542
|
it 'uses env https_proxy' do
|
522
543
|
with_env 'https_proxy' => 'https://proxy.com' do
|
523
544
|
conn = Faraday.new
|
524
|
-
expect(conn.instance_variable_get(
|
545
|
+
expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
|
525
546
|
expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com')
|
526
547
|
end
|
527
548
|
end
|
@@ -529,7 +550,7 @@ RSpec.describe Faraday::Connection do
|
|
529
550
|
it 'uses processes no_proxy before https_proxy' do
|
530
551
|
with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
|
531
552
|
conn = Faraday.new
|
532
|
-
expect(conn.instance_variable_get(
|
553
|
+
expect(conn.instance_variable_get(:@manual_proxy)).to be_falsey
|
533
554
|
expect(conn.proxy_for_request('https://google.co.uk')).to be_nil
|
534
555
|
end
|
535
556
|
end
|
@@ -539,7 +560,7 @@ RSpec.describe Faraday::Connection do
|
|
539
560
|
conn = Faraday.new
|
540
561
|
conn.proxy = 'http://proxy2.com'
|
541
562
|
|
542
|
-
expect(conn.instance_variable_get(
|
563
|
+
expect(conn.instance_variable_get(:@manual_proxy)).to be_truthy
|
543
564
|
expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com')
|
544
565
|
end
|
545
566
|
end
|
@@ -574,7 +595,7 @@ RSpec.describe Faraday::Connection do
|
|
574
595
|
end
|
575
596
|
|
576
597
|
conn.get(url)
|
577
|
-
expect(conn.instance_variable_get(
|
598
|
+
expect(conn.instance_variable_get(:@temp_proxy)).to be_nil
|
578
599
|
end
|
579
600
|
|
580
601
|
it 'dynamically check no proxy' do
|
@@ -33,6 +33,24 @@ RSpec.describe Faraday::Middleware do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
describe '#on_error' do
|
37
|
+
subject do
|
38
|
+
Class.new(described_class) do
|
39
|
+
def on_error(error)
|
40
|
+
# do nothing
|
41
|
+
end
|
42
|
+
end.new(app)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'is called by #call' do
|
46
|
+
expect(app).to receive(:call).and_raise(Faraday::ConnectionFailed)
|
47
|
+
is_expected.to receive(:call).and_call_original
|
48
|
+
is_expected.to receive(:on_error)
|
49
|
+
|
50
|
+
expect { subject.call(double) }.to raise_error(Faraday::ConnectionFailed)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
36
54
|
describe '#close' do
|
37
55
|
context "with app that doesn't support \#close" do
|
38
56
|
it 'should issue warning' do
|
@@ -27,6 +27,12 @@ RSpec.describe Faraday::Env do
|
|
27
27
|
expect(ssl.fetch(:verify, true)).to be_falsey
|
28
28
|
end
|
29
29
|
|
30
|
+
it 'handle verify_hostname when fetching' do
|
31
|
+
ssl = Faraday::SSLOptions.new
|
32
|
+
ssl.verify_hostname = true
|
33
|
+
expect(ssl.fetch(:verify_hostname, false)).to be_truthy
|
34
|
+
end
|
35
|
+
|
30
36
|
it 'retains custom members' do
|
31
37
|
env[:foo] = 'custom 1'
|
32
38
|
env[:bar] = :custom2
|
@@ -72,6 +72,41 @@ RSpec.describe Faraday::Request::Authorization do
|
|
72
72
|
include_examples 'does not interfere with existing authentication'
|
73
73
|
end
|
74
74
|
|
75
|
+
context 'with an argument' do
|
76
|
+
let(:response) { conn.get('/auth-echo', nil, 'middle' => 'crunchy surprise') }
|
77
|
+
|
78
|
+
context 'when passed a proc' do
|
79
|
+
let(:auth_config) { [proc { |env| "proc #{env.request_headers['middle']}" }] }
|
80
|
+
|
81
|
+
it { expect(response.body).to eq('Bearer proc crunchy surprise') }
|
82
|
+
|
83
|
+
include_examples 'does not interfere with existing authentication'
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when passed a lambda' do
|
87
|
+
let(:auth_config) { [->(env) { "lambda #{env.request_headers['middle']}" }] }
|
88
|
+
|
89
|
+
it { expect(response.body).to eq('Bearer lambda crunchy surprise') }
|
90
|
+
|
91
|
+
include_examples 'does not interfere with existing authentication'
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when passed a callable with an argument' do
|
95
|
+
let(:callable) do
|
96
|
+
Class.new do
|
97
|
+
def call(env)
|
98
|
+
"callable #{env.request_headers['middle']}"
|
99
|
+
end
|
100
|
+
end.new
|
101
|
+
end
|
102
|
+
let(:auth_config) { [callable] }
|
103
|
+
|
104
|
+
it { expect(response.body).to eq('Bearer callable crunchy surprise') }
|
105
|
+
|
106
|
+
include_examples 'does not interfere with existing authentication'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
75
110
|
context 'when passed too many arguments' do
|
76
111
|
let(:auth_config) { %w[baz foo] }
|
77
112
|
|
@@ -14,6 +14,7 @@ RSpec.describe Faraday::Request do
|
|
14
14
|
context 'when nothing particular is configured' do
|
15
15
|
it { expect(subject.http_method).to eq(:get) }
|
16
16
|
it { expect(subject.to_env(conn).ssl.verify).to be_falsey }
|
17
|
+
it { expect(subject.to_env(conn).ssl.verify_hostname).to be_falsey }
|
17
18
|
end
|
18
19
|
|
19
20
|
context 'when HTTP method is post' do
|
@@ -64,6 +64,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
64
64
|
expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
|
65
65
|
conn.get '/hello'
|
66
66
|
end
|
67
|
+
|
68
|
+
context 'when no route' do
|
69
|
+
it 'delegates logging to the formatter' do
|
70
|
+
expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
|
71
|
+
expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
|
72
|
+
|
73
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
74
|
+
end
|
75
|
+
end
|
67
76
|
end
|
68
77
|
|
69
78
|
context 'with custom formatter' do
|
@@ -94,6 +103,16 @@ RSpec.describe Faraday::Response::Logger do
|
|
94
103
|
expect(string_io.string).to match('GET http:/hello')
|
95
104
|
end
|
96
105
|
|
106
|
+
it 'logs status' do
|
107
|
+
conn.get '/hello', nil, accept: 'text/html'
|
108
|
+
expect(string_io.string).to match('Status 200')
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'does not log error message by default' do
|
112
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
113
|
+
expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
|
114
|
+
end
|
115
|
+
|
97
116
|
it 'logs request headers by default' do
|
98
117
|
conn.get '/hello', nil, accept: 'text/html'
|
99
118
|
expect(string_io.string).to match(%(Accept: "text/html))
|
@@ -188,6 +207,15 @@ RSpec.describe Faraday::Response::Logger do
|
|
188
207
|
end
|
189
208
|
end
|
190
209
|
|
210
|
+
context 'when logging errors' do
|
211
|
+
let(:logger_options) { { errors: true } }
|
212
|
+
|
213
|
+
it 'logs error message' do
|
214
|
+
expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
|
215
|
+
expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
191
219
|
context 'when using log_level' do
|
192
220
|
let(:logger_options) { { bodies: true, log_level: :debug } }
|
193
221
|
|
@@ -4,7 +4,7 @@ RSpec.describe Faraday::Response do
|
|
4
4
|
subject { Faraday::Response.new(env) }
|
5
5
|
|
6
6
|
let(:env) do
|
7
|
-
Faraday::Env.from(status: 404, body: 'yikes',
|
7
|
+
Faraday::Env.from(status: 404, body: 'yikes', url: Faraday::Utils.URI('https://lostisland.github.io/faraday'),
|
8
8
|
response_headers: { 'Content-Type' => 'text/plain' })
|
9
9
|
end
|
10
10
|
|
@@ -30,6 +30,7 @@ RSpec.describe Faraday::Response do
|
|
30
30
|
it { expect(hash[:status]).to eq(subject.status) }
|
31
31
|
it { expect(hash[:response_headers]).to eq(subject.headers) }
|
32
32
|
it { expect(hash[:body]).to eq(subject.body) }
|
33
|
+
it { expect(hash[:url]).to eq(subject.env.url) }
|
33
34
|
end
|
34
35
|
|
35
36
|
describe 'marshal serialization support' do
|
@@ -45,6 +46,7 @@ RSpec.describe Faraday::Response do
|
|
45
46
|
it { expect(loaded.env[:body]).to eq(env[:body]) }
|
46
47
|
it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) }
|
47
48
|
it { expect(loaded.env[:status]).to eq(env[:status]) }
|
49
|
+
it { expect(loaded.env[:url]).to eq(env[:url]) }
|
48
50
|
end
|
49
51
|
|
50
52
|
describe '#on_complete' do
|
@@ -57,11 +57,11 @@ RSpec.describe Faraday::Utils::Headers do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe '#parse' do
|
60
|
-
before { subject.parse(headers) }
|
61
|
-
|
62
60
|
context 'when response headers leave http status line out' do
|
63
61
|
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n" }
|
64
62
|
|
63
|
+
before { subject.parse(headers) }
|
64
|
+
|
65
65
|
it { expect(subject.keys).to eq(%w[Content-Type]) }
|
66
66
|
it { expect(subject['Content-Type']).to eq('text/html') }
|
67
67
|
it { expect(subject['content-type']).to eq('text/html') }
|
@@ -70,13 +70,31 @@ RSpec.describe Faraday::Utils::Headers do
|
|
70
70
|
context 'when response headers values include a colon' do
|
71
71
|
let(:headers) { "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://httpbingo.org/\r\n\r\n" }
|
72
72
|
|
73
|
+
before { subject.parse(headers) }
|
74
|
+
|
73
75
|
it { expect(subject['location']).to eq('http://httpbingo.org/') }
|
74
76
|
end
|
75
77
|
|
76
78
|
context 'when response headers include a blank line' do
|
77
79
|
let(:headers) { "HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n" }
|
78
80
|
|
81
|
+
before { subject.parse(headers) }
|
82
|
+
|
79
83
|
it { expect(subject['content-type']).to eq('text/html') }
|
80
84
|
end
|
85
|
+
|
86
|
+
context 'when response headers include already stored keys' do
|
87
|
+
let(:headers) { "HTTP/1.1 200 OK\r\nX-Numbers: 123\r\n\r\n" }
|
88
|
+
|
89
|
+
before do
|
90
|
+
h = subject
|
91
|
+
h[:x_numbers] = 8
|
92
|
+
h.parse(headers)
|
93
|
+
end
|
94
|
+
|
95
|
+
it do
|
96
|
+
expect(subject[:x_numbers]).to eq('8, 123')
|
97
|
+
end
|
98
|
+
end
|
81
99
|
end
|
82
100
|
end
|
data/spec/faraday/utils_spec.rb
CHANGED
@@ -37,7 +37,8 @@ shared_examples 'adapter examples' do |**options|
|
|
37
37
|
|
38
38
|
let(:conn) do
|
39
39
|
conn_options[:ssl] ||= {}
|
40
|
-
conn_options[:ssl][:ca_file] ||= ENV
|
40
|
+
conn_options[:ssl][:ca_file] ||= ENV.fetch('SSL_FILE', nil)
|
41
|
+
conn_options[:ssl][:verify_hostname] ||= ENV['SSL_VERIFY_HOSTNAME'] == 'yes'
|
41
42
|
|
42
43
|
Faraday.new(remote, conn_options) do |conn|
|
43
44
|
conn.request :url_encoded
|
@@ -153,12 +153,19 @@ shared_examples 'a request method' do |http_method|
|
|
153
153
|
let(:streamed) { [] }
|
154
154
|
|
155
155
|
context 'when response is empty' do
|
156
|
-
it do
|
156
|
+
it 'handles streaming' do
|
157
|
+
env = nil
|
157
158
|
conn.public_send(http_method, '/') do |req|
|
158
|
-
req.options.on_data = proc
|
159
|
+
req.options.on_data = proc do |chunk, size, block_env|
|
160
|
+
streamed << [chunk, size]
|
161
|
+
env ||= block_env
|
162
|
+
end
|
159
163
|
end
|
160
164
|
|
161
165
|
expect(streamed).to eq([['', 0]])
|
166
|
+
# TODO: enable this after updating all existing adapters to the new streaming API
|
167
|
+
# expect(env).to be_a(Faraday::Env)
|
168
|
+
# expect(env.status).to eq(200)
|
162
169
|
end
|
163
170
|
end
|
164
171
|
|
@@ -166,12 +173,19 @@ shared_examples 'a request method' do |http_method|
|
|
166
173
|
before { request_stub.to_return(body: big_string) }
|
167
174
|
|
168
175
|
it 'handles streaming' do
|
176
|
+
env = nil
|
169
177
|
response = conn.public_send(http_method, '/') do |req|
|
170
|
-
req.options.on_data = proc
|
178
|
+
req.options.on_data = proc do |chunk, size, block_env|
|
179
|
+
streamed << [chunk, size]
|
180
|
+
env ||= block_env
|
181
|
+
end
|
171
182
|
end
|
172
183
|
|
173
184
|
expect(response.body).to eq('')
|
174
185
|
check_streaming_response(streamed, chunk_size: 16 * 1024)
|
186
|
+
# TODO: enable this after updating all existing adapters to the new streaming API
|
187
|
+
# expect(env).to be_a(Faraday::Env)
|
188
|
+
# expect(env.status).to eq(200)
|
175
189
|
end
|
176
190
|
end
|
177
191
|
end
|
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.
|
4
|
+
version: 2.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "@technoweenie"
|
@@ -10,22 +10,28 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2023-01-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: faraday-net_http
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- - "
|
19
|
+
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '2.0'
|
22
|
+
- - "<"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '3.1'
|
22
25
|
type: :runtime
|
23
26
|
prerelease: false
|
24
27
|
version_requirements: !ruby/object:Gem::Requirement
|
25
28
|
requirements:
|
26
|
-
- - "
|
29
|
+
- - ">="
|
27
30
|
- !ruby/object:Gem::Version
|
28
31
|
version: '2.0'
|
32
|
+
- - "<"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '3.1'
|
29
35
|
- !ruby/object:Gem::Dependency
|
30
36
|
name: ruby2_keywords
|
31
37
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,7 +131,7 @@ licenses:
|
|
125
131
|
- MIT
|
126
132
|
metadata:
|
127
133
|
homepage_uri: https://lostisland.github.io/faraday
|
128
|
-
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.
|
134
|
+
changelog_uri: https://github.com/lostisland/faraday/releases/tag/v2.7.4
|
129
135
|
source_code_uri: https://github.com/lostisland/faraday
|
130
136
|
bug_tracker_uri: https://github.com/lostisland/faraday/issues
|
131
137
|
post_install_message:
|