curb 0.4.8.0 → 0.5.1.0
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/ext/curb.h +4 -4
- data/ext/curb_config.h +2 -0
- data/ext/curb_easy.c +124 -102
- data/ext/curb_multi.c +80 -59
- data/ext/curb_multi.h +1 -1
- data/ext/curb_postfield.c +1 -1
- data/ext/extconf.rb +3 -0
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +1 -1
- data/tests/bug_instance_post_differs_from_class_post.rb +1 -1
- data/tests/helper.rb +9 -1
- data/tests/require_last_or_segfault_script.rb +2 -2
- data/tests/tc_curl_download.rb +1 -1
- data/tests/tc_curl_easy.rb +42 -1
- data/tests/tc_curl_multi.rb +25 -1
- data/tests/tc_curl_postfield.rb +1 -1
- metadata +2 -2
data/ext/curb.h
CHANGED
@@ -20,11 +20,11 @@
|
|
20
20
|
#include "curb_macros.h"
|
21
21
|
|
22
22
|
// These should be managed from the Rake 'release' task.
|
23
|
-
#define CURB_VERSION "0.
|
24
|
-
#define CURB_VER_NUM
|
23
|
+
#define CURB_VERSION "0.5.1.0"
|
24
|
+
#define CURB_VER_NUM 510
|
25
25
|
#define CURB_VER_MAJ 0
|
26
|
-
#define CURB_VER_MIN
|
27
|
-
#define CURB_VER_MIC
|
26
|
+
#define CURB_VER_MIN 5
|
27
|
+
#define CURB_VER_MIC 1
|
28
28
|
#define CURB_VER_PATCH 0
|
29
29
|
|
30
30
|
|
data/ext/curb_config.h
CHANGED
data/ext/curb_easy.c
CHANGED
@@ -82,32 +82,6 @@ static size_t read_data_handler(void *ptr,
|
|
82
82
|
return read_bytes;
|
83
83
|
}
|
84
84
|
|
85
|
-
// PutStream *pstream = (PutStream*)stream;
|
86
|
-
// size_t sent_bytes = (size * nmemb);
|
87
|
-
// size_t remaining = pstream->len - pstream->offset;
|
88
|
-
/*
|
89
|
-
|
90
|
-
// amount remaining is less then the buffer to send - can send it all
|
91
|
-
if( remaining < sent_bytes ) {
|
92
|
-
memcpy(ptr, pstream->buffer+pstream->offset, remaining);
|
93
|
-
sent_bytes = remaining;
|
94
|
-
pstream->offset += remaining;
|
95
|
-
}
|
96
|
-
else if( remaining > sent_bytes ) { // sent_bytes <= remaining - send what we can fit in the buffer(ptr)
|
97
|
-
memcpy(ptr, pstream->buffer+pstream->offset, sent_bytes);
|
98
|
-
pstream->offset += sent_bytes;
|
99
|
-
}
|
100
|
-
else { // they're equal
|
101
|
-
memcpy(ptr, pstream->buffer+pstream->offset, --sent_bytes);
|
102
|
-
pstream->offset += sent_bytes;
|
103
|
-
}
|
104
|
-
if (sent_bytes == 0) {
|
105
|
-
free(pstream);
|
106
|
-
}
|
107
|
-
*/
|
108
|
-
|
109
|
-
//printf("sent_bytes: %ld of %ld\n", sent_bytes, remaining);
|
110
|
-
//return sent_bytes;
|
111
85
|
}
|
112
86
|
|
113
87
|
static size_t proc_data_handler(char *stream,
|
@@ -289,16 +263,16 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
289
263
|
|
290
264
|
new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
|
291
265
|
|
292
|
-
if (blk != Qnil) {
|
293
|
-
rb_funcall(blk, idCall, 1, new_curl);
|
294
|
-
}
|
295
|
-
|
296
266
|
/* set the rbce pointer to the curl handle */
|
297
267
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
298
268
|
if (ecode != CURLE_OK) {
|
299
269
|
raise_curl_easy_error_exception(ecode);
|
300
270
|
}
|
301
271
|
|
272
|
+
if (blk != Qnil) {
|
273
|
+
rb_funcall(blk, idCall, 1, new_curl);
|
274
|
+
}
|
275
|
+
|
302
276
|
return new_curl;
|
303
277
|
}
|
304
278
|
|
@@ -731,6 +705,70 @@ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
|
|
731
705
|
CURB_OBJECT_GETTER(ruby_curl_easy, postdata_buffer);
|
732
706
|
}
|
733
707
|
|
708
|
+
/*
|
709
|
+
* call-seq:
|
710
|
+
* easy.put_data = data => ""
|
711
|
+
*
|
712
|
+
* Points this Curl::Easy instance to data to be uploaded via PUT. This
|
713
|
+
* sets the request to a PUT type request - useful if you want to PUT via
|
714
|
+
* a multi handle.
|
715
|
+
*/
|
716
|
+
static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
717
|
+
ruby_curl_easy *rbce;
|
718
|
+
CURL *curl;
|
719
|
+
|
720
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
721
|
+
|
722
|
+
VALUE upload = ruby_curl_upload_new(cCurlUpload);
|
723
|
+
ruby_curl_upload_stream_set(upload,data);
|
724
|
+
|
725
|
+
curl = rbce->curl;
|
726
|
+
rbce->upload = upload; /* keep the upload object alive as long as
|
727
|
+
the easy handle is active or until the upload
|
728
|
+
is complete or terminated... */
|
729
|
+
|
730
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY,0);
|
731
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
732
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
733
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
734
|
+
|
735
|
+
/*
|
736
|
+
* we need to set specific headers for the PUT to work... so
|
737
|
+
* convert the internal headers structure to a HASH if one is set
|
738
|
+
*/
|
739
|
+
if (rbce->headers != Qnil) {
|
740
|
+
if (rb_type(rbce->headers) == T_ARRAY || rb_type(rbce->headers) == T_STRING) {
|
741
|
+
rb_raise(rb_eRuntimeError, "Must set headers as a HASH to modify the headers in an PUT request");
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
if (rb_respond_to(data, rb_intern("read"))) {
|
746
|
+
VALUE stat = rb_funcall(data, rb_intern("stat"), 0);
|
747
|
+
if( stat ) {
|
748
|
+
if( rb_hash_aref(rbce->headers, rb_str_new2("Expect")) == Qnil ) {
|
749
|
+
rb_hash_aset(rbce->headers, rb_str_new2("Expect"), rb_str_new2(""));
|
750
|
+
}
|
751
|
+
VALUE size = rb_funcall(stat, rb_intern("size"), 0);
|
752
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2INT(size));
|
753
|
+
}
|
754
|
+
else if( rb_hash_aref(rbce->headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
755
|
+
rb_hash_aset(rbce->headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
756
|
+
}
|
757
|
+
}
|
758
|
+
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
759
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
|
760
|
+
if( rb_hash_aref(rbce->headers, rb_str_new2("Expect")) == Qnil ) {
|
761
|
+
rb_hash_aset(rbce->headers, rb_str_new2("Expect"), rb_str_new2(""));
|
762
|
+
}
|
763
|
+
}
|
764
|
+
else {
|
765
|
+
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
766
|
+
}
|
767
|
+
|
768
|
+
// if we made it this far, all should be well.
|
769
|
+
return data;
|
770
|
+
}
|
771
|
+
|
734
772
|
/* ================== IMMED ATTRS ==================*/
|
735
773
|
|
736
774
|
/*
|
@@ -1631,8 +1669,11 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, VALUE *body_buffer, VALUE *hea
|
|
1631
1669
|
}
|
1632
1670
|
}
|
1633
1671
|
if (rbce->cacert != Qnil) {
|
1634
|
-
|
1672
|
+
#ifdef HAVE_CURL_CONFIG_CA
|
1673
|
+
curl_easy_setopt(curl, CURLOPT_CAINFO, CURL_CONFIG_CA);
|
1674
|
+
#else
|
1635
1675
|
curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/local/share/curl/curl-ca-bundle.crt");
|
1676
|
+
#endif
|
1636
1677
|
}
|
1637
1678
|
|
1638
1679
|
/* Set the user-agent string if specified */
|
@@ -1640,7 +1681,6 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, VALUE *body_buffer, VALUE *hea
|
|
1640
1681
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, StringValuePtr(rbce->useragent));
|
1641
1682
|
}
|
1642
1683
|
|
1643
|
-
|
1644
1684
|
/* Setup HTTP headers if necessary */
|
1645
1685
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
1646
1686
|
|
@@ -1667,6 +1707,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce, VALUE *body_buffer, VALUE *hea
|
|
1667
1707
|
*/
|
1668
1708
|
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, VALUE headerbuf, struct curl_slist *headers ) {
|
1669
1709
|
|
1710
|
+
CURL *curl = rbce->curl;
|
1711
|
+
|
1670
1712
|
// Free everything up
|
1671
1713
|
if (headers) {
|
1672
1714
|
curl_slist_free_all(headers);
|
@@ -1701,6 +1743,15 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, V
|
|
1701
1743
|
} else {
|
1702
1744
|
rbce->header_data = Qnil;
|
1703
1745
|
}
|
1746
|
+
|
1747
|
+
// clean up a PUT request's curl options.
|
1748
|
+
if (rbce->upload != Qnil) {
|
1749
|
+
rbce->upload = Qnil; // set the upload object to Qnil to let the GC clean up
|
1750
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
1751
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
1752
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
1753
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
1754
|
+
}
|
1704
1755
|
|
1705
1756
|
return Qnil;
|
1706
1757
|
}
|
@@ -1719,7 +1770,7 @@ static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
|
|
1719
1770
|
|
1720
1771
|
VALUE multi = ruby_curl_multi_new(cCurlMulti);
|
1721
1772
|
ruby_curl_multi_add(multi, self);
|
1722
|
-
VALUE ret =
|
1773
|
+
VALUE ret = rb_funcall(multi, rb_intern("perform"), 0);
|
1723
1774
|
|
1724
1775
|
/* check for errors in the easy response and raise exceptions if anything went wrong and their is no on_failure handler */
|
1725
1776
|
if( rbce->last_result != 0 && rbce->failure_proc == Qnil ) {
|
@@ -1822,9 +1873,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
1822
1873
|
rb_scan_args(argc, argv, "*", &args_ary);
|
1823
1874
|
|
1824
1875
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1825
|
-
curl =
|
1826
|
-
curl_easy_cleanup(rbce->curl);
|
1827
|
-
rbce->curl = curl;
|
1876
|
+
curl = rbce->curl;
|
1828
1877
|
|
1829
1878
|
if (rbce->multipart_form_post) {
|
1830
1879
|
VALUE ret;
|
@@ -1878,7 +1927,10 @@ static VALUE ruby_curl_easy_perform_head(VALUE self) {
|
|
1878
1927
|
|
1879
1928
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
1880
1929
|
|
1881
|
-
|
1930
|
+
VALUE ret = handle_perform(self,rbce);
|
1931
|
+
|
1932
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
1933
|
+
return ret;
|
1882
1934
|
}
|
1883
1935
|
|
1884
1936
|
/*
|
@@ -1914,62 +1966,25 @@ static VALUE ruby_curl_easy_set_head_option(VALUE self, VALUE onoff) {
|
|
1914
1966
|
static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
1915
1967
|
ruby_curl_easy *rbce;
|
1916
1968
|
CURL *curl;
|
1917
|
-
|
1969
|
+
|
1918
1970
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1919
|
-
|
1920
|
-
VALUE upload = ruby_curl_upload_new(cCurlUpload);
|
1921
|
-
ruby_curl_upload_stream_set(upload,data);
|
1922
|
-
|
1923
1971
|
curl = rbce->curl;
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
1930
|
-
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
1931
|
-
|
1932
|
-
/*
|
1933
|
-
* we need to set specific headers for the PUT to work... so
|
1934
|
-
* convert the internal headers structure to a HASH if one is set
|
1935
|
-
*/
|
1936
|
-
if (rbce->headers != Qnil) {
|
1937
|
-
if (rb_type(rbce->headers) == T_ARRAY || rb_type(rbce->headers) == T_STRING) {
|
1938
|
-
rb_raise(rb_eRuntimeError, "Must set headers as a HASH to modify the headers in an http_put request");
|
1939
|
-
}
|
1940
|
-
}
|
1941
|
-
|
1942
|
-
if (rb_respond_to(data, rb_intern("read"))) {
|
1943
|
-
VALUE stat = rb_funcall(data, rb_intern("stat"), 0);
|
1944
|
-
if( stat ) {
|
1945
|
-
if( rb_hash_aref(rbce->headers, rb_str_new2("Expect")) == Qnil ) {
|
1946
|
-
rb_hash_aset(rbce->headers, rb_str_new2("Expect"), rb_str_new2(""));
|
1947
|
-
}
|
1948
|
-
VALUE size = rb_funcall(stat, rb_intern("size"), 0);
|
1949
|
-
curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2INT(size));
|
1950
|
-
}
|
1951
|
-
else if( rb_hash_aref(rbce->headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
1952
|
-
rb_hash_aset(rbce->headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
1953
|
-
}
|
1954
|
-
}
|
1955
|
-
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
1956
|
-
curl_easy_setopt(curl, CURLOPT_INFILESIZE, RSTRING_LEN(data));
|
1957
|
-
if( rb_hash_aref(rbce->headers, rb_str_new2("Expect")) == Qnil ) {
|
1958
|
-
rb_hash_aset(rbce->headers, rb_str_new2("Expect"), rb_str_new2(""));
|
1959
|
-
}
|
1960
|
-
}
|
1961
|
-
else {
|
1962
|
-
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
1963
|
-
}
|
1964
|
-
|
1965
|
-
VALUE ret = handle_perform(self, rbce);
|
1966
|
-
/* cleanup */
|
1967
|
-
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
1968
|
-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
1969
|
-
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
1970
|
-
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
1972
|
+
|
1973
|
+
ruby_curl_easy_put_data_set(self, data);
|
1974
|
+
|
1975
|
+
return handle_perform(self, rbce);
|
1976
|
+
}
|
1971
1977
|
|
1972
|
-
|
1978
|
+
/*
|
1979
|
+
* call-seq:
|
1980
|
+
* Curl::Easy.http_put(url, data) {|c| ... }
|
1981
|
+
*
|
1982
|
+
* see easy.http_put
|
1983
|
+
*/
|
1984
|
+
static VALUE ruby_curl_easy_class_perform_put(VALUE klass, VALUE url, VALUE data) {
|
1985
|
+
VALUE c = ruby_curl_easy_new(1, &url, klass);
|
1986
|
+
ruby_curl_easy_perform_put(c, data);
|
1987
|
+
return c;
|
1973
1988
|
}
|
1974
1989
|
|
1975
1990
|
/* =================== DATA FUNCS =============== */
|
@@ -2531,6 +2546,21 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
2531
2546
|
#endif
|
2532
2547
|
}
|
2533
2548
|
|
2549
|
+
/*
|
2550
|
+
* call-seq:
|
2551
|
+
* easy.inspect => "#<Curl::Easy http://google.com/>"
|
2552
|
+
*/
|
2553
|
+
static VALUE ruby_curl_easy_inspect(VALUE self) {
|
2554
|
+
char buf[64];
|
2555
|
+
ruby_curl_easy *rbce;
|
2556
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2557
|
+
// "#<Net::HTTP http://www.google.com/:80 open=false>"
|
2558
|
+
snprintf(buf,sizeof(buf),"#<Curl::Easy %s", RSTRING_PTR(rbce->url));
|
2559
|
+
size_t r = strlen(buf);
|
2560
|
+
buf[r-1] = '>';
|
2561
|
+
return rb_str_new(buf,r);
|
2562
|
+
}
|
2563
|
+
|
2534
2564
|
|
2535
2565
|
/* ================== ESCAPING FUNCS ==============*/
|
2536
2566
|
|
@@ -2629,10 +2659,6 @@ static VALUE ruby_curl_easy_class_perform(int argc, VALUE *argv, VALUE klass) {
|
|
2629
2659
|
static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass) {
|
2630
2660
|
VALUE c = ruby_curl_easy_new(argc, argv, klass);
|
2631
2661
|
|
2632
|
-
if (rb_block_given_p()) {
|
2633
|
-
rb_yield(c);
|
2634
|
-
}
|
2635
|
-
|
2636
2662
|
ruby_curl_easy_perform_get(c);
|
2637
2663
|
return c;
|
2638
2664
|
}
|
@@ -2650,10 +2676,6 @@ static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass
|
|
2650
2676
|
static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE klass) {
|
2651
2677
|
VALUE c = ruby_curl_easy_new(argc, argv, klass);
|
2652
2678
|
|
2653
|
-
if (rb_block_given_p()) {
|
2654
|
-
rb_yield(c);
|
2655
|
-
}
|
2656
|
-
|
2657
2679
|
ruby_curl_easy_perform_delete(c);
|
2658
2680
|
return c;
|
2659
2681
|
}
|
@@ -2671,11 +2693,8 @@ static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE kl
|
|
2671
2693
|
static VALUE ruby_curl_easy_class_perform_head(int argc, VALUE *argv, VALUE klass) {
|
2672
2694
|
VALUE c = ruby_curl_easy_new(argc, argv, klass);
|
2673
2695
|
|
2674
|
-
if (rb_block_given_p()) {
|
2675
|
-
rb_yield(c);
|
2676
|
-
}
|
2677
|
-
|
2678
2696
|
ruby_curl_easy_perform_head(c);
|
2697
|
+
|
2679
2698
|
return c;
|
2680
2699
|
}
|
2681
2700
|
|
@@ -2731,6 +2750,7 @@ void init_curb_easy() {
|
|
2731
2750
|
rb_define_singleton_method(cCurlEasy, "http_get", ruby_curl_easy_class_perform_get, -1);
|
2732
2751
|
rb_define_singleton_method(cCurlEasy, "http_post", ruby_curl_easy_class_perform_post, -1);
|
2733
2752
|
rb_define_singleton_method(cCurlEasy, "http_head", ruby_curl_easy_class_perform_head, -1);
|
2753
|
+
rb_define_singleton_method(cCurlEasy, "http_put", ruby_curl_easy_class_perform_put, 2);
|
2734
2754
|
|
2735
2755
|
/* Attributes for config next perform */
|
2736
2756
|
rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
|
@@ -2764,6 +2784,7 @@ void init_curb_easy() {
|
|
2764
2784
|
rb_define_method(cCurlEasy, "useragent", ruby_curl_easy_useragent_get, 0);
|
2765
2785
|
rb_define_method(cCurlEasy, "post_body=", ruby_curl_easy_post_body_set, 1);
|
2766
2786
|
rb_define_method(cCurlEasy, "post_body", ruby_curl_easy_post_body_get, 0);
|
2787
|
+
rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
|
2767
2788
|
|
2768
2789
|
rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
|
2769
2790
|
rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
|
@@ -2855,6 +2876,7 @@ void init_curb_easy() {
|
|
2855
2876
|
rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
|
2856
2877
|
rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
|
2857
2878
|
rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
|
2879
|
+
rb_define_method(cCurlEasy, "inspect", ruby_curl_easy_inspect, 0);
|
2858
2880
|
|
2859
2881
|
/* Curl utils */
|
2860
2882
|
rb_define_method(cCurlEasy, "escape", ruby_curl_easy_escape, 1);
|
data/ext/curb_multi.c
CHANGED
@@ -57,6 +57,11 @@ static void curl_multi_flush_easy(VALUE key, VALUE easy, ruby_curl_multi *rbcm)
|
|
57
57
|
}
|
58
58
|
}
|
59
59
|
|
60
|
+
static int
|
61
|
+
rb_hash_clear_i(VALUE key, VALUE value, VALUE dummy) {
|
62
|
+
return ST_DELETE;
|
63
|
+
}
|
64
|
+
|
60
65
|
static void curl_multi_free(ruby_curl_multi *rbcm) {
|
61
66
|
|
62
67
|
//printf("hash entries: %d\n", RHASH(rbcm->requests)->tbl->num_entries );
|
@@ -64,7 +69,7 @@ static void curl_multi_free(ruby_curl_multi *rbcm) {
|
|
64
69
|
|
65
70
|
rb_hash_foreach( rbcm->requests, (int (*)())curl_multi_flush_easy, (VALUE)rbcm );
|
66
71
|
|
67
|
-
//rb_hash_clear(rbcm->requests)
|
72
|
+
rb_hash_foreach(rbcm->requests, rb_hash_clear_i, 0); //rb_hash_clear(rbcm->requests);
|
68
73
|
rbcm->requests = Qnil;
|
69
74
|
}
|
70
75
|
curl_multi_cleanup(rbcm->handle);
|
@@ -296,55 +301,57 @@ static VALUE ruby_curl_multi_cancel(VALUE self) {
|
|
296
301
|
return self;
|
297
302
|
}
|
298
303
|
|
299
|
-
static void
|
300
|
-
|
301
|
-
|
302
|
-
CURLcode ecode;
|
303
|
-
CURL *easy_handle;
|
304
|
+
static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int result) {
|
305
|
+
|
306
|
+
long response_code = -1;
|
304
307
|
ruby_curl_easy *rbce = NULL;
|
305
308
|
|
306
|
-
|
307
|
-
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
|
309
|
+
CURLcode ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&rbce);
|
308
310
|
|
309
|
-
|
310
|
-
|
311
|
-
|
311
|
+
if (ecode != 0) {
|
312
|
+
raise_curl_easy_error_exception(ecode);
|
313
|
+
}
|
312
314
|
|
313
|
-
|
314
|
-
result = msg->data.result;
|
315
|
-
if (easy_handle) {
|
316
|
-
ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&rbce);
|
317
|
-
if (ecode != 0) {
|
318
|
-
raise_curl_easy_error_exception(ecode);
|
319
|
-
}
|
320
|
-
rbce->last_result = result; // save the last easy result code
|
321
|
-
ruby_curl_multi_remove( self, rbce->self );
|
315
|
+
rbce->last_result = result; /* save the last easy result code */
|
322
316
|
|
323
|
-
|
324
|
-
|
325
|
-
|
317
|
+
ruby_curl_multi_remove( self, rbce->self );
|
318
|
+
|
319
|
+
if (rbce->complete_proc != Qnil) {
|
320
|
+
rb_funcall( rbce->complete_proc, idCall, 1, rbce->self );
|
321
|
+
}
|
326
322
|
|
327
|
-
|
328
|
-
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
323
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
329
324
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
}
|
334
|
-
}
|
335
|
-
else if (rbce->success_proc != Qnil &&
|
336
|
-
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
337
|
-
/* NOTE: we allow response_code == 0, in the case the file is being read from disk */
|
338
|
-
rb_funcall( rbce->success_proc, idCall, 1, rbce->self );
|
339
|
-
}
|
340
|
-
else if (rbce->failure_proc != Qnil &&
|
341
|
-
(response_code >= 300 && response_code <= 999)) {
|
342
|
-
rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
|
343
|
-
}
|
344
|
-
rbce->self = Qnil;
|
325
|
+
if (result != 0) {
|
326
|
+
if (rbce->failure_proc != Qnil) {
|
327
|
+
rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
|
345
328
|
}
|
346
|
-
|
347
|
-
|
329
|
+
}
|
330
|
+
else if (rbce->success_proc != Qnil &&
|
331
|
+
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
332
|
+
/* NOTE: we allow response_code == 0, in the case of non http requests e.g. reading from disk */
|
333
|
+
rb_funcall( rbce->success_proc, idCall, 1, rbce->self );
|
334
|
+
}
|
335
|
+
else if (rbce->failure_proc != Qnil &&
|
336
|
+
(response_code >= 300 && response_code <= 999)) {
|
337
|
+
rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
|
338
|
+
}
|
339
|
+
rbce->self = Qnil;
|
340
|
+
}
|
341
|
+
|
342
|
+
static void rb_curl_multi_read_info(VALUE self, CURLM *multi_handle) {
|
343
|
+
int msgs_left, result;
|
344
|
+
CURLMsg *msg;
|
345
|
+
CURL *easy_handle;
|
346
|
+
|
347
|
+
/* check for finished easy handles and remove from the multi handle */
|
348
|
+
while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
|
349
|
+
if (msg->msg == CURLMSG_DONE) {
|
350
|
+
easy_handle = msg->easy_handle;
|
351
|
+
result = msg->data.result;
|
352
|
+
if (easy_handle) {
|
353
|
+
rb_curl_mutli_handle_complete(self, easy_handle, result);
|
354
|
+
}
|
348
355
|
}
|
349
356
|
}
|
350
357
|
}
|
@@ -379,17 +386,19 @@ static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_runnin
|
|
379
386
|
*
|
380
387
|
* Run multi handles, looping selecting when data can be transfered
|
381
388
|
*/
|
382
|
-
VALUE ruby_curl_multi_perform(VALUE self) {
|
389
|
+
VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
383
390
|
CURLMcode mcode;
|
384
391
|
ruby_curl_multi *rbcm;
|
385
392
|
int maxfd, rc;
|
386
393
|
fd_set fdread, fdwrite, fdexcep;
|
387
394
|
|
388
|
-
long
|
395
|
+
long timeout_milliseconds;
|
389
396
|
struct timeval tv = {0, 0};
|
397
|
+
VALUE block = Qnil;
|
398
|
+
|
399
|
+
rb_scan_args(argc, argv, "0&", &block);
|
390
400
|
|
391
401
|
Data_Get_Struct(self, ruby_curl_multi, rbcm);
|
392
|
-
//rb_gc_mark(self);
|
393
402
|
|
394
403
|
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
395
404
|
|
@@ -406,37 +415,49 @@ VALUE ruby_curl_multi_perform(VALUE self) {
|
|
406
415
|
|
407
416
|
#ifdef HAVE_CURL_MULTI_TIMEOUT
|
408
417
|
/* get the curl suggested time out */
|
409
|
-
mcode = curl_multi_timeout(rbcm->handle, &
|
418
|
+
mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
|
410
419
|
if (mcode != CURLM_OK) {
|
411
420
|
raise_curl_multi_error_exception(mcode);
|
412
421
|
}
|
413
422
|
#else
|
414
423
|
/* libcurl doesn't have a timeout method defined... make a wild guess */
|
415
|
-
|
424
|
+
timeout_milliseconds = -1;
|
416
425
|
#endif
|
426
|
+
//printf("libcurl says wait: %ld ms or %ld s\n", timeout_milliseconds, timeout_milliseconds/1000);
|
417
427
|
|
418
|
-
if (
|
428
|
+
if (timeout_milliseconds == 0) { /* no delay */
|
419
429
|
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
420
430
|
continue;
|
421
431
|
}
|
422
|
-
else if
|
423
|
-
|
432
|
+
else if(timeout_milliseconds < 0) {
|
433
|
+
timeout_milliseconds = 500; /* wait half a second, libcurl doesn't know how long to wait */
|
424
434
|
}
|
425
|
-
|
426
|
-
if
|
427
|
-
|
435
|
+
#ifdef __APPLE_CC__
|
436
|
+
if(timeout_milliseconds > 1000) {
|
437
|
+
timeout_milliseconds = 1000; /* apple libcurl sometimes reports huge timeouts... let's cap it */
|
428
438
|
}
|
439
|
+
#endif
|
429
440
|
|
430
|
-
tv.tv_sec =
|
431
|
-
tv.tv_usec = (
|
441
|
+
tv.tv_sec = timeout_milliseconds / 1000; // convert milliseconds to seconds
|
442
|
+
tv.tv_usec = (timeout_milliseconds % 1000) * 1000; // get the remainder of milliseconds and convert to micro seconds
|
432
443
|
|
433
444
|
rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
|
434
|
-
|
445
|
+
switch(rc) {
|
446
|
+
case -1:
|
435
447
|
rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
|
448
|
+
break;
|
449
|
+
case 0:
|
450
|
+
if (block != Qnil) {
|
451
|
+
rb_funcall(block, rb_intern("call"), 1, self);
|
452
|
+
}
|
453
|
+
// if (rb_block_given_p()) {
|
454
|
+
// rb_yield(self);
|
455
|
+
// }
|
456
|
+
default:
|
457
|
+
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
458
|
+
break;
|
436
459
|
}
|
437
460
|
|
438
|
-
rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
|
439
|
-
|
440
461
|
}
|
441
462
|
|
442
463
|
return Qtrue;
|
@@ -461,5 +482,5 @@ void init_curb_multi() {
|
|
461
482
|
rb_define_method(cCurlMulti, "add", ruby_curl_multi_add, 1);
|
462
483
|
rb_define_method(cCurlMulti, "remove", ruby_curl_multi_remove, 1);
|
463
484
|
rb_define_method(cCurlMulti, "cancel!", ruby_curl_multi_cancel, 0);
|
464
|
-
rb_define_method(cCurlMulti, "perform", ruby_curl_multi_perform,
|
485
|
+
rb_define_method(cCurlMulti, "perform", ruby_curl_multi_perform, -1);
|
465
486
|
}
|
data/ext/curb_multi.h
CHANGED
@@ -21,7 +21,7 @@ typedef struct {
|
|
21
21
|
extern VALUE cCurlMulti;
|
22
22
|
void init_curb_multi();
|
23
23
|
VALUE ruby_curl_multi_new(VALUE klass);
|
24
|
-
VALUE ruby_curl_multi_perform(VALUE self);
|
24
|
+
VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self);
|
25
25
|
VALUE ruby_curl_multi_add(VALUE self, VALUE easy);
|
26
26
|
VALUE ruby_curl_multi_remove(VALUE self, VALUE easy);
|
27
27
|
|
data/ext/curb_postfield.c
CHANGED
data/ext/extconf.rb
CHANGED
@@ -5,6 +5,9 @@ dir_config('curl')
|
|
5
5
|
if find_executable('curl-config')
|
6
6
|
$CFLAGS << " #{`curl-config --cflags`.strip}"
|
7
7
|
$LIBS << " #{`curl-config --libs`.strip}"
|
8
|
+
ca_bundle_path=`curl-config --ca`.strip
|
9
|
+
$defs.push( %{-D HAVE_CURL_CONFIG_CA} )
|
10
|
+
$defs.push( %{-D CURL_CONFIG_CA='#{ca_bundle_path.inspect}'} )
|
8
11
|
elsif !have_library('curl') or !have_header('curl/curl.h')
|
9
12
|
fail <<-EOM
|
10
13
|
Can't find libcurl or curl/curl.h
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
2
|
require 'webrick'
|
3
3
|
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
4
4
|
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
@@ -23,7 +23,7 @@
|
|
23
23
|
# instance httppost. This bug is intermittent, but results in an
|
24
24
|
# exception from the first post when it occurs.
|
25
25
|
#
|
26
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
26
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
27
27
|
|
28
28
|
class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
|
29
29
|
def test_bug
|
data/tests/helper.rb
CHANGED
@@ -72,7 +72,15 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def do_POST(req,res)
|
75
|
-
|
75
|
+
if req.body
|
76
|
+
params = {}
|
77
|
+
req.body.split('&').map{|s| k,v=s.split('='); params[k] = v }
|
78
|
+
end
|
79
|
+
if params and params['s'] == '500'
|
80
|
+
res.status = 500
|
81
|
+
else
|
82
|
+
respond_with("POST\n#{req.body}",req,res)
|
83
|
+
end
|
76
84
|
end
|
77
85
|
|
78
86
|
def do_PUT(req,res)
|
@@ -21,8 +21,8 @@
|
|
21
21
|
# Aborted
|
22
22
|
# ------------------------------------------------------------------
|
23
23
|
#
|
24
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
|
25
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
24
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'ext')))
|
25
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
26
26
|
require 'curb'
|
27
27
|
require 'uri'
|
28
28
|
|
data/tests/tc_curl_download.rb
CHANGED
data/tests/tc_curl_easy.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
2
|
|
3
3
|
class TestCurbCurlEasy < Test::Unit::TestCase
|
4
4
|
def test_class_perform_01
|
@@ -68,6 +68,14 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
68
68
|
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
69
69
|
end
|
70
70
|
|
71
|
+
# test invalid use of new
|
72
|
+
def test_new_06
|
73
|
+
Curl::Easy.new(TestServlet.url) do|curl|
|
74
|
+
curl.http_post
|
75
|
+
assert_equal "POST\n", curl.body_str
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
71
79
|
def test_escape
|
72
80
|
c = Curl::Easy.new
|
73
81
|
|
@@ -499,6 +507,19 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
499
507
|
curl.http_post
|
500
508
|
assert_equal "POST\n", curl.body_str
|
501
509
|
end
|
510
|
+
|
511
|
+
def test_post_remote_is_easy_handle
|
512
|
+
# see: http://pastie.org/560852 and
|
513
|
+
# http://groups.google.com/group/curb---ruby-libcurl-bindings/browse_thread/thread/216bb2d9b037f347?hl=en
|
514
|
+
[:post, :get,:head,:delete].each do |method|
|
515
|
+
count = 0
|
516
|
+
curl = Curl::Easy.send("http_#{method}", TestServlet.url) do|c|
|
517
|
+
count += 1
|
518
|
+
assert_equal Curl::Easy, c.class
|
519
|
+
end
|
520
|
+
assert_equal 1, count, "For request method: #{method.to_s.upcase}"
|
521
|
+
end
|
522
|
+
end
|
502
523
|
|
503
524
|
def test_post_with_body_remote
|
504
525
|
curl = Curl::Easy.new(TestServlet.url)
|
@@ -555,6 +576,16 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
555
576
|
assert_match /^PUT/, curl.body_str
|
556
577
|
assert_match /message$/, curl.body_str
|
557
578
|
assert_match /application\/json/, curl.header_str
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_put_data
|
582
|
+
curl = Curl::Easy.new(TestServlet.url)
|
583
|
+
curl.put_data = 'message'
|
584
|
+
|
585
|
+
curl.perform
|
586
|
+
|
587
|
+
assert_match /^PUT/, curl.body_str
|
588
|
+
assert_match /message$/, curl.body_str
|
558
589
|
end
|
559
590
|
|
560
591
|
def test_put_remote_file
|
@@ -564,6 +595,16 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
564
595
|
end
|
565
596
|
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
|
566
597
|
end
|
598
|
+
|
599
|
+
def test_put_class_method
|
600
|
+
count = 0
|
601
|
+
curl = Curl::Easy.http_put(TestServlet.url,File.open(__FILE__,'rb')) do|c|
|
602
|
+
count += 1
|
603
|
+
assert_equal Curl::Easy, c.class
|
604
|
+
end
|
605
|
+
assert_equal 1, count
|
606
|
+
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
|
607
|
+
end
|
567
608
|
|
568
609
|
# Generate a self-signed cert with
|
569
610
|
# openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 \
|
data/tests/tc_curl_multi.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
2
|
|
3
3
|
class TestCurbCurlMulti < Test::Unit::TestCase
|
4
4
|
def teardown
|
@@ -54,6 +54,8 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
54
54
|
|
55
55
|
end
|
56
56
|
|
57
|
+
# NOTE: if this test runs slowly on Mac OSX, it is probably due to the use of a port install curl+ssl+ares install
|
58
|
+
# on my MacBook, this causes curl_easy_init to take nearly 0.01 seconds / * 100 below is 1 second too many!
|
57
59
|
def test_n_requests
|
58
60
|
n = 100
|
59
61
|
m = Curl::Multi.new
|
@@ -220,6 +222,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
220
222
|
m = nil
|
221
223
|
end
|
222
224
|
|
225
|
+
# This tests whether, ruby's GC will trash an out of scope easy handle
|
223
226
|
class TestForScope
|
224
227
|
attr_reader :buf
|
225
228
|
|
@@ -299,6 +302,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
299
302
|
Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
|
300
303
|
urls << root_uri + File.basename(path)
|
301
304
|
end
|
305
|
+
urls = urls[0..(urls.size/2)] # keep it fast, webrick...
|
302
306
|
Curl::Multi.get(urls, {:follow_location => true}, {:pipeline => true}) do|curl|
|
303
307
|
assert_equal 200, curl.response_code
|
304
308
|
end
|
@@ -321,6 +325,26 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
321
325
|
end
|
322
326
|
end
|
323
327
|
|
328
|
+
def test_mutli_recieves_500
|
329
|
+
m = Curl::Multi.new
|
330
|
+
e = Curl::Easy.new("http://127.0.0.1:9129/methods")
|
331
|
+
failure = false
|
332
|
+
e.post_body = "hello=world&s=500"
|
333
|
+
e.on_failure{|c,r| failure = true }
|
334
|
+
e.on_success{|c| failure = false }
|
335
|
+
m.add(e)
|
336
|
+
m.perform
|
337
|
+
assert failure
|
338
|
+
e2 = Curl::Easy.new(TestServlet.url)
|
339
|
+
e2.post_body = "hello=world"
|
340
|
+
e2.on_failure{|c,r| failure = true }
|
341
|
+
m.add(e2)
|
342
|
+
m.perform
|
343
|
+
failure = false
|
344
|
+
assert !failure
|
345
|
+
assert_equal "POST\nhello=world", e2.body_str
|
346
|
+
end
|
347
|
+
|
324
348
|
include TestServerMethods
|
325
349
|
|
326
350
|
def setup
|
data/tests/tc_curl_postfield.rb
CHANGED
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.
|
4
|
+
version: 0.5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ross Bamford
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-08-11 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|