faraday 0.17.6 → 1.10.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/CHANGELOG.md +156 -8
- data/LICENSE.md +1 -1
- data/README.md +16 -358
- data/Rakefile +1 -7
- data/examples/client_spec.rb +97 -0
- data/examples/client_test.rb +118 -0
- data/lib/faraday/adapter/test.rb +118 -69
- data/lib/faraday/adapter/typhoeus.rb +4 -1
- data/lib/faraday/adapter.rb +72 -22
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/autoload.rb +39 -36
- data/lib/faraday/connection.rb +343 -185
- data/lib/faraday/dependency_loader.rb +39 -0
- data/lib/faraday/deprecate.rb +7 -6
- data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
- data/lib/faraday/error.rb +28 -40
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/methods.rb +6 -0
- data/lib/faraday/middleware.rb +19 -25
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +32 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +36 -191
- data/lib/faraday/parameters.rb +4 -197
- data/lib/faraday/rack_builder.rb +76 -64
- data/lib/faraday/request/authorization.rb +51 -30
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/json.rb +55 -0
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +43 -23
- data/lib/faraday/request.rb +82 -44
- data/lib/faraday/response/json.rb +54 -0
- data/lib/faraday/response/logger.rb +20 -69
- data/lib/faraday/response/raise_error.rb +49 -18
- data/lib/faraday/response.rb +26 -20
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +38 -247
- data/lib/faraday/version.rb +5 -0
- data/lib/faraday.rb +134 -188
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +49 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/test_spec.rb +377 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +736 -0
- data/spec/faraday/deprecate_spec.rb +17 -17
- data/spec/faraday/error_spec.rb +12 -54
- data/spec/faraday/middleware_spec.rb +52 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +44 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +42 -0
- data/spec/faraday/params_encoders/nested_spec.rb +142 -0
- data/spec/faraday/rack_builder_spec.rb +345 -0
- data/spec/faraday/request/authorization_spec.rb +96 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/json_spec.rb +111 -0
- data/spec/faraday/request/url_encoded_spec.rb +83 -0
- data/spec/faraday/request_spec.rb +120 -0
- data/spec/faraday/response/json_spec.rb +119 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +68 -0
- data/spec/faraday/response/raise_error_spec.rb +78 -15
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +65 -36
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +105 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +262 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +210 -56
- data/lib/faraday/adapter/em_http.rb +0 -243
- data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
- data/lib/faraday/adapter/em_synchrony.rb +0 -106
- data/lib/faraday/adapter/excon.rb +0 -82
- data/lib/faraday/adapter/httpclient.rb +0 -128
- data/lib/faraday/adapter/net_http.rb +0 -153
- data/lib/faraday/adapter/net_http_persistent.rb +0 -68
- data/lib/faraday/adapter/patron.rb +0 -95
- data/lib/faraday/adapter/rack.rb +0 -58
- data/lib/faraday/request/multipart.rb +0 -68
- data/lib/faraday/request/retry.rb +0 -213
- data/lib/faraday/upload_io.rb +0 -77
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -30
- data/test/adapters/em_synchrony_test.rb +0 -32
- data/test/adapters/excon_test.rb +0 -30
- data/test/adapters/httpclient_test.rb +0 -34
- data/test/adapters/integration.rb +0 -263
- data/test/adapters/logger_test.rb +0 -136
- data/test/adapters/net_http_persistent_test.rb +0 -114
- data/test/adapters/net_http_test.rb +0 -79
- data/test/adapters/patron_test.rb +0 -40
- data/test/adapters/rack_test.rb +0 -38
- data/test/adapters/test_middleware_test.rb +0 -157
- data/test/adapters/typhoeus_test.rb +0 -38
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -109
- data/test/connection_test.rb +0 -738
- data/test/env_test.rb +0 -268
- data/test/helper.rb +0 -75
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -282
- data/test/middleware_stack_test.rb +0 -260
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -333
- data/test/parameters_test.rb +0 -157
- data/test/request_middleware_test.rb +0 -126
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -98
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requires Ruby with rspec and faraday gems.
|
4
|
+
# rspec client_spec.rb
|
5
|
+
|
6
|
+
require 'faraday'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
# Example API client
|
10
|
+
class Client
|
11
|
+
def initialize(conn)
|
12
|
+
@conn = conn
|
13
|
+
end
|
14
|
+
|
15
|
+
def sushi(jname, params: {})
|
16
|
+
res = @conn.get("/#{jname}", params)
|
17
|
+
data = JSON.parse(res.body)
|
18
|
+
data['name']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
RSpec.describe Client do
|
23
|
+
let(:stubs) { Faraday::Adapter::Test::Stubs.new }
|
24
|
+
let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
|
25
|
+
let(:client) { Client.new(conn) }
|
26
|
+
|
27
|
+
it 'parses name' do
|
28
|
+
stubs.get('/ebi') do |env|
|
29
|
+
# optional: you can inspect the Faraday::Env
|
30
|
+
expect(env.url.path).to eq('/ebi')
|
31
|
+
[
|
32
|
+
200,
|
33
|
+
{ 'Content-Type': 'application/javascript' },
|
34
|
+
'{"name": "shrimp"}'
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
# uncomment to trigger stubs.verify_stubbed_calls failure
|
39
|
+
# stubs.get('/unused') { [404, {}, ''] }
|
40
|
+
|
41
|
+
expect(client.sushi('ebi')).to eq('shrimp')
|
42
|
+
stubs.verify_stubbed_calls
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'handles 404' do
|
46
|
+
stubs.get('/ebi') do
|
47
|
+
[
|
48
|
+
404,
|
49
|
+
{ 'Content-Type': 'application/javascript' },
|
50
|
+
'{}'
|
51
|
+
]
|
52
|
+
end
|
53
|
+
expect(client.sushi('ebi')).to be_nil
|
54
|
+
stubs.verify_stubbed_calls
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'handles exception' do
|
58
|
+
stubs.get('/ebi') do
|
59
|
+
raise Faraday::ConnectionFailed, nil
|
60
|
+
end
|
61
|
+
|
62
|
+
expect { client.sushi('ebi') }.to raise_error(Faraday::ConnectionFailed)
|
63
|
+
stubs.verify_stubbed_calls
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'When the test stub is run in strict_mode' do
|
67
|
+
let(:stubs) { Faraday::Adapter::Test::Stubs.new(strict_mode: true) }
|
68
|
+
|
69
|
+
it 'verifies the all parameter values are identical' do
|
70
|
+
stubs.get('/ebi?abc=123') do
|
71
|
+
[
|
72
|
+
200,
|
73
|
+
{ 'Content-Type': 'application/javascript' },
|
74
|
+
'{"name": "shrimp"}'
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
# uncomment to raise Stubs::NotFound
|
79
|
+
# expect(client.sushi('ebi', params: { abc: 123, foo: 'Kappa' })).to eq('shrimp')
|
80
|
+
expect(client.sushi('ebi', params: { abc: 123 })).to eq('shrimp')
|
81
|
+
stubs.verify_stubbed_calls
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'When the Faraday connection is configured with FlatParamsEncoder' do
|
86
|
+
let(:conn) { Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) { |b| b.adapter(:test, stubs) } }
|
87
|
+
|
88
|
+
it 'handles the same multiple URL parameters' do
|
89
|
+
stubs.get('/ebi?a=x&a=y&a=z') { [200, { 'Content-Type' => 'application/json' }, '{"name": "shrimp"}'] }
|
90
|
+
|
91
|
+
# uncomment to raise Stubs::NotFound
|
92
|
+
# expect(client.sushi('ebi', params: { a: %w[x y] })).to eq('shrimp')
|
93
|
+
expect(client.sushi('ebi', params: { a: %w[x y z] })).to eq('shrimp')
|
94
|
+
stubs.verify_stubbed_calls
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requires Ruby with test-unit and faraday gems.
|
4
|
+
# ruby client_test.rb
|
5
|
+
|
6
|
+
require 'faraday'
|
7
|
+
require 'json'
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
# Example API client
|
11
|
+
class Client
|
12
|
+
def initialize(conn)
|
13
|
+
@conn = conn
|
14
|
+
end
|
15
|
+
|
16
|
+
def sushi(jname, params: {})
|
17
|
+
res = @conn.get("/#{jname}", params)
|
18
|
+
data = JSON.parse(res.body)
|
19
|
+
data['name']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Example API client test
|
24
|
+
class ClientTest < Test::Unit::TestCase
|
25
|
+
def test_sushi_name
|
26
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
27
|
+
stubs.get('/ebi') do |env|
|
28
|
+
# optional: you can inspect the Faraday::Env
|
29
|
+
assert_equal '/ebi', env.url.path
|
30
|
+
[
|
31
|
+
200,
|
32
|
+
{ 'Content-Type': 'application/javascript' },
|
33
|
+
'{"name": "shrimp"}'
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
# uncomment to trigger stubs.verify_stubbed_calls failure
|
38
|
+
# stubs.get('/unused') { [404, {}, ''] }
|
39
|
+
|
40
|
+
cli = client(stubs)
|
41
|
+
assert_equal 'shrimp', cli.sushi('ebi')
|
42
|
+
stubs.verify_stubbed_calls
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_sushi_404
|
46
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
47
|
+
stubs.get('/ebi') do
|
48
|
+
[
|
49
|
+
404,
|
50
|
+
{ 'Content-Type': 'application/javascript' },
|
51
|
+
'{}'
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
cli = client(stubs)
|
56
|
+
assert_nil cli.sushi('ebi')
|
57
|
+
stubs.verify_stubbed_calls
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_sushi_exception
|
61
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
62
|
+
stubs.get('/ebi') do
|
63
|
+
raise Faraday::ConnectionFailed, nil
|
64
|
+
end
|
65
|
+
|
66
|
+
cli = client(stubs)
|
67
|
+
assert_raise Faraday::ConnectionFailed do
|
68
|
+
cli.sushi('ebi')
|
69
|
+
end
|
70
|
+
stubs.verify_stubbed_calls
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_strict_mode
|
74
|
+
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
|
75
|
+
stubs.get('/ebi?abc=123') do
|
76
|
+
[
|
77
|
+
200,
|
78
|
+
{ 'Content-Type': 'application/javascript' },
|
79
|
+
'{"name": "shrimp"}'
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
83
|
+
cli = client(stubs)
|
84
|
+
assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123 })
|
85
|
+
|
86
|
+
# uncomment to raise Stubs::NotFound
|
87
|
+
# assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123, foo: 'Kappa' })
|
88
|
+
stubs.verify_stubbed_calls
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_non_default_params_encoder
|
92
|
+
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
|
93
|
+
stubs.get('/ebi?a=x&a=y&a=z') do
|
94
|
+
[
|
95
|
+
200,
|
96
|
+
{ 'Content-Type': 'application/javascript' },
|
97
|
+
'{"name": "shrimp"}'
|
98
|
+
]
|
99
|
+
end
|
100
|
+
conn = Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
|
101
|
+
builder.adapter :test, stubs
|
102
|
+
end
|
103
|
+
|
104
|
+
cli = Client.new(conn)
|
105
|
+
assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y z] })
|
106
|
+
|
107
|
+
# uncomment to raise Stubs::NotFound
|
108
|
+
# assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y] })
|
109
|
+
stubs.verify_stubbed_calls
|
110
|
+
end
|
111
|
+
|
112
|
+
def client(stubs)
|
113
|
+
conn = Faraday.new do |builder|
|
114
|
+
builder.adapter :test, stubs
|
115
|
+
end
|
116
|
+
Client.new(conn)
|
117
|
+
end
|
118
|
+
end
|
data/lib/faraday/adapter/test.rb
CHANGED
@@ -1,51 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
class Adapter
|
3
|
-
#
|
4
|
-
#
|
5
|
+
# @example
|
5
6
|
# test = Faraday::Connection.new do
|
6
7
|
# use Faraday::Adapter::Test do |stub|
|
7
|
-
# #
|
8
|
+
# # Define matcher to match the request
|
8
9
|
# stub.get '/resource.json' do
|
9
10
|
# # return static content
|
10
11
|
# [200, {'Content-Type' => 'application/json'}, 'hi world']
|
11
12
|
# end
|
12
|
-
#
|
13
|
+
#
|
13
14
|
# # response with content generated based on request
|
14
15
|
# stub.get '/showget' do |env|
|
15
16
|
# [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
|
16
17
|
# end
|
17
|
-
#
|
18
|
-
# # regular expression can be used as matching filter
|
18
|
+
#
|
19
|
+
# # A regular expression can be used as matching filter
|
19
20
|
# stub.get /\A\/items\/(\d+)\z/ do |env, meta|
|
20
|
-
# # in case regular expression is used an instance of MatchData
|
21
|
-
#
|
21
|
+
# # in case regular expression is used, an instance of MatchData
|
22
|
+
# # can be received
|
23
|
+
# [200,
|
24
|
+
# {'Content-Type' => 'text/plain'},
|
25
|
+
# "showing item: #{meta[:match_data][1]}"
|
26
|
+
# ]
|
22
27
|
# end
|
28
|
+
#
|
29
|
+
# # You can set strict_mode to exactly match the stubbed requests.
|
30
|
+
# stub.strict_mode = true
|
23
31
|
# end
|
24
32
|
# end
|
25
|
-
#
|
33
|
+
#
|
26
34
|
# resp = test.get '/resource.json'
|
27
35
|
# resp.body # => 'hi world'
|
28
|
-
#
|
36
|
+
#
|
29
37
|
# resp = test.get '/showget'
|
30
38
|
# resp.body # => 'get'
|
31
|
-
#
|
39
|
+
#
|
32
40
|
# resp = test.get '/items/1'
|
33
41
|
# resp.body # => 'showing item: 1'
|
34
|
-
#
|
42
|
+
#
|
35
43
|
# resp = test.get '/items/2'
|
36
44
|
# resp.body # => 'showing item: 2'
|
37
|
-
#
|
38
|
-
|
39
45
|
class Test < Faraday::Adapter
|
40
46
|
attr_accessor :stubs
|
41
47
|
|
48
|
+
# A stack of Stubs
|
42
49
|
class Stubs
|
43
50
|
class NotFound < StandardError
|
44
51
|
end
|
45
52
|
|
46
|
-
def initialize
|
47
|
-
# {:
|
48
|
-
@stack
|
53
|
+
def initialize(strict_mode: false)
|
54
|
+
# { get: [Stub, Stub] }
|
55
|
+
@stack = {}
|
56
|
+
@consumed = {}
|
57
|
+
@strict_mode = strict_mode
|
49
58
|
yield(self) if block_given?
|
50
59
|
end
|
51
60
|
|
@@ -53,17 +62,20 @@ module Faraday
|
|
53
62
|
@stack.empty?
|
54
63
|
end
|
55
64
|
|
56
|
-
|
57
|
-
|
65
|
+
# @param env [Faraday::Env]
|
66
|
+
def match(env)
|
67
|
+
request_method = env[:method]
|
68
|
+
return false unless @stack.key?(request_method)
|
69
|
+
|
58
70
|
stack = @stack[request_method]
|
59
71
|
consumed = (@consumed[request_method] ||= [])
|
60
72
|
|
61
|
-
stub, meta = matches?(stack,
|
73
|
+
stub, meta = matches?(stack, env)
|
62
74
|
if stub
|
63
75
|
consumed << stack.delete(stub)
|
64
76
|
return stub, meta
|
65
77
|
end
|
66
|
-
matches?(consumed,
|
78
|
+
matches?(consumed, env)
|
67
79
|
end
|
68
80
|
|
69
81
|
def get(path, headers = {}, &block)
|
@@ -74,15 +86,15 @@ module Faraday
|
|
74
86
|
new_stub(:head, path, headers, &block)
|
75
87
|
end
|
76
88
|
|
77
|
-
def post(path, body=nil, headers = {}, &block)
|
89
|
+
def post(path, body = nil, headers = {}, &block)
|
78
90
|
new_stub(:post, path, headers, body, &block)
|
79
91
|
end
|
80
92
|
|
81
|
-
def put(path, body=nil, headers = {}, &block)
|
93
|
+
def put(path, body = nil, headers = {}, &block)
|
82
94
|
new_stub(:put, path, headers, body, &block)
|
83
95
|
end
|
84
96
|
|
85
|
-
def patch(path, body=nil, headers = {}, &block)
|
97
|
+
def patch(path, body = nil, headers = {}, &block)
|
86
98
|
new_stub(:patch, path, headers, body, &block)
|
87
99
|
end
|
88
100
|
|
@@ -98,76 +110,109 @@ module Faraday
|
|
98
110
|
def verify_stubbed_calls
|
99
111
|
failed_stubs = []
|
100
112
|
@stack.each do |method, stubs|
|
101
|
-
|
102
|
-
|
113
|
+
next if stubs.empty?
|
114
|
+
|
115
|
+
failed_stubs.concat(
|
116
|
+
stubs.map do |stub|
|
103
117
|
"Expected #{method} #{stub}."
|
104
|
-
|
118
|
+
end
|
119
|
+
)
|
120
|
+
end
|
121
|
+
raise failed_stubs.join(' ') unless failed_stubs.empty?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Set strict_mode. If the value is true, this adapter tries to find matched requests strictly,
|
125
|
+
# which means that all of a path, parameters, and headers must be the same as an actual request.
|
126
|
+
def strict_mode=(value)
|
127
|
+
@strict_mode = value
|
128
|
+
@stack.each do |_method, stubs|
|
129
|
+
stubs.each do |stub|
|
130
|
+
stub.strict_mode = value
|
105
131
|
end
|
106
132
|
end
|
107
|
-
raise failed_stubs.join(" ") unless failed_stubs.size == 0
|
108
133
|
end
|
109
134
|
|
110
135
|
protected
|
111
136
|
|
112
|
-
def new_stub(request_method, path, headers = {}, body=nil, &block)
|
137
|
+
def new_stub(request_method, path, headers = {}, body = nil, &block)
|
113
138
|
normalized_path, host =
|
114
139
|
if path.is_a?(Regexp)
|
115
140
|
path
|
116
141
|
else
|
117
|
-
[
|
142
|
+
[
|
143
|
+
Faraday::Utils.normalize_path(path),
|
144
|
+
Faraday::Utils.URI(path).host
|
145
|
+
]
|
118
146
|
end
|
147
|
+
path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
|
148
|
+
headers = Utils::Headers.new(headers)
|
119
149
|
|
120
|
-
|
150
|
+
stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
|
151
|
+
(@stack[request_method] ||= []) << stub
|
121
152
|
end
|
122
153
|
|
123
|
-
|
154
|
+
# @param stack [Hash]
|
155
|
+
# @param env [Faraday::Env]
|
156
|
+
def matches?(stack, env)
|
124
157
|
stack.each do |stub|
|
125
|
-
match_result, meta = stub.matches?(
|
158
|
+
match_result, meta = stub.matches?(env)
|
126
159
|
return stub, meta if match_result
|
127
160
|
end
|
128
161
|
nil
|
129
162
|
end
|
130
163
|
end
|
131
164
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
request_path, request_query = request_uri.split('?')
|
143
|
-
request_params = request_query ?
|
144
|
-
Faraday::Utils.parse_nested_query(request_query) :
|
145
|
-
{}
|
146
|
-
# meta is a hash use as carrier
|
165
|
+
# Stub request
|
166
|
+
class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
|
167
|
+
# @param env [Faraday::Env]
|
168
|
+
def matches?(env)
|
169
|
+
request_host = env[:url].host
|
170
|
+
request_path = Faraday::Utils.normalize_path(env[:url].path)
|
171
|
+
request_headers = env.request_headers
|
172
|
+
request_body = env[:body]
|
173
|
+
|
174
|
+
# meta is a hash used as carrier
|
147
175
|
# that will be yielded to consumer block
|
148
176
|
meta = {}
|
149
|
-
|
177
|
+
[(host.nil? || host == request_host) &&
|
150
178
|
path_match?(request_path, meta) &&
|
151
|
-
params_match?(
|
179
|
+
params_match?(env) &&
|
152
180
|
(body.to_s.size.zero? || request_body == body) &&
|
153
|
-
headers_match?(request_headers), meta
|
181
|
+
headers_match?(request_headers), meta]
|
154
182
|
end
|
155
183
|
|
156
184
|
def path_match?(request_path, meta)
|
157
|
-
if path.is_a?
|
185
|
+
if path.is_a?(Regexp)
|
158
186
|
!!(meta[:match_data] = path.match(request_path))
|
159
187
|
else
|
160
188
|
path == request_path
|
161
189
|
end
|
162
190
|
end
|
163
191
|
|
164
|
-
|
192
|
+
# @param env [Faraday::Env]
|
193
|
+
def params_match?(env)
|
194
|
+
request_params = env[:params]
|
195
|
+
params = env.params_encoder.decode(query) || {}
|
196
|
+
|
197
|
+
if strict_mode
|
198
|
+
return Set.new(params) == Set.new(request_params)
|
199
|
+
end
|
200
|
+
|
165
201
|
params.keys.all? do |key|
|
166
202
|
request_params[key] == params[key]
|
167
203
|
end
|
168
204
|
end
|
169
205
|
|
170
206
|
def headers_match?(request_headers)
|
207
|
+
if strict_mode
|
208
|
+
headers_with_user_agent = headers.dup.tap do |hs|
|
209
|
+
# NOTE: Set User-Agent in case it's not set when creating Stubs.
|
210
|
+
# Users would not want to set Faraday's User-Agent explicitly.
|
211
|
+
hs[:user_agent] ||= Connection::USER_AGENT
|
212
|
+
end
|
213
|
+
return Set.new(headers_with_user_agent) == Set.new(request_headers)
|
214
|
+
end
|
215
|
+
|
171
216
|
headers.keys.all? do |key|
|
172
217
|
request_headers[key] == headers[key]
|
173
218
|
end
|
@@ -178,7 +223,7 @@ module Faraday
|
|
178
223
|
end
|
179
224
|
end
|
180
225
|
|
181
|
-
def initialize(app, stubs=nil, &block)
|
226
|
+
def initialize(app, stubs = nil, &block)
|
182
227
|
super(app)
|
183
228
|
@stubs = stubs || Stubs.new
|
184
229
|
configure(&block) if block
|
@@ -188,24 +233,28 @@ module Faraday
|
|
188
233
|
yield(stubs)
|
189
234
|
end
|
190
235
|
|
236
|
+
# @param env [Faraday::Env]
|
191
237
|
def call(env)
|
192
238
|
super
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
block_arity = stub.block.arity
|
202
|
-
status, headers, body = (block_arity >= 0) ?
|
203
|
-
stub.block.call(*[env, meta].take(block_arity)) :
|
204
|
-
stub.block.call(env, meta)
|
205
|
-
save_response(env, status, body, headers)
|
206
|
-
else
|
207
|
-
raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
|
239
|
+
|
240
|
+
env.request.params_encoder ||= Faraday::Utils.default_params_encoder
|
241
|
+
env[:params] = env.params_encoder.decode(env[:url].query) || {}
|
242
|
+
stub, meta = stubs.match(env)
|
243
|
+
|
244
|
+
unless stub
|
245
|
+
raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
|
246
|
+
"#{env[:url]} #{env[:body]}"
|
208
247
|
end
|
248
|
+
|
249
|
+
block_arity = stub.block.arity
|
250
|
+
status, headers, body =
|
251
|
+
if block_arity >= 0
|
252
|
+
stub.block.call(*[env, meta].take(block_arity))
|
253
|
+
else
|
254
|
+
stub.block.call(env, meta)
|
255
|
+
end
|
256
|
+
save_response(env, status, body, headers)
|
257
|
+
|
209
258
|
@app.call(env)
|
210
259
|
end
|
211
260
|
end
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
class Adapter
|
3
|
-
# This class is just a stub, the real adapter is in
|
5
|
+
# Typhoeus adapter. This class is just a stub, the real adapter is in
|
6
|
+
# https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
|
4
7
|
class Typhoeus < Faraday::Adapter
|
5
8
|
# Needs to define this method in order to support Typhoeus <= 1.3.0
|
6
9
|
def call; end
|
data/lib/faraday/adapter.rb
CHANGED
@@ -1,43 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
|
-
#
|
4
|
+
# Base class for all Faraday adapters. Adapters are
|
3
5
|
# responsible for fulfilling a Faraday request.
|
4
|
-
class Adapter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
:excon => [:Excon, 'excon'],
|
16
|
-
:rack => [:Rack, 'rack'],
|
17
|
-
:httpclient => [:HTTPClient, 'httpclient']
|
18
|
-
|
19
|
-
# Public: This module marks an Adapter as supporting parallel requests.
|
6
|
+
class Adapter
|
7
|
+
extend MiddlewareRegistry
|
8
|
+
extend DependencyLoader
|
9
|
+
|
10
|
+
CONTENT_LENGTH = 'Content-Length'
|
11
|
+
|
12
|
+
register_middleware File.expand_path('adapter', __dir__),
|
13
|
+
test: [:Test, 'test'],
|
14
|
+
typhoeus: [:Typhoeus, 'typhoeus']
|
15
|
+
|
16
|
+
# This module marks an Adapter as supporting parallel requests.
|
20
17
|
module Parallelism
|
21
18
|
attr_writer :supports_parallel
|
22
|
-
|
19
|
+
|
20
|
+
def supports_parallel?
|
21
|
+
@supports_parallel
|
22
|
+
end
|
23
23
|
|
24
24
|
def inherited(subclass)
|
25
25
|
super
|
26
|
-
subclass.supports_parallel =
|
26
|
+
subclass.supports_parallel = supports_parallel?
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
extend Parallelism
|
31
31
|
self.supports_parallel = false
|
32
32
|
|
33
|
-
def initialize(
|
34
|
-
|
33
|
+
def initialize(_app = nil, opts = {}, &block)
|
34
|
+
@app = ->(env) { env.response }
|
35
35
|
@connection_options = opts
|
36
36
|
@config_block = block
|
37
37
|
end
|
38
38
|
|
39
|
+
# Yields or returns an adapter's configured connection. Depends on
|
40
|
+
# #build_connection being defined on this adapter.
|
41
|
+
#
|
42
|
+
# @param env [Faraday::Env, Hash] The env object for a faraday request.
|
43
|
+
#
|
44
|
+
# @return The return value of the given block, or the HTTP connection object
|
45
|
+
# if no block is given.
|
46
|
+
def connection(env)
|
47
|
+
conn = build_connection(env)
|
48
|
+
return conn unless block_given?
|
49
|
+
|
50
|
+
yield conn
|
51
|
+
end
|
52
|
+
|
53
|
+
# Close any persistent connections. The adapter should still be usable
|
54
|
+
# after calling close.
|
55
|
+
def close
|
56
|
+
# Possible implementation:
|
57
|
+
# @app.close if @app.respond_to?(:close)
|
58
|
+
end
|
59
|
+
|
39
60
|
def call(env)
|
40
61
|
env.clear_body if env.needs_body?
|
62
|
+
env.response = Response.new
|
41
63
|
end
|
42
64
|
|
43
65
|
private
|
@@ -45,11 +67,39 @@ module Faraday
|
|
45
67
|
def save_response(env, status, body, headers = nil, reason_phrase = nil)
|
46
68
|
env.status = status
|
47
69
|
env.body = body
|
48
|
-
env.reason_phrase = reason_phrase
|
70
|
+
env.reason_phrase = reason_phrase&.to_s&.strip
|
49
71
|
env.response_headers = Utils::Headers.new.tap do |response_headers|
|
50
72
|
response_headers.update headers unless headers.nil?
|
51
73
|
yield(response_headers) if block_given?
|
52
74
|
end
|
75
|
+
|
76
|
+
env.response.finish(env) unless env.parallel?
|
77
|
+
env.response
|
78
|
+
end
|
79
|
+
|
80
|
+
# Fetches either a read, write, or open timeout setting. Defaults to the
|
81
|
+
# :timeout value if a more specific one is not given.
|
82
|
+
#
|
83
|
+
# @param type [Symbol] Describes which timeout setting to get: :read,
|
84
|
+
# :write, or :open.
|
85
|
+
# @param options [Hash] Hash containing Symbol keys like :timeout,
|
86
|
+
# :read_timeout, :write_timeout, :open_timeout, or
|
87
|
+
# :timeout
|
88
|
+
#
|
89
|
+
# @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
|
90
|
+
# has been set.
|
91
|
+
def request_timeout(type, options)
|
92
|
+
key = TIMEOUT_KEYS.fetch(type) do
|
93
|
+
msg = "Expected :read, :write, :open. Got #{type.inspect} :("
|
94
|
+
raise ArgumentError, msg
|
95
|
+
end
|
96
|
+
options[key] || options[:timeout]
|
53
97
|
end
|
98
|
+
|
99
|
+
TIMEOUT_KEYS = {
|
100
|
+
read: :read_timeout,
|
101
|
+
open: :open_timeout,
|
102
|
+
write: :write_timeout
|
103
|
+
}.freeze
|
54
104
|
end
|
55
105
|
end
|