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