curb 0.9.3 → 1.0.2

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.
data/ext/curb_postfield.c CHANGED
@@ -195,9 +195,9 @@ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
195
195
 
196
196
  /*
197
197
  * call-seq:
198
- * Curl::PostField.content(name, content) => #<Curl::PostField...>
199
- * Curl::PostField.content(name, content, content_type = nil) => #<Curl::PostField...>
200
- * Curl::PostField.content(name, content_type = nil) { |field| ... } => #<Curl::PostField...>
198
+ * Curl::PostField.content(name, content) => #<Curl::PostField...>
199
+ * Curl::PostField.content(name, content, content_type = nil) => #<Curl::PostField...>
200
+ * Curl::PostField.content(name, content_type = nil) { |field| ... } => #<Curl::PostField...>
201
201
  *
202
202
  * Create a new Curl::PostField, supplying the field name, content,
203
203
  * and, optionally, Content-type (curl will attempt to determine this if
@@ -241,9 +241,9 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
241
241
 
242
242
  /*
243
243
  * call-seq:
244
- * Curl::PostField.file(name, local_file_name) => #&lt;Curl::PostField...&gt;
245
- * Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) => #&lt;Curl::PostField...&gt;
246
- * Curl::PostField.file(name, remote_file_name) { |field| ... } => #&lt;Curl::PostField...&gt;
244
+ * Curl::PostField.file(name, local_file_name) => #<Curl::PostField...>
245
+ * Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) => #<Curl::PostField...>
246
+ * Curl::PostField.file(name, remote_file_name) { |field| ... } => #<Curl::PostField...>
247
247
  *
248
248
  * Create a new Curl::PostField for a file upload field, supplying the local filename
249
249
  * to read from, and optionally the remote filename (defaults to the local name).
@@ -399,7 +399,7 @@ static VALUE ruby_curl_postfield_remote_file_get(VALUE self) {
399
399
 
400
400
  /*
401
401
  * call-seq:
402
- * field.set_content_proc { |field| ... } => &lt;old proc&gt;
402
+ * field.set_content_proc { |field| ... } => <old proc>
403
403
  *
404
404
  * Set a content proc for this field. This proc will be called during the
405
405
  * perform to supply the content for this field, overriding any setting
@@ -498,6 +498,8 @@ void init_curb_postfield() {
498
498
 
499
499
  cCurlPostField = rb_define_class_under(mCurl, "PostField", rb_cObject);
500
500
 
501
+ rb_undef_alloc_func(cCurlPostField);
502
+
501
503
  /* Class methods */
502
504
  rb_define_singleton_method(cCurlPostField, "content", ruby_curl_postfield_new_content, -1);
503
505
  rb_define_singleton_method(cCurlPostField, "file", ruby_curl_postfield_new_file, -1);
data/ext/curb_upload.c CHANGED
@@ -72,6 +72,7 @@ VALUE ruby_curl_upload_offset_get(VALUE self) {
72
72
  /* =================== INIT LIB =====================*/
73
73
  void init_curb_upload() {
74
74
  cCurlUpload = rb_define_class_under(mCurl, "Upload", rb_cObject);
75
+ rb_undef_alloc_func(cCurlUpload);
75
76
  rb_define_singleton_method(cCurlUpload, "new", ruby_curl_upload_new, 0);
76
77
  rb_define_method(cCurlUpload, "stream=", ruby_curl_upload_stream_set, 1);
77
78
  rb_define_method(cCurlUpload, "stream", ruby_curl_upload_stream_get, 0);
data/ext/extconf.rb CHANGED
@@ -18,6 +18,8 @@ elsif !have_library('curl') or !have_header('curl/curl.h')
18
18
  fail <<-EOM
19
19
  Can't find libcurl or curl/curl.h
20
20
 
21
+ Make sure development libs (ie libcurl4-openssl-dev) are installed on the system.
22
+
21
23
  Try passing --with-curl-dir or --with-curl-lib and --with-curl-include
22
24
  options to extconf.
23
25
  EOM
@@ -59,6 +61,9 @@ def have_constant(name)
59
61
  end
60
62
  end
61
63
 
64
+ have_constant "curlopt_tcp_keepalive"
65
+ have_constant "curlopt_tcp_keepidle"
66
+ have_constant "curlopt_tcp_keepintvl"
62
67
  have_constant "curlinfo_appconnect_time"
63
68
  have_constant "curlinfo_redirect_time"
64
69
  have_constant "curlinfo_response_code"
@@ -66,6 +71,7 @@ have_constant "curlinfo_filetime"
66
71
  have_constant "curlinfo_redirect_count"
67
72
  have_constant "curlinfo_os_errno"
68
73
  have_constant "curlinfo_num_connects"
74
+ have_constant "curlinfo_cookielist"
69
75
  have_constant "curlinfo_ftp_entry_path"
70
76
  have_constant "curl_version_ssl"
71
77
  have_constant "curl_version_libz"
@@ -83,6 +89,7 @@ have_constant "curlproxy_http"
83
89
  have_constant "curlproxy_socks4"
84
90
  have_constant "curlproxy_socks4a"
85
91
  have_constant "curlproxy_socks5"
92
+ have_constant "curlproxy_socks5_hostname"
86
93
  have_constant "curlauth_basic"
87
94
  have_constant "curlauth_digest"
88
95
  have_constant "curlauth_gssnegotiate"
@@ -101,6 +108,12 @@ have_constant "curle_send_fail_rewind"
101
108
  have_constant "curle_ssl_engine_initfailed"
102
109
  have_constant "curle_login_denied"
103
110
 
111
+ # older than 7.10.0
112
+ have_constant "curlopt_nosignal"
113
+
114
+ # older than 7.16.0
115
+ have_constant "curlmopt_pipelining"
116
+
104
117
  # older than 7.16.3
105
118
  have_constant "curlmopt_maxconnects"
106
119
 
@@ -145,6 +158,8 @@ have_func("curl_multi_timeout")
145
158
  have_func("curl_multi_fdset")
146
159
  have_func("curl_multi_perform")
147
160
 
161
+ have_constant "curlopt_haproxyprotocol"
162
+
148
163
  # constants
149
164
  have_constant "curlopt_interleavefunction"
150
165
  have_constant "curlopt_interleavedata"
@@ -209,6 +224,7 @@ have_constant "curlopt_httppost"
209
224
  have_constant "curlopt_referer"
210
225
  have_constant "curlopt_useragent"
211
226
  have_constant "curlopt_httpheader"
227
+ have_constant "curlopt_proxyheader"
212
228
  have_constant "curlopt_http200aliases"
213
229
  have_constant "curlopt_cookie"
214
230
  have_constant "curlopt_cookiefile"
@@ -318,14 +334,17 @@ have_constant "curlopt_sslengine"
318
334
  have_constant "curlopt_sslengine_default"
319
335
  have_constant "curlopt_sslversion"
320
336
  have_constant "curl_sslversion_default"
321
- have_constant "curl_sslversion_tlsv1"
322
- have_constant "curl_sslversion_sslv2"
323
- have_constant "curl_sslversion_sslv3"
337
+ have_constant :CURL_SSLVERSION_TLSv1
338
+ have_constant :CURL_SSLVERSION_SSLv2
339
+ have_constant :CURL_SSLVERSION_SSLv3
324
340
 
325
341
  # Added in 7.34.0
326
- have_constant "curl_sslversion_tlsv1_0"
327
- have_constant "curl_sslversion_tlsv1_1"
328
- have_constant "curl_sslversion_tlsv1_2"
342
+ have_constant :CURL_SSLVERSION_TLSv1_0
343
+ have_constant :CURL_SSLVERSION_TLSv1_1
344
+ have_constant :CURL_SSLVERSION_TLSv1_2
345
+
346
+ # Added in 7.52.0
347
+ have_constant :CURL_SSLVERSION_TLSv1_3
329
348
 
330
349
  have_constant "curlopt_ssl_verifypeer"
331
350
  have_constant "curlopt_cainfo"
@@ -360,6 +379,16 @@ have_constant "curle_not_built_in"
360
379
 
361
380
  have_constant "curle_obsolete" # removed in 7.24 ?
362
381
 
382
+ have_constant "curle_ftp_pret_failed"
383
+ have_constant "curle_rtsp_cseq_error"
384
+ have_constant "curle_rtsp_session_error"
385
+ have_constant "curle_ftp_bad_file_list"
386
+ have_constant "curle_chunk_failed"
387
+ have_constant "curle_no_connection_available"
388
+ have_constant "curle_ssl_pinnedpubkeynotmatch"
389
+ have_constant "curle_ssl_invalidcertstatus"
390
+ have_constant "curle_http2_stream"
391
+
363
392
  # gssapi/spnego delegation related constants
364
393
  have_constant "curlopt_gssapi_delegation"
365
394
  have_constant "curlgssapi_delegation_policy_flag"
@@ -370,6 +399,45 @@ have_constant "CURLM_ADDED_ALREADY"
370
399
  # added in 7.40.0
371
400
  have_constant "curlopt_unix_socket_path"
372
401
 
402
+ # added in 7.42.0
403
+ have_constant "curlopt_path_as_is"
404
+
405
+ # added in 7.43.0
406
+ have_constant "curlopt_pipewait"
407
+
408
+ have_constant "curlopt_proxy_ssl_verifyhost"
409
+
410
+ # protocol constants
411
+ have_constant "curlproto_all"
412
+ have_constant "curlproto_dict"
413
+ have_constant "curlproto_file"
414
+ have_constant "curlproto_ftp"
415
+ have_constant "curlproto_ftps"
416
+ have_constant "curlproto_gopher"
417
+ have_constant "curlproto_http"
418
+ have_constant "curlproto_https"
419
+ have_constant "curlproto_imap"
420
+ have_constant "curlproto_imaps"
421
+ have_constant "curlproto_ldap"
422
+ have_constant "curlproto_ldaps"
423
+ have_constant "curlproto_pop3"
424
+ have_constant "curlproto_pop3s"
425
+ have_constant "curlproto_rtmp"
426
+ have_constant "curlproto_rtmpe"
427
+ have_constant "curlproto_rtmps"
428
+ have_constant "curlproto_rtmpt"
429
+ have_constant "curlproto_rtmpte"
430
+ have_constant "curlproto_rtmpts"
431
+ have_constant "curlproto_rtsp"
432
+ have_constant "curlproto_scp"
433
+ have_constant "curlproto_sftp"
434
+ have_constant "curlproto_smb"
435
+ have_constant "curlproto_smbs"
436
+ have_constant "curlproto_smtp"
437
+ have_constant "curlproto_smtps"
438
+ have_constant "curlproto_telnet"
439
+ have_constant "curlproto_tftp"
440
+
373
441
  if try_compile('int main() { return 0; }','-Wall')
374
442
  $CFLAGS << ' -Wall'
375
443
  end
@@ -397,6 +465,8 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
397
465
 
398
466
  have_func('rb_thread_blocking_region')
399
467
  have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
468
+ have_header('ruby/io.h')
469
+ have_func('rb_io_stdio_file')
400
470
 
401
471
  create_header('curb_config.h')
402
472
  create_makefile('curb_core')
data/lib/curb.rb CHANGED
@@ -1 +1,2 @@
1
+ # frozen_string_literal: true
1
2
  require 'curl'
data/lib/curl/easy.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
3
  class Easy
3
4
 
@@ -19,9 +20,9 @@ module Curl
19
20
  # easy.status => String
20
21
  #
21
22
  def status
22
- # Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF'
23
- statuses = self.header_str.scan(/HTTP\/\d\.\d\s(\d+\s.*)\r\n/).map{ |match| match[0] }
24
- statuses.last.strip
23
+ # Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP (Opt:)Reason-Phrase CRLF'
24
+ statuses = self.header_str.to_s.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map {|match| match[1] }
25
+ statuses.last.strip if statuses.length > 0
25
26
  end
26
27
 
27
28
  #
@@ -68,9 +69,15 @@ module Curl
68
69
  ret = self.multi.perform
69
70
  self.multi.remove self
70
71
 
72
+ if Curl::Multi.autoclose
73
+ self.multi.close
74
+ self.multi = nil
75
+ end
76
+
71
77
  if self.last_result != 0 && self.on_failure.nil?
72
- error = Curl::Easy.error(self.last_result)
73
- raise error.first.new(error.last)
78
+ (err_class, err_summary) = Curl::Easy.error(self.last_result)
79
+ err_detail = self.last_error
80
+ raise err_class.new([err_summary, err_detail].compact.join(": "))
74
81
  end
75
82
 
76
83
  ret
@@ -314,7 +321,7 @@ module Curl
314
321
 
315
322
  #
316
323
  # call-seq:
317
- # Curl::Easy.perform(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
324
+ # Curl::Easy.perform(url) { |easy| ... } => #<Curl::Easy...>
318
325
  #
319
326
  # Convenience method that creates a new Curl::Easy instance with
320
327
  # the specified URL and calls the general +perform+ method, before returning
@@ -332,7 +339,7 @@ module Curl
332
339
 
333
340
  #
334
341
  # call-seq:
335
- # Curl::Easy.http_get(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
342
+ # Curl::Easy.http_get(url) { |easy| ... } => #<Curl::Easy...>
336
343
  #
337
344
  # Convenience method that creates a new Curl::Easy instance with
338
345
  # the specified URL and calls +http_get+, before returning the new instance.
@@ -349,7 +356,7 @@ module Curl
349
356
 
350
357
  #
351
358
  # call-seq:
352
- # Curl::Easy.http_head(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
359
+ # Curl::Easy.http_head(url) { |easy| ... } => #<Curl::Easy...>
353
360
  #
354
361
  # Convenience method that creates a new Curl::Easy instance with
355
362
  # the specified URL and calls +http_head+, before returning the new instance.
@@ -403,7 +410,7 @@ module Curl
403
410
 
404
411
  #
405
412
  # call-seq:
406
- # Curl::Easy.http_delete(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
413
+ # Curl::Easy.http_delete(url) { |easy| ... } => #<Curl::Easy...>
407
414
  #
408
415
  # Convenience method that creates a new Curl::Easy instance with
409
416
  # the specified URL and calls +http_delete+, before returning the new instance.
data/lib/curl/multi.rb CHANGED
@@ -1,12 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
-
3
3
  class Multi
4
4
  class << self
5
5
  # call-seq:
6
6
  # Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
7
7
  # easy
8
8
  # end
9
- #
9
+ #
10
10
  # Blocking call to fetch multiple url's in parallel.
11
11
  def get(urls, easy_options={}, multi_options={}, &blk)
12
12
  url_confs = []
@@ -25,10 +25,10 @@ module Curl
25
25
  # {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
26
26
  # easy_handle_on_request_complete
27
27
  # end
28
- #
28
+ #
29
29
  # Blocking call to POST multiple form's in parallel.
30
- #
31
- # urls_with_config: is a hash of url's pointing to the postfields to send
30
+ #
31
+ # urls_with_config: is a hash of url's pointing to the postfields to send
32
32
  # easy_options: are a set of common options to set on all easy handles
33
33
  # multi_options: options to set on the Curl::Multi handle
34
34
  #
@@ -49,10 +49,10 @@ module Curl
49
49
  # {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
50
50
  # easy_handle_on_request_complete
51
51
  # end
52
- #
52
+ #
53
53
  # Blocking call to POST multiple form's in parallel.
54
- #
55
- # urls_with_config: is a hash of url's pointing to the postfields to send
54
+ #
55
+ # urls_with_config: is a hash of url's pointing to the postfields to send
56
56
  # easy_options: are a set of common options to set on all easy handles
57
57
  # multi_options: options to set on the Curl::Multi handle
58
58
  #
@@ -79,7 +79,7 @@ module Curl
79
79
  # Blocking call to issue multiple HTTP requests with varying verb's.
80
80
  #
81
81
  # urls_with_config: is a hash of url's pointing to the easy handle options as well as the special option :method, that can by one of [:get, :post, :put, :delete, :head], when no verb is provided e.g. :method => nil -> GET is used
82
- # multi_options: options for the multi handle
82
+ # multi_options: options for the multi handle
83
83
  # blk: a callback, that yeilds when a handle is completed
84
84
  #
85
85
  def http(urls_with_config, multi_options={}, &blk)
@@ -128,7 +128,7 @@ module Curl
128
128
 
129
129
  # headers is a special key
130
130
  headers.each {|k,v| easy.headers[k] = v } if headers
131
-
131
+
132
132
  #
133
133
  # use the remaining options as specific configuration to the easy handle
134
134
  # bad options should raise an undefined method error
@@ -144,7 +144,7 @@ module Curl
144
144
 
145
145
  max_connects.times do
146
146
  conf = urls_with_config.pop
147
- add_free_handle.call conf, nil
147
+ add_free_handle.call(conf, nil) if conf
148
148
  break if urls_with_config.empty?
149
149
  end
150
150
 
@@ -153,7 +153,7 @@ module Curl
153
153
  if urls_with_config.size > 0 && free_handles.size > 0
154
154
  easy = free_handles.pop
155
155
  conf = urls_with_config.pop
156
- add_free_handle.call conf, easy
156
+ add_free_handle.call(conf, easy) if conf
157
157
  end
158
158
  end
159
159
 
@@ -168,6 +168,7 @@ module Curl
168
168
  end
169
169
  free_handles = nil
170
170
  end
171
+
171
172
  end
172
173
 
173
174
  # call-seq:
@@ -175,7 +176,7 @@ module Curl
175
176
  # Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
176
177
  #
177
178
  # will create 2 new files file1.txt and file2.txt
178
- #
179
+ #
179
180
  # 2 files will be opened, and remain open until the call completes
180
181
  #
181
182
  # when using the :post or :put method, urls should be a hash, including the individual post fields per post
@@ -242,7 +243,45 @@ module Curl
242
243
  }
243
244
  raise errors unless errors.empty?
244
245
  end
246
+ end
245
247
 
248
+ def cancel!
249
+ requests.each do |_,easy|
250
+ remove(easy)
251
+ end
246
252
  end
253
+
254
+ def idle?
255
+ requests.empty?
256
+ end
257
+
258
+ def requests
259
+ @requests ||= {}
260
+ end
261
+
262
+ def add(easy)
263
+ return self if requests[easy.object_id]
264
+ requests[easy.object_id] = easy
265
+ _add(easy)
266
+ self
267
+ end
268
+
269
+ def remove(easy)
270
+ return self if !requests[easy.object_id]
271
+ requests.delete(easy.object_id)
272
+ _remove(easy)
273
+ self
274
+ end
275
+
276
+ def close
277
+ requests.values.each {|easy|
278
+ _remove(easy)
279
+ }
280
+ @requests = {}
281
+ _close
282
+ self
283
+ end
284
+
285
+
247
286
  end
248
287
  end
data/lib/curl.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'curb_core'
2
3
  require 'curl/easy'
3
4
  require 'curl/multi'
@@ -6,14 +7,22 @@ require 'cgi'
6
7
 
7
8
  # expose shortcut methods
8
9
  module Curl
9
-
10
+
10
11
  def self.http(verb, url, post_body=nil, put_data=nil, &block)
11
- handle = Thread.current[:curb_curl] ||= Curl::Easy.new
12
- handle.reset
12
+ if Thread.current[:curb_curl_yielding]
13
+ handle = Curl::Easy.new # we can't reuse this
14
+ else
15
+ handle = Thread.current[:curb_curl] ||= Curl::Easy.new
16
+ handle.reset
17
+ end
13
18
  handle.url = url
14
19
  handle.post_body = post_body if post_body
15
20
  handle.put_data = put_data if put_data
16
- yield handle if block_given?
21
+ if block_given?
22
+ Thread.current[:curb_curl_yielding] = true
23
+ yield handle
24
+ Thread.current[:curb_curl_yielding] = false
25
+ end
17
26
  handle.http(verb)
18
27
  handle
19
28
  end
@@ -47,14 +56,13 @@ module Curl
47
56
  end
48
57
 
49
58
  def self.urlalize(url, params={})
50
- query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
51
- if url.match(/\?/) && query_str.size > 0
52
- "#{url}&#{query_str}"
53
- elsif query_str.size > 0
54
- "#{url}?#{query_str}"
55
- else
56
- url
57
- end
59
+ uri = URI(url)
60
+ # early return if we didn't specify any extra params
61
+ return uri.to_s if (params || {}).empty?
62
+
63
+ params_query = URI.encode_www_form(params || {})
64
+ uri.query = [uri.query.to_s, params_query].reject(&:empty?).join('&')
65
+ uri.to_s
58
66
  end
59
67
 
60
68
  def self.postalize(params={})
@@ -20,11 +20,21 @@ class BugCrashOnDebug < Test::Unit::TestCase
20
20
  end
21
21
  puts 'b'
22
22
  c = Curl::Easy.new('http://127.0.0.1:9999/test')
23
- c.on_debug do|x|
24
- puts x.inspect
25
- raise "error" # this will get swallowed
23
+ did_raise = false
24
+ did_call = false
25
+ begin
26
+ c.on_success do|x|
27
+ puts x.inspect
28
+ did_call = true
29
+ raise "error" # this will get swallowed
30
+ end
31
+ c.perform
32
+ rescue => e
33
+ did_raise = true
26
34
  end
27
- c.perform
35
+ puts c.response_code
36
+ assert did_raise
37
+ assert did_call
28
38
  puts 'c'
29
39
  ensure
30
40
  puts 'd'
@@ -28,7 +28,8 @@ class BugCrashOnDebug < Test::Unit::TestCase
28
28
  assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
29
29
  c.close
30
30
  ensure
31
- server.shutdown
31
+ server&.shutdown
32
+ thread&.exit
32
33
  end
33
34
 
34
35
  def test_on_progress_abort
@@ -67,7 +68,8 @@ class BugCrashOnDebug < Test::Unit::TestCase
67
68
  assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
68
69
  c.close
69
70
  ensure
70
- server.shutdown
71
+ server&.shutdown
72
+ thread&.exit
71
73
  end
72
74
 
73
75
  end
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+ require 'webrick'
3
+ class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
4
+ class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
5
+
6
+ class BugFollowRedirect288 < Test::Unit::TestCase
7
+ def test_follow_redirect_with_no_redirect
8
+ server = WEBrick::HTTPServer.new( :Port => 9999 )
9
+ server.mount_proc("/test") do|req,res|
10
+ res.body = "hi"
11
+ res['Content-Type'] = "text/html"
12
+ end
13
+ server.mount_proc("/redirect_to_test") do|req,res|
14
+ res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, "/test")
15
+ end
16
+
17
+ thread = Thread.new(server) do|srv|
18
+ srv.start
19
+ end
20
+
21
+ c = Curl::Easy.new('http://127.0.0.1:9999/test')
22
+ did_call_redirect = false
23
+ c.on_redirect do|x|
24
+ did_call_redirect = true
25
+ end
26
+ c.perform
27
+
28
+ assert !did_call_redirect, "should reach this point redirect should not have been called"
29
+
30
+ c = Curl::Easy.new('http://127.0.0.1:9999/test')
31
+ did_call_redirect = false
32
+ c.on_redirect do|x|
33
+ did_call_redirect = true
34
+ end
35
+ c.follow_location = true
36
+ c.perform
37
+
38
+ assert_equal 0, c.redirect_count
39
+ assert !did_call_redirect, "should reach this point redirect should not have been called"
40
+
41
+ c = Curl::Easy.new('http://127.0.0.1:9999/redirect_to_test')
42
+ did_call_redirect = false
43
+ c.on_redirect do|x|
44
+ did_call_redirect = true
45
+ end
46
+ c.perform
47
+ assert_equal 307, c.response_code
48
+
49
+ assert did_call_redirect, "we should have called on_redirect"
50
+
51
+ c = Curl::Easy.new('http://127.0.0.1:9999/redirect_to_test')
52
+ did_call_redirect = false
53
+ c.follow_location = true
54
+ # NOTE: while this API is not supported by libcurl e.g. there is no redirect function callback in libcurl we could
55
+ # add support in ruby for this by executing this callback if redirect_count is greater than 0 at the end of a request in curb_multi.c
56
+ c.on_redirect do|x|
57
+ did_call_redirect = true
58
+ end
59
+ c.perform
60
+ assert_equal 1, c.redirect_count
61
+ assert_equal 200, c.response_code
62
+
63
+ assert did_call_redirect, "we should have called on_redirect"
64
+
65
+ c.url = 'http://127.0.0.1:9999/test'
66
+ c.perform
67
+ assert_equal 0, c.redirect_count
68
+ assert_equal 200, c.response_code
69
+
70
+ did_raise = false
71
+ begin
72
+ c = Curl::Easy.new('http://127.0.0.1:9999/redirect_to_test')
73
+ did_call_redirect = false
74
+ c.on_redirect do|x|
75
+ raise "raise"
76
+ did_call_redirect = true
77
+ end
78
+ c.perform
79
+ rescue => e
80
+ did_raise = true
81
+ end
82
+ assert did_raise
83
+ assert_equal 307, c.response_code
84
+
85
+ ensure
86
+ server.stop
87
+ thread.join
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+
4
+ require 'curb'
5
+
6
+ class BugIssue102 < Test::Unit::TestCase
7
+
8
+ def test_gc_closewait
9
+ 100.times do
10
+ responses = {}
11
+ requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
12
+ m = Curl::Multi.new
13
+ # add a few easy handles
14
+ requests.each do |url|
15
+ responses[url] = ""
16
+ c = Curl::Easy.new(url) do|curl|
17
+ curl.follow_location = true
18
+ curl.on_body{|data| responses[url] << data; data.size }
19
+ curl.on_success {|easy| #puts "success, add more easy handles"
20
+ }
21
+ end
22
+ m.add(c)
23
+ end
24
+
25
+ m.perform do
26
+ #puts "idling... can do some work here"
27
+ end
28
+ GC.start
29
+ end
30
+ end
31
+
32
+ end