curb 1.2.2 → 1.3.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.
@@ -32,6 +32,23 @@ class TestCurbCurlEasy < Test::Unit::TestCase
32
32
  assert_match(/GET/, http.body)
33
33
  end
34
34
 
35
+ def test_resolve_clear_keeps_handle_usable
36
+ host = "curb.invalid"
37
+ url = "http://#{host}:#{TestServlet.port}#{TestServlet.path}"
38
+ mapping = "#{host}:#{TestServlet.port}:127.0.0.1"
39
+
40
+ http = Curl::Easy.new(url)
41
+ http.dns_cache_timeout = 0
42
+ http.resolve = [mapping]
43
+ http.get
44
+ assert_match(/GET/, http.body)
45
+
46
+ http.resolve = nil
47
+ http.url = TestServlet.url
48
+ http.get
49
+ assert_match(/GET/, http.body)
50
+ end
51
+
35
52
  def test_curlopt_stderr_with_file
36
53
  # does not work with Tempfile directly
37
54
  path = Tempfile.new('curb_test_curlopt_stderr').path
@@ -106,6 +123,248 @@ class TestCurbCurlEasy < Test::Unit::TestCase
106
123
  assert_equal "", easy.body_str.to_s
107
124
  end
108
125
 
126
+ def test_perform_releases_failed_implicit_multi_without_follow_up_easy_perform
127
+ Curl::Easy.flush_deferred_multi_closes
128
+ assert_equal 0, Curl::Easy.deferred_multi_closes.length
129
+
130
+ easy, implicit_multi = capture_failed_implicit_multi_cleanup_state
131
+
132
+ assert_nil easy.multi
133
+ assert_equal({}, implicit_multi.requests)
134
+ assert_equal false, implicit_multi.instance_variable_get(:@deferred_close)
135
+ assert_equal 0, Curl::Easy.deferred_multi_closes.length
136
+ ensure
137
+ easy.multi = nil if defined?(easy) && easy
138
+ implicit_multi.close if defined?(implicit_multi) && implicit_multi
139
+ Curl::Easy.flush_deferred_multi_closes
140
+ end
141
+
142
+ def test_deferred_multi_closes_stay_with_their_owner_thread_across_retry
143
+ Curl::Easy.flush_deferred_multi_closes(all_threads: true)
144
+ multi = deferred_close_stub_multi(failures: 1)
145
+
146
+ Curl::Easy.defer_multi_close(multi, nil)
147
+
148
+ Curl::Easy.flush_deferred_multi_closes
149
+ assert_equal 1, multi.close_attempts
150
+ assert_equal true, multi.instance_variable_get(:@deferred_close)
151
+ assert_equal 1, Curl::Easy.deferred_multi_closes.length
152
+
153
+ Thread.new { Curl::Easy.flush_deferred_multi_closes }.join
154
+ assert_equal 1, multi.close_attempts
155
+ assert_equal true, multi.instance_variable_get(:@deferred_close)
156
+ assert_equal 1, Curl::Easy.deferred_multi_closes.length
157
+
158
+ Curl::Easy.flush_deferred_multi_closes
159
+ assert_equal 2, multi.close_attempts
160
+ assert_equal true, multi.closed?
161
+ assert_equal false, multi.instance_variable_get(:@deferred_close)
162
+ assert_equal 0, Curl::Easy.deferred_multi_closes.length
163
+ ensure
164
+ Curl::Easy.flush_deferred_multi_closes(all_threads: true)
165
+ end
166
+
167
+ def capture_created_multis
168
+ created_multis = []
169
+ multi_singleton = class << Curl::Multi; self; end
170
+
171
+ multi_singleton.__send__(:alias_method, :__curb_test_original_new, :new)
172
+ multi_singleton.__send__(:define_method, :new) do |*args, &block|
173
+ multi = __curb_test_original_new(*args, &block)
174
+ created_multis << multi
175
+ multi
176
+ end
177
+
178
+ yield created_multis
179
+ ensure
180
+ if defined?(multi_singleton) && multi_singleton.method_defined?(:__curb_test_original_new)
181
+ multi_singleton.__send__(:remove_method, :new)
182
+ multi_singleton.__send__(:alias_method, :new, :__curb_test_original_new)
183
+ multi_singleton.__send__(:remove_method, :__curb_test_original_new)
184
+ end
185
+ end
186
+
187
+ def capture_failed_implicit_multi_cleanup_state
188
+ created_multis = nil
189
+ easy = nil
190
+
191
+ capture_created_multis do |captured_multis|
192
+ created_multis = captured_multis
193
+ easy = Curl::Easy.new(TestServlet.url)
194
+ easy.on_complete { raise "complete blew up" }
195
+
196
+ error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
197
+ assert_equal "complete blew up", error.message
198
+ end
199
+
200
+ assert_equal 1, created_multis.length, "test should observe one implicit multi created by Easy#perform"
201
+
202
+ [easy, created_multis.first]
203
+ end
204
+
205
+ def deferred_close_stub_multi(failures:)
206
+ Object.new.tap do |multi|
207
+ requests = {}
208
+ remaining_failures = failures
209
+ close_attempts = 0
210
+ closed = false
211
+
212
+ multi.define_singleton_method(:requests) { requests }
213
+ multi.define_singleton_method(:_close) do
214
+ close_attempts += 1
215
+ if remaining_failures.positive?
216
+ remaining_failures -= 1
217
+ raise "close failed"
218
+ end
219
+
220
+ closed = true
221
+ end
222
+ multi.define_singleton_method(:close_attempts) { close_attempts }
223
+ multi.define_singleton_method(:closed?) { closed }
224
+ end
225
+ end
226
+
227
+ def test_perform_restores_explicit_multi_after_callback_error
228
+ multi = Curl::Multi.new
229
+ easy = Curl::Easy.new(TestServlet.url)
230
+ easy.multi = multi
231
+ easy.on_complete { raise "complete blew up" }
232
+
233
+ error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
234
+ assert_equal "complete blew up", error.message
235
+ assert_same multi, easy.multi
236
+ assert_equal({}, multi.requests)
237
+
238
+ easy.on_complete { |_curl| }
239
+ easy.perform
240
+
241
+ assert_same multi, easy.multi
242
+ assert_equal "GET", easy.body_str
243
+ ensure
244
+ easy.multi = nil if defined?(easy) && easy && easy.multi.equal?(multi)
245
+ multi.close if defined?(multi) && multi
246
+ end
247
+
248
+ def test_perform_restores_cached_implicit_multi_after_callback_error
249
+ Curl::Multi.autoclose = false
250
+
251
+ easy = Curl::Easy.new(TestServlet.url)
252
+ easy.perform
253
+
254
+ cached_multi = easy.multi
255
+ easy.on_complete { raise "complete blew up" }
256
+
257
+ error = assert_raise(Curl::Err::AbortedByCallbackError) { easy.perform }
258
+ assert_equal "complete blew up", error.message
259
+ assert_same cached_multi, easy.multi
260
+ assert_equal({}, cached_multi.requests)
261
+
262
+ easy.on_complete { |_curl| }
263
+ easy.perform
264
+
265
+ assert_same cached_multi, easy.multi
266
+ assert_equal "GET", easy.body_str
267
+ ensure
268
+ easy.multi = nil if defined?(easy) && easy
269
+ cached_multi.close if defined?(cached_multi) && cached_multi
270
+ Curl::Multi.autoclose = false
271
+ end
272
+
273
+ def test_close_clears_explicit_idle_easy_multi_reference
274
+ easy = Curl::Easy.new($TEST_URL)
275
+ multi = Curl::Multi.new
276
+ easy.multi = multi
277
+
278
+ assert_same multi, easy.multi
279
+ assert_equal({}, multi.requests)
280
+
281
+ multi.close
282
+
283
+ assert_nil easy.multi
284
+ end
285
+
286
+ def test_close_clears_cached_idle_easy_multi_reference
287
+ Curl::Multi.autoclose = false
288
+
289
+ easy = Curl::Easy.new($TEST_URL)
290
+ easy.perform
291
+
292
+ cached_multi = easy.multi
293
+ assert_not_nil cached_multi
294
+ assert_equal({}, cached_multi.requests)
295
+
296
+ cached_multi.close
297
+
298
+ assert_nil easy.multi
299
+ ensure
300
+ easy.multi = nil if defined?(easy) && easy
301
+ Curl::Multi.autoclose = false
302
+ end
303
+
304
+ def test_multi_assignment_rejects_non_multi_objects
305
+ easy = Curl::Easy.new($TEST_URL)
306
+
307
+ error = assert_raise(TypeError) { easy.multi = Object.new }
308
+
309
+ assert_match(/Curl::Multi/, error.message)
310
+ assert_nil easy.multi
311
+ end
312
+
313
+ def test_perform_can_reuse_explicit_multi_when_autoclose_is_enabled
314
+ Curl::Multi.autoclose = true
315
+
316
+ easy = Curl::Easy.new(TestServlet.url)
317
+ multi = Curl::Multi.new
318
+
319
+ easy.multi = multi
320
+ easy.perform
321
+
322
+ assert_nil easy.multi
323
+ assert_equal({}, multi.requests)
324
+
325
+ easy.multi = multi
326
+ easy.perform
327
+
328
+ assert_nil easy.multi
329
+ assert_equal({}, multi.requests)
330
+ assert_equal "GET", easy.body_str
331
+ ensure
332
+ easy.multi = nil if defined?(easy) && easy
333
+ multi.close if defined?(multi) && multi
334
+ Curl::Multi.autoclose = false
335
+ end
336
+
337
+ def test_perform_reraises_on_body_exception_for_frozen_easy
338
+ easy = Curl::Easy.new($TEST_URL)
339
+ callback_error = Class.new(RuntimeError)
340
+ easy.on_body { raise callback_error, "body blew up" }
341
+ easy.freeze
342
+
343
+ error = assert_raise(callback_error) { easy.perform }
344
+
345
+ assert_equal "body blew up", error.message
346
+ end
347
+
348
+ def test_perform_preserves_implicit_multi_when_autoclose_is_disabled
349
+ Curl::Multi.autoclose = false
350
+
351
+ easy = Curl::Easy.new(TestServlet.url)
352
+ easy.perform
353
+
354
+ first_multi = easy.multi
355
+ assert_not_nil first_multi
356
+ assert_equal({}, first_multi.requests)
357
+
358
+ easy.perform
359
+
360
+ assert_same first_multi, easy.multi
361
+ assert_equal "GET", easy.body_str
362
+ ensure
363
+ easy.multi = nil if defined?(easy) && easy
364
+ first_multi.close if defined?(first_multi) && first_multi
365
+ Curl::Multi.autoclose = false
366
+ end
367
+
109
368
  def test_curlopt_stderr_fails_with_tempdir
110
369
  Tempfile.open('curb_test_curlopt_stderr') do |tempfile|
111
370
  easy = Curl::Easy.new(TestServlet.url)
@@ -736,6 +995,27 @@ class TestCurbCurlEasy < Test::Unit::TestCase
736
995
  assert_raises(ArgumentError) { c.resolve_mode = :bad }
737
996
  end
738
997
 
998
+ def test_http_version_accessors
999
+ c = Curl::Easy.new
1000
+ assert_equal Curl::HTTP_NONE, c.http_version
1001
+
1002
+ c.http_version = Curl::HTTP_1_1
1003
+ assert_equal Curl::HTTP_1_1, c.http_version
1004
+
1005
+ if Curl.const_defined?(:HTTP_2TLS)
1006
+ c.http_version = Curl::HTTP_2TLS
1007
+ assert_equal Curl::HTTP_2TLS, c.http_version
1008
+ end
1009
+
1010
+ if Curl.const_defined?(:HTTP_2_PRIOR_KNOWLEDGE)
1011
+ c.http_version = Curl::HTTP_2_PRIOR_KNOWLEDGE
1012
+ assert_equal Curl::HTTP_2_PRIOR_KNOWLEDGE, c.http_version
1013
+ end
1014
+
1015
+ c.http_version = nil
1016
+ assert_equal Curl::HTTP_NONE, c.http_version
1017
+ end
1018
+
739
1019
  def test_enable_cookies
740
1020
  c = Curl::Easy.new
741
1021
  assert !c.enable_cookies?
@@ -900,7 +1180,85 @@ class TestCurbCurlEasy < Test::Unit::TestCase
900
1180
 
901
1181
  assert_equal "PUT\nfoo=bar&encoded%20string=val", curl.body_str
902
1182
  end
903
-
1183
+
1184
+ def test_post_body_from_to_s_keeps_string_buffer_alive
1185
+ post_body = Object.new
1186
+ def post_body.to_s
1187
+ 'foo=bar&encoded%20string=val'
1188
+ end
1189
+
1190
+ curl = Curl::Easy.new(TestServlet.url)
1191
+ curl.post_body = post_body
1192
+
1193
+ assert_equal 'foo=bar&encoded%20string=val', curl.post_body
1194
+
1195
+ GC.start
1196
+ GC.compact if GC.respond_to?(:compact)
1197
+
1198
+ curl.perform
1199
+ assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
1200
+ end
1201
+
1202
+ def test_post_body_preserves_assigned_snapshot_when_original_string_is_mutated
1203
+ omit('CURLOPT_COPYPOSTFIELDS is not available in this build') unless Curl.const_defined?(:CURLOPT_COPYPOSTFIELDS)
1204
+
1205
+ curl = Curl::Easy.new(TestServlet.url)
1206
+ post_body = String.new('alpha=1')
1207
+ curl.post_body = post_body
1208
+
1209
+ post_body.replace('beta=2')
1210
+
1211
+ assert_equal 'beta=2', post_body
1212
+ assert_equal 'alpha=1', curl.post_body
1213
+
1214
+ curl.perform
1215
+
1216
+ assert_equal "POST\nalpha=1", curl.body_str
1217
+ assert_equal 'alpha=1', curl.post_body
1218
+ end
1219
+
1220
+ def test_setopt_postfields_keeps_string_buffer_alive
1221
+ curl = Curl::Easy.new(TestServlet.url)
1222
+ curl.set(Curl::CURLOPT_POSTFIELDS, 'foo=bar&encoded%20string=val')
1223
+
1224
+ assert_equal 'foo=bar&encoded%20string=val', curl.post_body
1225
+
1226
+ GC.start
1227
+ GC.compact if GC.respond_to?(:compact)
1228
+
1229
+ curl.perform
1230
+ assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
1231
+ end
1232
+
1233
+ def test_setopt_postfields_preserves_assigned_snapshot_when_original_string_is_mutated
1234
+ omit('CURLOPT_COPYPOSTFIELDS is not available in this build') unless Curl.const_defined?(:CURLOPT_COPYPOSTFIELDS)
1235
+
1236
+ curl = Curl::Easy.new(TestServlet.url)
1237
+ post_body = String.new('alpha=1')
1238
+ curl.set(Curl::CURLOPT_POSTFIELDS, post_body)
1239
+
1240
+ post_body.replace('beta=2')
1241
+
1242
+ assert_equal 'beta=2', post_body
1243
+ assert_equal 'alpha=1', curl.post_body
1244
+
1245
+ curl.perform
1246
+
1247
+ assert_equal "POST\nalpha=1", curl.body_str
1248
+ assert_equal 'alpha=1', curl.post_body
1249
+ end
1250
+
1251
+ def test_setopt_postfields_nil_preserves_post_request
1252
+ curl = Curl::Easy.new(TestServlet.url)
1253
+ curl.set(Curl::CURLOPT_POST, true)
1254
+ curl.set(Curl::CURLOPT_POSTFIELDS, nil)
1255
+
1256
+ curl.perform
1257
+
1258
+ assert_nil curl.post_body
1259
+ assert_equal "POST\n", curl.body_str
1260
+ end
1261
+
904
1262
  def test_form_body_remote
905
1263
  curl = Curl::Easy.new(TestServlet.url)
906
1264
  curl.http_post('foo=bar', 'encoded%20string=val')
@@ -930,6 +1288,19 @@ class TestCurbCurlEasy < Test::Unit::TestCase
930
1288
  }
931
1289
  end
932
1290
 
1291
+ def test_multipart_form_reuse_clears_previous_form
1292
+ curl = Curl::Easy.new(TestServlet.url)
1293
+ curl.multipart_form_post = true
1294
+ curl.http_post(Curl::PostField.content('document_id', '5'))
1295
+ assert_match(/document_id/, curl.body_str)
1296
+
1297
+ curl.multipart_form_post = false
1298
+ curl.post_body = 'foo=bar'
1299
+ curl.http_post
1300
+
1301
+ assert_equal "POST\nfoo=bar", curl.body_str
1302
+ end
1303
+
933
1304
  def test_delete_remote
934
1305
  curl = Curl::Easy.new(TestServlet.url)
935
1306
  curl.http_delete
@@ -1293,6 +1664,84 @@ class TestCurbCurlEasy < Test::Unit::TestCase
1293
1664
  end
1294
1665
  end
1295
1666
 
1667
+ def test_close_in_on_progress_is_blocked
1668
+ curl = Curl::Easy.new(TestServlet.url)
1669
+ did_raise = false
1670
+
1671
+ curl.on_progress do |_dltotal, _dlnow, _ultotal, _ulnow|
1672
+ unless did_raise
1673
+ begin
1674
+ curl.close
1675
+ rescue RuntimeError
1676
+ did_raise = true
1677
+ end
1678
+ end
1679
+ true
1680
+ end
1681
+
1682
+ curl.perform
1683
+ assert did_raise
1684
+ end
1685
+
1686
+ def test_close_in_on_debug_is_blocked
1687
+ curl = Curl::Easy.new(TestServlet.url)
1688
+ did_raise = false
1689
+
1690
+ curl.on_debug do |_type, _data|
1691
+ unless did_raise
1692
+ begin
1693
+ curl.close
1694
+ rescue RuntimeError
1695
+ did_raise = true
1696
+ end
1697
+ end
1698
+ end
1699
+
1700
+ curl.perform
1701
+ assert did_raise
1702
+ end
1703
+
1704
+ def test_close_in_upload_read_is_blocked
1705
+ curl = Curl::Easy.new(TestServlet.url)
1706
+
1707
+ reader_class = Class.new do
1708
+ attr_reader :close_blocked
1709
+
1710
+ def initialize(curl)
1711
+ @curl = curl
1712
+ @done = false
1713
+ @close_blocked = false
1714
+ end
1715
+
1716
+ def read(_len)
1717
+ return nil if @done
1718
+
1719
+ @done = true
1720
+ begin
1721
+ @curl.close
1722
+ rescue RuntimeError
1723
+ @close_blocked = true
1724
+ end
1725
+
1726
+ 'hello'
1727
+ end
1728
+
1729
+ def seek(_offset, _whence = SEEK_SET)
1730
+ 0
1731
+ end
1732
+
1733
+ def stat
1734
+ Struct.new(:size).new(5)
1735
+ end
1736
+ end
1737
+
1738
+ reader = reader_class.new(curl)
1739
+ curl.http_put(reader)
1740
+
1741
+ assert reader.close_blocked
1742
+ assert_equal "PUT\nhello", curl.body_str
1743
+ end
1744
+
1296
1745
  def test_set_unsupported_options
1297
1746
  curl = Curl::Easy.new
1298
1747
  assert_raises TypeError do