curb 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64402c665924d5c24d6fa01dff9dd9f41d522ef1ca6e663d2038a204bd0290b4
4
- data.tar.gz: 645f0b0f29804b105b9a4caaa1b2132d9d18b5dd4d678072e7e41a1d8d73771a
3
+ metadata.gz: dce5f49b09bacccf705e3d25ba29031dd4fc82c2721860eef02bb4a8af2dd0e2
4
+ data.tar.gz: 9456ed69688f2236bdd17f338e26faaf46b91f0fd4e51b3a48d5551ff8fdc433
5
5
  SHA512:
6
- metadata.gz: f86cb2a29633a86820862e35a5a1113c859e55636a50e779ab4235ccc54fb3b38a894edb8fcc090522ceb509ac0c2da329f708a9c109a2f871ce9c718984729c
7
- data.tar.gz: a2d20ac0b5aee80de2aa37f4c49b923c5e6b19c2b0dd82d4466d14b21f0988644baa893bd23950380efec0ab028c9f1fd9c1dfc6d2ab7c97246c86bb2aad5cf2
6
+ metadata.gz: df6ab81576ef567878331724c1600c59ff923be34d3a71bd31d07e4999880743e73c31a502bab8aaece54099fd5142bf954dbf004fffd38f0e6698750e3f9682
7
+ data.tar.gz: 5b7b867979da88d328e9f71a4a6eb7183430de26902311cb8678b443a6c53cf50aa62952f277bc2c2821bafc2af48c0e28067f7dce512ff7c2912b195bc27ad5
data/README.markdown CHANGED
@@ -7,7 +7,7 @@ Curb (probably CUrl-RuBy or something) provides Ruby-language bindings for the
7
7
  libcurl(3), a fully-featured client-side URL transfer library.
8
8
  cURL and libcurl live at [http://curl.haxx.se/](http://curl.haxx.se/) .
9
9
 
10
- Curb is a work-in-progress, and currently only supports libcurl's 'easy' and 'multi' modes.
10
+ Curb is a work-in-progress, and currently only supports libcurl's `easy` and `multi` modes.
11
11
 
12
12
  ## License
13
13
 
@@ -16,10 +16,26 @@ Ruby license. See the LICENSE file for the gory details.
16
16
 
17
17
  ## You will need
18
18
 
19
- * A working Ruby installation (2.1+)
20
- * A working (lib)curl installation, with development stuff (7.5+, tested with 7.19.x)
19
+ * A working Ruby installation (`1.8.7+` will work but `2.1+` preferred)
20
+ * A working libcurl development installation
21
+ (Ideally one of the versions listed in the compatibility chart below that maps to your `curb` version)
21
22
  * A sane build environment (e.g. gcc, make)
22
23
 
24
+ ## Version Compatibility chart
25
+
26
+ A **non-exhaustive** set of compatibility versions of the libcurl library
27
+ with this gem are as follows. (Note that these are only the ones that have been
28
+ tested and reported to work across a variety of platforms / rubies)
29
+
30
+ | Gem Version | Release Date | libcurl versions |
31
+ | ----------- | ----------- | ---------------- |
32
+ | 0.9.8 | Jan 2019 | 7.58 - 7.63 |
33
+ | 0.9.7 | Nov 2018 | 7.56 - 7.60 |
34
+ | 0.9.6 | May 2018 | 7.51 - 7.59 |
35
+ | 0.9.5 | May 2018 | 7.51 - 7.59 |
36
+ | 0.9.4 | Aug 2017 | 7.41 - 7.58 |
37
+ | 0.9.3 | Apr 2016 | 7.26 - 7.58 |
38
+
23
39
  ## Installation...
24
40
 
25
41
  ... will usually be as simple as:
@@ -31,6 +47,10 @@ the [development version of libcurl](http://curl.haxx.se/gknw.net/7.39.0/dist-w3
31
47
  line (alter paths to your curl location, but remember to use forward slashes):
32
48
 
33
49
  gem install curb --platform=ruby -- --with-curl-lib=C:/curl-7.39.0-devel-mingw32/lib --with-curl-include=C:/curl-7.39.0-devel-mingw32/include
50
+
51
+ Note that with Windows moving from one method of compiling to another as of Ruby `2.4` (DevKit -> MYSYS2),
52
+ the usage of Ruby `2.4+` with this gem on windows is unlikely to work. It is advised to use the
53
+ latest version of Ruby 2.3 available [HERE](https://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-2.3.3.exe)
34
54
 
35
55
  Or, if you downloaded the archive:
36
56
 
@@ -47,6 +67,12 @@ expand on the above instructions, please report the issue at http://github.com/t
47
67
 
48
68
  On Ubuntu, the dependencies can be satisfied by installing the following packages:
49
69
 
70
+ 18.04 and onwards
71
+
72
+ $ sudo apt-get install libcurl4 libcurl3-gnutls libcurl4-openssl-dev
73
+
74
+ < 18.04
75
+
50
76
  $ sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev
51
77
 
52
78
  On RedHat:
data/Rakefile CHANGED
@@ -57,22 +57,20 @@ MAKEOPTS = ENV['MAKE_OPTS'] || ''
57
57
  CURB_SO = "ext/curb_core.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
58
58
 
59
59
  file 'ext/Makefile' => 'ext/extconf.rb' do
60
- Dir.chdir('ext') do
61
- shell('ruby', 'extconf.rb', ENV['EXTCONF_OPTS'].to_s, live_stdout: STDOUT)
62
- end
60
+ shell(['ruby', 'extconf.rb', ENV['EXTCONF_OPTS'].to_s],
61
+ { :live_stdout => STDOUT , :cwd => "#{Dir.pwd}/ext" }
62
+ ).error!
63
63
  end
64
64
 
65
65
  def make(target = '')
66
- Dir.chdir('ext') do
67
- pid = system("#{MAKECMD} #{MAKEOPTS} #{target}")
68
- $?.exitstatus
69
- end
66
+ shell(["#{MAKECMD}", "#{MAKEOPTS}", "#{target}"].reject(&:empty?),
67
+ { :live_stdout => STDOUT, :cwd => "#{Dir.pwd}/ext" }
68
+ ).error!
70
69
  end
71
70
 
72
71
  # Let make handle dependencies between c/o/so - we'll just run it.
73
72
  file CURB_SO => (['ext/Makefile'] + Dir['ext/*.c'] + Dir['ext/*.h']) do
74
- m = make
75
- fail "Make failed (status #{m})" unless m == 0
73
+ make
76
74
  end
77
75
 
78
76
  desc "Compile the shared object"
@@ -80,8 +78,7 @@ task :compile => [CURB_SO]
80
78
 
81
79
  desc "Install to your site_ruby directory"
82
80
  task :install do
83
- m = make 'install'
84
- fail "Make install failed (status #{m})" unless m == 0
81
+ make 'install'
85
82
  end
86
83
 
87
84
  # Test Tasks ---------------------------------------------------------
@@ -186,7 +183,7 @@ else
186
183
  spec_source = File.read File.join(File.dirname(__FILE__),'curb.gemspec')
187
184
  spec = nil
188
185
  # see: http://gist.github.com/16215
189
- Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
186
+ Thread.new { spec = eval("#{spec_source}") }.join
190
187
  spec.validate
191
188
  Gem::Package.build(spec)
192
189
  end
data/ext/banned.h ADDED
@@ -0,0 +1,32 @@
1
+ #ifndef BANNED_H
2
+ #define BANNED_H
3
+
4
+ /*
5
+ * This header lists functions that have been banned from our code base,
6
+ * because they're too easy to misuse (and even if used correctly,
7
+ * complicate audits). Including this header turns them into compile-time
8
+ * errors.
9
+ */
10
+
11
+ #define BANNED(func) sorry_##func##_is_a_banned_function
12
+
13
+ #undef strcpy
14
+ #define strcpy(x,y) BANNED(strcpy)
15
+ #undef strcat
16
+ #define strcat(x,y) BANNED(strcat)
17
+ #undef strncpy
18
+ #define strncpy(x,y,n) BANNED(strncpy)
19
+ #undef strncat
20
+ #define strncat(x,y,n) BANNED(strncat)
21
+
22
+ #undef sprintf
23
+ #undef vsprintf
24
+ #ifdef HAVE_VARIADIC_MACROS
25
+ #define sprintf(...) BANNED(sprintf)
26
+ #define vsprintf(...) BANNED(vsprintf)
27
+ #else
28
+ #define sprintf(buf,fmt,arg) BANNED(sprintf)
29
+ #define vsprintf(buf,fmt,arg) BANNED(sprintf)
30
+ #endif
31
+
32
+ #endif /* BANNED_H */
data/ext/curb.c CHANGED
@@ -292,18 +292,26 @@ void Init_curb_core() {
292
292
  #endif
293
293
 
294
294
  #ifdef CURL_VERSION_SSL
295
- rb_define_const(mCurl, "CURL_SSLVERSION_DEFAULT", LONG2NUM(CURL_SSLVERSION_DEFAULT));
295
+ rb_define_const(mCurl, "CURL_SSLVERSION_DEFAULT", LONG2NUM(CURL_SSLVERSION_DEFAULT));
296
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_DEFAULT", LONG2NUM(CURL_SSLVERSION_MAX_DEFAULT));
296
297
  rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1", LONG2NUM(CURL_SSLVERSION_TLSv1));
297
298
  rb_define_const(mCurl, "CURL_SSLVERSION_SSLv2", LONG2NUM(CURL_SSLVERSION_SSLv2));
298
299
  rb_define_const(mCurl, "CURL_SSLVERSION_SSLv3", LONG2NUM(CURL_SSLVERSION_SSLv3));
299
300
  #if HAVE_CURL_SSLVERSION_TLSV1_0
300
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_0", LONG2NUM(CURL_SSLVERSION_TLSv1_0));
301
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_0", LONG2NUM(CURL_SSLVERSION_TLSv1_0));
302
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_0", LONG2NUM(CURL_SSLVERSION_MAX_TLSv1_0));
301
303
  #endif
302
304
  #if HAVE_CURL_SSLVERSION_TLSV1_1
303
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_1", LONG2NUM(CURL_SSLVERSION_TLSv1_1));
305
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_1", LONG2NUM(CURL_SSLVERSION_TLSv1_1));
306
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_1", LONG2NUM(CURL_SSLVERSION_MAX_TLSv1_1));
304
307
  #endif
305
308
  #if HAVE_CURL_SSLVERSION_TLSV1_2
306
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_2", LONG2NUM(CURL_SSLVERSION_TLSv1_2));
309
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_2", LONG2NUM(CURL_SSLVERSION_TLSv1_2));
310
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_2", LONG2NUM(CURL_SSLVERSION_MAX_TLSv1_2));
311
+ #endif
312
+ #if HAVE_CURL_SSLVERSION_TLSV1_3
313
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_3", LONG2NUM(CURL_SSLVERSION_TLSv1_3));
314
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_3", LONG2NUM(CURL_SSLVERSION_MAX_TLSv1_3));
307
315
  #endif
308
316
 
309
317
  rb_define_const(mCurl, "CURL_USESSL_CONTROL", LONG2NUM(CURB_FTPSSL_CONTROL));
@@ -316,13 +324,20 @@ void Init_curb_core() {
316
324
  rb_define_const(mCurl, "CURL_SSLVERSION_SSLv2", LONG2NUM(-1));
317
325
  rb_define_const(mCurl, "CURL_SSLVERSION_SSLv3", LONG2NUM(-1));
318
326
  #if HAVE_CURL_SSLVERSION_TLSv1_0
319
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_0", LONG2NUM(-1));
327
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_0", LONG2NUM(-1));
328
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_0", LONG2NUM(-1));
320
329
  #endif
321
330
  #if HAVE_CURL_SSLVERSION_TLSv1_1
322
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_1", LONG2NUM(-1));
331
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_1", LONG2NUM(-1));
332
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_1", LONG2NUM(-1));
323
333
  #endif
324
334
  #if HAVE_CURL_SSLVERSION_TLSv1_2
325
- rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_2", LONG2NUM(-1));
335
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_2", LONG2NUM(-1));
336
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_2", LONG2NUM(-1));
337
+ #endif
338
+ #if HAVE_CURL_SSLVERSION_TLSv1_3
339
+ rb_define_const(mCurl, "CURL_SSLVERSION_TLSv1_3", LONG2NUM(-1));
340
+ rb_define_const(mCurl, "CURL_SSLVERSION_MAX_TLSv1_3", LONG2NUM(-1));
326
341
  #endif
327
342
 
328
343
  rb_define_const(mCurl, "CURL_USESSL_CONTROL", LONG2NUM(-1));
@@ -925,12 +940,19 @@ void Init_curb_core() {
925
940
  #endif
926
941
  #if HAVE_CURL_SSLVERSION_TLSv1_0
927
942
  CURB_DEFINE(CURL_SSLVERSION_TLSv1_0);
943
+ CURB_DEFINE(CURL_SSLVERSION_MAX_TLSv1_0);
928
944
  #endif
929
945
  #if HAVE_CURL_SSLVERSION_TLSv1_1
930
946
  CURB_DEFINE(CURL_SSLVERSION_TLSv1_1);
947
+ CURB_DEFINE(CURL_SSLVERSION_MAX_TLSv1_1);
931
948
  #endif
932
949
  #if HAVE_CURL_SSLVERSION_TLSv1_2
933
950
  CURB_DEFINE(CURL_SSLVERSION_TLSv1_2);
951
+ CURB_DEFINE(CURL_SSLVERSION_MAX_TLSv1_2);
952
+ #endif
953
+ #if HAVE_CURL_SSLVERSION_TLSv1_3
954
+ CURB_DEFINE(CURL_SSLVERSION_TLSv1_3);
955
+ CURB_DEFINE(CURL_SSLVERSION_MAX_TLSv1_3);
934
956
  #endif
935
957
  #if HAVE_CURLOPT_SSL_VERIFYPEER
936
958
  CURB_DEFINE(CURLOPT_SSL_VERIFYPEER);
@@ -1040,6 +1062,132 @@ void Init_curb_core() {
1040
1062
  CURB_DEFINE(CURLOPT_PIPEWAIT);
1041
1063
  #endif
1042
1064
 
1065
+ #if HAVE_CURLOPT_TCP_KEEPALIVE
1066
+ CURB_DEFINE(CURLOPT_TCP_KEEPALIVE);
1067
+ CURB_DEFINE(CURLOPT_TCP_KEEPIDLE);
1068
+ CURB_DEFINE(CURLOPT_TCP_KEEPINTVL);
1069
+ #endif
1070
+
1071
+ #if HAVE_CURLOPT_HAPROXYPROTOCOL
1072
+ CURB_DEFINE(CURLOPT_HAPROXYPROTOCOL);
1073
+ #endif
1074
+
1075
+ #if HAVE_CURLPROTO_RTMPTE
1076
+ CURB_DEFINE(CURLPROTO_RTMPTE);
1077
+ #endif
1078
+
1079
+ #if HAVE_CURLPROTO_RTMPTS
1080
+ CURB_DEFINE(CURLPROTO_RTMPTS);
1081
+ #endif
1082
+
1083
+ #if HAVE_CURLPROTO_SMBS
1084
+ CURB_DEFINE(CURLPROTO_SMBS);
1085
+ #endif
1086
+
1087
+ #if HAVE_CURLPROTO_LDAP
1088
+ CURB_DEFINE(CURLPROTO_LDAP);
1089
+ #endif
1090
+
1091
+ #if HAVE_CURLPROTO_FTP
1092
+ CURB_DEFINE(CURLPROTO_FTP);
1093
+ #endif
1094
+
1095
+ #if HAVE_CURLPROTO_SMTPS
1096
+ CURB_DEFINE(CURLPROTO_SMTPS);
1097
+ #endif
1098
+
1099
+ #if HAVE_CURLPROTO_HTTP
1100
+ CURB_DEFINE(CURLPROTO_HTTP);
1101
+ #endif
1102
+
1103
+ #if HAVE_CURLPROTO_SMTP
1104
+ CURB_DEFINE(CURLPROTO_SMTP);
1105
+ #endif
1106
+
1107
+ #if HAVE_CURLPROTO_TFTP
1108
+ CURB_DEFINE(CURLPROTO_TFTP);
1109
+ #endif
1110
+
1111
+ #if HAVE_CURLPROTO_LDAPS
1112
+ CURB_DEFINE(CURLPROTO_LDAPS);
1113
+ #endif
1114
+
1115
+ #if HAVE_CURLPROTO_IMAPS
1116
+ CURB_DEFINE(CURLPROTO_IMAPS);
1117
+ #endif
1118
+
1119
+ #if HAVE_CURLPROTO_SCP
1120
+ CURB_DEFINE(CURLPROTO_SCP);
1121
+ #endif
1122
+
1123
+ #if HAVE_CURLPROTO_SFTP
1124
+ CURB_DEFINE(CURLPROTO_SFTP);
1125
+ #endif
1126
+
1127
+ #if HAVE_CURLPROTO_TELNET
1128
+ CURB_DEFINE(CURLPROTO_TELNET);
1129
+ #endif
1130
+
1131
+ #if HAVE_CURLPROTO_FILE
1132
+ CURB_DEFINE(CURLPROTO_FILE);
1133
+ #endif
1134
+
1135
+ #if HAVE_CURLPROTO_FTPS
1136
+ CURB_DEFINE(CURLPROTO_FTPS);
1137
+ #endif
1138
+
1139
+ #if HAVE_CURLPROTO_HTTPS
1140
+ CURB_DEFINE(CURLPROTO_HTTPS);
1141
+ #endif
1142
+
1143
+ #if HAVE_CURLPROTO_IMAP
1144
+ CURB_DEFINE(CURLPROTO_IMAP);
1145
+ #endif
1146
+
1147
+ #if HAVE_CURLPROTO_POP3
1148
+ CURB_DEFINE(CURLPROTO_POP3);
1149
+ #endif
1150
+
1151
+ #if HAVE_CURLPROTO_GOPHER
1152
+ CURB_DEFINE(CURLPROTO_GOPHER);
1153
+ #endif
1154
+
1155
+ #if HAVE_CURLPROTO_DICT
1156
+ CURB_DEFINE(CURLPROTO_DICT);
1157
+ #endif
1158
+
1159
+ #if HAVE_CURLPROTO_SMB
1160
+ CURB_DEFINE(CURLPROTO_SMB);
1161
+ #endif
1162
+
1163
+ #if HAVE_CURLPROTO_RTMP
1164
+ CURB_DEFINE(CURLPROTO_RTMP);
1165
+ #endif
1166
+
1167
+ #if HAVE_CURLPROTO_ALL
1168
+ CURB_DEFINE(CURLPROTO_ALL);
1169
+ #endif
1170
+
1171
+ #if HAVE_CURLPROTO_RTMPE
1172
+ CURB_DEFINE(CURLPROTO_RTMPE);
1173
+ #endif
1174
+
1175
+ #if HAVE_CURLPROTO_RTMPS
1176
+ CURB_DEFINE(CURLPROTO_RTMPS);
1177
+ #endif
1178
+
1179
+ #if HAVE_CURLPROTO_RTMPT
1180
+ CURB_DEFINE(CURLPROTO_RTMPT);
1181
+ #endif
1182
+
1183
+ #if HAVE_CURLPROTO_POP3S
1184
+ CURB_DEFINE(CURLPROTO_POP3S);
1185
+ #endif
1186
+
1187
+ #if HAVE_CURLPROTO_RTSP
1188
+ CURB_DEFINE(CURLPROTO_RTSP);
1189
+ #endif
1190
+
1043
1191
  #if LIBCURL_VERSION_NUM >= 0x072B00 /* 7.43.0 */
1044
1192
  CURB_DEFINE(CURLPIPE_NOTHING);
1045
1193
  CURB_DEFINE(CURLPIPE_HTTP1);
data/ext/curb.h CHANGED
@@ -9,8 +9,16 @@
9
9
  #define __CURB_H
10
10
 
11
11
  #include <ruby.h>
12
+
13
+ #ifdef HAVE_RUBY_IO_H
14
+ #include "ruby/io.h"
15
+ #else
16
+ #include "rubyio.h" // ruby 1.8
17
+ #endif
18
+
12
19
  #include <curl/curl.h>
13
20
 
21
+ #include "banned.h"
14
22
  #include "curb_config.h"
15
23
  #include "curb_easy.h"
16
24
  #include "curb_errors.h"
@@ -20,11 +28,11 @@
20
28
  #include "curb_macros.h"
21
29
 
22
30
  // These should be managed from the Rake 'release' task.
23
- #define CURB_VERSION "0.9.8"
24
- #define CURB_VER_NUM 908
25
- #define CURB_VER_MAJ 0
26
- #define CURB_VER_MIN 9
27
- #define CURB_VER_MIC 8
31
+ #define CURB_VERSION "1.0.0"
32
+ #define CURB_VER_NUM 1000
33
+ #define CURB_VER_MAJ 1
34
+ #define CURB_VER_MIN 0
35
+ #define CURB_VER_MIC 0
28
36
  #define CURB_VER_PATCH 0
29
37
 
30
38
 
@@ -41,6 +49,11 @@
41
49
  #define RHASH_SIZE(hash) RHASH(hash)->tbl->num_entries
42
50
  #endif
43
51
 
52
+ // ruby 1.8 does not provide the macro
53
+ #ifndef DBL2NUM
54
+ #define DBL2NUM(dbl) rb_float_new(dbl)
55
+ #endif
56
+
44
57
  extern VALUE mCurl;
45
58
 
46
59
  extern void Init_curb_core();
data/ext/curb_easy.c CHANGED
@@ -25,6 +25,12 @@ static VALUE rbstrAmp;
25
25
 
26
26
  VALUE cCurlEasy;
27
27
 
28
+ // for Ruby 1.8
29
+ #ifndef HAVE_RB_IO_STDIO_FILE
30
+ static FILE * rb_io_stdio_file(rb_io_t *fptr) {
31
+ return fptr->f;
32
+ }
33
+ #endif
28
34
 
29
35
  /* ================== CURL HANDLER FUNCS ==============*/
30
36
 
@@ -247,6 +253,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
247
253
  curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
248
254
  curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
249
255
  curl_easy_cleanup(rbce->curl);
256
+ rbce->curl = NULL;
250
257
  }
251
258
  }
252
259
 
@@ -261,6 +268,8 @@ void curl_easy_free(ruby_curl_easy *rbce) {
261
268
  static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
262
269
  rbce->opts = rb_hash_new();
263
270
 
271
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
272
+
264
273
  rbce->curl_headers = NULL;
265
274
  rbce->curl_proxy_headers = NULL;
266
275
  rbce->curl_ftp_commands = NULL;
@@ -348,8 +357,9 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
348
357
 
349
358
  ruby_curl_easy_zero(rbce);
350
359
 
351
- rb_easy_set("url", url);
360
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
352
361
 
362
+ rb_easy_set("url", url);
353
363
 
354
364
  /* set the pointer to the curl handle */
355
365
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
@@ -385,6 +395,8 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
385
395
  newrbce->curl_ftp_commands = NULL;
386
396
  newrbce->curl_resolve = NULL;
387
397
 
398
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
399
+
388
400
  return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
389
401
  }
390
402
 
@@ -454,7 +466,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
454
466
  curl_easy_reset(rbce->curl);
455
467
  ruby_curl_easy_zero(rbce);
456
468
 
457
- /* rest clobbers the private setting, so reset it to self */
469
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
470
+
471
+ /* reset clobbers the private setting, so reset it to self */
458
472
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
459
473
  if (ecode != CURLE_OK) {
460
474
  raise_curl_easy_error_exception(ecode);
@@ -1532,6 +1546,7 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
1532
1546
  * Curl::CURL_SSLVERSION_TLSv1_0
1533
1547
  * Curl::CURL_SSLVERSION_TLSv1_1
1534
1548
  * Curl::CURL_SSLVERSION_TLSv1_2
1549
+ * Curl::CURL_SSLVERSION_TLSv1_3
1535
1550
  */
1536
1551
  static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
1537
1552
  CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
@@ -2543,7 +2558,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2543
2558
  *
2544
2559
  * Clean up a connection
2545
2560
  *
2546
- * Always returns Qtrue.
2561
+ * Always returns Qnil.
2547
2562
  */
2548
2563
  VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2549
2564
 
@@ -2583,6 +2598,9 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2583
2598
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
2584
2599
  }
2585
2600
 
2601
+ // set values on cleanup to nil
2602
+ rb_easy_del("multi");
2603
+
2586
2604
  return Qnil;
2587
2605
  }
2588
2606
 
@@ -2597,6 +2615,8 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2597
2615
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2598
2616
  curl = rbce->curl;
2599
2617
 
2618
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2619
+
2600
2620
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
2601
2621
 
2602
2622
  retval = rb_funcall(self, rb_intern("perform"), 0);
@@ -2662,6 +2682,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2662
2682
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2663
2683
  curl = rbce->curl;
2664
2684
 
2685
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2686
+
2665
2687
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2666
2688
 
2667
2689
  if (rbce->multipart_form_post) {
@@ -2733,6 +2755,8 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2733
2755
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2734
2756
  curl = rbce->curl;
2735
2757
 
2758
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2759
+
2736
2760
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2737
2761
  ruby_curl_easy_put_data_set(self, data);
2738
2762
 
@@ -2945,7 +2969,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
2945
2969
  * Retrieve the time, in seconds, it took from the start until the SSL/SSH
2946
2970
  * connect/handshake to the remote host was completed. This time is most often
2947
2971
  * very near to the pre transfer time, except for cases such as HTTP
2948
- * pippelining where the pretransfer time can be delayed due to waits in line
2972
+ * pipelining where the pretransfer time can be delayed due to waits in line
2949
2973
  * for the pipeline and more.
2950
2974
  */
2951
2975
  #if defined(HAVE_CURLINFO_APPCONNECT_TIME)
@@ -3438,6 +3462,21 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
3438
3462
  return LONG2NUM(rbce->last_result);
3439
3463
  }
3440
3464
 
3465
+ /*
3466
+ * call-seq:
3467
+ * easy.last_error => "Error details" or nil
3468
+ */
3469
+ static VALUE ruby_curl_easy_last_error(VALUE self) {
3470
+ ruby_curl_easy *rbce;
3471
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3472
+
3473
+ if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
3474
+ return rb_str_new2(rbce->err_buf);
3475
+ } else {
3476
+ return Qnil;
3477
+ }
3478
+ }
3479
+
3441
3480
  /*
3442
3481
  * call-seq:
3443
3482
  * easy.setopt Fixnum, value => value
@@ -3447,6 +3486,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
3447
3486
  static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3448
3487
  ruby_curl_easy *rbce;
3449
3488
  long option = NUM2LONG(opt);
3489
+ rb_io_t *open_f_ptr;
3450
3490
 
3451
3491
  Data_Get_Struct(self, ruby_curl_easy, rbce);
3452
3492
 
@@ -3535,6 +3575,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3535
3575
  case CURLOPT_TCP_NODELAY: {
3536
3576
  curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
3537
3577
  } break;
3578
+ case CURLOPT_RANGE: {
3579
+ curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
3580
+ } break;
3538
3581
  case CURLOPT_RESUME_FROM: {
3539
3582
  curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
3540
3583
  } break;
@@ -3571,6 +3614,38 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3571
3614
  case CURLOPT_MAXFILESIZE:
3572
3615
  curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
3573
3616
  break;
3617
+ #endif
3618
+ #if HAVE_CURLOPT_TCP_KEEPALIVE
3619
+ case CURLOPT_TCP_KEEPALIVE:
3620
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
3621
+ break;
3622
+ case CURLOPT_TCP_KEEPIDLE:
3623
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
3624
+ break;
3625
+ case CURLOPT_TCP_KEEPINTVL:
3626
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
3627
+ break;
3628
+ #endif
3629
+ #if HAVE_CURLOPT_HAPROXYPROTOCOL
3630
+ case CURLOPT_HAPROXYPROTOCOL:
3631
+ curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
3632
+ break;
3633
+ #endif
3634
+ case CURLOPT_STDERR:
3635
+ // libcurl requires raw FILE pointer and this should be IO object in Ruby.
3636
+ // Tempfile or StringIO won't work.
3637
+ Check_Type(val, T_FILE);
3638
+ GetOpenFile(val, open_f_ptr);
3639
+ curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
3640
+ break;
3641
+ case CURLOPT_PROTOCOLS:
3642
+ case CURLOPT_REDIR_PROTOCOLS:
3643
+ curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
3644
+ break;
3645
+ #if HAVE_CURLOPT_SSL_SESSIONID_CACHE
3646
+ case CURLOPT_SSL_SESSIONID_CACHE:
3647
+ curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
3648
+ break;
3574
3649
  #endif
3575
3650
  default:
3576
3651
  rb_raise(rb_eTypeError, "Curb unsupported option");
@@ -3879,6 +3954,7 @@ void init_curb_easy() {
3879
3954
  rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
3880
3955
  rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
3881
3956
  rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
3957
+ rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
3882
3958
 
3883
3959
  rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
3884
3960
  rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
data/ext/curb_easy.h CHANGED
@@ -36,6 +36,9 @@ typedef struct {
36
36
  /* The handler */
37
37
  CURL *curl;
38
38
 
39
+ /* Buffer for error details from CURLOPT_ERRORBUFFER */
40
+ char err_buf[CURL_ERROR_SIZE];
41
+
39
42
  VALUE opts; /* rather then allocate everything we might need to store, allocate a Hash and only store objects we actually use... */
40
43
  VALUE multi; /* keep a multi handle alive for each easy handle not being used by a multi handle. This improves easy performance when not within a multi context */
41
44
 
data/ext/extconf.rb CHANGED
@@ -18,6 +18,8 @@ elsif !have_library('curl') or !have_header('curl/curl.h')
18
18
  fail <<-EOM
19
19
  Can't find libcurl or curl/curl.h
20
20
 
21
+ Make sure development libs (ie libcurl4-openssl-dev) are installed on the system.
22
+
21
23
  Try passing --with-curl-dir or --with-curl-lib and --with-curl-include
22
24
  options to extconf.
23
25
  EOM
@@ -59,6 +61,9 @@ def have_constant(name)
59
61
  end
60
62
  end
61
63
 
64
+ have_constant "curlopt_tcp_keepalive"
65
+ have_constant "curlopt_tcp_keepidle"
66
+ have_constant "curlopt_tcp_keepintvl"
62
67
  have_constant "curlinfo_appconnect_time"
63
68
  have_constant "curlinfo_redirect_time"
64
69
  have_constant "curlinfo_response_code"
@@ -153,6 +158,8 @@ have_func("curl_multi_timeout")
153
158
  have_func("curl_multi_fdset")
154
159
  have_func("curl_multi_perform")
155
160
 
161
+ have_constant "curlopt_haproxyprotocol"
162
+
156
163
  # constants
157
164
  have_constant "curlopt_interleavefunction"
158
165
  have_constant "curlopt_interleavedata"
@@ -336,6 +343,9 @@ have_constant :CURL_SSLVERSION_TLSv1_0
336
343
  have_constant :CURL_SSLVERSION_TLSv1_1
337
344
  have_constant :CURL_SSLVERSION_TLSv1_2
338
345
 
346
+ # Added in 7.52.0
347
+ have_constant :CURL_SSLVERSION_TLSv1_3
348
+
339
349
  have_constant "curlopt_ssl_verifypeer"
340
350
  have_constant "curlopt_cainfo"
341
351
  have_constant "curlopt_issuercert"
@@ -395,6 +405,37 @@ have_constant "curlopt_path_as_is"
395
405
  # added in 7.43.0
396
406
  have_constant "curlopt_pipewait"
397
407
 
408
+ # protocol constants
409
+ have_constant "curlproto_all"
410
+ have_constant "curlproto_dict"
411
+ have_constant "curlproto_file"
412
+ have_constant "curlproto_ftp"
413
+ have_constant "curlproto_ftps"
414
+ have_constant "curlproto_gopher"
415
+ have_constant "curlproto_http"
416
+ have_constant "curlproto_https"
417
+ have_constant "curlproto_imap"
418
+ have_constant "curlproto_imaps"
419
+ have_constant "curlproto_ldap"
420
+ have_constant "curlproto_ldaps"
421
+ have_constant "curlproto_pop3"
422
+ have_constant "curlproto_pop3s"
423
+ have_constant "curlproto_rtmp"
424
+ have_constant "curlproto_rtmpe"
425
+ have_constant "curlproto_rtmps"
426
+ have_constant "curlproto_rtmpt"
427
+ have_constant "curlproto_rtmpte"
428
+ have_constant "curlproto_rtmpts"
429
+ have_constant "curlproto_rtsp"
430
+ have_constant "curlproto_scp"
431
+ have_constant "curlproto_sftp"
432
+ have_constant "curlproto_smb"
433
+ have_constant "curlproto_smbs"
434
+ have_constant "curlproto_smtp"
435
+ have_constant "curlproto_smtps"
436
+ have_constant "curlproto_telnet"
437
+ have_constant "curlproto_tftp"
438
+
398
439
  if try_compile('int main() { return 0; }','-Wall')
399
440
  $CFLAGS << ' -Wall'
400
441
  end
@@ -422,6 +463,8 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
422
463
 
423
464
  have_func('rb_thread_blocking_region')
424
465
  have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
466
+ have_header('ruby/io.h')
467
+ have_func('rb_io_stdio_file')
425
468
 
426
469
  create_header('curb_config.h')
427
470
  create_makefile('curb_core')
data/lib/curb.rb CHANGED
@@ -1 +1,2 @@
1
+ # frozen_string_literal: true
1
2
  require 'curl'
data/lib/curl/easy.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
3
  class Easy
3
4
 
@@ -68,9 +69,15 @@ module Curl
68
69
  ret = self.multi.perform
69
70
  self.multi.remove self
70
71
 
72
+ if Curl::Multi.autoclose
73
+ self.multi.close
74
+ self.multi = nil
75
+ end
76
+
71
77
  if self.last_result != 0 && self.on_failure.nil?
72
- error = Curl::Easy.error(self.last_result)
73
- raise error.first.new(self.head)
78
+ (err_class, err_summary) = Curl::Easy.error(self.last_result)
79
+ err_detail = self.last_error
80
+ raise err_class.new([err_summary, err_detail].compact.join(": "))
74
81
  end
75
82
 
76
83
  ret
data/lib/curl/multi.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Curl
2
3
  class Multi
3
4
  class << self
@@ -143,7 +144,7 @@ module Curl
143
144
 
144
145
  max_connects.times do
145
146
  conf = urls_with_config.pop
146
- add_free_handle.call conf, nil
147
+ add_free_handle.call(conf, nil) if conf
147
148
  break if urls_with_config.empty?
148
149
  end
149
150
 
@@ -152,7 +153,7 @@ module Curl
152
153
  if urls_with_config.size > 0 && free_handles.size > 0
153
154
  easy = free_handles.pop
154
155
  conf = urls_with_config.pop
155
- add_free_handle.call conf, easy
156
+ add_free_handle.call(conf, easy) if conf
156
157
  end
157
158
  end
158
159
 
data/lib/curl.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'curb_core'
2
3
  require 'curl/easy'
3
4
  require 'curl/multi'
data/tests/helper.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # Copyright (c)2006 Ross Bamford. See LICENSE.
3
3
  $CURB_TESTING = true
4
4
  require 'uri'
5
+ require 'stringio'
5
6
 
6
7
  $TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), '..'))
7
8
  $EXTDIR = File.join($TOPDIR, 'ext')
@@ -142,7 +143,6 @@ module TestServerMethods
142
143
  def server_setup(port=9129,servlet=TestServlet)
143
144
  @__port = port
144
145
  if (@server ||= nil).nil? and !File.exist?(locked_file)
145
-
146
146
  File.open(locked_file,'w') {|f| f << 'locked' }
147
147
  if TEST_SINGLE_THREADED
148
148
  rd, wr = IO.pipe
@@ -10,6 +10,66 @@ class TestCurbCurlEasy < Test::Unit::TestCase
10
10
  Curl.reset
11
11
  end
12
12
 
13
+ def test_curlopt_stderr_with_file
14
+ # does not work with Tempfile directly
15
+ path = Tempfile.new('curb_test_curlopt_stderr').path
16
+ File.open(path, 'w') do |file|
17
+ easy = Curl::Easy.new(TestServlet.url)
18
+ easy.verbose = true
19
+ easy.setopt(Curl::CURLOPT_STDERR, file)
20
+ easy.perform
21
+ end
22
+ output = File.read(path)
23
+
24
+ assert_match(/HTTP\/1\.1\ 200\ OK(?:\ )?/, output)
25
+ assert_match('Host: 127.0.0.1:9129', output)
26
+ end
27
+
28
+ def test_curlopt_stderr_with_io
29
+ path = Tempfile.new('curb_test_curlopt_stderr').path
30
+ fd = IO.sysopen(path, 'w')
31
+ io = IO.for_fd(fd)
32
+
33
+ easy = Curl::Easy.new(TestServlet.url)
34
+ easy.verbose = true
35
+ easy.setopt(Curl::CURLOPT_STDERR, io)
36
+ easy.perform
37
+
38
+
39
+ output = File.read(path)
40
+
41
+ assert_match(output, 'HTTP/1.1 200 OK')
42
+ assert_match(output, 'Host: 127.0.0.1:9129')
43
+ end
44
+
45
+ def test_curlopt_stderr_fails_with_tempdir
46
+ Tempfile.open('curb_test_curlopt_stderr') do |tempfile|
47
+ easy = Curl::Easy.new(TestServlet.url)
48
+
49
+ assert_raise(TypeError) do
50
+ easy.setopt(Curl::CURLOPT_STDERR, tempfile)
51
+ end
52
+ end
53
+ end
54
+
55
+ def test_curlopt_stderr_fails_with_stringio
56
+ stringio = StringIO.new
57
+ easy = Curl::Easy.new(TestServlet.url)
58
+
59
+ assert_raise(TypeError) do
60
+ easy.setopt(Curl::CURLOPT_STDERR, stringio)
61
+ end
62
+ end
63
+
64
+ def test_curlopt_stderr_fails_with_string
65
+ string = String.new
66
+ easy = Curl::Easy.new(TestServlet.url)
67
+
68
+ assert_raise(TypeError) do
69
+ easy.setopt(Curl::CURLOPT_STDERR, string)
70
+ end
71
+ end
72
+
13
73
  def test_exception
14
74
  begin
15
75
  Curl.get('NOT_FOUND_URL')
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class TestCurbCurlMaxFileSize < Test::Unit::TestCase
4
+ def setup
5
+ @easy = Curl::Easy.new
6
+ end
7
+
8
+ def test_maxfilesize
9
+ @easy.set(Curl::CURLOPT_MAXFILESIZE, 5000000)
10
+ end
11
+
12
+ end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+ require 'set'
2
3
 
3
4
  class TestCurbCurlMulti < Test::Unit::TestCase
4
5
  def teardown
@@ -9,19 +10,58 @@ class TestCurbCurlMulti < Test::Unit::TestCase
9
10
  # for https://github.com/taf2/curb/issues/277
10
11
  # must connect to an external
11
12
  def test_connection_keepalive
12
- # 0123456 default & reserved RubyVM. It will probably include 7 from Dir.glob
13
- open_fds = lambda do
14
- `/usr/sbin/lsof -p #{Process.pid} | egrep "TCP|UDP" | wc -l`.strip.to_i
13
+ # this test fails with libcurl 7.22.0. I didn't investigate, but it may be related
14
+ # to CURLOPT_MAXCONNECTS bug fixed in 7.30.0:
15
+ # https://github.com/curl/curl/commit/e87e76e2dc108efb1cae87df496416f49c55fca0
16
+ omit("Skip, libcurl too old (< 7.22.0)") if Curl::CURL_VERSION.split('.')[1].to_i <= 22
17
+
18
+ @server.shutdown if @server
19
+ @test_thread.kill if @test_thread
20
+ @server = nil
21
+ File.unlink(locked_file)
22
+ Curl::Multi.autoclose = true
23
+ assert Curl::Multi.autoclose
24
+ # XXX: thought maybe we can clean house here to have the full suite pass in osx... but for now running this test in isolate does pass
25
+ # additionally, if ss allows this to pass on linux without requesting google i think this is a good trade off... leaving some of the thoughts below
26
+ # in hopes that coming back to this later will find it and remember how to fix it
27
+ # types = Set.new
28
+ # close_types = Set.new([TCPServer,TCPSocket,Socket,Curl::Multi, Curl::Easy,WEBrick::Log])
29
+ # ObjectSpace.each_object {|o|
30
+ # if o.respond_to?(:close)
31
+ # types << o.class
32
+ # end
33
+ # if close_types.include?(o.class)
34
+ # o.close
35
+ # end
36
+ # }
37
+ #puts "unique types: #{types.to_a.join("\n")}"
38
+ GC.start # cleanup FDs left over from other tests
39
+ server_setup
40
+ GC.start # cleanup FDs left over from other tests
41
+
42
+ if `which ss`.strip.size == 0
43
+ # osx need lsof still :(
44
+ open_fds = lambda do
45
+ out = `/usr/sbin/lsof -p #{Process.pid} | egrep "TCP|UDP"`# | egrep ':#{TestServlet.port} ' | egrep ESTABLISHED`# | wc -l`.strip.to_i
46
+ #puts out.lines.join("\n")
47
+ out.lines.size
48
+ end
49
+ else
50
+ ss = `which ss`.strip
51
+ open_fds = lambda do
52
+ `#{ss} -n4 state established dport = :#{TestServlet.port} | wc -l`.strip.to_i
53
+ end
15
54
  end
55
+ Curl::Multi.autoclose = false
16
56
  before_open = open_fds.call
57
+ #puts "before_open: #{before_open.inspect}"
17
58
  assert !Curl::Multi.autoclose
18
59
  multi = Curl::Multi.new
19
60
  multi.max_connects = 1 # limit to 1 connection within the multi handle
20
61
 
21
62
  did_complete = false
22
63
  5.times do |n|
23
- # NOTE: we use google here because connecting to our TEST_URL as a local host address appears to not register correctly with lsof as a socket... if anyone knows a better way would be great to not have an external dependency here in the test
24
- easy = Curl::Easy.new("http://google.com/") do |curl|
64
+ easy = Curl::Easy.new(TestServlet.url) do |curl|
25
65
  curl.timeout = 5 # ensure we don't hang for ever connecting to an external host
26
66
  curl.on_complete {
27
67
  did_complete = true
@@ -33,18 +73,19 @@ class TestCurbCurlMulti < Test::Unit::TestCase
33
73
  multi.perform
34
74
  assert did_complete
35
75
  after_open = open_fds.call
36
- assert_equal (after_open - before_open), 1, "with max connections set to 1 at this point the connection to google should still be open"
76
+ #puts "after_open: #{after_open} before_open: #{before_open.inspect}"
77
+ assert_equal 1, (after_open - before_open), "with max connections set to 1 at this point the connection to google should still be open"
37
78
  multi.close
38
79
 
39
80
  after_open = open_fds.call
40
- assert_equal (after_open - before_open), 0, "after closing the multi handle all connections should be closed"
81
+ #puts "after_open: #{after_open} before_open: #{before_open.inspect}"
82
+ assert_equal 0, (after_open - before_open), "after closing the multi handle all connections should be closed"
41
83
 
42
84
  Curl::Multi.autoclose = true
43
85
  multi = Curl::Multi.new
44
86
  did_complete = false
45
87
  5.times do |n|
46
- # NOTE: we use google here because connecting to our TEST_URL as a local host address appears to not register correctly with lsof as a socket... if anyone knows a better way would be great to not have an external dependency here in the test
47
- easy = Curl::Easy.new("http://google.com/") do |curl|
88
+ easy = Curl::Easy.new(TestServlet.url) do |curl|
48
89
  curl.timeout = 5 # ensure we don't hang for ever connecting to an external host
49
90
  curl.on_complete {
50
91
  did_complete = true
@@ -56,7 +97,8 @@ class TestCurbCurlMulti < Test::Unit::TestCase
56
97
  multi.perform
57
98
  assert did_complete
58
99
  after_open = open_fds.call
59
- assert_equal (after_open - before_open), 0, "auto close the connections"
100
+ #puts "after_open: #{after_open} before_open: #{before_open.inspect}"
101
+ assert_equal 0, (after_open - before_open), "auto close the connections"
60
102
  ensure
61
103
  Curl::Multi.autoclose = false # restore default
62
104
  end
@@ -2,63 +2,63 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
2
 
3
3
  class TestCurbCurlPostfield < Test::Unit::TestCase
4
4
  def test_private_new
5
- assert_raise(NoMethodError) { Curl::PostField.new }
5
+ assert_raise(NoMethodError) { Curl::PostField.new }
6
6
  end
7
-
7
+
8
8
  def test_new_content_01
9
9
  pf = Curl::PostField.content('foo', 'bar')
10
-
10
+
11
11
  assert_equal 'foo', pf.name
12
12
  assert_equal 'bar', pf.content
13
13
  assert_nil pf.content_type
14
14
  assert_nil pf.local_file
15
- assert_nil pf.remote_file
15
+ assert_nil pf.remote_file
16
16
  assert_nil pf.set_content_proc
17
17
  end
18
-
18
+
19
19
  def test_new_content_02
20
20
  pf = Curl::PostField.content('foo', 'bar', 'text/html')
21
-
21
+
22
22
  assert_equal 'foo', pf.name
23
23
  assert_equal 'bar', pf.content
24
24
  assert_equal 'text/html', pf.content_type
25
25
  assert_nil pf.local_file
26
26
  assert_nil pf.remote_file
27
- assert_nil pf.set_content_proc
28
- end
29
-
27
+ assert_nil pf.set_content_proc
28
+ end
29
+
30
30
  def test_new_content_03
31
31
  l = lambda { |field| "never gets run" }
32
32
  pf = Curl::PostField.content('foo', &l)
33
-
33
+
34
34
  assert_equal 'foo', pf.name
35
35
  assert_nil pf.content
36
36
  assert_nil pf.content_type
37
37
  assert_nil pf.local_file
38
38
  assert_nil pf.remote_file
39
-
39
+
40
40
  # N.B. This doesn't just get the proc, but also removes it.
41
41
  assert_equal l, pf.set_content_proc
42
- end
42
+ end
43
43
 
44
44
  def test_new_content_04
45
45
  l = lambda { |field| "never gets run" }
46
46
  pf = Curl::PostField.content('foo', 'text/html', &l)
47
-
47
+
48
48
  assert_equal 'foo', pf.name
49
49
  assert_nil pf.content
50
50
  assert_equal 'text/html', pf.content_type
51
51
  assert_nil pf.local_file
52
52
  assert_nil pf.remote_file
53
-
53
+
54
54
  # N.B. This doesn't just get the proc, but also removes it.
55
55
  assert_equal l, pf.set_content_proc
56
- end
56
+ end
57
57
 
58
58
 
59
59
  def test_new_file_01
60
60
  pf = Curl::PostField.file('foo', 'localname')
61
-
61
+
62
62
  assert_equal 'foo', pf.name
63
63
  assert_equal 'localname', pf.local_file
64
64
  assert_equal 'localname', pf.remote_file
@@ -67,44 +67,44 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
67
67
  assert_nil pf.content
68
68
  assert_nil pf.set_content_proc
69
69
  end
70
-
70
+
71
71
  def test_new_file_02
72
72
  pf = Curl::PostField.file('foo', 'localname', 'remotename')
73
-
73
+
74
74
  assert_equal 'foo', pf.name
75
75
  assert_equal 'localname', pf.local_file
76
76
  assert_equal 'remotename', pf.remote_file
77
77
  assert_nil pf.content_type
78
78
  assert_nil pf.content
79
79
  assert_nil pf.set_content_proc
80
- end
81
-
80
+ end
81
+
82
82
  def test_new_file_03
83
83
  l = lambda { |field| "never gets run" }
84
84
  pf = Curl::PostField.file('foo', 'remotename', &l)
85
-
85
+
86
86
  assert_equal 'foo', pf.name
87
87
  assert_equal 'remotename', pf.remote_file
88
88
  assert_nil pf.local_file
89
89
  assert_nil pf.content_type
90
90
  assert_nil pf.content
91
-
91
+
92
92
  # N.B. This doesn't just get the proc, but also removes it.
93
93
  assert_equal l, pf.set_content_proc
94
- end
94
+ end
95
95
 
96
96
  def test_new_file_04
97
97
  assert_raise(ArgumentError) do
98
98
  # no local name, no block
99
99
  Curl::PostField.file('foo')
100
100
  end
101
-
101
+
102
102
  assert_raise(ArgumentError) do
103
103
  # no remote name with block
104
104
  Curl::PostField.file('foo') { |field| "never runs" }
105
105
  end
106
106
  end
107
-
107
+
108
108
  def test_new_file_05
109
109
  # local gets ignored when supplying a block, but remote
110
110
  # is still set up properly.
@@ -118,15 +118,15 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
118
118
  assert_nil pf.content
119
119
 
120
120
  assert_equal l, pf.set_content_proc
121
- end
122
-
121
+ end
122
+
123
123
  def test_to_s_01
124
- pf = Curl::PostField.content('foo', 'bar')
124
+ pf = Curl::PostField.content('foo', 'bar')
125
125
  assert_equal "foo=bar", pf.to_s
126
126
  end
127
127
 
128
128
  def test_to_s_02
129
- pf = Curl::PostField.content('foo', 'bar ton')
129
+ pf = Curl::PostField.content('foo', 'bar ton')
130
130
  assert_equal "foo=bar%20ton", pf.to_s
131
131
  end
132
132
 
@@ -0,0 +1,37 @@
1
+ class TestCurbCurlProtocols < Test::Unit::TestCase
2
+ include TestServerMethods
3
+
4
+ def setup
5
+ @easy = Curl::Easy.new
6
+ @easy.set :protocols, Curl::CURLPROTO_HTTP | Curl::CURLPROTO_HTTPS
7
+ @easy.follow_location = true
8
+ server_setup
9
+ end
10
+
11
+ def test_protocol_allowed
12
+ @easy.set :url, "http://127.0.0.1:9129/this_file_does_not_exist.html"
13
+ @easy.perform
14
+ assert_equal 404, @easy.response_code
15
+ end
16
+
17
+ def test_protocol_denied
18
+ @easy.set :url, "gopher://google.com/"
19
+ assert_raises Curl::Err::UnsupportedProtocolError do
20
+ @easy.perform
21
+ end
22
+ end
23
+
24
+ def test_redir_protocol_allowed
25
+ @easy.set :url, TestServlet.url + "/redirect"
26
+ @easy.set :redir_protocols, Curl::CURLPROTO_HTTP
27
+ @easy.perform
28
+ end
29
+
30
+ def test_redir_protocol_denied
31
+ @easy.set :url, TestServlet.url + "/redirect"
32
+ @easy.set :redir_protocols, Curl::CURLPROTO_HTTPS
33
+ assert_raises Curl::Err::UnsupportedProtocolError do
34
+ @easy.perform
35
+ end
36
+ end
37
+ end
data/tests/timeout.rb CHANGED
@@ -17,9 +17,13 @@ class TestCurbTimeouts < Test::Unit::TestCase
17
17
  def test_overall_timeout_on_dead_transfer
18
18
  curl = Curl::Easy.new(wait_url(2))
19
19
  curl.timeout = 1
20
- assert_raise(Curl::Err::TimeoutError) do
20
+ exception = assert_raise(Curl::Err::TimeoutError) do
21
21
  curl.http_get
22
22
  end
23
+ assert_match(
24
+ /^Timeout was reached: Operation timed out after/,
25
+ exception.message
26
+ )
23
27
  end
24
28
 
25
29
  def test_overall_timeout_ms_on_dead_transfer
@@ -44,16 +48,20 @@ class TestCurbTimeouts < Test::Unit::TestCase
44
48
  curl = Curl::Easy.new(serve_url(100, 2, 3))
45
49
  curl.timeout = 1
46
50
  # transfer is aborted despite data being exchanged
47
- assert_raise(Curl::Err::TimeoutError) do
51
+ exception = assert_raise(Curl::Err::TimeoutError) do
48
52
  curl.http_get
49
53
  end
54
+ assert_match(
55
+ /^Timeout was reached: Operation timed out after/,
56
+ exception.message
57
+ )
50
58
  end
51
59
 
52
60
  def test_low_speed_time_on_slow_transfer
53
61
  curl = Curl::Easy.new(serve_url(100, 1, 3))
54
62
  curl.low_speed_time = 2
55
63
  # use default low_speed_limit of 1
56
- assert true, curl.http_get
64
+ assert_equal true, curl.http_get
57
65
  end
58
66
 
59
67
  def test_low_speed_time_on_very_slow_transfer
@@ -63,18 +71,26 @@ class TestCurbTimeouts < Test::Unit::TestCase
63
71
  # XXX for some reason this test fails if low speed limit is not specified
64
72
  curl.low_speed_limit = 1
65
73
  # use default low_speed_limit of 1
66
- assert_raise(Curl::Err::TimeoutError) do
74
+ exception = assert_raise(Curl::Err::TimeoutError) do
67
75
  curl.http_get
68
76
  end
77
+ assert_match(
78
+ /^Timeout was reached: Operation too slow/,
79
+ exception.message
80
+ )
69
81
  end
70
82
 
71
83
  def test_low_speed_limit_on_slow_transfer
72
84
  curl = Curl::Easy.new(serve_url(10, 1, 3))
73
85
  curl.low_speed_time = 2
74
86
  curl.low_speed_limit = 1000
75
- assert_raise(Curl::Err::TimeoutError) do
87
+ exception = assert_raise(Curl::Err::TimeoutError) do
76
88
  curl.http_get
77
89
  end
90
+ assert_match(
91
+ /^Timeout was reached: Operation too slow/,
92
+ exception.message
93
+ )
78
94
  end
79
95
 
80
96
  def test_clearing_low_speed_time
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.8
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Bamford
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-28 00:00:00.000000000 Z
12
+ date: 2022-01-14 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
15
15
  for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
@@ -26,6 +26,7 @@ files:
26
26
  - README.markdown
27
27
  - Rakefile
28
28
  - doc.rb
29
+ - ext/banned.h
29
30
  - ext/curb.c
30
31
  - ext/curb.h
31
32
  - ext/curb_easy.c
@@ -65,14 +66,16 @@ files:
65
66
  - tests/tc_curl_easy.rb
66
67
  - tests/tc_curl_easy_resolve.rb
67
68
  - tests/tc_curl_easy_setopt.rb
69
+ - tests/tc_curl_maxfilesize.rb
68
70
  - tests/tc_curl_multi.rb
69
71
  - tests/tc_curl_postfield.rb
72
+ - tests/tc_curl_protocols.rb
70
73
  - tests/timeout.rb
71
74
  - tests/timeout_server.rb
72
75
  - tests/unittests.rb
73
- homepage: http://curb.rubyforge.org/
76
+ homepage: https://github.com/taf2/curb
74
77
  licenses:
75
- - Ruby
78
+ - MIT
76
79
  metadata: {}
77
80
  post_install_message:
78
81
  rdoc_options:
@@ -92,35 +95,36 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
95
  - !ruby/object:Gem::Version
93
96
  version: '0'
94
97
  requirements: []
95
- rubyforge_project: curb
96
- rubygems_version: 2.7.7
98
+ rubygems_version: 3.3.3
97
99
  signing_key:
98
100
  specification_version: 4
99
101
  summary: Ruby libcurl bindings
100
102
  test_files:
101
- - tests/tc_curl_multi.rb
102
103
  - tests/alltests.rb
103
- - tests/tc_curl_easy_setopt.rb
104
- - tests/tc_curl.rb
105
- - tests/bug_postfields_crash.rb
106
- - tests/bug_crash_on_progress.rb
107
- - tests/helper.rb
108
- - tests/bug_postfields_crash2.rb
109
- - tests/bug_require_last_or_segfault.rb
110
- - tests/timeout.rb
111
104
  - tests/bug_crash_on_debug.rb
112
- - tests/unittests.rb
113
- - tests/bug_issue102.rb
105
+ - tests/bug_crash_on_progress.rb
114
106
  - tests/bug_curb_easy_blocks_ruby_threads.rb
115
- - tests/bug_multi_segfault.rb
107
+ - tests/bug_curb_easy_post_with_string_no_content_length_header.rb
116
108
  - tests/bug_instance_post_differs_from_class_post.rb
109
+ - tests/bug_issue102.rb
110
+ - tests/bug_multi_segfault.rb
111
+ - tests/bug_postfields_crash.rb
112
+ - tests/bug_postfields_crash2.rb
113
+ - tests/bug_require_last_or_segfault.rb
114
+ - tests/bugtests.rb
115
+ - tests/helper.rb
116
+ - tests/mem_check.rb
117
117
  - tests/require_last_or_segfault_script.rb
118
- - tests/timeout_server.rb
118
+ - tests/signals.rb
119
+ - tests/tc_curl.rb
119
120
  - tests/tc_curl_download.rb
120
121
  - tests/tc_curl_easy.rb
121
- - tests/mem_check.rb
122
- - tests/tc_curl_postfield.rb
123
- - tests/bugtests.rb
124
122
  - tests/tc_curl_easy_resolve.rb
125
- - tests/signals.rb
126
- - tests/bug_curb_easy_post_with_string_no_content_length_header.rb
123
+ - tests/tc_curl_easy_setopt.rb
124
+ - tests/tc_curl_maxfilesize.rb
125
+ - tests/tc_curl_multi.rb
126
+ - tests/tc_curl_postfield.rb
127
+ - tests/tc_curl_protocols.rb
128
+ - tests/timeout.rb
129
+ - tests/timeout_server.rb
130
+ - tests/unittests.rb