faraday 0.15.0 → 1.10.0
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 +380 -0
- data/LICENSE.md +1 -1
- data/README.md +17 -345
- data/Rakefile +7 -0
- 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 +37 -0
- 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 +118 -38
- 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 +39 -193
- data/lib/faraday/parameters.rb +4 -196
- data/lib/faraday/rack_builder.rb +77 -65
- 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 +93 -32
- data/lib/faraday/response/json.rb +54 -0
- data/lib/faraday/response/logger.rb +20 -69
- data/lib/faraday/response/raise_error.rb +49 -14
- data/lib/faraday/response.rb +29 -23
- 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 -189
- 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/error_spec.rb +60 -0
- 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 +169 -0
- 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 +132 -0
- 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 +222 -29
- 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 -79
- data/lib/faraday/adapter/httpclient.rb +0 -128
- data/lib/faraday/adapter/net_http.rb +0 -137
- data/lib/faraday/adapter/net_http_persistent.rb +0 -63
- data/lib/faraday/adapter/patron.rb +0 -100
- data/lib/faraday/adapter/rack.rb +0 -58
- data/lib/faraday/request/multipart.rb +0 -68
- data/lib/faraday/request/retry.rb +0 -211
- data/lib/faraday/upload_io.rb +0 -67
@@ -0,0 +1,736 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_examples 'initializer with url' do
|
4
|
+
context 'with simple url' do
|
5
|
+
let(:address) { 'http://sushi.com' }
|
6
|
+
|
7
|
+
it { expect(subject.host).to eq('sushi.com') }
|
8
|
+
it { expect(subject.port).to eq(80) }
|
9
|
+
it { expect(subject.scheme).to eq('http') }
|
10
|
+
it { expect(subject.path_prefix).to eq('/') }
|
11
|
+
it { expect(subject.params).to eq({}) }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with complex url' do
|
15
|
+
let(:address) { 'http://sushi.com:815/fish?a=1' }
|
16
|
+
|
17
|
+
it { expect(subject.port).to eq(815) }
|
18
|
+
it { expect(subject.path_prefix).to eq('/fish') }
|
19
|
+
it { expect(subject.params).to eq('a' => '1') }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with IPv6 address' do
|
23
|
+
let(:address) { 'http://[::1]:85/' }
|
24
|
+
|
25
|
+
it { expect(subject.host).to eq('[::1]') }
|
26
|
+
it { expect(subject.port).to eq(85) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
shared_examples 'default connection options' do
|
31
|
+
after { Faraday.default_connection_options = nil }
|
32
|
+
|
33
|
+
it 'works with implicit url' do
|
34
|
+
conn = Faraday.new 'http://sushi.com/foo'
|
35
|
+
expect(conn.options.timeout).to eq(10)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'works with option url' do
|
39
|
+
conn = Faraday.new url: 'http://sushi.com/foo'
|
40
|
+
expect(conn.options.timeout).to eq(10)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'works with instance connection options' do
|
44
|
+
conn = Faraday.new 'http://sushi.com/foo', request: { open_timeout: 1 }
|
45
|
+
expect(conn.options.timeout).to eq(10)
|
46
|
+
expect(conn.options.open_timeout).to eq(1)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'default connection options persist with an instance overriding' do
|
50
|
+
conn = Faraday.new 'http://nigiri.com/bar'
|
51
|
+
conn.options.timeout = 1
|
52
|
+
expect(Faraday.default_connection_options.request.timeout).to eq(10)
|
53
|
+
|
54
|
+
other = Faraday.new url: 'https://sushi.com/foo'
|
55
|
+
other.options.timeout = 1
|
56
|
+
|
57
|
+
expect(Faraday.default_connection_options.request.timeout).to eq(10)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'default connection uses default connection options' do
|
61
|
+
expect(Faraday.default_connection.options.timeout).to eq(10)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
RSpec.describe Faraday::Connection do
|
66
|
+
let(:conn) { Faraday::Connection.new(url, options) }
|
67
|
+
let(:url) { nil }
|
68
|
+
let(:options) { nil }
|
69
|
+
|
70
|
+
describe '.new' do
|
71
|
+
subject { conn }
|
72
|
+
|
73
|
+
context 'with implicit url param' do
|
74
|
+
# Faraday::Connection.new('http://sushi.com')
|
75
|
+
let(:url) { address }
|
76
|
+
|
77
|
+
it_behaves_like 'initializer with url'
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with explicit url param' do
|
81
|
+
# Faraday::Connection.new(url: 'http://sushi.com')
|
82
|
+
let(:url) { { url: address } }
|
83
|
+
|
84
|
+
it_behaves_like 'initializer with url'
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'with custom builder' do
|
88
|
+
let(:custom_builder) { Faraday::RackBuilder.new }
|
89
|
+
let(:options) { { builder: custom_builder } }
|
90
|
+
|
91
|
+
it { expect(subject.builder).to eq(custom_builder) }
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'with custom params' do
|
95
|
+
let(:options) { { params: { a: 1 } } }
|
96
|
+
|
97
|
+
it { expect(subject.params).to eq('a' => 1) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with custom params and params in url' do
|
101
|
+
let(:url) { 'http://sushi.com/fish?a=1&b=2' }
|
102
|
+
let(:options) { { params: { a: 3 } } }
|
103
|
+
it { expect(subject.params).to eq('a' => 3, 'b' => '2') }
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with custom headers' do
|
107
|
+
let(:options) { { headers: { user_agent: 'Faraday' } } }
|
108
|
+
|
109
|
+
it { expect(subject.headers['User-agent']).to eq('Faraday') }
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with ssl false' do
|
113
|
+
let(:options) { { ssl: { verify: false } } }
|
114
|
+
|
115
|
+
it { expect(subject.ssl.verify?).to be_falsey }
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'with empty block' do
|
119
|
+
let(:conn) { Faraday::Connection.new {} }
|
120
|
+
|
121
|
+
it { expect(conn.builder.handlers.size).to eq(0) }
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'with block' do
|
125
|
+
let(:conn) do
|
126
|
+
Faraday::Connection.new(params: { 'a' => '1' }) do |faraday|
|
127
|
+
faraday.adapter :net_http
|
128
|
+
faraday.url_prefix = 'http://sushi.com/omnom'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it { expect(conn.builder.handlers.size).to eq(0) }
|
133
|
+
it { expect(conn.path_prefix).to eq('/omnom') }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#close' do
|
138
|
+
it 'can close underlying app' do
|
139
|
+
expect(conn.app).to receive(:close)
|
140
|
+
conn.close
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'basic_auth' do
|
145
|
+
subject { conn }
|
146
|
+
|
147
|
+
context 'calling the #basic_auth method' do
|
148
|
+
before { subject.basic_auth 'Aladdin', 'open sesame' }
|
149
|
+
|
150
|
+
it { expect(subject.headers['Authorization']).to eq('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') }
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'adding basic auth info to url' do
|
154
|
+
let(:url) { 'http://Aladdin:open%20sesame@sushi.com/fish' }
|
155
|
+
|
156
|
+
it { expect(subject.headers['Authorization']).to eq('Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==') }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#token_auth' do
|
161
|
+
before { subject.token_auth('abcdef', nonce: 'abc') }
|
162
|
+
|
163
|
+
it { expect(subject.headers['Authorization']).to eq('Token nonce="abc", token="abcdef"') }
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#build_exclusive_url' do
|
167
|
+
context 'with relative path' do
|
168
|
+
subject { conn.build_exclusive_url('sake.html') }
|
169
|
+
|
170
|
+
it 'uses connection host as default host' do
|
171
|
+
conn.host = 'sushi.com'
|
172
|
+
expect(subject.host).to eq('sushi.com')
|
173
|
+
expect(subject.scheme).to eq('http')
|
174
|
+
end
|
175
|
+
|
176
|
+
it do
|
177
|
+
conn.path_prefix = '/fish'
|
178
|
+
expect(subject.path).to eq('/fish/sake.html')
|
179
|
+
end
|
180
|
+
|
181
|
+
it do
|
182
|
+
conn.path_prefix = '/'
|
183
|
+
expect(subject.path).to eq('/sake.html')
|
184
|
+
end
|
185
|
+
|
186
|
+
it do
|
187
|
+
conn.path_prefix = 'fish'
|
188
|
+
expect(subject.path).to eq('/fish/sake.html')
|
189
|
+
end
|
190
|
+
|
191
|
+
it do
|
192
|
+
conn.path_prefix = '/fish/'
|
193
|
+
expect(subject.path).to eq('/fish/sake.html')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'with absolute path' do
|
198
|
+
subject { conn.build_exclusive_url('/sake.html') }
|
199
|
+
|
200
|
+
after { expect(subject.path).to eq('/sake.html') }
|
201
|
+
|
202
|
+
it { conn.path_prefix = '/fish' }
|
203
|
+
it { conn.path_prefix = '/' }
|
204
|
+
it { conn.path_prefix = 'fish' }
|
205
|
+
it { conn.path_prefix = '/fish/' }
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'with complete url' do
|
209
|
+
subject { conn.build_exclusive_url('http://sushi.com/sake.html?a=1') }
|
210
|
+
|
211
|
+
it { expect(subject.scheme).to eq('http') }
|
212
|
+
it { expect(subject.host).to eq('sushi.com') }
|
213
|
+
it { expect(subject.port).to eq(80) }
|
214
|
+
it { expect(subject.path).to eq('/sake.html') }
|
215
|
+
it { expect(subject.query).to eq('a=1') }
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'overrides connection port for absolute url' do
|
219
|
+
conn.port = 23
|
220
|
+
uri = conn.build_exclusive_url('http://sushi.com')
|
221
|
+
expect(uri.port).to eq(80)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'does not add ending slash given nil url' do
|
225
|
+
conn.url_prefix = 'http://sushi.com/nigiri'
|
226
|
+
uri = conn.build_exclusive_url
|
227
|
+
expect(uri.path).to eq('/nigiri')
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'does not add ending slash given empty url' do
|
231
|
+
conn.url_prefix = 'http://sushi.com/nigiri'
|
232
|
+
uri = conn.build_exclusive_url('')
|
233
|
+
expect(uri.path).to eq('/nigiri')
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'does not use connection params' do
|
237
|
+
conn.url_prefix = 'http://sushi.com/nigiri'
|
238
|
+
conn.params = { a: 1 }
|
239
|
+
expect(conn.build_exclusive_url.to_s).to eq('http://sushi.com/nigiri')
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'allows to provide params argument' do
|
243
|
+
conn.url_prefix = 'http://sushi.com/nigiri'
|
244
|
+
conn.params = { a: 1 }
|
245
|
+
params = Faraday::Utils::ParamsHash.new
|
246
|
+
params[:a] = 2
|
247
|
+
uri = conn.build_exclusive_url(nil, params)
|
248
|
+
expect(uri.to_s).to eq('http://sushi.com/nigiri?a=2')
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'handles uri instances' do
|
252
|
+
uri = conn.build_exclusive_url(URI('/sake.html'))
|
253
|
+
expect(uri.path).to eq('/sake.html')
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'always returns new URI instance' do
|
257
|
+
conn.url_prefix = 'http://sushi.com'
|
258
|
+
uri1 = conn.build_exclusive_url(nil)
|
259
|
+
uri2 = conn.build_exclusive_url(nil)
|
260
|
+
expect(uri1).not_to equal(uri2)
|
261
|
+
end
|
262
|
+
|
263
|
+
context 'with url_prefixed connection' do
|
264
|
+
let(:url) { 'http://sushi.com/sushi/' }
|
265
|
+
|
266
|
+
it 'parses url and changes scheme' do
|
267
|
+
conn.scheme = 'https'
|
268
|
+
uri = conn.build_exclusive_url('sake.html')
|
269
|
+
expect(uri.to_s).to eq('https://sushi.com/sushi/sake.html')
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'joins url to base with ending slash' do
|
273
|
+
uri = conn.build_exclusive_url('sake.html')
|
274
|
+
expect(uri.to_s).to eq('http://sushi.com/sushi/sake.html')
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'used default base with ending slash' do
|
278
|
+
uri = conn.build_exclusive_url
|
279
|
+
expect(uri.to_s).to eq('http://sushi.com/sushi/')
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'overrides base' do
|
283
|
+
uri = conn.build_exclusive_url('/sake/')
|
284
|
+
expect(uri.to_s).to eq('http://sushi.com/sake/')
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'with colon in path' do
|
289
|
+
let(:url) { 'http://service.com' }
|
290
|
+
|
291
|
+
it 'joins url to base when used absolute path' do
|
292
|
+
conn = Faraday.new(url: url)
|
293
|
+
uri = conn.build_exclusive_url('/service:search?limit=400')
|
294
|
+
expect(uri.to_s).to eq('http://service.com/service:search?limit=400')
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'joins url to base when used relative path' do
|
298
|
+
conn = Faraday.new(url: url)
|
299
|
+
uri = conn.build_exclusive_url('service:search?limit=400')
|
300
|
+
expect(uri.to_s).to eq('http://service.com/service%3Asearch?limit=400')
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'joins url to base when used with path prefix' do
|
304
|
+
conn = Faraday.new(url: url)
|
305
|
+
conn.path_prefix = '/api'
|
306
|
+
uri = conn.build_exclusive_url('service:search?limit=400')
|
307
|
+
expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400')
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe '#build_url' do
|
313
|
+
let(:url) { 'http://sushi.com/nigiri' }
|
314
|
+
|
315
|
+
it 'uses params' do
|
316
|
+
conn.params = { a: 1, b: 1 }
|
317
|
+
expect(conn.build_url.to_s).to eq('http://sushi.com/nigiri?a=1&b=1')
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'merges params' do
|
321
|
+
conn.params = { a: 1, b: 1 }
|
322
|
+
url = conn.build_url(nil, b: 2, c: 3)
|
323
|
+
expect(url.to_s).to eq('http://sushi.com/nigiri?a=1&b=2&c=3')
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
describe '#build_request' do
|
328
|
+
let(:url) { 'https://asushi.com/sake.html' }
|
329
|
+
let(:request) { conn.build_request(:get) }
|
330
|
+
|
331
|
+
before do
|
332
|
+
conn.headers = { 'Authorization' => 'token abc123' }
|
333
|
+
request.headers.delete('Authorization')
|
334
|
+
end
|
335
|
+
|
336
|
+
it { expect(conn.headers.keys).to eq(['Authorization']) }
|
337
|
+
it { expect(conn.headers.include?('Authorization')).to be_truthy }
|
338
|
+
it { expect(request.headers.keys).to be_empty }
|
339
|
+
it { expect(request.headers.include?('Authorization')).to be_falsey }
|
340
|
+
end
|
341
|
+
|
342
|
+
describe '#to_env' do
|
343
|
+
subject { conn.build_request(:get).to_env(conn).url }
|
344
|
+
|
345
|
+
let(:url) { 'http://sushi.com/sake.html' }
|
346
|
+
let(:options) { { params: @params } }
|
347
|
+
|
348
|
+
it 'parses url params into query' do
|
349
|
+
@params = { 'a[b]' => '1 + 2' }
|
350
|
+
expect(subject.query).to eq('a%5Bb%5D=1+%2B+2')
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'escapes per spec' do
|
354
|
+
@params = { 'a' => '1+2 foo~bar.-baz' }
|
355
|
+
expect(subject.query).to eq('a=1%2B2+foo~bar.-baz')
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'bracketizes nested params in query' do
|
359
|
+
@params = { 'a' => { 'b' => 'c' } }
|
360
|
+
expect(subject.query).to eq('a%5Bb%5D=c')
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'bracketizes repeated params in query' do
|
364
|
+
@params = { 'a' => [1, 2] }
|
365
|
+
expect(subject.query).to eq('a%5B%5D=1&a%5B%5D=2')
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'without braketizing repeated params in query' do
|
369
|
+
@params = { 'a' => [1, 2] }
|
370
|
+
conn.options.params_encoder = Faraday::FlatParamsEncoder
|
371
|
+
expect(subject.query).to eq('a=1&a=2')
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
describe 'proxy support' do
|
376
|
+
it 'accepts string' do
|
377
|
+
with_env 'http_proxy' => 'http://env-proxy.com:80' do
|
378
|
+
conn.proxy = 'http://proxy.com'
|
379
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
it 'accepts uri' do
|
384
|
+
with_env 'http_proxy' => 'http://env-proxy.com:80' do
|
385
|
+
conn.proxy = URI.parse('http://proxy.com')
|
386
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'accepts hash with string uri' do
|
391
|
+
with_env 'http_proxy' => 'http://env-proxy.com:80' do
|
392
|
+
conn.proxy = { uri: 'http://proxy.com', user: 'rick' }
|
393
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
394
|
+
expect(conn.proxy.user).to eq('rick')
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'accepts hash' do
|
399
|
+
with_env 'http_proxy' => 'http://env-proxy.com:80' do
|
400
|
+
conn.proxy = { uri: URI.parse('http://proxy.com'), user: 'rick' }
|
401
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
402
|
+
expect(conn.proxy.user).to eq('rick')
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'accepts http env' do
|
407
|
+
with_env 'http_proxy' => 'http://env-proxy.com:80' do
|
408
|
+
expect(conn.proxy.host).to eq('env-proxy.com')
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'accepts http env with auth' do
|
413
|
+
with_env 'http_proxy' => 'http://a%40b:my%20pass@proxy.com:80' do
|
414
|
+
expect(conn.proxy.user).to eq('a@b')
|
415
|
+
expect(conn.proxy.password).to eq('my pass')
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'accepts env without scheme' do
|
420
|
+
with_env 'http_proxy' => 'localhost:8888' do
|
421
|
+
uri = conn.proxy[:uri]
|
422
|
+
expect(uri.host).to eq('localhost')
|
423
|
+
expect(uri.port).to eq(8888)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'fetches no proxy from nil env' do
|
428
|
+
with_env 'http_proxy' => nil do
|
429
|
+
expect(conn.proxy).to be_nil
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'fetches no proxy from blank env' do
|
434
|
+
with_env 'http_proxy' => '' do
|
435
|
+
expect(conn.proxy).to be_nil
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
it 'does not accept uppercase env' do
|
440
|
+
with_env 'HTTP_PROXY' => 'http://localhost:8888/' do
|
441
|
+
expect(conn.proxy).to be_nil
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'allows when url in no proxy list' do
|
446
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
447
|
+
conn = Faraday::Connection.new('http://example.com')
|
448
|
+
expect(conn.proxy).to be_nil
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'allows when url in no proxy list with url_prefix' do
|
453
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
454
|
+
conn = Faraday::Connection.new
|
455
|
+
conn.url_prefix = 'http://example.com'
|
456
|
+
expect(conn.proxy).to be_nil
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'allows when prefixed url is not in no proxy list' do
|
461
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
462
|
+
conn = Faraday::Connection.new('http://prefixedexample.com')
|
463
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'allows when subdomain url is in no proxy list' do
|
468
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
469
|
+
conn = Faraday::Connection.new('http://subdomain.example.com')
|
470
|
+
expect(conn.proxy).to be_nil
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'allows when url not in no proxy list' do
|
475
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example2.com' do
|
476
|
+
conn = Faraday::Connection.new('http://example.com')
|
477
|
+
expect(conn.proxy.host).to eq('proxy.com')
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
it 'allows when ip address is not in no proxy list but url is' do
|
482
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'localhost' do
|
483
|
+
conn = Faraday::Connection.new('http://127.0.0.1')
|
484
|
+
expect(conn.proxy).to be_nil
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
it 'allows when url is not in no proxy list but ip address is' do
|
489
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => '127.0.0.1' do
|
490
|
+
conn = Faraday::Connection.new('http://localhost')
|
491
|
+
expect(conn.proxy).to be_nil
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'allows in multi element no proxy list' do
|
496
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example0.com,example.com,example1.com' do
|
497
|
+
expect(Faraday::Connection.new('http://example0.com').proxy).to be_nil
|
498
|
+
expect(Faraday::Connection.new('http://example.com').proxy).to be_nil
|
499
|
+
expect(Faraday::Connection.new('http://example1.com').proxy).to be_nil
|
500
|
+
expect(Faraday::Connection.new('http://example2.com').proxy.host).to eq('proxy.com')
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'test proxy requires uri' do
|
505
|
+
expect { conn.proxy = { uri: :bad_uri, user: 'rick' } }.to raise_error(ArgumentError)
|
506
|
+
end
|
507
|
+
|
508
|
+
it 'uses env http_proxy' do
|
509
|
+
with_env 'http_proxy' => 'http://proxy.com' do
|
510
|
+
conn = Faraday.new
|
511
|
+
expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
|
512
|
+
expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com')
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
it 'uses processes no_proxy before http_proxy' do
|
517
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do
|
518
|
+
conn = Faraday.new
|
519
|
+
expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
|
520
|
+
expect(conn.proxy_for_request('http://google.co.uk')).to be_nil
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
it 'uses env https_proxy' do
|
525
|
+
with_env 'https_proxy' => 'https://proxy.com' do
|
526
|
+
conn = Faraday.new
|
527
|
+
expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
|
528
|
+
expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com')
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
it 'uses processes no_proxy before https_proxy' do
|
533
|
+
with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
|
534
|
+
conn = Faraday.new
|
535
|
+
expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
|
536
|
+
expect(conn.proxy_for_request('https://google.co.uk')).to be_nil
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
it 'gives priority to manually set proxy' do
|
541
|
+
with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
|
542
|
+
conn = Faraday.new
|
543
|
+
conn.proxy = 'http://proxy2.com'
|
544
|
+
|
545
|
+
expect(conn.instance_variable_get('@manual_proxy')).to be_truthy
|
546
|
+
expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com')
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'ignores env proxy if set that way' do
|
551
|
+
with_env_proxy_disabled do
|
552
|
+
with_env 'http_proxy' => 'http://duncan.proxy.com:80' do
|
553
|
+
expect(conn.proxy).to be_nil
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
context 'performing a request' do
|
559
|
+
before { stub_request(:get, 'http://example.com') }
|
560
|
+
|
561
|
+
it 'dynamically checks proxy' do
|
562
|
+
with_env 'http_proxy' => 'http://proxy.com:80' do
|
563
|
+
conn = Faraday.new
|
564
|
+
expect(conn.proxy.uri.host).to eq('proxy.com')
|
565
|
+
|
566
|
+
conn.get('http://example.com') do |req|
|
567
|
+
expect(req.options.proxy.uri.host).to eq('proxy.com')
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
conn.get('http://example.com')
|
572
|
+
expect(conn.instance_variable_get('@temp_proxy')).to be_nil
|
573
|
+
end
|
574
|
+
|
575
|
+
it 'dynamically check no proxy' do
|
576
|
+
with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
|
577
|
+
conn = Faraday.new
|
578
|
+
|
579
|
+
expect(conn.proxy.uri.host).to eq('proxy.com')
|
580
|
+
|
581
|
+
conn.get('http://example.com') do |req|
|
582
|
+
expect(req.options.proxy).to be_nil
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
describe '#dup' do
|
590
|
+
subject { conn.dup }
|
591
|
+
|
592
|
+
let(:url) { 'http://sushi.com/foo' }
|
593
|
+
let(:options) do
|
594
|
+
{
|
595
|
+
ssl: { verify: :none },
|
596
|
+
headers: { 'content-type' => 'text/plain' },
|
597
|
+
params: { 'a' => '1' },
|
598
|
+
request: { timeout: 5 }
|
599
|
+
}
|
600
|
+
end
|
601
|
+
|
602
|
+
it { expect(subject.build_exclusive_url).to eq(conn.build_exclusive_url) }
|
603
|
+
it { expect(subject.headers['content-type']).to eq('text/plain') }
|
604
|
+
it { expect(subject.params['a']).to eq('1') }
|
605
|
+
|
606
|
+
context 'after manual changes' do
|
607
|
+
before do
|
608
|
+
subject.basic_auth('', '')
|
609
|
+
subject.headers['content-length'] = 12
|
610
|
+
subject.params['b'] = '2'
|
611
|
+
subject.options[:open_timeout] = 10
|
612
|
+
end
|
613
|
+
|
614
|
+
it { expect(subject.builder.handlers.size).to eq(1) }
|
615
|
+
it { expect(conn.builder.handlers.size).to eq(1) }
|
616
|
+
it { expect(conn.headers.key?('content-length')).to be_falsey }
|
617
|
+
it { expect(conn.params.key?('b')).to be_falsey }
|
618
|
+
it { expect(subject.options[:timeout]).to eq(5) }
|
619
|
+
it { expect(conn.options[:open_timeout]).to be_nil }
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
describe '#respond_to?' do
|
624
|
+
it { expect(Faraday.respond_to?(:get)).to be_truthy }
|
625
|
+
it { expect(Faraday.respond_to?(:post)).to be_truthy }
|
626
|
+
end
|
627
|
+
|
628
|
+
describe 'default_connection_options' do
|
629
|
+
context 'assigning a default value' do
|
630
|
+
before do
|
631
|
+
Faraday.default_connection_options = nil
|
632
|
+
Faraday.default_connection_options.request.timeout = 10
|
633
|
+
end
|
634
|
+
|
635
|
+
it_behaves_like 'default connection options'
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'assigning a hash' do
|
639
|
+
before { Faraday.default_connection_options = { request: { timeout: 10 } } }
|
640
|
+
|
641
|
+
it_behaves_like 'default connection options'
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
describe 'request params' do
|
646
|
+
context 'with simple url' do
|
647
|
+
let(:url) { 'http://example.com' }
|
648
|
+
let!(:stubbed) { stub_request(:get, 'http://example.com?a=a&p=3') }
|
649
|
+
|
650
|
+
after { expect(stubbed).to have_been_made.once }
|
651
|
+
|
652
|
+
it 'test_overrides_request_params' do
|
653
|
+
conn.get('?p=2&a=a', p: 3)
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'test_overrides_request_params_block' do
|
657
|
+
conn.get('?p=1&a=a', p: 2) do |req|
|
658
|
+
req.params[:p] = 3
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
it 'test_overrides_request_params_block_url' do
|
663
|
+
conn.get(nil, p: 2) do |req|
|
664
|
+
req.url('?p=1&a=a', 'p' => 3)
|
665
|
+
end
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
context 'with url and extra params' do
|
670
|
+
let(:url) { 'http://example.com?a=1&b=2' }
|
671
|
+
let(:options) { { params: { c: 3 } } }
|
672
|
+
|
673
|
+
it 'merges connection and request params' do
|
674
|
+
stubbed = stub_request(:get, 'http://example.com?a=1&b=2&c=3&limit=5&page=1')
|
675
|
+
conn.get('?page=1', limit: 5)
|
676
|
+
expect(stubbed).to have_been_made.once
|
677
|
+
end
|
678
|
+
|
679
|
+
it 'allows to override all params' do
|
680
|
+
stubbed = stub_request(:get, 'http://example.com?b=b')
|
681
|
+
conn.get('?p=1&a=a', p: 2) do |req|
|
682
|
+
expect(req.params[:a]).to eq('a')
|
683
|
+
expect(req.params['c']).to eq(3)
|
684
|
+
expect(req.params['p']).to eq(2)
|
685
|
+
req.params = { b: 'b' }
|
686
|
+
expect(req.params['b']).to eq('b')
|
687
|
+
end
|
688
|
+
expect(stubbed).to have_been_made.once
|
689
|
+
end
|
690
|
+
|
691
|
+
it 'allows to set params_encoder for single request' do
|
692
|
+
encoder = Object.new
|
693
|
+
def encoder.encode(params)
|
694
|
+
params.map { |k, v| "#{k.upcase}-#{v.to_s.upcase}" }.join(',')
|
695
|
+
end
|
696
|
+
stubbed = stub_request(:get, 'http://example.com/?A-1,B-2,C-3,FEELING-BLUE')
|
697
|
+
|
698
|
+
conn.get('/', feeling: 'blue') do |req|
|
699
|
+
req.options.params_encoder = encoder
|
700
|
+
end
|
701
|
+
expect(stubbed).to have_been_made.once
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
context 'with default params encoder' do
|
706
|
+
let!(:stubbed) { stub_request(:get, 'http://example.com?color%5B%5D=red&color%5B%5D=blue') }
|
707
|
+
after { expect(stubbed).to have_been_made.once }
|
708
|
+
|
709
|
+
it 'supports array params in url' do
|
710
|
+
conn.get('http://example.com?color[]=red&color[]=blue')
|
711
|
+
end
|
712
|
+
|
713
|
+
it 'supports array params in params' do
|
714
|
+
conn.get('http://example.com', color: %w[red blue])
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
context 'with flat params encoder' do
|
719
|
+
let(:options) { { request: { params_encoder: Faraday::FlatParamsEncoder } } }
|
720
|
+
let!(:stubbed) { stub_request(:get, 'http://example.com?color=blue') }
|
721
|
+
after { expect(stubbed).to have_been_made.once }
|
722
|
+
|
723
|
+
it 'supports array params in params' do
|
724
|
+
conn.get('http://example.com', color: %w[red blue])
|
725
|
+
end
|
726
|
+
|
727
|
+
context 'with array param in url' do
|
728
|
+
let(:url) { 'http://example.com?color[]=red&color[]=blue' }
|
729
|
+
|
730
|
+
it do
|
731
|
+
conn.get('/')
|
732
|
+
end
|
733
|
+
end
|
734
|
+
end
|
735
|
+
end
|
736
|
+
end
|