ghazel-curb 0.7.9.1 → 0.7.15.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +16 -3
- data/ext/curb.c +2 -0
- data/ext/curb.h +4 -4
- data/ext/curb_easy.c +25 -13
- data/ext/curb_multi.c +16 -24
- data/lib/curb.rb +39 -6
- data/lib/curl.rb +0 -1
- data/tests/tc_curl_easy.rb +36 -2
- metadata +5 -5
data/README
CHANGED
@@ -45,14 +45,19 @@ documentation with:
|
|
45
45
|
|
46
46
|
$ rake doc
|
47
47
|
|
48
|
-
##
|
48
|
+
## Usage & examples
|
49
|
+
|
50
|
+
Curb provides two classes:
|
51
|
+
|
52
|
+
+ Curl::Easy - simple API, for day-to-day tasks.
|
53
|
+
+ Curl::Multi - more advanced API, for operating on multiple URLs simultaneously.
|
49
54
|
|
50
55
|
### Simple fetch via HTTP:
|
51
56
|
|
52
57
|
c = Curl::Easy.perform("http://www.google.co.uk")
|
53
58
|
puts c.body_str
|
54
59
|
|
55
|
-
|
60
|
+
Same thing, more manual:
|
56
61
|
|
57
62
|
c = Curl::Easy.new("http://www.google.co.uk")
|
58
63
|
c.perform
|
@@ -65,7 +70,7 @@ documentation with:
|
|
65
70
|
curl.verbose = true
|
66
71
|
end
|
67
72
|
|
68
|
-
|
73
|
+
Same thing, more manual:
|
69
74
|
|
70
75
|
c = Curl::Easy.new("http://www.google.co.uk") do |curl|
|
71
76
|
curl.headers["User-Agent"] = "myapp-0.0"
|
@@ -74,6 +79,14 @@ documentation with:
|
|
74
79
|
|
75
80
|
c.perform
|
76
81
|
|
82
|
+
### HTTP basic authentication:
|
83
|
+
|
84
|
+
c = Curl::Easy.new("http://github.com/")
|
85
|
+
c.http_auth_types = :basic
|
86
|
+
c.username = 'foo'
|
87
|
+
c.password = 'bar'
|
88
|
+
c.perform
|
89
|
+
|
77
90
|
### Supplying custom handlers:
|
78
91
|
|
79
92
|
c = Curl::Easy.new("http://www.google.co.uk")
|
data/ext/curb.c
CHANGED
data/ext/curb.h
CHANGED
@@ -20,12 +20,12 @@
|
|
20
20
|
#include "curb_macros.h"
|
21
21
|
|
22
22
|
// These should be managed from the Rake 'release' task.
|
23
|
-
#define CURB_VERSION "0.7.
|
24
|
-
#define CURB_VER_NUM
|
23
|
+
#define CURB_VERSION "0.7.15"
|
24
|
+
#define CURB_VER_NUM 715
|
25
25
|
#define CURB_VER_MAJ 0
|
26
26
|
#define CURB_VER_MIN 7
|
27
|
-
#define CURB_VER_MIC
|
28
|
-
#define CURB_VER_PATCH
|
27
|
+
#define CURB_VER_MIC 1
|
28
|
+
#define CURB_VER_PATCH 5
|
29
29
|
|
30
30
|
|
31
31
|
// Maybe not yet defined in Ruby
|
data/ext/curb_easy.c
CHANGED
@@ -815,7 +815,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
815
815
|
the easy handle is active or until the upload
|
816
816
|
is complete or terminated... */
|
817
817
|
|
818
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY,0);
|
818
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
819
819
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
820
820
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
821
821
|
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
@@ -840,7 +840,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
840
840
|
|
841
841
|
if (rb_respond_to(data, rb_intern("read"))) {
|
842
842
|
VALUE stat = rb_funcall(data, rb_intern("stat"), 0);
|
843
|
-
if( stat ) {
|
843
|
+
if( stat && rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil) {
|
844
844
|
VALUE size;
|
845
845
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
846
846
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
@@ -848,9 +848,13 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
848
848
|
size = rb_funcall(stat, rb_intern("size"), 0);
|
849
849
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
|
850
850
|
}
|
851
|
-
else if( rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
851
|
+
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
852
852
|
rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
853
853
|
}
|
854
|
+
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
|
855
|
+
VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
|
856
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
|
857
|
+
}
|
854
858
|
}
|
855
859
|
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
856
860
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
|
@@ -1812,7 +1816,10 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
1812
1816
|
/***********************************************
|
1813
1817
|
* This is an rb_iterate callback used to set up http headers.
|
1814
1818
|
*/
|
1815
|
-
static VALUE cb_each_http_header(VALUE header,
|
1819
|
+
static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
1820
|
+
struct curl_slist **list;
|
1821
|
+
Data_Get_Struct(wrap, struct curl_slist *, list);
|
1822
|
+
|
1816
1823
|
VALUE header_str = Qnil;
|
1817
1824
|
|
1818
1825
|
//rb_p(header);
|
@@ -1841,7 +1848,10 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
|
|
1841
1848
|
/***********************************************
|
1842
1849
|
* This is an rb_iterate callback used to set up ftp commands.
|
1843
1850
|
*/
|
1844
|
-
static VALUE cb_each_ftp_command(VALUE ftp_command,
|
1851
|
+
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
1852
|
+
struct curl_slist **list;
|
1853
|
+
Data_Get_Struct(wrap, struct curl_slist *, list);
|
1854
|
+
|
1845
1855
|
VALUE ftp_command_string = rb_obj_as_string(ftp_command);
|
1846
1856
|
*list = curl_slist_append(*list, StringValuePtr(ftp_command));
|
1847
1857
|
|
@@ -1903,16 +1913,16 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
|
|
1903
1913
|
curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
|
1904
1914
|
}
|
1905
1915
|
|
1906
|
-
if (
|
1907
|
-
curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
|
1908
|
-
} else {
|
1916
|
+
if (rb_easy_nil("proxy_url")) {
|
1909
1917
|
curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
|
1918
|
+
} else {
|
1919
|
+
curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
|
1910
1920
|
}
|
1911
1921
|
|
1912
|
-
if (
|
1913
|
-
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxy_pwd"));
|
1914
|
-
} else {
|
1922
|
+
if (rb_easy_nil("proxypwd")) {
|
1915
1923
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
1924
|
+
} else {
|
1925
|
+
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
|
1916
1926
|
}
|
1917
1927
|
|
1918
1928
|
// body/header procs
|
@@ -2118,7 +2128,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
|
|
2118
2128
|
|
2119
2129
|
if (!rb_easy_nil("headers")) {
|
2120
2130
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
|
2121
|
-
|
2131
|
+
VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, hdrs);
|
2132
|
+
rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, wrap);
|
2122
2133
|
} else {
|
2123
2134
|
VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
|
2124
2135
|
*hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
|
@@ -2132,7 +2143,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
|
|
2132
2143
|
/* Setup FTP commands if necessary */
|
2133
2144
|
if (!rb_easy_nil("ftp_commands")) {
|
2134
2145
|
if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
|
2135
|
-
|
2146
|
+
VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, cmds);
|
2147
|
+
rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, wrap);
|
2136
2148
|
}
|
2137
2149
|
|
2138
2150
|
if (*cmds) {
|
data/ext/curb_multi.c
CHANGED
@@ -39,13 +39,9 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
|
39
39
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
40
40
|
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running);
|
41
41
|
|
42
|
-
static void rb_curl_multi_mark_all_easy(VALUE key, VALUE rbeasy, ruby_curl_multi *rbcm) {
|
43
|
-
rb_gc_mark(rbeasy);
|
44
|
-
}
|
45
|
-
|
46
42
|
static void curl_multi_mark(ruby_curl_multi *rbcm) {
|
47
43
|
rb_gc_mark(rbcm->requests);
|
48
|
-
|
44
|
+
rb_gc_mark(rbcm->requests);
|
49
45
|
}
|
50
46
|
|
51
47
|
static void curl_multi_flush_easy(VALUE key, VALUE easy, ruby_curl_multi *rbcm) {
|
@@ -482,29 +478,23 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
482
478
|
|
483
479
|
if (timeout_milliseconds == 0) { /* no delay */
|
484
480
|
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
481
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
482
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
485
483
|
continue;
|
486
484
|
}
|
487
|
-
else if (timeout_milliseconds < 0) {
|
488
|
-
timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
|
489
|
-
}
|
490
485
|
|
491
|
-
if (timeout_milliseconds > cCurlMutiDefaulttimeout) {
|
492
|
-
timeout_milliseconds = cCurlMutiDefaulttimeout; /*
|
486
|
+
if (timeout_milliseconds < 0 || timeout_milliseconds > cCurlMutiDefaulttimeout) {
|
487
|
+
timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
|
488
|
+
/* or buggy versions libcurl sometimes reports huge timeouts... let's cap it */
|
493
489
|
}
|
494
490
|
|
495
491
|
tv.tv_sec = 0; /* never wait longer than 1 second */
|
496
492
|
tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */
|
497
493
|
|
498
|
-
if (timeout_milliseconds == 0) { /* no delay */
|
499
|
-
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
500
|
-
continue;
|
501
|
-
}
|
502
|
-
|
503
|
-
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
504
|
-
|
505
494
|
FD_ZERO(&fdread);
|
506
495
|
FD_ZERO(&fdwrite);
|
507
496
|
FD_ZERO(&fdexcep);
|
497
|
+
|
508
498
|
/* load the fd sets from the multi handle */
|
509
499
|
mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
510
500
|
if (mcode != CURLM_OK) {
|
@@ -513,7 +503,7 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
513
503
|
|
514
504
|
#ifdef _WIN32
|
515
505
|
create_crt_fd(&fdread, &crt_fdread);
|
516
|
-
create_crt_fd(&fdwrite, &
|
506
|
+
create_crt_fd(&fdwrite, &crt_fdwrite);
|
517
507
|
create_crt_fd(&fdexcep, &crt_fdexcep);
|
518
508
|
#endif
|
519
509
|
|
@@ -521,7 +511,7 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
521
511
|
|
522
512
|
#ifdef _WIN32
|
523
513
|
cleanup_crt_fd(&fdread, &crt_fdread);
|
524
|
-
cleanup_crt_fd(&fdwrite, &
|
514
|
+
cleanup_crt_fd(&fdwrite, &crt_fdwrite);
|
525
515
|
cleanup_crt_fd(&fdexcep, &crt_fdexcep);
|
526
516
|
#endif
|
527
517
|
|
@@ -529,17 +519,19 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
529
519
|
case -1:
|
530
520
|
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
531
521
|
break;
|
532
|
-
case 0:
|
522
|
+
case 0: /* timeout */
|
523
|
+
default: /* action */
|
524
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
533
525
|
rb_curl_multi_read_info( self, rbcm->handle );
|
534
526
|
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
535
|
-
default:
|
536
|
-
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
537
527
|
break;
|
538
528
|
}
|
539
529
|
}
|
540
|
-
|
541
|
-
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
530
|
+
|
542
531
|
} while( rbcm->running );
|
532
|
+
|
533
|
+
rb_curl_multi_read_info( self, rbcm->handle );
|
534
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
543
535
|
|
544
536
|
return Qtrue;
|
545
537
|
}
|
data/lib/curb.rb
CHANGED
@@ -77,7 +77,7 @@ module Curl
|
|
77
77
|
urls.each do|url|
|
78
78
|
url_confs << {:url => url, :method => :get}.merge(easy_options)
|
79
79
|
end
|
80
|
-
self.http(url_confs, multi_options) {|c,code,method| blk.call(c) }
|
80
|
+
self.http(url_confs, multi_options) {|c,code,method| blk.call(c) if blk }
|
81
81
|
end
|
82
82
|
|
83
83
|
# call-seq:
|
@@ -148,17 +148,25 @@ module Curl
|
|
148
148
|
#
|
149
149
|
def http(urls_with_config, multi_options={}, &blk)
|
150
150
|
m = Curl::Multi.new
|
151
|
+
|
152
|
+
# maintain a sane number of easy handles
|
153
|
+
multi_options[:max_connects] = max_connects = multi_options.key?(:max_connects) ? multi_options[:max_connects] : 10
|
154
|
+
|
155
|
+
free_handles = [] # keep a list of free easy handles
|
156
|
+
|
151
157
|
# configure the multi handle
|
152
158
|
multi_options.each { |k,v| m.send("#{k}=", v) }
|
153
159
|
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
|
154
160
|
|
155
|
-
|
156
|
-
c
|
161
|
+
add_free_handle = proc do|conf, easy|
|
162
|
+
c = conf.dup # avoid being destructive to input
|
157
163
|
url = c.delete(:url)
|
158
164
|
method = c.delete(:method)
|
159
165
|
headers = c.delete(:headers)
|
160
166
|
|
161
|
-
easy = Curl::Easy.new
|
167
|
+
easy = Curl::Easy.new if easy.nil?
|
168
|
+
|
169
|
+
easy.url = url
|
162
170
|
|
163
171
|
# assign callbacks
|
164
172
|
callbacks.each do |cb|
|
@@ -191,10 +199,35 @@ module Curl
|
|
191
199
|
#
|
192
200
|
c.each { |k,v| easy.send("#{k}=",v) }
|
193
201
|
|
194
|
-
easy.on_complete {|curl,code|
|
202
|
+
easy.on_complete {|curl,code|
|
203
|
+
free_handles << curl
|
204
|
+
blk.call(curl,code,method) if blk
|
205
|
+
}
|
195
206
|
m.add(easy)
|
196
207
|
end
|
197
|
-
|
208
|
+
|
209
|
+
max_connects.times do
|
210
|
+
conf = urls_with_config.pop
|
211
|
+
add_free_handle.call conf, nil
|
212
|
+
break if urls_with_config.empty?
|
213
|
+
end
|
214
|
+
|
215
|
+
consume_free_handles = proc do
|
216
|
+
# as we idle consume free handles
|
217
|
+
if urls_with_config.size > 0 && free_handles.size > 0
|
218
|
+
easy = free_handles.pop
|
219
|
+
conf = urls_with_config.pop
|
220
|
+
add_free_handle.call conf, easy
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
until urls_with_config.empty?
|
225
|
+
m.perform do
|
226
|
+
consume_free_handles.call
|
227
|
+
end
|
228
|
+
consume_free_handles.call
|
229
|
+
end
|
230
|
+
free_handles = nil
|
198
231
|
end
|
199
232
|
|
200
233
|
# call-seq:
|
data/lib/curl.rb
CHANGED
data/tests/tc_curl_easy.rb
CHANGED
@@ -224,7 +224,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
224
224
|
|
225
225
|
assert_equal $TEST_URL, c.url
|
226
226
|
assert_equal "http://some.proxy", c.proxy_url
|
227
|
-
|
227
|
+
|
228
228
|
c.proxy_url = nil
|
229
229
|
assert_equal $TEST_URL, c.url
|
230
230
|
assert_nil c.proxy_url
|
@@ -566,7 +566,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
566
566
|
def test_post_remote
|
567
567
|
curl = Curl::Easy.new(TestServlet.url)
|
568
568
|
curl.http_post([Curl::PostField.content('document_id', 5)])
|
569
|
-
assert_equal "POST\
|
569
|
+
assert_equal "POST\ndocument_id=5", curl.unescape(curl.body_str)
|
570
570
|
end
|
571
571
|
|
572
572
|
def test_post_remote_is_easy_handle
|
@@ -853,6 +853,40 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
853
853
|
assert_equal 'GET', curl.body_str
|
854
854
|
end
|
855
855
|
|
856
|
+
def test_easy_can_put_with_content_length
|
857
|
+
curl = Curl::Easy.new(TestServlet.url)
|
858
|
+
rd, wr = IO.pipe
|
859
|
+
buf = (("hello")* (1000 / 5))
|
860
|
+
|
861
|
+
producer = Thread.new do
|
862
|
+
5.times do
|
863
|
+
wr << buf
|
864
|
+
sleep 0.1 # act as a slow producer
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
consumer = Thread.new do
|
869
|
+
|
870
|
+
#curl.verbose = true
|
871
|
+
curl.headers['Content-Length'] = buf.size * 5
|
872
|
+
curl.headers['User-Agent'] = "Something else"
|
873
|
+
curl.headers['Content-Type'] = "text/javascript"
|
874
|
+
curl.headers['Date'] = Time.now.httpdate
|
875
|
+
curl.headers['Host'] = 's3.amazonaws.com'
|
876
|
+
curl.headers['Accept'] = '*/*'
|
877
|
+
curl.headers['Authorization'] = 'Foo Bar Biz Baz'
|
878
|
+
curl.http_put(rd)
|
879
|
+
assert_match /^PUT/, curl.body_str
|
880
|
+
assert_match /hello$/, curl.body_str
|
881
|
+
curl.header_str
|
882
|
+
curl.body_str
|
883
|
+
end
|
884
|
+
|
885
|
+
producer.join
|
886
|
+
wr.close
|
887
|
+
consumer.join
|
888
|
+
|
889
|
+
end
|
856
890
|
|
857
891
|
include TestServerMethods
|
858
892
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghazel-curb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 73
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 7
|
9
|
-
-
|
9
|
+
- 15
|
10
10
|
- 1
|
11
|
-
version: 0.7.
|
11
|
+
version: 0.7.15.1
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Ross Bamford
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date:
|
20
|
+
date: 2011-03-20 00:00:00 -07:00
|
21
21
|
default_executable:
|
22
22
|
dependencies: []
|
23
23
|
|
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
102
|
requirements: []
|
103
103
|
|
104
104
|
rubyforge_project: curb
|
105
|
-
rubygems_version: 1.
|
105
|
+
rubygems_version: 1.5.2
|
106
106
|
signing_key:
|
107
107
|
specification_version: 3
|
108
108
|
summary: Ruby libcurl bindings
|