curb 0.7.8 → 0.7.9

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