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.
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 +17 -345
  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 +118 -69
  9. data/lib/faraday/adapter/typhoeus.rb +4 -1
  10. data/lib/faraday/adapter.rb +72 -22
  11. data/lib/faraday/adapter_registry.rb +30 -0
  12. data/lib/faraday/autoload.rb +39 -36
  13. data/lib/faraday/connection.rb +343 -185
  14. data/lib/faraday/dependency_loader.rb +37 -0
  15. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  16. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  17. data/lib/faraday/error.rb +118 -38
  18. data/lib/faraday/logging/formatter.rb +105 -0
  19. data/lib/faraday/methods.rb +6 -0
  20. data/lib/faraday/middleware.rb +19 -25
  21. data/lib/faraday/middleware_registry.rb +129 -0
  22. data/lib/faraday/options/connection_options.rb +22 -0
  23. data/lib/faraday/options/env.rb +181 -0
  24. data/lib/faraday/options/proxy_options.rb +32 -0
  25. data/lib/faraday/options/request_options.rb +22 -0
  26. data/lib/faraday/options/ssl_options.rb +59 -0
  27. data/lib/faraday/options.rb +39 -193
  28. data/lib/faraday/parameters.rb +4 -196
  29. data/lib/faraday/rack_builder.rb +77 -65
  30. data/lib/faraday/request/authorization.rb +51 -30
  31. data/lib/faraday/request/basic_authentication.rb +14 -7
  32. data/lib/faraday/request/instrumentation.rb +45 -27
  33. data/lib/faraday/request/json.rb +55 -0
  34. data/lib/faraday/request/token_authentication.rb +15 -10
  35. data/lib/faraday/request/url_encoded.rb +43 -23
  36. data/lib/faraday/request.rb +93 -32
  37. data/lib/faraday/response/json.rb +54 -0
  38. data/lib/faraday/response/logger.rb +20 -69
  39. data/lib/faraday/response/raise_error.rb +49 -14
  40. data/lib/faraday/response.rb +29 -23
  41. data/lib/faraday/utils/headers.rb +139 -0
  42. data/lib/faraday/utils/params_hash.rb +61 -0
  43. data/lib/faraday/utils.rb +38 -247
  44. data/lib/faraday/version.rb +5 -0
  45. data/lib/faraday.rb +134 -189
  46. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  47. data/spec/faraday/adapter/em_http_spec.rb +49 -0
  48. data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
  49. data/spec/faraday/adapter/excon_spec.rb +49 -0
  50. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  51. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  52. data/spec/faraday/adapter/patron_spec.rb +18 -0
  53. data/spec/faraday/adapter/rack_spec.rb +8 -0
  54. data/spec/faraday/adapter/test_spec.rb +377 -0
  55. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  56. data/spec/faraday/adapter_registry_spec.rb +28 -0
  57. data/spec/faraday/adapter_spec.rb +55 -0
  58. data/spec/faraday/composite_read_io_spec.rb +80 -0
  59. data/spec/faraday/connection_spec.rb +736 -0
  60. data/spec/faraday/error_spec.rb +60 -0
  61. data/spec/faraday/middleware_spec.rb +52 -0
  62. data/spec/faraday/options/env_spec.rb +70 -0
  63. data/spec/faraday/options/options_spec.rb +297 -0
  64. data/spec/faraday/options/proxy_options_spec.rb +44 -0
  65. data/spec/faraday/options/request_options_spec.rb +19 -0
  66. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  67. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  68. data/spec/faraday/rack_builder_spec.rb +345 -0
  69. data/spec/faraday/request/authorization_spec.rb +96 -0
  70. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  71. data/spec/faraday/request/json_spec.rb +111 -0
  72. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  73. data/spec/faraday/request_spec.rb +120 -0
  74. data/spec/faraday/response/json_spec.rb +119 -0
  75. data/spec/faraday/response/logger_spec.rb +220 -0
  76. data/spec/faraday/response/middleware_spec.rb +68 -0
  77. data/spec/faraday/response/raise_error_spec.rb +169 -0
  78. data/spec/faraday/response_spec.rb +75 -0
  79. data/spec/faraday/utils/headers_spec.rb +82 -0
  80. data/spec/faraday/utils_spec.rb +56 -0
  81. data/spec/faraday_spec.rb +37 -0
  82. data/spec/spec_helper.rb +132 -0
  83. data/spec/support/disabling_stub.rb +14 -0
  84. data/spec/support/fake_safe_buffer.rb +15 -0
  85. data/spec/support/helper_methods.rb +133 -0
  86. data/spec/support/shared_examples/adapter.rb +105 -0
  87. data/spec/support/shared_examples/params_encoder.rb +18 -0
  88. data/spec/support/shared_examples/request_method.rb +262 -0
  89. data/spec/support/streaming_response_checker.rb +35 -0
  90. data/spec/support/webmock_rack_app.rb +68 -0
  91. metadata +222 -29
  92. data/lib/faraday/adapter/em_http.rb +0 -243
  93. data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
  94. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
  95. data/lib/faraday/adapter/em_synchrony.rb +0 -106
  96. data/lib/faraday/adapter/excon.rb +0 -79
  97. data/lib/faraday/adapter/httpclient.rb +0 -128
  98. data/lib/faraday/adapter/net_http.rb +0 -137
  99. data/lib/faraday/adapter/net_http_persistent.rb +0 -63
  100. data/lib/faraday/adapter/patron.rb +0 -100
  101. data/lib/faraday/adapter/rack.rb +0 -58
  102. data/lib/faraday/request/multipart.rb +0 -68
  103. data/lib/faraday/request/retry.rb +0 -211
  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