curb 0.5.8.0-x86-linux → 0.7.7-x86-linux
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of curb might be problematic. Click here for more details.
- data/README +2 -1
- data/Rakefile +20 -1
- data/ext/curb.c +26 -0
- data/ext/curb.h +6 -4
- data/ext/curb.o +0 -0
- data/ext/curb_core.so +0 -0
- data/ext/curb_easy.c +734 -304
- data/ext/curb_easy.h +26 -45
- data/ext/curb_easy.o +0 -0
- data/ext/curb_errors.c +7 -0
- data/ext/curb_errors.h +1 -0
- data/ext/curb_errors.o +0 -0
- data/ext/curb_macros.h +41 -0
- data/ext/curb_multi.c +119 -94
- data/ext/curb_multi.o +0 -0
- data/ext/curb_postfield.c +9 -9
- data/ext/curb_postfield.o +0 -0
- data/ext/curb_upload.o +0 -0
- data/ext/extconf.rb +20 -10
- data/lib/curb.rb +71 -0
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
- data/tests/bug_multi_segfault.rb +6 -2
- data/tests/bug_postfields_crash.rb +26 -0
- data/tests/bug_postfields_crash2.rb +57 -0
- data/tests/bugtests.rb +9 -0
- data/tests/helper.rb +17 -7
- data/tests/mem_check.rb +65 -0
- data/tests/tc_curl_easy.rb +116 -2
- data/tests/tc_curl_multi.rb +49 -9
- metadata +39 -5
data/ext/curb_multi.o
CHANGED
Binary file
|
data/ext/curb_postfield.c
CHANGED
@@ -41,7 +41,7 @@ void append_to_form(VALUE self,
|
|
41
41
|
// is a file upload field
|
42
42
|
if (rbcpf->content_proc != Qnil) {
|
43
43
|
// with content proc
|
44
|
-
rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, self);
|
44
|
+
rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, 1, self);
|
45
45
|
|
46
46
|
if (rbcpf->remote_file == Qnil) {
|
47
47
|
rb_raise(eCurlErrInvalidPostField, "Cannot post file upload field with no filename");
|
@@ -281,7 +281,7 @@ static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
|
281
281
|
rbcpf->content = Qnil;
|
282
282
|
rbcpf->content_type = Qnil;
|
283
283
|
rbcpf->buffer_str = Qnil;
|
284
|
-
|
284
|
+
|
285
285
|
return Data_Wrap_Struct(cCurlPostField, curl_postfield_mark, curl_postfield_free, rbcpf);
|
286
286
|
}
|
287
287
|
|
@@ -428,9 +428,9 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
|
|
428
428
|
Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
|
429
429
|
|
430
430
|
if ((rbcpf->local_file == Qnil) && (rbcpf->remote_file == Qnil)) {
|
431
|
-
if (rbcpf->name != Qnil) {
|
431
|
+
if (rbcpf->name != Qnil && rb_type(rbcpf->name) == T_STRING) {
|
432
432
|
|
433
|
-
char *tmpchrs = curl_escape(
|
433
|
+
char *tmpchrs = curl_escape(StringValuePtr(rbcpf->name), RSTRING_LEN(rbcpf->name));
|
434
434
|
|
435
435
|
if (!tmpchrs) {
|
436
436
|
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
|
@@ -465,14 +465,14 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
|
|
465
465
|
result = escd_name;
|
466
466
|
rb_str_cat(result, "=", 1);
|
467
467
|
rb_str_concat(result, escd_content);
|
468
|
-
}
|
468
|
+
}
|
469
469
|
}
|
470
470
|
} else {
|
471
|
-
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string");
|
472
|
-
}
|
471
|
+
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d", __FILE__, __LINE__);
|
472
|
+
}
|
473
473
|
} else {
|
474
|
-
rb_raise(eCurlErrInvalidPostField, "
|
475
|
-
}
|
474
|
+
rb_raise(eCurlErrInvalidPostField, "Local file and remote file are both nil %s:%d", __FILE__, __LINE__);
|
475
|
+
}
|
476
476
|
|
477
477
|
return result;
|
478
478
|
}
|
data/ext/curb_postfield.o
CHANGED
Binary file
|
data/ext/curb_upload.o
CHANGED
Binary file
|
data/ext/extconf.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'mkmf'
|
2
|
+
puts $CFLAGS.inspect
|
2
3
|
|
3
4
|
dir_config('curl')
|
4
5
|
|
5
6
|
if find_executable('curl-config')
|
6
|
-
$CFLAGS << " #{`curl-config --cflags`.strip}"
|
7
|
+
$CFLAGS << " #{`curl-config --cflags`.strip} -g"
|
7
8
|
if ENV['STATIC_BUILD']
|
8
9
|
$LIBS << " #{`curl-config --static-libs`.strip}"
|
9
10
|
else
|
@@ -24,15 +25,16 @@ elsif !have_library('curl') or !have_header('curl/curl.h')
|
|
24
25
|
end
|
25
26
|
|
26
27
|
# Check arch flags
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
$CFLAGS
|
34
|
-
|
35
|
-
|
28
|
+
# TODO: detect mismatched arch types when libcurl mac ports is mixed with native mac ruby or vice versa
|
29
|
+
#archs = $CFLAGS.scan(/-arch\s(.*?)\s/).first # get the first arch flag
|
30
|
+
#if archs and archs.size >= 1
|
31
|
+
# # need to reduce the number of archs...
|
32
|
+
# # guess the first one is correct... at least the first one is probably the ruby installed arch...
|
33
|
+
# # this could lead to compiled binaries that crash at runtime...
|
34
|
+
# $CFLAGS.gsub!(/-arch\s(.*?)\s/,' ')
|
35
|
+
# $CFLAGS << " -arch #{archs.first}"
|
36
|
+
# puts "Selected arch: #{archs.first}"
|
37
|
+
#end
|
36
38
|
|
37
39
|
def define(s)
|
38
40
|
$defs.push( format("-D HAVE_%s", s.to_s.upcase) )
|
@@ -109,6 +111,14 @@ have_constant "curle_again"
|
|
109
111
|
have_constant "curle_ssl_crl_badfile"
|
110
112
|
have_constant "curle_ssl_issuer_error"
|
111
113
|
|
114
|
+
# username/password added in 7.19.1
|
115
|
+
have_constant "curlopt_username"
|
116
|
+
have_constant "curlopt_password"
|
117
|
+
have_constant "curlinfo_primary_ip"
|
118
|
+
|
119
|
+
# ie quirk added in 7.19.3
|
120
|
+
have_constant "curlauth_digest_ie"
|
121
|
+
|
112
122
|
# centos 4.5 build of libcurl
|
113
123
|
have_constant "curlm_bad_socket"
|
114
124
|
have_constant "curlm_unknown_option"
|
data/lib/curb.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'curb_core'
|
2
2
|
|
3
3
|
module Curl
|
4
|
+
|
4
5
|
class Easy
|
5
6
|
class << self
|
6
7
|
|
@@ -54,6 +55,7 @@ module Curl
|
|
54
55
|
self.cert
|
55
56
|
end
|
56
57
|
end
|
58
|
+
|
57
59
|
class Multi
|
58
60
|
class << self
|
59
61
|
# call-seq:
|
@@ -140,6 +142,7 @@ module Curl
|
|
140
142
|
m = Curl::Multi.new
|
141
143
|
# configure the multi handle
|
142
144
|
multi_options.each { |k,v| m.send("#{k}=", v) }
|
145
|
+
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
|
143
146
|
|
144
147
|
urls_with_config.each do|conf|
|
145
148
|
c = conf.dup # avoid being destructive to input
|
@@ -149,6 +152,12 @@ module Curl
|
|
149
152
|
|
150
153
|
easy = Curl::Easy.new(url)
|
151
154
|
|
155
|
+
# assign callbacks
|
156
|
+
callbacks.each do |cb|
|
157
|
+
cbproc = c.delete(cb)
|
158
|
+
easy.send(cb,&cbproc) if cbproc
|
159
|
+
end
|
160
|
+
|
152
161
|
case method
|
153
162
|
when :post
|
154
163
|
fields = c.delete(:post_fields)
|
@@ -179,6 +188,68 @@ module Curl
|
|
179
188
|
end
|
180
189
|
m.perform
|
181
190
|
end
|
191
|
+
|
192
|
+
# call-seq:
|
193
|
+
#
|
194
|
+
# Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
|
195
|
+
#
|
196
|
+
# will create 2 new files file1.txt and file2.txt
|
197
|
+
#
|
198
|
+
# 2 files will be opened, and remain open until the call completes
|
199
|
+
#
|
200
|
+
# when using the :post or :put method, urls should be a hash, including the individual post fields per post
|
201
|
+
#
|
202
|
+
def download(urls,easy_options={},multi_options={},download_paths=nil,&blk)
|
203
|
+
procs = []
|
204
|
+
files = []
|
205
|
+
urls_with_config = []
|
206
|
+
url_to_download_paths = {}
|
207
|
+
|
208
|
+
urls.each_with_index do|urlcfg,i|
|
209
|
+
if urlcfg.is_a?(Hash)
|
210
|
+
url = url[:url]
|
211
|
+
else
|
212
|
+
url = urlcfg
|
213
|
+
end
|
214
|
+
|
215
|
+
if download_paths and download_paths[i]
|
216
|
+
download_path = download_paths[i]
|
217
|
+
else
|
218
|
+
download_path = File.basename(url)
|
219
|
+
end
|
220
|
+
|
221
|
+
lambda do|dp|
|
222
|
+
file = File.open(dp,"wb")
|
223
|
+
procs << (lambda {|data| file.write data; data.size })
|
224
|
+
files << file
|
225
|
+
end.call(download_path)
|
226
|
+
|
227
|
+
if urlcfg.is_a?(Hash)
|
228
|
+
urls_with_config << urlcfg.merge({:on_body => procs.last}.merge(easy_options))
|
229
|
+
else
|
230
|
+
urls_with_config << {:url => url, :on_body => procs.last, :method => :get}.merge(easy_options)
|
231
|
+
end
|
232
|
+
url_to_download_paths[url] = download_path # store for later
|
233
|
+
end
|
234
|
+
|
235
|
+
if blk
|
236
|
+
Curl::Multi.http(urls_with_config, multi_options) {|c,code,method| blk.call(c,url_to_download_paths[c.url]) }
|
237
|
+
else
|
238
|
+
Curl::Multi.http(urls_with_config, multi_options)
|
239
|
+
end
|
240
|
+
|
241
|
+
ensure
|
242
|
+
errors = []
|
243
|
+
files.each {|f|
|
244
|
+
begin
|
245
|
+
f.close
|
246
|
+
rescue => e
|
247
|
+
errors << e
|
248
|
+
end
|
249
|
+
}
|
250
|
+
raise errors unless errors.empty?
|
251
|
+
end
|
252
|
+
|
182
253
|
end
|
183
254
|
end
|
184
255
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
=begin
|
2
|
+
From jwhitmire
|
3
|
+
Todd, I'm trying to use curb to post data to a REST url. We're using it to post support questions from our iphone app directly to tender. The post looks good to me, but curl is not adding the content-length header so I get a 411 length required response from the server.
|
4
|
+
|
5
|
+
Here's my post block, do you see anything obvious? Do I need to manually add the Content-Length header?
|
6
|
+
|
7
|
+
c = Curl::Easy.http_post(url) do |curl|
|
8
|
+
curl.headers["User-Agent"] = "Curl/Ruby"
|
9
|
+
if user
|
10
|
+
curl.headers["X-Multipass"] = user.multipass
|
11
|
+
else
|
12
|
+
curl.headers["X-Tender-Auth"] = TOKEN
|
13
|
+
end
|
14
|
+
curl.headers["Accept"] = "application/vnd.tender-v1+json"
|
15
|
+
|
16
|
+
curl.post_body = params.map{|f,k| "#{curl.escape(f)}=#{curl.escape(k)}"}.join('&')
|
17
|
+
|
18
|
+
curl.verbose = true
|
19
|
+
curl.follow_location = true
|
20
|
+
curl.enable_cookies = true
|
21
|
+
end
|
22
|
+
Any insight you care to share would be helpful. Thanks.
|
23
|
+
=end
|
24
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
25
|
+
require 'webrick'
|
26
|
+
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
27
|
+
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
28
|
+
|
29
|
+
class BugCurbEasyPostWithStringNoContentLengthHeader < Test::Unit::TestCase
|
30
|
+
def test_bug_workaround
|
31
|
+
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
32
|
+
server.mount_proc("/test") do|req,res|
|
33
|
+
assert_equal '15', req['Content-Length']
|
34
|
+
res.body = "hi"
|
35
|
+
res['Content-Type'] = "text/html"
|
36
|
+
end
|
37
|
+
|
38
|
+
thread = Thread.new(server) do|srv|
|
39
|
+
srv.start
|
40
|
+
end
|
41
|
+
params = {:cat => "hat", :foo => "bar"}
|
42
|
+
|
43
|
+
post_body = params.map{|f,k| "#{Curl::Easy.new.escape(f)}=#{Curl::Easy.new.escape(k)}"}.join('&')
|
44
|
+
c = Curl::Easy.http_post("http://127.0.0.1:9999/test",post_body) do |curl|
|
45
|
+
curl.headers["User-Agent"] = "Curl/Ruby"
|
46
|
+
curl.headers["X-Tender-Auth"] = "A Token"
|
47
|
+
curl.headers["Accept"] = "application/vnd.tender-v1+json"
|
48
|
+
|
49
|
+
curl.follow_location = true
|
50
|
+
curl.enable_cookies = true
|
51
|
+
end
|
52
|
+
|
53
|
+
server.shutdown
|
54
|
+
thread.join
|
55
|
+
end
|
56
|
+
def test_bug
|
57
|
+
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
58
|
+
server.mount_proc("/test") do|req,res|
|
59
|
+
assert_equal '15', req['Content-Length']
|
60
|
+
res.body = "hi"
|
61
|
+
res['Content-Type'] = "text/html"
|
62
|
+
end
|
63
|
+
|
64
|
+
thread = Thread.new(server) do|srv|
|
65
|
+
srv.start
|
66
|
+
end
|
67
|
+
params = {:cat => "hat", :foo => "bar"}
|
68
|
+
|
69
|
+
c = Curl::Easy.http_post("http://127.0.0.1:9999/test") do |curl|
|
70
|
+
curl.headers["User-Agent"] = "Curl/Ruby"
|
71
|
+
curl.headers["X-Tender-Auth"] = "A Token"
|
72
|
+
curl.headers["Accept"] = "application/vnd.tender-v1+json"
|
73
|
+
|
74
|
+
curl.post_body = params.map{|f,k| "#{curl.escape(f)}=#{curl.escape(k)}"}.join('&')
|
75
|
+
|
76
|
+
curl.follow_location = true
|
77
|
+
curl.enable_cookies = true
|
78
|
+
end
|
79
|
+
|
80
|
+
server.shutdown
|
81
|
+
thread.join
|
82
|
+
end
|
83
|
+
end
|
data/tests/bug_multi_segfault.rb
CHANGED
@@ -6,5 +6,9 @@
|
|
6
6
|
$:.unshift File.expand_path(File.join(File.dirname(__FILE__),'..','ext'))
|
7
7
|
$:.unshift File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
8
8
|
require 'curb'
|
9
|
-
|
10
|
-
|
9
|
+
|
10
|
+
class BugMultiSegfault < Test::Unit::TestCase
|
11
|
+
def test_bug
|
12
|
+
multi = Curl::Multi.new
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# From GICodeWarrior:
|
2
|
+
#
|
3
|
+
# $ ruby crash_curb.rb
|
4
|
+
# crash_curb.rb:7: [BUG] Segmentation fault
|
5
|
+
# ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux]
|
6
|
+
#
|
7
|
+
# Aborted
|
8
|
+
# crash_curb.rb:
|
9
|
+
# #!/usr/bin/ruby
|
10
|
+
# require 'rubygems'
|
11
|
+
# require 'curb'
|
12
|
+
#
|
13
|
+
# curl = Curl::Easy.new('http://example.com/')
|
14
|
+
# curl.multipart_form_post = true
|
15
|
+
# curl.http_post(Curl::PostField.file('test', 'test.xml'){'example data'})
|
16
|
+
# Ubuntu 9.10
|
17
|
+
# curb gem version 0.6.2.1
|
18
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
19
|
+
|
20
|
+
class BugPostFieldsCrash < Test::Unit::TestCase
|
21
|
+
def test_crash
|
22
|
+
curl = Curl::Easy.new('http://example.com/')
|
23
|
+
curl.multipart_form_post = true
|
24
|
+
curl.http_post(Curl::PostField.file('test', 'test.xml'){'example data'})
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Not sure if this is an IRB bug, but thought you guys should know.
|
2
|
+
#
|
3
|
+
# ** My Ruby version: ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux]
|
4
|
+
# ** Version of Rubygems: 1.3.5
|
5
|
+
# ** Version of the Curb gem: 0.6.6.0
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# Transcript of IRB session:
|
9
|
+
# ------------------------------------------------------------------------------------------------------------------
|
10
|
+
# irb(main):001:0> a = {
|
11
|
+
# irb(main):002:1* :type => :pie,
|
12
|
+
# irb(main):003:1* :series => {
|
13
|
+
# irb(main):004:2* :names => [:a,:b],
|
14
|
+
# irb(main):005:2* :values => [70,30],
|
15
|
+
# irb(main):006:2* :colors => [:red,:green]
|
16
|
+
# irb(main):007:2> },
|
17
|
+
# irb(main):008:1* :output_format => :png
|
18
|
+
# irb(main):009:1> }
|
19
|
+
# => {:type=>:pie, :output_format=>:png, :series=>{:names=>[:a, :b], :values=>[70, 30], :colors=>[:red, :green]}}
|
20
|
+
# irb(main):010:0> post = []
|
21
|
+
# => []
|
22
|
+
# irb(main):011:0> require 'rubygems'
|
23
|
+
# => true
|
24
|
+
# irb(main):012:0> require 'curb'
|
25
|
+
# => true
|
26
|
+
# irb(main):013:0> include Curl
|
27
|
+
# => Object
|
28
|
+
# irb(main):014:0> a.each_pair do |k,v|
|
29
|
+
# irb(main):015:1* post << PostField.content(k,v)
|
30
|
+
# irb(main):016:1> end
|
31
|
+
# => {:type=>:pie, :output_format=>:png, :series=>{:names=>[:a, :b], :values=>[70, 30], :colors=>[:red, :green]}}
|
32
|
+
# irb(main):017:0> post
|
33
|
+
# /usr/lib/ruby/1.8/irb.rb:302: [BUG] Segmentation fault
|
34
|
+
# ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux]
|
35
|
+
#
|
36
|
+
# Aborted
|
37
|
+
# ------------------------------------------------------------------------------------------------------------------
|
38
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
39
|
+
|
40
|
+
class BugPostFieldsCrash2 < Test::Unit::TestCase
|
41
|
+
def test_crash
|
42
|
+
a = {
|
43
|
+
:type => :pie,
|
44
|
+
:series => {
|
45
|
+
:names => [:a,:b],
|
46
|
+
:values => [70,30],
|
47
|
+
:colors => [:red,:green]
|
48
|
+
},
|
49
|
+
:output_format => :png
|
50
|
+
}
|
51
|
+
post = []
|
52
|
+
a.each_pair do |k,v|
|
53
|
+
post << Curl::PostField.content(k,v)
|
54
|
+
end
|
55
|
+
post.inspect
|
56
|
+
end
|
57
|
+
end
|
data/tests/bugtests.rb
ADDED
data/tests/helper.rb
CHANGED
@@ -11,6 +11,7 @@ $:.unshift($EXTDIR)
|
|
11
11
|
|
12
12
|
require 'curb'
|
13
13
|
require 'test/unit'
|
14
|
+
require 'fileutils'
|
14
15
|
|
15
16
|
$TEST_URL = "file://#{URI.escape(File.expand_path(__FILE__).tr('\\','/').tr(':','|'))}"
|
16
17
|
|
@@ -59,6 +60,7 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
59
60
|
|
60
61
|
def respond_with(method,req,res)
|
61
62
|
res.body = method.to_s
|
63
|
+
$auth_header = req['Authorization']
|
62
64
|
res['Content-Type'] = "text/plain"
|
63
65
|
end
|
64
66
|
|
@@ -72,14 +74,18 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
72
74
|
end
|
73
75
|
|
74
76
|
def do_POST(req,res)
|
75
|
-
if req.
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
if req.query['filename'].nil?
|
78
|
+
if req.body
|
79
|
+
params = {}
|
80
|
+
req.body.split('&').map{|s| k,v=s.split('='); params[k] = v }
|
81
|
+
end
|
82
|
+
if params and params['s'] == '500'
|
83
|
+
res.status = 500
|
84
|
+
else
|
85
|
+
respond_with("POST\n#{req.body}",req,res)
|
86
|
+
end
|
81
87
|
else
|
82
|
-
respond_with(
|
88
|
+
respond_with(req.query['filename'],req,res)
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
@@ -92,6 +98,10 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
92
98
|
respond_with(:DELETE,req,res)
|
93
99
|
end
|
94
100
|
|
101
|
+
def do_PURGE(req,res)
|
102
|
+
respond_with(:PURGE,req,res)
|
103
|
+
end
|
104
|
+
|
95
105
|
end
|
96
106
|
|
97
107
|
module TestServerMethods
|