faraday 0.17.3 → 1.4.1

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +156 -8
  3. data/LICENSE.md +1 -1
  4. data/README.md +16 -358
  5. data/Rakefile +1 -7
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday.rb +120 -189
  9. data/lib/faraday/adapter.rb +77 -22
  10. data/lib/faraday/adapter/em_http.rb +148 -102
  11. data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
  12. data/lib/faraday/adapter/em_synchrony.rb +110 -63
  13. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  14. data/lib/faraday/adapter/httpclient.rb +83 -59
  15. data/lib/faraday/adapter/patron.rb +80 -43
  16. data/lib/faraday/adapter/rack.rb +30 -13
  17. data/lib/faraday/adapter/test.rb +86 -53
  18. data/lib/faraday/adapter/typhoeus.rb +4 -1
  19. data/lib/faraday/adapter_registry.rb +30 -0
  20. data/lib/faraday/autoload.rb +44 -36
  21. data/lib/faraday/connection.rb +313 -182
  22. data/lib/faraday/dependency_loader.rb +37 -0
  23. data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
  24. data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
  25. data/lib/faraday/error.rb +29 -35
  26. data/lib/faraday/file_part.rb +128 -0
  27. data/lib/faraday/logging/formatter.rb +105 -0
  28. data/lib/faraday/methods.rb +6 -0
  29. data/lib/faraday/middleware.rb +19 -25
  30. data/lib/faraday/middleware_registry.rb +129 -0
  31. data/lib/faraday/options.rb +36 -191
  32. data/lib/faraday/options/connection_options.rb +22 -0
  33. data/lib/faraday/options/env.rb +181 -0
  34. data/lib/faraday/options/proxy_options.rb +28 -0
  35. data/lib/faraday/options/request_options.rb +22 -0
  36. data/lib/faraday/options/ssl_options.rb +59 -0
  37. data/lib/faraday/param_part.rb +53 -0
  38. data/lib/faraday/parameters.rb +4 -197
  39. data/lib/faraday/rack_builder.rb +76 -64
  40. data/lib/faraday/request.rb +86 -44
  41. data/lib/faraday/request/authorization.rb +44 -30
  42. data/lib/faraday/request/basic_authentication.rb +14 -7
  43. data/lib/faraday/request/instrumentation.rb +45 -27
  44. data/lib/faraday/request/multipart.rb +86 -48
  45. data/lib/faraday/request/retry.rb +197 -171
  46. data/lib/faraday/request/token_authentication.rb +15 -10
  47. data/lib/faraday/request/url_encoded.rb +43 -23
  48. data/lib/faraday/response.rb +24 -20
  49. data/lib/faraday/response/logger.rb +22 -69
  50. data/lib/faraday/response/raise_error.rb +49 -18
  51. data/lib/faraday/utils.rb +38 -247
  52. data/lib/faraday/utils/headers.rb +139 -0
  53. data/lib/faraday/utils/params_hash.rb +61 -0
  54. data/lib/faraday/version.rb +5 -0
  55. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  56. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  57. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  58. data/spec/faraday/adapter/excon_spec.rb +49 -0
  59. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  60. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  61. data/spec/faraday/adapter/patron_spec.rb +18 -0
  62. data/spec/faraday/adapter/rack_spec.rb +8 -0
  63. data/spec/faraday/adapter/test_spec.rb +260 -0
  64. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  65. data/spec/faraday/adapter_registry_spec.rb +28 -0
  66. data/spec/faraday/adapter_spec.rb +55 -0
  67. data/spec/faraday/composite_read_io_spec.rb +80 -0
  68. data/spec/faraday/connection_spec.rb +721 -0
  69. data/spec/faraday/error_spec.rb +12 -54
  70. data/spec/faraday/middleware_spec.rb +52 -0
  71. data/spec/faraday/options/env_spec.rb +70 -0
  72. data/spec/faraday/options/options_spec.rb +297 -0
  73. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  74. data/spec/faraday/options/request_options_spec.rb +19 -0
  75. data/spec/faraday/params_encoders/flat_spec.rb +42 -0
  76. data/spec/faraday/params_encoders/nested_spec.rb +142 -0
  77. data/spec/faraday/rack_builder_spec.rb +345 -0
  78. data/spec/faraday/request/authorization_spec.rb +88 -0
  79. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  80. data/spec/faraday/request/multipart_spec.rb +302 -0
  81. data/spec/faraday/request/retry_spec.rb +242 -0
  82. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  83. data/spec/faraday/request_spec.rb +120 -0
  84. data/spec/faraday/response/logger_spec.rb +220 -0
  85. data/spec/faraday/response/middleware_spec.rb +68 -0
  86. data/spec/faraday/response/raise_error_spec.rb +78 -15
  87. data/spec/faraday/response_spec.rb +75 -0
  88. data/spec/faraday/utils/headers_spec.rb +82 -0
  89. data/spec/faraday/utils_spec.rb +56 -0
  90. data/spec/faraday_spec.rb +37 -0
  91. data/spec/spec_helper.rb +63 -36
  92. data/spec/support/disabling_stub.rb +14 -0
  93. data/spec/support/fake_safe_buffer.rb +15 -0
  94. data/spec/support/helper_methods.rb +133 -0
  95. data/spec/support/shared_examples/adapter.rb +105 -0
  96. data/spec/support/shared_examples/params_encoder.rb +18 -0
  97. data/spec/support/shared_examples/request_method.rb +262 -0
  98. data/spec/support/streaming_response_checker.rb +35 -0
  99. data/spec/support/webmock_rack_app.rb +68 -0
  100. metadata +124 -41
  101. data/lib/faraday/adapter/excon.rb +0 -82
  102. data/lib/faraday/adapter/net_http.rb +0 -152
  103. data/lib/faraday/adapter/net_http_persistent.rb +0 -68
  104. data/lib/faraday/deprecate.rb +0 -107
  105. data/lib/faraday/upload_io.rb +0 -67
  106. data/spec/faraday/deprecate_spec.rb +0 -69
  107. data/test/adapters/default_test.rb +0 -14
  108. data/test/adapters/em_http_test.rb +0 -30
  109. data/test/adapters/em_synchrony_test.rb +0 -32
  110. data/test/adapters/excon_test.rb +0 -30
  111. data/test/adapters/httpclient_test.rb +0 -34
  112. data/test/adapters/integration.rb +0 -263
  113. data/test/adapters/logger_test.rb +0 -136
  114. data/test/adapters/net_http_persistent_test.rb +0 -114
  115. data/test/adapters/net_http_test.rb +0 -79
  116. data/test/adapters/patron_test.rb +0 -40
  117. data/test/adapters/rack_test.rb +0 -38
  118. data/test/adapters/test_middleware_test.rb +0 -157
  119. data/test/adapters/typhoeus_test.rb +0 -38
  120. data/test/authentication_middleware_test.rb +0 -65
  121. data/test/composite_read_io_test.rb +0 -109
  122. data/test/connection_test.rb +0 -738
  123. data/test/env_test.rb +0 -268
  124. data/test/helper.rb +0 -75
  125. data/test/live_server.rb +0 -67
  126. data/test/middleware/instrumentation_test.rb +0 -88
  127. data/test/middleware/retry_test.rb +0 -282
  128. data/test/middleware_stack_test.rb +0 -260
  129. data/test/multibyte.txt +0 -1
  130. data/test/options_test.rb +0 -333
  131. data/test/parameters_test.rb +0 -157
  132. data/test/request_middleware_test.rb +0 -126
  133. data/test/response_middleware_test.rb +0 -72
  134. data/test/strawberry.rb +0 -2
  135. data/test/utils_test.rb +0 -98
@@ -0,0 +1,721 @@
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
+ context 'with url_prefixed connection' do
257
+ let(:url) { 'http://sushi.com/sushi/' }
258
+
259
+ it 'parses url and changes scheme' do
260
+ conn.scheme = 'https'
261
+ uri = conn.build_exclusive_url('sake.html')
262
+ expect(uri.to_s).to eq('https://sushi.com/sushi/sake.html')
263
+ end
264
+
265
+ it 'joins url to base with ending slash' do
266
+ uri = conn.build_exclusive_url('sake.html')
267
+ expect(uri.to_s).to eq('http://sushi.com/sushi/sake.html')
268
+ end
269
+
270
+ it 'used default base with ending slash' do
271
+ uri = conn.build_exclusive_url
272
+ expect(uri.to_s).to eq('http://sushi.com/sushi/')
273
+ end
274
+
275
+ it 'overrides base' do
276
+ uri = conn.build_exclusive_url('/sake/')
277
+ expect(uri.to_s).to eq('http://sushi.com/sake/')
278
+ end
279
+ end
280
+
281
+ context 'with colon in path' do
282
+ let(:url) { 'http://service.com' }
283
+
284
+ it 'joins url to base when used absolute path' do
285
+ conn = Faraday.new(url: url)
286
+ uri = conn.build_exclusive_url('/service:search?limit=400')
287
+ expect(uri.to_s).to eq('http://service.com/service:search?limit=400')
288
+ end
289
+
290
+ it 'joins url to base when used relative path' do
291
+ conn = Faraday.new(url: url)
292
+ uri = conn.build_exclusive_url('service:search?limit=400')
293
+ expect(uri.to_s).to eq('http://service.com/service%3Asearch?limit=400')
294
+ end
295
+
296
+ it 'joins url to base when used with path prefix' do
297
+ conn = Faraday.new(url: url)
298
+ conn.path_prefix = '/api'
299
+ uri = conn.build_exclusive_url('service:search?limit=400')
300
+ expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400')
301
+ end
302
+ end
303
+ end
304
+
305
+ describe '#build_url' do
306
+ let(:url) { 'http://sushi.com/nigiri' }
307
+
308
+ it 'uses params' do
309
+ conn.params = { a: 1, b: 1 }
310
+ expect(conn.build_url.to_s).to eq('http://sushi.com/nigiri?a=1&b=1')
311
+ end
312
+
313
+ it 'merges params' do
314
+ conn.params = { a: 1, b: 1 }
315
+ url = conn.build_url(nil, b: 2, c: 3)
316
+ expect(url.to_s).to eq('http://sushi.com/nigiri?a=1&b=2&c=3')
317
+ end
318
+ end
319
+
320
+ describe '#build_request' do
321
+ let(:url) { 'https://asushi.com/sake.html' }
322
+ let(:request) { conn.build_request(:get) }
323
+
324
+ before do
325
+ conn.headers = { 'Authorization' => 'token abc123' }
326
+ request.headers.delete('Authorization')
327
+ end
328
+
329
+ it { expect(conn.headers.keys).to eq(['Authorization']) }
330
+ it { expect(conn.headers.include?('Authorization')).to be_truthy }
331
+ it { expect(request.headers.keys).to be_empty }
332
+ it { expect(request.headers.include?('Authorization')).to be_falsey }
333
+ end
334
+
335
+ describe '#to_env' do
336
+ subject { conn.build_request(:get).to_env(conn).url }
337
+
338
+ let(:url) { 'http://sushi.com/sake.html' }
339
+ let(:options) { { params: @params } }
340
+
341
+ it 'parses url params into query' do
342
+ @params = { 'a[b]' => '1 + 2' }
343
+ expect(subject.query).to eq('a%5Bb%5D=1+%2B+2')
344
+ end
345
+
346
+ it 'escapes per spec' do
347
+ @params = { 'a' => '1+2 foo~bar.-baz' }
348
+ expect(subject.query).to eq('a=1%2B2+foo~bar.-baz')
349
+ end
350
+
351
+ it 'bracketizes nested params in query' do
352
+ @params = { 'a' => { 'b' => 'c' } }
353
+ expect(subject.query).to eq('a%5Bb%5D=c')
354
+ end
355
+
356
+ it 'bracketizes repeated params in query' do
357
+ @params = { 'a' => [1, 2] }
358
+ expect(subject.query).to eq('a%5B%5D=1&a%5B%5D=2')
359
+ end
360
+
361
+ it 'without braketizing repeated params in query' do
362
+ @params = { 'a' => [1, 2] }
363
+ conn.options.params_encoder = Faraday::FlatParamsEncoder
364
+ expect(subject.query).to eq('a=1&a=2')
365
+ end
366
+ end
367
+
368
+ describe 'proxy support' do
369
+ it 'accepts string' do
370
+ with_env 'http_proxy' => 'http://env-proxy.com:80' do
371
+ conn.proxy = 'http://proxy.com'
372
+ expect(conn.proxy.host).to eq('proxy.com')
373
+ end
374
+ end
375
+
376
+ it 'accepts uri' do
377
+ with_env 'http_proxy' => 'http://env-proxy.com:80' do
378
+ conn.proxy = URI.parse('http://proxy.com')
379
+ expect(conn.proxy.host).to eq('proxy.com')
380
+ end
381
+ end
382
+
383
+ it 'accepts hash with string uri' do
384
+ with_env 'http_proxy' => 'http://env-proxy.com:80' do
385
+ conn.proxy = { uri: 'http://proxy.com', user: 'rick' }
386
+ expect(conn.proxy.host).to eq('proxy.com')
387
+ expect(conn.proxy.user).to eq('rick')
388
+ end
389
+ end
390
+
391
+ it 'accepts hash' do
392
+ with_env 'http_proxy' => 'http://env-proxy.com:80' do
393
+ conn.proxy = { uri: URI.parse('http://proxy.com'), user: 'rick' }
394
+ expect(conn.proxy.host).to eq('proxy.com')
395
+ expect(conn.proxy.user).to eq('rick')
396
+ end
397
+ end
398
+
399
+ it 'accepts http env' do
400
+ with_env 'http_proxy' => 'http://env-proxy.com:80' do
401
+ expect(conn.proxy.host).to eq('env-proxy.com')
402
+ end
403
+ end
404
+
405
+ it 'accepts http env with auth' do
406
+ with_env 'http_proxy' => 'http://a%40b:my%20pass@proxy.com:80' do
407
+ expect(conn.proxy.user).to eq('a@b')
408
+ expect(conn.proxy.password).to eq('my pass')
409
+ end
410
+ end
411
+
412
+ it 'accepts env without scheme' do
413
+ with_env 'http_proxy' => 'localhost:8888' do
414
+ uri = conn.proxy[:uri]
415
+ expect(uri.host).to eq('localhost')
416
+ expect(uri.port).to eq(8888)
417
+ end
418
+ end
419
+
420
+ it 'fetches no proxy from nil env' do
421
+ with_env 'http_proxy' => nil do
422
+ expect(conn.proxy).to be_nil
423
+ end
424
+ end
425
+
426
+ it 'fetches no proxy from blank env' do
427
+ with_env 'http_proxy' => '' do
428
+ expect(conn.proxy).to be_nil
429
+ end
430
+ end
431
+
432
+ it 'does not accept uppercase env' do
433
+ with_env 'HTTP_PROXY' => 'http://localhost:8888/' do
434
+ expect(conn.proxy).to be_nil
435
+ end
436
+ end
437
+
438
+ it 'allows when url in no proxy list' do
439
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
440
+ conn = Faraday::Connection.new('http://example.com')
441
+ expect(conn.proxy).to be_nil
442
+ end
443
+ end
444
+
445
+ it 'allows when prefixed url is not in no proxy list' do
446
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
447
+ conn = Faraday::Connection.new('http://prefixedexample.com')
448
+ expect(conn.proxy.host).to eq('proxy.com')
449
+ end
450
+ end
451
+
452
+ it 'allows when subdomain url is in no proxy list' do
453
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
454
+ conn = Faraday::Connection.new('http://subdomain.example.com')
455
+ expect(conn.proxy).to be_nil
456
+ end
457
+ end
458
+
459
+ it 'allows when url not in no proxy list' do
460
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example2.com' do
461
+ conn = Faraday::Connection.new('http://example.com')
462
+ expect(conn.proxy.host).to eq('proxy.com')
463
+ end
464
+ end
465
+
466
+ it 'allows when ip address is not in no proxy list but url is' do
467
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'localhost' do
468
+ conn = Faraday::Connection.new('http://127.0.0.1')
469
+ expect(conn.proxy).to be_nil
470
+ end
471
+ end
472
+
473
+ it 'allows when url is not in no proxy list but ip address is' do
474
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => '127.0.0.1' do
475
+ conn = Faraday::Connection.new('http://localhost')
476
+ expect(conn.proxy).to be_nil
477
+ end
478
+ end
479
+
480
+ it 'allows in multi element no proxy list' do
481
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example0.com,example.com,example1.com' do
482
+ expect(Faraday::Connection.new('http://example0.com').proxy).to be_nil
483
+ expect(Faraday::Connection.new('http://example.com').proxy).to be_nil
484
+ expect(Faraday::Connection.new('http://example1.com').proxy).to be_nil
485
+ expect(Faraday::Connection.new('http://example2.com').proxy.host).to eq('proxy.com')
486
+ end
487
+ end
488
+
489
+ it 'test proxy requires uri' do
490
+ expect { conn.proxy = { uri: :bad_uri, user: 'rick' } }.to raise_error(ArgumentError)
491
+ end
492
+
493
+ it 'uses env http_proxy' do
494
+ with_env 'http_proxy' => 'http://proxy.com' do
495
+ conn = Faraday.new
496
+ expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
497
+ expect(conn.proxy_for_request('http://google.co.uk').host).to eq('proxy.com')
498
+ end
499
+ end
500
+
501
+ it 'uses processes no_proxy before http_proxy' do
502
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'google.co.uk' do
503
+ conn = Faraday.new
504
+ expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
505
+ expect(conn.proxy_for_request('http://google.co.uk')).to be_nil
506
+ end
507
+ end
508
+
509
+ it 'uses env https_proxy' do
510
+ with_env 'https_proxy' => 'https://proxy.com' do
511
+ conn = Faraday.new
512
+ expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
513
+ expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy.com')
514
+ end
515
+ end
516
+
517
+ it 'uses processes no_proxy before https_proxy' do
518
+ with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
519
+ conn = Faraday.new
520
+ expect(conn.instance_variable_get('@manual_proxy')).to be_falsey
521
+ expect(conn.proxy_for_request('https://google.co.uk')).to be_nil
522
+ end
523
+ end
524
+
525
+ it 'gives priority to manually set proxy' do
526
+ with_env 'https_proxy' => 'https://proxy.com', 'no_proxy' => 'google.co.uk' do
527
+ conn = Faraday.new
528
+ conn.proxy = 'http://proxy2.com'
529
+
530
+ expect(conn.instance_variable_get('@manual_proxy')).to be_truthy
531
+ expect(conn.proxy_for_request('https://google.co.uk').host).to eq('proxy2.com')
532
+ end
533
+ end
534
+
535
+ it 'ignores env proxy if set that way' do
536
+ with_env_proxy_disabled do
537
+ with_env 'http_proxy' => 'http://duncan.proxy.com:80' do
538
+ expect(conn.proxy).to be_nil
539
+ end
540
+ end
541
+ end
542
+
543
+ context 'performing a request' do
544
+ before { stub_request(:get, 'http://example.com') }
545
+
546
+ it 'dynamically checks proxy' do
547
+ with_env 'http_proxy' => 'http://proxy.com:80' do
548
+ conn = Faraday.new
549
+ expect(conn.proxy.uri.host).to eq('proxy.com')
550
+
551
+ conn.get('http://example.com') do |req|
552
+ expect(req.options.proxy.uri.host).to eq('proxy.com')
553
+ end
554
+ end
555
+
556
+ conn.get('http://example.com')
557
+ expect(conn.instance_variable_get('@temp_proxy')).to be_nil
558
+ end
559
+
560
+ it 'dynamically check no proxy' do
561
+ with_env 'http_proxy' => 'http://proxy.com', 'no_proxy' => 'example.com' do
562
+ conn = Faraday.new
563
+
564
+ expect(conn.proxy.uri.host).to eq('proxy.com')
565
+
566
+ conn.get('http://example.com') do |req|
567
+ expect(req.options.proxy).to be_nil
568
+ end
569
+ end
570
+ end
571
+ end
572
+ end
573
+
574
+ describe '#dup' do
575
+ subject { conn.dup }
576
+
577
+ let(:url) { 'http://sushi.com/foo' }
578
+ let(:options) do
579
+ {
580
+ ssl: { verify: :none },
581
+ headers: { 'content-type' => 'text/plain' },
582
+ params: { 'a' => '1' },
583
+ request: { timeout: 5 }
584
+ }
585
+ end
586
+
587
+ it { expect(subject.build_exclusive_url).to eq(conn.build_exclusive_url) }
588
+ it { expect(subject.headers['content-type']).to eq('text/plain') }
589
+ it { expect(subject.params['a']).to eq('1') }
590
+
591
+ context 'after manual changes' do
592
+ before do
593
+ subject.basic_auth('', '')
594
+ subject.headers['content-length'] = 12
595
+ subject.params['b'] = '2'
596
+ subject.options[:open_timeout] = 10
597
+ end
598
+
599
+ it { expect(subject.builder.handlers.size).to eq(1) }
600
+ it { expect(conn.builder.handlers.size).to eq(1) }
601
+ it { expect(conn.headers.key?('content-length')).to be_falsey }
602
+ it { expect(conn.params.key?('b')).to be_falsey }
603
+ it { expect(subject.options[:timeout]).to eq(5) }
604
+ it { expect(conn.options[:open_timeout]).to be_nil }
605
+ end
606
+ end
607
+
608
+ describe '#respond_to?' do
609
+ it { expect(Faraday.respond_to?(:get)).to be_truthy }
610
+ it { expect(Faraday.respond_to?(:post)).to be_truthy }
611
+ end
612
+
613
+ describe 'default_connection_options' do
614
+ context 'assigning a default value' do
615
+ before do
616
+ Faraday.default_connection_options = nil
617
+ Faraday.default_connection_options.request.timeout = 10
618
+ end
619
+
620
+ it_behaves_like 'default connection options'
621
+ end
622
+
623
+ context 'assigning a hash' do
624
+ before { Faraday.default_connection_options = { request: { timeout: 10 } } }
625
+
626
+ it_behaves_like 'default connection options'
627
+ end
628
+ end
629
+
630
+ describe 'request params' do
631
+ context 'with simple url' do
632
+ let(:url) { 'http://example.com' }
633
+ let!(:stubbed) { stub_request(:get, 'http://example.com?a=a&p=3') }
634
+
635
+ after { expect(stubbed).to have_been_made.once }
636
+
637
+ it 'test_overrides_request_params' do
638
+ conn.get('?p=2&a=a', p: 3)
639
+ end
640
+
641
+ it 'test_overrides_request_params_block' do
642
+ conn.get('?p=1&a=a', p: 2) do |req|
643
+ req.params[:p] = 3
644
+ end
645
+ end
646
+
647
+ it 'test_overrides_request_params_block_url' do
648
+ conn.get(nil, p: 2) do |req|
649
+ req.url('?p=1&a=a', 'p' => 3)
650
+ end
651
+ end
652
+ end
653
+
654
+ context 'with url and extra params' do
655
+ let(:url) { 'http://example.com?a=1&b=2' }
656
+ let(:options) { { params: { c: 3 } } }
657
+
658
+ it 'merges connection and request params' do
659
+ stubbed = stub_request(:get, 'http://example.com?a=1&b=2&c=3&limit=5&page=1')
660
+ conn.get('?page=1', limit: 5)
661
+ expect(stubbed).to have_been_made.once
662
+ end
663
+
664
+ it 'allows to override all params' do
665
+ stubbed = stub_request(:get, 'http://example.com?b=b')
666
+ conn.get('?p=1&a=a', p: 2) do |req|
667
+ expect(req.params[:a]).to eq('a')
668
+ expect(req.params['c']).to eq(3)
669
+ expect(req.params['p']).to eq(2)
670
+ req.params = { b: 'b' }
671
+ expect(req.params['b']).to eq('b')
672
+ end
673
+ expect(stubbed).to have_been_made.once
674
+ end
675
+
676
+ it 'allows to set params_encoder for single request' do
677
+ encoder = Object.new
678
+ def encoder.encode(params)
679
+ params.map { |k, v| "#{k.upcase}-#{v.to_s.upcase}" }.join(',')
680
+ end
681
+ stubbed = stub_request(:get, 'http://example.com/?A-1,B-2,C-3,FEELING-BLUE')
682
+
683
+ conn.get('/', feeling: 'blue') do |req|
684
+ req.options.params_encoder = encoder
685
+ end
686
+ expect(stubbed).to have_been_made.once
687
+ end
688
+ end
689
+
690
+ context 'with default params encoder' do
691
+ let!(:stubbed) { stub_request(:get, 'http://example.com?color%5B%5D=red&color%5B%5D=blue') }
692
+ after { expect(stubbed).to have_been_made.once }
693
+
694
+ it 'supports array params in url' do
695
+ conn.get('http://example.com?color[]=red&color[]=blue')
696
+ end
697
+
698
+ it 'supports array params in params' do
699
+ conn.get('http://example.com', color: %w[red blue])
700
+ end
701
+ end
702
+
703
+ context 'with flat params encoder' do
704
+ let(:options) { { request: { params_encoder: Faraday::FlatParamsEncoder } } }
705
+ let!(:stubbed) { stub_request(:get, 'http://example.com?color=blue') }
706
+ after { expect(stubbed).to have_been_made.once }
707
+
708
+ it 'supports array params in params' do
709
+ conn.get('http://example.com', color: %w[red blue])
710
+ end
711
+
712
+ context 'with array param in url' do
713
+ let(:url) { 'http://example.com?color[]=red&color[]=blue' }
714
+
715
+ it do
716
+ conn.get('/')
717
+ end
718
+ end
719
+ end
720
+ end
721
+ end