curb 0.9.7 → 0.9.8
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.
- 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
|