faraday 0.17.3 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
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