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