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 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