curb 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Rakefile +25 -9
- data/ext/curb.c +10 -0
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +213 -18
- data/ext/curb_easy.h +3 -0
- data/ext/curb_multi.c +126 -161
- data/ext/curb_multi.h +0 -1
- data/ext/extconf.rb +2 -0
- data/lib/curl/easy.rb +1 -1
- data/lib/curl/multi.rb +39 -1
- data/tests/helper.rb +78 -0
- data/tests/tc_curl_easy.rb +50 -16
- data/tests/tc_curl_multi.rb +67 -5
- metadata +4 -4
data/ext/curb_multi.h
CHANGED
data/ext/extconf.rb
CHANGED
@@ -84,6 +84,7 @@ have_constant "curlproxy_http"
|
|
84
84
|
have_constant "curlproxy_socks4"
|
85
85
|
have_constant "curlproxy_socks4a"
|
86
86
|
have_constant "curlproxy_socks5"
|
87
|
+
have_constant "curlproxy_socks5_hostname"
|
87
88
|
have_constant "curlauth_basic"
|
88
89
|
have_constant "curlauth_digest"
|
89
90
|
have_constant "curlauth_gssnegotiate"
|
@@ -216,6 +217,7 @@ have_constant "curlopt_httppost"
|
|
216
217
|
have_constant "curlopt_referer"
|
217
218
|
have_constant "curlopt_useragent"
|
218
219
|
have_constant "curlopt_httpheader"
|
220
|
+
have_constant "curlopt_proxyheader"
|
219
221
|
have_constant "curlopt_http200aliases"
|
220
222
|
have_constant "curlopt_cookie"
|
221
223
|
have_constant "curlopt_cookiefile"
|
data/lib/curl/easy.rb
CHANGED
data/lib/curl/multi.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Curl
|
2
|
-
|
3
2
|
class Multi
|
4
3
|
class << self
|
5
4
|
# call-seq:
|
@@ -168,6 +167,7 @@ module Curl
|
|
168
167
|
end
|
169
168
|
free_handles = nil
|
170
169
|
end
|
170
|
+
|
171
171
|
end
|
172
172
|
|
173
173
|
# call-seq:
|
@@ -242,7 +242,45 @@ module Curl
|
|
242
242
|
}
|
243
243
|
raise errors unless errors.empty?
|
244
244
|
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def cancel!
|
248
|
+
requests.each do |_,easy|
|
249
|
+
remove(easy)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def idle?
|
254
|
+
requests.empty?
|
255
|
+
end
|
245
256
|
|
257
|
+
def requests
|
258
|
+
@requests ||= {}
|
246
259
|
end
|
260
|
+
|
261
|
+
def add(easy)
|
262
|
+
return self if requests[easy.object_id]
|
263
|
+
requests[easy.object_id] = easy
|
264
|
+
_add(easy)
|
265
|
+
self
|
266
|
+
end
|
267
|
+
|
268
|
+
def remove(easy)
|
269
|
+
return self if !requests[easy.object_id]
|
270
|
+
requests.delete(easy.object_id)
|
271
|
+
_remove(easy)
|
272
|
+
self
|
273
|
+
end
|
274
|
+
|
275
|
+
def close
|
276
|
+
requests.values.each {|easy|
|
277
|
+
_remove(easy)
|
278
|
+
}
|
279
|
+
@requests = {}
|
280
|
+
_close
|
281
|
+
self
|
282
|
+
end
|
283
|
+
|
284
|
+
|
247
285
|
end
|
248
286
|
end
|
data/tests/helper.rb
CHANGED
@@ -207,3 +207,81 @@ module TestServerMethods
|
|
207
207
|
rescue Errno::EADDRINUSE
|
208
208
|
end
|
209
209
|
end
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
# Backport for Ruby 1.8
|
214
|
+
module Backports
|
215
|
+
module Ruby18
|
216
|
+
module URIFormEncoding
|
217
|
+
TBLENCWWWCOMP_ = {}
|
218
|
+
TBLDECWWWCOMP_ = {}
|
219
|
+
|
220
|
+
def encode_www_form_component(str)
|
221
|
+
if TBLENCWWWCOMP_.empty?
|
222
|
+
256.times do |i|
|
223
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
224
|
+
end
|
225
|
+
TBLENCWWWCOMP_[' '] = '+'
|
226
|
+
TBLENCWWWCOMP_.freeze
|
227
|
+
end
|
228
|
+
str.to_s.gsub( /([^*\-.0-9A-Z_a-z])/ ) {|*| TBLENCWWWCOMP_[$1] }
|
229
|
+
end
|
230
|
+
|
231
|
+
def decode_www_form_component(str)
|
232
|
+
if TBLDECWWWCOMP_.empty?
|
233
|
+
256.times do |i|
|
234
|
+
h, l = i>>4, i&15
|
235
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
236
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
237
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
238
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
239
|
+
end
|
240
|
+
TBLDECWWWCOMP_['+'] = ' '
|
241
|
+
TBLDECWWWCOMP_.freeze
|
242
|
+
end
|
243
|
+
|
244
|
+
raise ArgumentError, "invalid %-encoding (#{str.dump})" unless /\A(?:%[[:xdigit:]]{2}|[^%]+)*\z/ =~ str
|
245
|
+
str.gsub( /(\+|%[[:xdigit:]]{2})/ ) {|*| TBLDECWWWCOMP_[$1] }
|
246
|
+
end
|
247
|
+
|
248
|
+
def encode_www_form( enum )
|
249
|
+
enum.map do |k,v|
|
250
|
+
if v.nil?
|
251
|
+
encode_www_form_component(k)
|
252
|
+
elsif v.respond_to?(:to_ary)
|
253
|
+
v.to_ary.map do |w|
|
254
|
+
str = encode_www_form_component(k)
|
255
|
+
unless w.nil?
|
256
|
+
str << '='
|
257
|
+
str << encode_www_form_component(w)
|
258
|
+
end
|
259
|
+
end.join('&')
|
260
|
+
else
|
261
|
+
str = encode_www_form_component(k)
|
262
|
+
str << '='
|
263
|
+
str << encode_www_form_component(v)
|
264
|
+
end
|
265
|
+
end.join('&')
|
266
|
+
end
|
267
|
+
|
268
|
+
WFKV_ = '(?:%\h\h|[^%#=;&])'
|
269
|
+
def decode_www_form(str, _)
|
270
|
+
return [] if str.to_s == ''
|
271
|
+
|
272
|
+
unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/ =~ str
|
273
|
+
raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})"
|
274
|
+
end
|
275
|
+
ary = []
|
276
|
+
$&.scan(/([^=;&]+)=([^;&]*)/) do
|
277
|
+
ary << [decode_www_form_component($1, enc), decode_www_form_component($2, enc)]
|
278
|
+
end
|
279
|
+
ary
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
unless URI.methods.include?(:encode_www_form)
|
286
|
+
URI.extend(Backports::Ruby18::URIFormEncoding)
|
287
|
+
end
|
data/tests/tc_curl_easy.rb
CHANGED
@@ -28,8 +28,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
28
28
|
c = Curl.get($TEST_URL)
|
29
29
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
30
30
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body)
|
31
|
-
assert_equal "", c.header_str
|
32
|
-
assert_equal "", c.head
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
@@ -41,7 +39,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
41
39
|
assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL)
|
42
40
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
43
41
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body)
|
44
|
-
assert_equal "", c.header_str
|
45
42
|
end
|
46
43
|
|
47
44
|
def test_class_perform_02
|
@@ -49,7 +46,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
49
46
|
assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL) { |curl| curl.on_body { |d| data << d; d.length } }
|
50
47
|
|
51
48
|
assert_nil c.body_str
|
52
|
-
assert_equal "", c.header_str
|
53
49
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, data)
|
54
50
|
end
|
55
51
|
|
@@ -144,7 +140,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
144
140
|
c = Curl::Easy.new($TEST_URL)
|
145
141
|
assert_equal true, c.http_get
|
146
142
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
147
|
-
assert_equal "", c.header_str
|
148
143
|
end
|
149
144
|
|
150
145
|
def test_get_02
|
@@ -156,7 +151,6 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
156
151
|
assert_equal true, c.http_get
|
157
152
|
|
158
153
|
assert_nil c.body_str
|
159
|
-
assert_equal "", c.header_str
|
160
154
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, data)
|
161
155
|
end
|
162
156
|
|
@@ -339,29 +333,69 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
339
333
|
c.max_redirects = nil
|
340
334
|
assert_nil c.max_redirects
|
341
335
|
end
|
342
|
-
|
336
|
+
|
337
|
+
def test_timeout_with_floats
|
338
|
+
c = Curl::Easy.new($TEST_URL)
|
339
|
+
|
340
|
+
c.timeout = 1.5
|
341
|
+
assert_equal 1500, c.timeout_ms
|
342
|
+
assert_equal 1.5, c.timeout
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_timeout_with_negative
|
346
|
+
c = Curl::Easy.new($TEST_URL)
|
347
|
+
|
348
|
+
c.timeout = -1.5
|
349
|
+
assert_equal 0, c.timeout
|
350
|
+
assert_equal 0, c.timeout_ms
|
351
|
+
|
352
|
+
c.timeout = -4.8
|
353
|
+
assert_equal 0, c.timeout
|
354
|
+
assert_equal 0, c.timeout_ms
|
355
|
+
end
|
356
|
+
|
343
357
|
def test_timeout_01
|
344
358
|
c = Curl::Easy.new($TEST_URL)
|
345
|
-
|
346
|
-
|
347
|
-
|
359
|
+
|
360
|
+
assert_equal 0, c.timeout
|
361
|
+
|
348
362
|
c.timeout = 3
|
349
363
|
assert_equal 3, c.timeout
|
350
|
-
|
351
|
-
c.timeout =
|
352
|
-
|
364
|
+
|
365
|
+
c.timeout = 0
|
366
|
+
assert_equal 0, c.timeout
|
353
367
|
end
|
354
368
|
|
355
369
|
def test_timeout_ms_01
|
356
370
|
c = Curl::Easy.new($TEST_URL)
|
357
371
|
|
358
|
-
|
372
|
+
assert_equal 0, c.timeout_ms
|
359
373
|
|
360
374
|
c.timeout_ms = 100
|
361
375
|
assert_equal 100, c.timeout_ms
|
362
376
|
|
363
377
|
c.timeout_ms = nil
|
364
|
-
|
378
|
+
assert_equal 0, c.timeout_ms
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_timeout_ms_with_floats
|
382
|
+
c = Curl::Easy.new($TEST_URL)
|
383
|
+
|
384
|
+
c.timeout_ms = 55.5
|
385
|
+
assert_equal 55, c.timeout_ms
|
386
|
+
assert_equal 0.055, c.timeout
|
387
|
+
end
|
388
|
+
|
389
|
+
def test_timeout_ms_with_negative
|
390
|
+
c = Curl::Easy.new($TEST_URL)
|
391
|
+
|
392
|
+
c.timeout_ms = -1.5
|
393
|
+
assert_equal 0, c.timeout
|
394
|
+
assert_equal 0, c.timeout_ms
|
395
|
+
|
396
|
+
c.timeout_ms = -4.8
|
397
|
+
assert_equal 0, c.timeout
|
398
|
+
assert_equal 0, c.timeout_ms
|
365
399
|
end
|
366
400
|
|
367
401
|
def test_connect_timeout_01
|
@@ -608,7 +642,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
608
642
|
def test_cookielist
|
609
643
|
c = Curl::Easy.new TestServlet.url
|
610
644
|
c.enable_cookies = true
|
611
|
-
c.post_body = URI.encode_www_form
|
645
|
+
c.post_body = URI.encode_www_form('c' => 'somename=somevalue')
|
612
646
|
assert_nil c.cookielist
|
613
647
|
c.perform
|
614
648
|
assert_match(/somevalue/, c.cookielist.join(''))
|
data/tests/tc_curl_multi.rb
CHANGED
@@ -6,6 +6,69 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
6
6
|
ObjectSpace.garbage_collect
|
7
7
|
end
|
8
8
|
|
9
|
+
# for https://github.com/taf2/curb/issues/277
|
10
|
+
# must connect to an external
|
11
|
+
def test_connection_keepalive
|
12
|
+
# 0123456 default & reserved RubyVM. It will probably include 7 from Dir.glob
|
13
|
+
open_fds = lambda do
|
14
|
+
`/usr/sbin/lsof -p #{Process.pid} | egrep "TCP|UDP" | wc -l`.strip.to_i
|
15
|
+
end
|
16
|
+
before_open = open_fds.call
|
17
|
+
assert !Curl::Multi.autoclose
|
18
|
+
multi = Curl::Multi.new
|
19
|
+
multi.max_connects = 1 # limit to 1 connection within the multi handle
|
20
|
+
|
21
|
+
did_complete = false
|
22
|
+
5.times do |n|
|
23
|
+
# NOTE: we use google here because connecting to our TEST_URL as a local host address appears to not register correctly with lsof as a socket... if anyone knows a better way would be great to not have an external dependency here in the test
|
24
|
+
easy = Curl::Easy.new("http://google.com/") do |curl|
|
25
|
+
curl.timeout = 5 # ensure we don't hang for ever connecting to an external host
|
26
|
+
curl.on_complete {
|
27
|
+
did_complete = true
|
28
|
+
}
|
29
|
+
end
|
30
|
+
multi.add(easy)
|
31
|
+
end
|
32
|
+
|
33
|
+
multi.perform
|
34
|
+
assert did_complete
|
35
|
+
after_open = open_fds.call
|
36
|
+
assert_equal (after_open - before_open), 1, "with max connections set to 1 at this point the connection to google should still be open"
|
37
|
+
multi.close
|
38
|
+
|
39
|
+
after_open = open_fds.call
|
40
|
+
assert_equal (after_open - before_open), 0, "after closing the multi handle all connections should be closed"
|
41
|
+
|
42
|
+
Curl::Multi.autoclose = true
|
43
|
+
multi = Curl::Multi.new
|
44
|
+
did_complete = false
|
45
|
+
5.times do |n|
|
46
|
+
# NOTE: we use google here because connecting to our TEST_URL as a local host address appears to not register correctly with lsof as a socket... if anyone knows a better way would be great to not have an external dependency here in the test
|
47
|
+
easy = Curl::Easy.new("http://google.com/") do |curl|
|
48
|
+
curl.timeout = 5 # ensure we don't hang for ever connecting to an external host
|
49
|
+
curl.on_complete {
|
50
|
+
did_complete = true
|
51
|
+
}
|
52
|
+
end
|
53
|
+
multi.add(easy)
|
54
|
+
end
|
55
|
+
|
56
|
+
multi.perform
|
57
|
+
assert did_complete
|
58
|
+
after_open = open_fds.call
|
59
|
+
assert_equal (after_open - before_open), 0, "auto close the connections"
|
60
|
+
ensure
|
61
|
+
Curl::Multi.autoclose = false # restore default
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_connection_autoclose
|
65
|
+
assert !Curl::Multi.autoclose
|
66
|
+
Curl::Multi.autoclose = true
|
67
|
+
assert Curl::Multi.autoclose
|
68
|
+
ensure
|
69
|
+
Curl::Multi.autoclose = false # restore default
|
70
|
+
end
|
71
|
+
|
9
72
|
def test_new_multi_01
|
10
73
|
d1 = ""
|
11
74
|
c1 = Curl::Easy.new($TEST_URL) do |curl|
|
@@ -125,7 +188,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
125
188
|
def test_requests
|
126
189
|
m = Curl::Multi.new
|
127
190
|
|
128
|
-
assert_equal(
|
191
|
+
assert_equal(0, m.requests.length, 'A new Curl::Multi handle should have no requests')
|
129
192
|
|
130
193
|
10.times do
|
131
194
|
m.add(Curl::Easy.new($TEST_URL))
|
@@ -135,7 +198,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
135
198
|
|
136
199
|
m.perform
|
137
200
|
|
138
|
-
assert_equal(
|
201
|
+
assert_equal(0, m.requests.length, 'A new Curl::Multi handle should have no requests after a perform')
|
139
202
|
end
|
140
203
|
|
141
204
|
def test_cancel
|
@@ -148,7 +211,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
148
211
|
|
149
212
|
m.cancel!
|
150
213
|
|
151
|
-
assert_equal(
|
214
|
+
assert_equal(0, m.requests.size, 'A new Curl::Multi handle should have no requests after being canceled')
|
152
215
|
end
|
153
216
|
|
154
217
|
def test_with_success
|
@@ -192,7 +255,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
192
255
|
c1.on_success do|c|
|
193
256
|
success_called1 = true
|
194
257
|
#puts "success 1 called: #{c.body_str.inspect}"
|
195
|
-
|
258
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
196
259
|
end
|
197
260
|
|
198
261
|
c1.on_failure do|c,rc|
|
@@ -484,5 +547,4 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
484
547
|
def setup
|
485
548
|
server_setup
|
486
549
|
end
|
487
|
-
|
488
550
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ross Bamford
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-01-28 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
|
15
15
|
for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
|
@@ -72,7 +72,7 @@ files:
|
|
72
72
|
- tests/unittests.rb
|
73
73
|
homepage: http://curb.rubyforge.org/
|
74
74
|
licenses:
|
75
|
-
-
|
75
|
+
- Ruby
|
76
76
|
metadata: {}
|
77
77
|
post_install_message:
|
78
78
|
rdoc_options:
|
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
93
|
version: '0'
|
94
94
|
requirements: []
|
95
95
|
rubyforge_project: curb
|
96
|
-
rubygems_version: 2.
|
96
|
+
rubygems_version: 2.7.7
|
97
97
|
signing_key:
|
98
98
|
specification_version: 4
|
99
99
|
summary: Ruby libcurl bindings
|