faraday 0.15.4 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +380 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +16 -344
  5. data/Rakefile +7 -0
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday.rb +127 -190
  9. data/lib/faraday/adapter.rb +72 -22
  10. data/lib/faraday/adapter/test.rb +86 -53
  11. data/lib/faraday/adapter/typhoeus.rb +4 -1
  12. data/lib/faraday/adapter_registry.rb +30 -0
  13. data/lib/faraday/autoload.rb +39 -36
  14. data/lib/faraday/connection.rb +320 -183
  15. data/lib/faraday/dependency_loader.rb +37 -0
  16. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  17. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  18. data/lib/faraday/error.rb +123 -37
  19. data/lib/faraday/file_part.rb +128 -0
  20. data/lib/faraday/logging/formatter.rb +105 -0
  21. data/lib/faraday/methods.rb +6 -0
  22. data/lib/faraday/middleware.rb +19 -25
  23. data/lib/faraday/middleware_registry.rb +129 -0
  24. data/lib/faraday/options.rb +39 -194
  25. data/lib/faraday/options/connection_options.rb +22 -0
  26. data/lib/faraday/options/env.rb +181 -0
  27. data/lib/faraday/options/proxy_options.rb +32 -0
  28. data/lib/faraday/options/request_options.rb +22 -0
  29. data/lib/faraday/options/ssl_options.rb +59 -0
  30. data/lib/faraday/param_part.rb +53 -0
  31. data/lib/faraday/parameters.rb +4 -197
  32. data/lib/faraday/rack_builder.rb +77 -65
  33. data/lib/faraday/request.rb +86 -44
  34. data/lib/faraday/request/authorization.rb +44 -30
  35. data/lib/faraday/request/basic_authentication.rb +14 -7
  36. data/lib/faraday/request/instrumentation.rb +45 -27
  37. data/lib/faraday/request/multipart.rb +86 -48
  38. data/lib/faraday/request/retry.rb +198 -169
  39. data/lib/faraday/request/token_authentication.rb +15 -10
  40. data/lib/faraday/request/url_encoded.rb +43 -23
  41. data/lib/faraday/response.rb +27 -23
  42. data/lib/faraday/response/logger.rb +22 -69
  43. data/lib/faraday/response/raise_error.rb +49 -14
  44. data/lib/faraday/utils.rb +38 -247
  45. data/lib/faraday/utils/headers.rb +139 -0
  46. data/lib/faraday/utils/params_hash.rb +61 -0
  47. data/lib/faraday/version.rb +5 -0
  48. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  49. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  50. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  51. data/spec/faraday/adapter/excon_spec.rb +49 -0
  52. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  53. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  54. data/spec/faraday/adapter/patron_spec.rb +18 -0
  55. data/spec/faraday/adapter/rack_spec.rb +8 -0
  56. data/spec/faraday/adapter/test_spec.rb +260 -0
  57. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  58. data/spec/faraday/adapter_registry_spec.rb +28 -0
  59. data/spec/faraday/adapter_spec.rb +55 -0
  60. data/spec/faraday/composite_read_io_spec.rb +80 -0
  61. data/spec/faraday/connection_spec.rb +736 -0
  62. data/spec/faraday/error_spec.rb +60 -0
  63. data/spec/faraday/middleware_spec.rb +52 -0
  64. data/spec/faraday/options/env_spec.rb +70 -0
  65. data/spec/faraday/options/options_spec.rb +297 -0
  66. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  67. data/spec/faraday/options/request_options_spec.rb +19 -0
  68. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  69. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  70. data/spec/faraday/rack_builder_spec.rb +345 -0
  71. data/spec/faraday/request/authorization_spec.rb +88 -0
  72. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  73. data/spec/faraday/request/multipart_spec.rb +302 -0
  74. data/spec/faraday/request/retry_spec.rb +242 -0
  75. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  76. data/spec/faraday/request_spec.rb +120 -0
  77. data/spec/faraday/response/logger_spec.rb +220 -0
  78. data/spec/faraday/response/middleware_spec.rb +68 -0
  79. data/spec/faraday/response/raise_error_spec.rb +169 -0
  80. data/spec/faraday/response_spec.rb +75 -0
  81. data/spec/faraday/utils/headers_spec.rb +82 -0
  82. data/spec/faraday/utils_spec.rb +56 -0
  83. data/spec/faraday_spec.rb +37 -0
  84. data/spec/spec_helper.rb +132 -0
  85. data/spec/support/disabling_stub.rb +14 -0
  86. data/spec/support/fake_safe_buffer.rb +15 -0
  87. data/spec/support/helper_methods.rb +133 -0
  88. data/spec/support/shared_examples/adapter.rb +105 -0
  89. data/spec/support/shared_examples/params_encoder.rb +18 -0
  90. data/spec/support/shared_examples/request_method.rb +262 -0
  91. data/spec/support/streaming_response_checker.rb +35 -0
  92. data/spec/support/webmock_rack_app.rb +68 -0
  93. metadata +206 -19
  94. data/lib/faraday/adapter/em_http.rb +0 -243
  95. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  96. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  97. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  98. data/lib/faraday/adapter/excon.rb +0 -82
  99. data/lib/faraday/adapter/httpclient.rb +0 -128
  100. data/lib/faraday/adapter/net_http.rb +0 -152
  101. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  102. data/lib/faraday/adapter/patron.rb +0 -95
  103. data/lib/faraday/adapter/rack.rb +0 -58
  104. 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