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 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.4.8.0"
24
- #define CURB_VER_NUM 480
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 4
27
- #define CURB_VER_MIC 8
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
@@ -1,5 +1,7 @@
1
1
  #ifndef CURB_CONFIG_H
2
2
  #define CURB_CONFIG_H
3
+ #define HAVE_CURL_CONFIG_CA 1
4
+ #define CURL_CONFIG_CA ""
3
5
  #define HAVE_CURLINFO_REDIRECT_TIME 1
4
6
  #define HAVE_CURLINFO_RESPONSE_CODE 1
5
7
  #define HAVE_CURLINFO_FILETIME 1
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
- // XXX: This should really be using the output of 'curl-config --ca'
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 = ruby_curl_multi_perform(multi);
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 = curl_easy_duphandle(rbce->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
- return handle_perform(self,rbce);
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
- rbce->upload = upload; /* keep the upload object alive as long as
1925
- the easy handle is active or until the upload
1926
- is complete or terminated... */
1927
-
1928
- curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
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
- return ret;
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 rb_curl_multi_read_info(VALUE self, CURLM *multi_handle) {
300
- int msgs_left, result;
301
- CURLMsg *msg;
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
- /* check for finished easy handles and remove from the multi handle */
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
- if (msg->msg != CURLMSG_DONE) {
310
- continue;
311
- }
311
+ if (ecode != 0) {
312
+ raise_curl_easy_error_exception(ecode);
313
+ }
312
314
 
313
- easy_handle = msg->easy_handle;
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
- if (rbce->complete_proc != Qnil) {
324
- rb_funcall( rbce->complete_proc, idCall, 1, rbce->self );
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
- long response_code = -1;
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
- if (result != 0) {
331
- if (rbce->failure_proc != Qnil) {
332
- rb_funcall( rbce->failure_proc, idCall, 2, rbce->self, rb_curl_easy_error(result) );
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
- else {
347
- //printf( "missing easy handle\n" );
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 timeout;
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, &timeout);
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
- timeout = 1; /* wait a second */
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 (timeout == 0) { /* no delay */
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 (timeout == -1) {
423
- timeout = 1; /* wait a second */
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 (rb_block_given_p()) {
427
- rb_yield(self);
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 = timeout / 1000;
431
- tv.tv_usec = (timeout * 1000) % 1000000;
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
- if (rc < 0) {
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, 0);
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
@@ -143,7 +143,7 @@ void append_to_form(VALUE self,
143
143
  }
144
144
 
145
145
  if (result != 0) {
146
- char *reason;
146
+ const char *reason = NULL;
147
147
 
148
148
  switch (result) {
149
149
  case CURL_FORMADD_MEMORY:
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
- respond_with("POST\n#{req.body}",req,res)
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
 
@@ -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 TestCurbCurlDownload < Test::Unit::TestCase
4
4
  include TestServerMethods
@@ -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 \
@@ -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
@@ -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 TestCurbCurlPostfield < Test::Unit::TestCase
4
4
  def test_private_new
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.8.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-07-21 00:00:00 -04:00
13
+ date: 2009-08-11 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies: []
16
16