faraday 0.17.3 → 2.7.4

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