curb 0.9.8 → 1.0.0

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