ghazel-curb 0.7.9.1 → 0.7.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -45,14 +45,19 @@ documentation with:
45
45
 
46
46
  $ rake doc
47
47
 
48
- ## Examples
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
- ### Same thing, more manual:
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
- ### Same thing, more manual:
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
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "curb.h"
9
+ #include "curb_upload.h"
9
10
 
10
11
  VALUE mCurl;
11
12
 
@@ -370,4 +371,5 @@ void Init_curb_core() {
370
371
  init_curb_easy();
371
372
  init_curb_postfield();
372
373
  init_curb_multi();
374
+ init_curb_upload();
373
375
  }
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.9"
24
- #define CURB_VER_NUM 790
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 9
28
- #define CURB_VER_PATCH 0
27
+ #define CURB_VER_MIC 1
28
+ #define CURB_VER_PATCH 5
29
29
 
30
30
 
31
31
  // Maybe not yet defined in Ruby
@@ -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, struct curl_slist **list) {
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, struct curl_slist **list) {
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 (!rb_easy_nil("proxy_url")) {
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 (!rb_easy_nil("proxypwd")) {
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
- rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, (VALUE)hdrs);
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
- rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, (VALUE)cmds);
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) {
@@ -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
- rb_hash_foreach( rbcm->requests, (int (*)())rb_curl_multi_mark_all_easy, (VALUE)rbcm );
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; /* buggy versions libcurl sometimes reports huge timeouts... let's cap it */
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, &crt_fdrwrite);
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, &crt_fdrwrite);
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
- rb_curl_multi_read_info( self, rbcm->handle );
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
  }
@@ -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
- urls_with_config.each do|conf|
156
- c = conf.dup # avoid being destructive to input
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(url)
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| blk.call(curl,code,method) } if blk
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
- m.perform
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:
@@ -1,2 +1 @@
1
1
  require 'curb'
2
-
@@ -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\ndocument%5Fid=5", curl.body_str
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: 81
4
+ hash: 73
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 9
9
+ - 15
10
10
  - 1
11
- version: 0.7.9.1
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: 2010-12-22 00:00:00 -08:00
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.4.2
105
+ rubygems_version: 1.5.2
106
106
  signing_key:
107
107
  specification_version: 3
108
108
  summary: Ruby libcurl bindings