curb 0.7.8 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -156,3 +156,9 @@ documentation with:
156
156
  requests.each do|url|
157
157
  puts responses[url]
158
158
  end
159
+
160
+ ### Easy Callbacks
161
+
162
+ on_success: is called when the response code is 20x
163
+ on_failure: is called when the response code is not success, including redirects e.g. 30x
164
+ on_complete: is called in all cases.
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.7.8"
24
- #define CURB_VER_NUM 708
23
+ #define CURB_VERSION "0.7.9"
24
+ #define CURB_VER_NUM 790
25
25
  #define CURB_VER_MAJ 0
26
26
  #define CURB_VER_MIN 7
27
- #define CURB_VER_MIC 8
27
+ #define CURB_VER_MIC 9
28
28
  #define CURB_VER_PATCH 0
29
29
 
30
30
 
@@ -137,7 +137,7 @@ static int proc_debug_handler(CURL *curl,
137
137
 
138
138
  /* ================== MARK/FREE FUNC ==================*/
139
139
  void curl_easy_mark(ruby_curl_easy *rbce) {
140
- rb_gc_mark(rbce->opts);
140
+ if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
141
141
  if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
142
142
  }
143
143
 
@@ -181,6 +181,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
181
181
  rbce->connect_timeout = 0;
182
182
  rbce->dns_cache_timeout = 60;
183
183
  rbce->ftp_response_timeout = 0;
184
+ rbce->low_speed_limit = 0;
185
+ rbce->low_speed_time = 0;
184
186
  rbce->ssl_version = -1;
185
187
  rbce->use_ssl = -1;
186
188
  rbce->ftp_filemethod = -1;
@@ -197,6 +199,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
197
199
  rbce->verbose = 0;
198
200
  rbce->multipart_form_post = 0;
199
201
  rbce->enable_cookies = 0;
202
+ rbce->ignore_content_length = 0;
200
203
  }
201
204
 
202
205
  /*
@@ -225,14 +228,15 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
225
228
  rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
226
229
  }
227
230
 
231
+ new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
232
+
228
233
  rbce->multi = Qnil;
234
+ rbce->opts = Qnil;
229
235
 
230
236
  ruby_curl_easy_zero(rbce);
231
237
 
232
238
  rb_easy_set("url", url);
233
239
 
234
- new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
235
-
236
240
  /* set the new_curl pointer to the curl handle */
237
241
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)new_curl);
238
242
  if (ecode != CURLE_OK) {
@@ -331,6 +335,12 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
331
335
  raise_curl_easy_error_exception(ecode);
332
336
  }
333
337
 
338
+ /* Free everything up */
339
+ if (rbce->curl_headers) {
340
+ curl_slist_free_all(rbce->curl_headers);
341
+ rbce->curl_headers = NULL;
342
+ }
343
+
334
344
  return opts_dup;
335
345
  }
336
346
 
@@ -826,7 +836,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
826
836
  rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
827
837
  }
828
838
  size = rb_funcall(stat, rb_intern("size"), 0);
829
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2INT(size));
839
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
830
840
  }
831
841
  else if( rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
832
842
  rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
@@ -1002,7 +1012,8 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
1002
1012
 
1003
1013
  rb_scan_args(argc, argv, "*", &args_ary);
1004
1014
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1005
- len = RARRAY_LEN(args_ary);
1015
+
1016
+ len = (int)RARRAY_LEN(args_ary);
1006
1017
 
1007
1018
  if (len == 1 && (TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM || rb_ary_entry(args_ary,0) == Qnil)) {
1008
1019
  if (rb_ary_entry(args_ary,0) == Qnil) {
@@ -1188,6 +1199,51 @@ static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self, VALUE ftp_respo
1188
1199
  CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
1189
1200
  }
1190
1201
 
1202
+ /*
1203
+ * call-seq:
1204
+ * easy.low_speed_limit = fixnum or nil => fixnum or nil
1205
+ *
1206
+ * Set the transfer speed (in bytes per second) that the transfer should be
1207
+ * below during +low_speed_time+ seconds for the library to consider it too
1208
+ * slow and abort.
1209
+ */
1210
+ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limit) {
1211
+ CURB_IMMED_SETTER(ruby_curl_easy, low_speed_limit, 0);
1212
+ }
1213
+
1214
+ /*
1215
+ * call-seq:
1216
+ * easy.low_speed_limit => fixnum or nil
1217
+ *
1218
+ * Obtain the minimum transfer speed over +low_speed+time+ below which the
1219
+ * transfer will be aborted.
1220
+ */
1221
+ static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self, VALUE low_speed_limit) {
1222
+ CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
1223
+ }
1224
+
1225
+ /*
1226
+ * call-seq:
1227
+ * easy.low_speed_time = fixnum or nil => fixnum or nil
1228
+ *
1229
+ * Set the time (in seconds) that the transfer should be below the
1230
+ * +low_speed_limit+ for the library to consider it too slow and abort.
1231
+ */
1232
+ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time) {
1233
+ CURB_IMMED_SETTER(ruby_curl_easy, low_speed_time, 0);
1234
+ }
1235
+
1236
+ /*
1237
+ * call-seq:
1238
+ * easy.low_speed_time => fixnum or nil
1239
+ *
1240
+ * Obtain the time that the transfer should be below +low_speed_limit+ for
1241
+ * the library to abort it.
1242
+ */
1243
+ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time) {
1244
+ CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
1245
+ }
1246
+
1191
1247
  /*
1192
1248
  * call-seq:
1193
1249
  * easy.username = string => string
@@ -1425,8 +1481,8 @@ static VALUE ruby_curl_easy_header_in_body_set(VALUE self, VALUE header_in_body)
1425
1481
  * call-seq:
1426
1482
  * easy.header_in_body? => boolean
1427
1483
  *
1428
- * Determine whether this Curl instance will verify the SSL peer
1429
- * certificate.
1484
+ * Determine whether this Curl instance will return HTTP headers
1485
+ * combined with body data.
1430
1486
  */
1431
1487
  static VALUE ruby_curl_easy_header_in_body_q(VALUE self) {
1432
1488
  CURB_BOOLEAN_GETTER(ruby_curl_easy, header_in_body);
@@ -1592,6 +1648,31 @@ static VALUE ruby_curl_easy_enable_cookies_q(VALUE self) {
1592
1648
  CURB_BOOLEAN_GETTER(ruby_curl_easy, enable_cookies);
1593
1649
  }
1594
1650
 
1651
+ /*
1652
+ * call-seq:
1653
+ * easy.ignore_content_length = boolean
1654
+ *
1655
+ * Configure whether this Curl::Easy instance should ignore the content
1656
+ * length header.
1657
+ */
1658
+ static VALUE ruby_curl_easy_ignore_content_length_set(VALUE self, VALUE ignore_content_length)
1659
+ {
1660
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, ignore_content_length);
1661
+ }
1662
+
1663
+ /*
1664
+ * call-seq:
1665
+ * easy.ignore_content_length? => boolean
1666
+ *
1667
+ * Determine whether this Curl::Easy instance ignores the content
1668
+ * length header.
1669
+ */
1670
+ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
1671
+ CURB_BOOLEAN_GETTER(ruby_curl_easy, ignore_content_length);
1672
+ }
1673
+
1674
+
1675
+
1595
1676
  /* ================= EVENT PROCS ================== */
1596
1677
 
1597
1678
  /*
@@ -1895,6 +1976,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1895
1976
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
1896
1977
  curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
1897
1978
 
1979
+ curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
1980
+
1981
+
1898
1982
  #if LIBCURL_VERSION_NUM >= 0x070a08
1899
1983
  curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
1900
1984
  #else
@@ -1903,6 +1987,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1903
1987
  }
1904
1988
  #endif
1905
1989
 
1990
+ curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
1991
+ curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
1992
+
1906
1993
  // Set up localport / proxy port
1907
1994
  // FIXME these won't get returned to default if they're unset Ruby
1908
1995
  if (rbce->proxy_port > 0) {
@@ -2054,10 +2141,10 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2054
2141
  VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2055
2142
 
2056
2143
  CURL *curl = rbce->curl;
2057
- struct curl_slist *headers = rbce->curl_headers;
2058
- // Free everything up
2059
- if (headers) {
2060
- curl_slist_free_all(headers);
2144
+
2145
+ /* Free everything up */
2146
+ if (rbce->curl_headers) {
2147
+ curl_slist_free_all(rbce->curl_headers);
2061
2148
  rbce->curl_headers = NULL;
2062
2149
  }
2063
2150
 
@@ -2067,7 +2154,7 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2067
2154
  rbce->curl_ftp_commands = NULL;
2068
2155
  }
2069
2156
 
2070
- // clean up a PUT request's curl options.
2157
+ /* clean up a PUT request's curl options. */
2071
2158
  if (!rb_easy_nil("upload")) {
2072
2159
  rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
2073
2160
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
@@ -2132,7 +2219,7 @@ static VALUE ruby_curl_easy_perform_get(VALUE self) {
2132
2219
  /*
2133
2220
  * Common implementation of easy.http(verb) and easy.http_delete
2134
2221
  */
2135
- static VALUE ruby_curl_easy_perform_verb_str(VALUE self, char *verb) {
2222
+ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2136
2223
  ruby_curl_easy *rbce;
2137
2224
  CURL *curl;
2138
2225
  VALUE retval;
@@ -3042,9 +3129,9 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
3042
3129
  if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
3043
3130
 
3044
3131
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
3045
- result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str));
3132
+ result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str));
3046
3133
  #else
3047
- result = (char*)curl_escape(StringValuePtr(str), RSTRING_LEN(str));
3134
+ result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
3048
3135
  #endif
3049
3136
 
3050
3137
  rresult = rb_str_new2(result);
@@ -3070,7 +3157,7 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3070
3157
  Data_Get_Struct(self, ruby_curl_easy, rbce);
3071
3158
 
3072
3159
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
3073
- result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), RSTRING_LEN(str), &rlen);
3160
+ result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
3074
3161
  #else
3075
3162
  result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
3076
3163
  rlen = strlen(result);
@@ -3274,6 +3361,10 @@ void init_curb_easy() {
3274
3361
  rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
3275
3362
  rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
3276
3363
  rb_define_method(cCurlEasy, "ftp_response_timeout", ruby_curl_easy_ftp_response_timeout_get, 0);
3364
+ rb_define_method(cCurlEasy, "low_speed_limit=", ruby_curl_easy_low_speed_limit_set, 1);
3365
+ rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
3366
+ rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
3367
+ rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
3277
3368
  rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
3278
3369
  rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
3279
3370
  rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
@@ -3309,6 +3400,8 @@ void init_curb_easy() {
3309
3400
  rb_define_method(cCurlEasy, "multipart_form_post?", ruby_curl_easy_multipart_form_post_q, 0);
3310
3401
  rb_define_method(cCurlEasy, "enable_cookies=", ruby_curl_easy_enable_cookies_set, 1);
3311
3402
  rb_define_method(cCurlEasy, "enable_cookies?", ruby_curl_easy_enable_cookies_q, 0);
3403
+ rb_define_method(cCurlEasy, "ignore_content_length=", ruby_curl_easy_ignore_content_length_set, 1);
3404
+ rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
3312
3405
 
3313
3406
  rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
3314
3407
  rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
@@ -51,6 +51,8 @@ typedef struct {
51
51
  unsigned long connect_timeout;
52
52
  long dns_cache_timeout;
53
53
  unsigned long ftp_response_timeout;
54
+ long low_speed_limit;
55
+ long low_speed_time;
54
56
  long ssl_version;
55
57
  long use_ssl;
56
58
  long ftp_filemethod;
@@ -67,6 +69,7 @@ typedef struct {
67
69
  char verbose;
68
70
  char multipart_form_post;
69
71
  char enable_cookies;
72
+ char ignore_content_length;
70
73
  struct curl_slist *curl_headers;
71
74
  struct curl_slist *curl_ftp_commands;
72
75
 
@@ -456,7 +456,7 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
456
456
  }
457
457
 
458
458
  tv.tv_sec = 0; /* never wait longer than 1 second */
459
- tv.tv_usec = timeout_milliseconds * 1000;
459
+ tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */
460
460
 
461
461
  if (timeout_milliseconds == 0) { /* no delay */
462
462
  rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
@@ -109,7 +109,7 @@ void append_to_form(VALUE self,
109
109
  } else {
110
110
  // is a content field
111
111
  if (rbcpf->content_proc != Qnil) {
112
- rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, self);
112
+ rbcpf->buffer_str = rb_funcall(rbcpf->content_proc, idCall, 1, self);
113
113
 
114
114
  if (rbcpf->content_type == Qnil) {
115
115
  result = curl_formadd(first, last, CURLFORM_PTRNAME, StringValuePtr(rbcpf->name),
@@ -209,7 +209,7 @@ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
209
209
  */
210
210
  static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass) {
211
211
  ruby_curl_postfield *rbcpf = ALLOC(ruby_curl_postfield);
212
-
212
+
213
213
  // wierdness - we actually require two args, unless a block is provided, but
214
214
  // we have to work that out below.
215
215
  rb_scan_args(argc, argv, "12&", &rbcpf->name, &rbcpf->content, &rbcpf->content_type, &rbcpf->content_proc);
@@ -443,7 +443,7 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
443
443
  rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d, make sure your field name responds_to :to_s", __FILE__, __LINE__);
444
444
  }
445
445
 
446
- char *tmpchrs = curl_escape(StringValuePtr(name), RSTRING_LEN(name));
446
+ char *tmpchrs = curl_escape(StringValuePtr(name), (int)RSTRING_LEN(name));
447
447
 
448
448
  if (!tmpchrs) {
449
449
  rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name `%s'", tmpchrs);
@@ -472,7 +472,7 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
472
472
  }
473
473
  }
474
474
  //fprintf(stderr, "encoding content: %ld - %s\n", RSTRING_LEN(tmpcontent), RSTRING_PTR(tmpcontent) );
475
- tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), RSTRING_LEN(tmpcontent));
475
+ tmpchrs = curl_escape(RSTRING_PTR(tmpcontent), (int)RSTRING_LEN(tmpcontent));
476
476
  if (!tmpchrs) {
477
477
  rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content `%s'", tmpchrs);
478
478
  } else {
@@ -56,7 +56,7 @@ VALUE ruby_curl_upload_stream_get(VALUE self) {
56
56
  VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
57
57
  ruby_curl_upload *rbcu;
58
58
  Data_Get_Struct(self, ruby_curl_upload, rbcu);
59
- rbcu->offset = FIX2INT(offset);
59
+ rbcu->offset = FIX2LONG(offset);
60
60
  return offset;
61
61
  }
62
62
  /*
@@ -1,5 +1,4 @@
1
1
  require 'mkmf'
2
- puts $CFLAGS.inspect
3
2
 
4
3
  dir_config('curl')
5
4
 
@@ -26,16 +26,24 @@ module Curl
26
26
  def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
27
27
  curl = Curl::Easy.new(url, &blk)
28
28
 
29
- File.open(filename, "wb") do |output|
30
- old_on_body = curl.on_body do |data|
29
+ output = if filename.is_a? IO
30
+ filename.binmode if filename.respond_to?(:binmode)
31
+ filename
32
+ else
33
+ File.open(filename, 'wb')
34
+ end
35
+
36
+ begin
37
+ old_on_body = curl.on_body do |data|
31
38
  result = old_on_body ? old_on_body.call(data) : data.length
32
39
  output << data if result == data.length
33
40
  result
34
41
  end
35
-
36
42
  curl.perform
37
- end
38
-
43
+ ensure
44
+ output.close rescue IOError
45
+ end
46
+
39
47
  return curl
40
48
  end
41
49
  end
@@ -200,6 +208,7 @@ module Curl
200
208
  # when using the :post or :put method, urls should be a hash, including the individual post fields per post
201
209
  #
202
210
  def download(urls,easy_options={},multi_options={},download_paths=nil,&blk)
211
+ errors = []
203
212
  procs = []
204
213
  files = []
205
214
  urls_with_config = []
@@ -218,10 +227,11 @@ module Curl
218
227
  download_path = File.basename(url)
219
228
  end
220
229
 
221
- lambda do|dp|
230
+ file = lambda do|dp|
222
231
  file = File.open(dp,"wb")
223
232
  procs << (lambda {|data| file.write data; data.size })
224
233
  files << file
234
+ file
225
235
  end.call(download_path)
226
236
 
227
237
  if urlcfg.is_a?(Hash)
@@ -229,17 +239,27 @@ module Curl
229
239
  else
230
240
  urls_with_config << {:url => url, :on_body => procs.last, :method => :get}.merge(easy_options)
231
241
  end
232
- url_to_download_paths[url] = download_path # store for later
242
+ url_to_download_paths[url] = {:path => download_path, :file => file} # store for later
233
243
  end
234
244
 
235
245
  if blk
236
- Curl::Multi.http(urls_with_config, multi_options) {|c,code,method| blk.call(c,url_to_download_paths[c.url]) }
246
+ # when injecting the block, ensure file is closed before yielding
247
+ Curl::Multi.http(urls_with_config, multi_options) do |c,code,method|
248
+ info = url_to_download_paths[c.url]
249
+ begin
250
+ file = info[:file]
251
+ files.reject!{|f| f == file }
252
+ file.close
253
+ rescue => e
254
+ errors << e
255
+ end
256
+ blk.call(c,info[:path])
257
+ end
237
258
  else
238
259
  Curl::Multi.http(urls_with_config, multi_options)
239
260
  end
240
261
 
241
262
  ensure
242
- errors = []
243
263
  files.each {|f|
244
264
  begin
245
265
  f.close
@@ -178,5 +178,6 @@ module TestServerMethods
178
178
  at_exit{exit_code.call}
179
179
 
180
180
  end
181
+ rescue Errno::EADDRINUSE
181
182
  end
182
183
  end
@@ -7,7 +7,7 @@ class TestCurbCurlDownload < Test::Unit::TestCase
7
7
  server_setup
8
8
  end
9
9
 
10
- def test_download_url_to_file
10
+ def test_download_url_to_file_via_string
11
11
  dl_url = "http://127.0.0.1:9129/ext/curb_easy.c"
12
12
  dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
13
13
 
@@ -18,6 +18,49 @@ class TestCurbCurlDownload < Test::Unit::TestCase
18
18
  File.unlink(dl_path) if File.exist?(dl_path)
19
19
  end
20
20
 
21
+ def test_download_url_to_file_via_file_io
22
+ dl_url = "http://127.0.0.1:9129/ext/curb_easy.c"
23
+ dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
24
+ io = File.open(dl_path, 'wb')
25
+
26
+ curb = Curl::Easy.download(dl_url, io)
27
+ assert io.closed?
28
+ assert File.exist?(dl_path)
29
+ assert_equal File.read(File.join(File.dirname(__FILE__), '..','ext','curb_easy.c')), File.read(dl_path)
30
+ ensure
31
+ File.unlink(dl_path) if File.exist?(dl_path)
32
+ end
33
+
34
+ def test_download_url_to_file_via_io
35
+ dl_url = "http://127.0.0.1:9129/ext/curb_easy.c"
36
+ dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
37
+ reader, writer = IO.pipe
38
+
39
+ # Write to local file
40
+ fork do
41
+ begin
42
+ writer.close
43
+ File.open(dl_path, 'wb') { |file| file << reader.read }
44
+ ensure
45
+ reader.close rescue IOError # if the stream has already been closed
46
+ end
47
+ end
48
+
49
+ # Download remote source
50
+ begin
51
+ reader.close
52
+ curb = Curl::Easy.download(dl_url, writer)
53
+ Process.wait
54
+ ensure
55
+ writer.close rescue IOError # if the stream has already been closed, which occurs in Easy::download
56
+ end
57
+
58
+ assert File.exist?(dl_path)
59
+ assert_equal File.read(File.join(File.dirname(__FILE__), '..','ext','curb_easy.c')), File.read(dl_path)
60
+ ensure
61
+ File.unlink(dl_path) if File.exist?(dl_path)
62
+ end
63
+
21
64
  def test_download_bad_url_gives_404
22
65
  dl_url = "http://127.0.0.1:9129/this_file_does_not_exist.html"
23
66
  dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
@@ -354,6 +354,30 @@ class TestCurbCurlEasy < Test::Unit::TestCase
354
354
  assert_equal 30, c.dns_cache_timeout
355
355
  end
356
356
 
357
+ def test_low_speed_limit_01
358
+ c = Curl::Easy.new($TEST_URL)
359
+
360
+ assert_nil c.low_speed_limit
361
+
362
+ c.low_speed_limit = 3
363
+ assert_equal 3, c.low_speed_limit
364
+
365
+ c.low_speed_limit = nil
366
+ assert_nil c.low_speed_limit
367
+ end
368
+
369
+ def test_low_speed_time_01
370
+ c = Curl::Easy.new($TEST_URL)
371
+
372
+ assert_nil c.low_speed_time
373
+
374
+ c.low_speed_time = 3
375
+ assert_equal 3, c.low_speed_time
376
+
377
+ c.low_speed_time = nil
378
+ assert_nil c.low_speed_time
379
+ end
380
+
357
381
  def test_on_body
358
382
  blk = lambda { |i| i.length }
359
383
 
@@ -476,6 +500,13 @@ class TestCurbCurlEasy < Test::Unit::TestCase
476
500
  assert c.multipart_form_post?
477
501
  end
478
502
 
503
+ def test_ignore_content_length
504
+ c = Curl::Easy.new
505
+ assert !c.ignore_content_length?
506
+ assert c.ignore_content_length = true
507
+ assert c.ignore_content_length?
508
+ end
509
+
479
510
  def test_enable_cookies
480
511
  c = Curl::Easy.new
481
512
  assert !c.enable_cookies?
@@ -664,24 +695,26 @@ class TestCurbCurlEasy < Test::Unit::TestCase
664
695
  def test_cert
665
696
  curl = Curl::Easy.new(TestServlet.url)
666
697
  curl.cert= File.join(File.dirname(__FILE__),"cert.pem")
667
- assert /cert.pem$/,curl.cert
698
+ assert_match /cert.pem$/,curl.cert
668
699
  end
669
700
 
670
701
  def test_cert_with_password
671
702
  curl = Curl::Easy.new(TestServlet.url)
672
703
  curl.cert= File.join(File.dirname(__FILE__),"cert.pem:password")
673
- assert /cert.pem$/,curl.cert
704
+ assert_match /cert.pem$/,curl.cert
674
705
  end
675
706
 
676
707
  def test_cert_type
677
708
  curl = Curl::Easy.new(TestServlet.url)
678
709
  curl.certtype= "DER"
679
- assert "DER", curl.certtype
710
+ assert_equal "DER", curl.certtype
680
711
  end
681
712
 
682
713
  def test_default_certtype
683
714
  curl = Curl::Easy.new(TestServlet.url)
684
- assert "PEM", curl.certtype
715
+ assert_nil curl.certtype
716
+ curl.certtype = "PEM"
717
+ assert_equal "PEM", curl.certtype
685
718
  end
686
719
 
687
720
  # Generate a CA cert with instructions at
@@ -689,13 +722,13 @@ class TestCurbCurlEasy < Test::Unit::TestCase
689
722
  def test_ca_cert
690
723
  curl = Curl::Easy.new(TestServlet.url)
691
724
  curl.cacert= File.join(File.dirname(__FILE__),"cacert.pem")
692
- assert /cacert.pem$/, curl.cacert
725
+ assert_match /cacert.pem$/, curl.cacert
693
726
  end
694
727
 
695
728
  def test_user_agent
696
729
  curl = Curl::Easy.new(TestServlet.url)
697
730
  curl.useragent= "Curb-Easy/Ruby"
698
- assert /ScrubDog$/,curl.useragent
731
+ assert_equal "Curb-Easy/Ruby",curl.useragent
699
732
  end
700
733
 
701
734
  def test_username_password
@@ -315,15 +315,20 @@ class TestCurbCurlMulti < Test::Unit::TestCase
315
315
  downloads = []
316
316
  file_info = {}
317
317
  FileUtils.mkdir("tmp/")
318
+
319
+ # for each file store the size by file name
318
320
  Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
319
321
  urls << (root_uri + File.basename(path))
320
322
  downloads << "tmp/" + File.basename(path)
321
- file_info[File.basename(path)] = {:size => File.size(path)}
323
+ file_info[File.basename(path)] = {:size => File.size(path), :path => path}
322
324
  end
325
+
326
+ # start downloads
323
327
  Curl::Multi.download(urls,{},{},downloads) do|curl,download_path|
324
328
  assert_equal 200, curl.response_code
325
329
  assert File.exist?(download_path)
326
- assert file_info[File.basename(download_path)][:size], File.size(download_path)
330
+ store = file_info[File.basename(download_path)]
331
+ assert_equal file_info[File.basename(download_path)][:size], File.size(download_path), "incomplete download: #{download_path}"
327
332
  end
328
333
  ensure
329
334
  FileUtils.rm_rf("tmp/")
@@ -0,0 +1,100 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ # Run server with: ruby -rubygems timeout_server.rb -p 9128
4
+
5
+ # Note that curl requires all timeouts to be integers -
6
+ # curl_easy_setopt does not have a provision for floating-point values
7
+
8
+ class TestCurbTimeouts < Test::Unit::TestCase
9
+ def test_no_timeout_by_default
10
+ curl = Curl::Easy.new(wait_url(2))
11
+ start = Time.now
12
+ assert_equal true, curl.http_get
13
+ elapsed = Time.now - start
14
+ assert elapsed > 2
15
+ end
16
+
17
+ def test_overall_timeout_on_dead_transfer
18
+ curl = Curl::Easy.new(wait_url(2))
19
+ curl.timeout = 1
20
+ assert_raise(Curl::Err::TimeoutError) do
21
+ curl.http_get
22
+ end
23
+ end
24
+
25
+ def test_clearing_timeout
26
+ curl = Curl::Easy.new(wait_url(2))
27
+ curl.timeout = 1
28
+ curl.timeout = nil
29
+ start = Time.now
30
+ assert_equal true, curl.http_get
31
+ elapsed = Time.now - start
32
+ assert elapsed > 2
33
+ end
34
+
35
+ def test_overall_timeout_on_slow_transfer
36
+ curl = Curl::Easy.new(serve_url(100, 2, 3))
37
+ curl.timeout = 1
38
+ # transfer is aborted despite data being exchanged
39
+ assert_raise(Curl::Err::TimeoutError) do
40
+ curl.http_get
41
+ end
42
+ end
43
+
44
+ def test_low_speed_time_on_slow_transfer
45
+ curl = Curl::Easy.new(serve_url(100, 1, 3))
46
+ curl.low_speed_time = 2
47
+ # use default low_speed_limit of 1
48
+ assert true, curl.http_get
49
+ end
50
+
51
+ def test_low_speed_time_on_very_slow_transfer
52
+ # send data slower than required
53
+ curl = Curl::Easy.new(serve_url(10, 2, 3))
54
+ curl.low_speed_time = 1
55
+ # XXX for some reason this test fails if low speed limit is not specified
56
+ curl.low_speed_limit = 1
57
+ # use default low_speed_limit of 1
58
+ assert_raise(Curl::Err::TimeoutError) do
59
+ curl.http_get
60
+ end
61
+ end
62
+
63
+ def test_low_speed_limit_on_slow_transfer
64
+ curl = Curl::Easy.new(serve_url(10, 1, 3))
65
+ curl.low_speed_time = 2
66
+ curl.low_speed_limit = 1000
67
+ assert_raise(Curl::Err::TimeoutError) do
68
+ curl.http_get
69
+ end
70
+ end
71
+
72
+ def test_clearing_low_speed_time
73
+ curl = Curl::Easy.new(serve_url(100, 2, 3))
74
+ curl.low_speed_time = 1
75
+ curl.low_speed_time = nil
76
+ assert_equal true, curl.http_get
77
+ end
78
+
79
+ def test_clearing_low_speed_limit
80
+ curl = Curl::Easy.new(serve_url(10, 1, 3))
81
+ curl.low_speed_time = 2
82
+ curl.low_speed_limit = 1000
83
+ curl.low_speed_limit = nil
84
+ assert_equal true, curl.http_get
85
+ end
86
+
87
+ private
88
+
89
+ def wait_url(time)
90
+ "#{server_base}/wait/#{time}"
91
+ end
92
+
93
+ def serve_url(chunk_size, time, count)
94
+ "#{server_base}/serve/#{chunk_size}/every/#{time}/for/#{count}"
95
+ end
96
+
97
+ def server_base
98
+ 'http://127.0.0.1:9128'
99
+ end
100
+ end
@@ -0,0 +1,33 @@
1
+ # This Sinatra application must be run with mongrel
2
+ # or possibly with unicorn for the serve action to work properly.
3
+ # See http://efreedom.com/Question/1-3669674/Streaming-Data-Sinatra-Rack-Application
4
+
5
+ require 'sinatra'
6
+
7
+ get '/wait/:time' do |time|
8
+ time = time.to_i
9
+ sleep(time)
10
+ "Slept #{time} at #{Time.now}"
11
+ end
12
+
13
+ # http://efreedom.com/Question/1-3027435/Way-Flush-Html-Wire-Sinatra
14
+ class Streamer
15
+ def initialize(time, chunks)
16
+ @time = time
17
+ @chunks = chunks
18
+ end
19
+
20
+ def each
21
+ @chunks.each do |chunk|
22
+ sleep(@time)
23
+ yield chunk
24
+ end
25
+ end
26
+ end
27
+
28
+ get '/serve/:chunk_size/every/:time/for/:count' do |chunk_size, time, count|
29
+ chunk_size, time, count = chunk_size.to_i, time.to_i, count.to_i
30
+ chunk = 'x' * chunk_size
31
+ chunks = [chunk] * count
32
+ Streamer.new(time, chunks)
33
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curb
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 8
10
- version: 0.7.8
9
+ - 9
10
+ version: 0.7.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ross Bamford
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-08-17 00:00:00 -04:00
19
+ date: 2010-12-22 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies: []
22
22
 
@@ -66,6 +66,8 @@ files:
66
66
  - tests/tc_curl_easy.rb
67
67
  - tests/tc_curl_multi.rb
68
68
  - tests/tc_curl_postfield.rb
69
+ - tests/timeout.rb
70
+ - tests/timeout_server.rb
69
71
  - tests/unittests.rb
70
72
  has_rdoc: true
71
73
  homepage: http://curb.rubyforge.org/
@@ -120,4 +122,6 @@ test_files:
120
122
  - tests/tc_curl_easy.rb
121
123
  - tests/tc_curl_multi.rb
122
124
  - tests/tc_curl_postfield.rb
125
+ - tests/timeout.rb
126
+ - tests/timeout_server.rb
123
127
  - tests/unittests.rb