curb 0.9.6 → 0.9.11

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
- SHA1:
3
- metadata.gz: 53aeed05cc43efb7e736097fd212e43a8b25e21b
4
- data.tar.gz: 129c6741252ba30006df855fb7543eba7e706fca
2
+ SHA256:
3
+ metadata.gz: ecd73a0ad8d98960321b8d523e25bad95ff25e8900e8acb187051ca40c7a1cba
4
+ data.tar.gz: c154996d92946fe83fa12d695b073d5026e4a55e92efd177bfad021461f2b313
5
5
  SHA512:
6
- metadata.gz: e2f6065c80853bdc3d17d69316e202b7f7f73d5ab4925171fa50847e370978b67f4419144559305beb002a7e91dc5cf6b359b1d643237cb17699c37ba07d936f
7
- data.tar.gz: b76fd1724733c9566e4150c4467370ca63a40838f59e8b6ab1412d8b893eca1ebfe12cca6bb8ac59f607292498daa4e97d06fd9239ac7d651b5441b4e2f2abfa
6
+ metadata.gz: 48854a4f0d77befe0e81b31a3d39e826b2ef65d58d0226b617a355ba8d063ab4998853a8709ae6d2e3c4629c09ff987099398a1c884b76d95dcf956d941fc660
7
+ data.tar.gz: 3291675a74eb40f42d936bb65689da7d5f295e038ed019482d2cf115ba878232ce4e40aeb125d0fe786b5e82428320938ff3c75592a5c54a2d51fbe8589a0931
@@ -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 (1.8+, tested with 1.8.6, 1.8.7, 1.9.1, and 1.9.2)
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:
@@ -30,7 +46,11 @@ On Windows, make sure you're using the [DevKit](http://rubyinstaller.org/downloa
30
46
  the [development version of libcurl](http://curl.haxx.se/gknw.net/7.39.0/dist-w32/curl-7.39.0-devel-mingw32.zip). Unzip, then run this in your command
31
47
  line (alter paths to your curl location, but remember to use forward slashes):
32
48
 
33
- gem install curb --platform=ruby -- --with-curl-lib=C:/curl-7.39.0-devel-mingw32/bin --with-curl-include=C:/curl-7.39.0-devel-mingw32/include
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
 
@@ -134,9 +154,9 @@ c.perform
134
154
  ### HTTP "insecure" SSL connections (like curl -k, --insecure) to avoid Curl::Err::SSLCACertificateError:
135
155
 
136
156
  ```ruby
137
- c = Curl::Easy.new("https://github.com/")
138
- c.ssl_verify_peer = false
139
- c.perform
157
+ c = Curl::Easy.new("https://github.com/")
158
+ c.ssl_verify_peer = false
159
+ c.perform
140
160
  ```
141
161
 
142
162
  ### Supplying custom handlers:
data/Rakefile CHANGED
@@ -2,11 +2,6 @@
2
2
  #
3
3
  require 'rake/clean'
4
4
  require 'rake/testtask'
5
- begin
6
- require 'rdoc/task'
7
- rescue LoadError => e
8
- require 'rake/rdoctask'
9
- end
10
5
 
11
6
  CLEAN.include '**/*.o'
12
7
  CLEAN.include "**/*.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
@@ -15,6 +10,22 @@ CLOBBER.include '**/*.log'
15
10
  CLOBBER.include '**/Makefile'
16
11
  CLOBBER.include '**/extconf.h'
17
12
 
13
+ # Not available for really old rubies, but that's ok.
14
+ begin
15
+ require 'pry'
16
+ rescue LoadError
17
+ puts "Failed to load pry."
18
+ end
19
+
20
+ # Load support ruby and rake files (in this order)
21
+ Dir.glob('tasks/*.rb').each { |r| load r}
22
+ Dir.glob('tasks/*.rake').each { |r| load r}
23
+
24
+ desc 'Print Ruby major version (ie "2_5")'
25
+ task :ruby_version do
26
+ print current_ruby_major
27
+ end
28
+
18
29
  def announce(msg='')
19
30
  $stderr.puts msg
20
31
  end
@@ -43,12 +54,11 @@ end
43
54
  make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
44
55
  MAKECMD = ENV['MAKE_CMD'] || make_program
45
56
  MAKEOPTS = ENV['MAKE_OPTS'] || ''
46
-
47
57
  CURB_SO = "ext/curb_core.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
48
58
 
49
59
  file 'ext/Makefile' => 'ext/extconf.rb' do
50
60
  Dir.chdir('ext') do
51
- ruby "extconf.rb #{ENV['EXTCONF_OPTS']}"
61
+ shell('ruby', 'extconf.rb', ENV['EXTCONF_OPTS'].to_s, live_stdout: STDOUT)
52
62
  end
53
63
  end
54
64
 
@@ -89,12 +99,12 @@ if ENV['RELTEST']
89
99
  else
90
100
  task :alltests => [:unittests, :bugtests]
91
101
  end
92
-
102
+
93
103
  Rake::TestTask.new(:unittests) do |t|
94
104
  t.test_files = FileList['tests/tc_*.rb']
95
105
  t.verbose = false
96
106
  end
97
-
107
+
98
108
  Rake::TestTask.new(:bugtests) do |t|
99
109
  t.test_files = FileList['tests/bug_*.rb']
100
110
  t.verbose = false
@@ -136,6 +146,12 @@ end
136
146
 
137
147
  desc "Publish the RDoc documentation to project web site"
138
148
  task :doc_upload => [ :doc ] do
149
+ begin
150
+ require 'rdoc/task'
151
+ rescue LoadError => e
152
+ require 'rake/rdoctask'
153
+ end
154
+
139
155
  if ENV['RELTEST']
140
156
  announce "Release Task Testing, skipping doc upload"
141
157
  else
@@ -170,7 +186,7 @@ else
170
186
  spec_source = File.read File.join(File.dirname(__FILE__),'curb.gemspec')
171
187
  spec = nil
172
188
  # see: http://gist.github.com/16215
173
- Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
189
+ Thread.new { spec = eval("#{spec_source}") }.join
174
190
  spec.validate
175
191
  Gem::Package.build(spec)
176
192
  end
@@ -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
@@ -352,6 +352,13 @@ void Init_curb_core() {
352
352
  rb_define_const(mCurl, "CURLPROXY_SOCKS5", LONG2NUM(-2));
353
353
  #endif
354
354
 
355
+ /* When passed to Curl::Easy#proxy_type , indicates that the proxy is a SOCKS5 proxy (and that the proxy should resolve the hostname). (libcurl >= 7.17.2) */
356
+ #ifdef HAVE_CURLPROXY_SOCKS5_HOSTNAME
357
+ rb_define_const(mCurl, "CURLPROXY_SOCKS5_HOSTNAME", LONG2NUM(CURLPROXY_SOCKS5_HOSTNAME));
358
+ #else
359
+ rb_define_const(mCurl, "CURLPROXY_SOCKS5_HOSTNAME", LONG2NUM(-2));
360
+ #endif
361
+
355
362
  /* When passed to Curl::Easy#http_auth_types or Curl::Easy#proxy_auth_types, directs libcurl to use Basic authentication. */
356
363
  #ifdef HAVE_CURLAUTH_BASIC
357
364
  rb_define_const(mCurl, "CURLAUTH_BASIC", LONG2NUM(CURLAUTH_BASIC));
@@ -585,6 +592,9 @@ void Init_curb_core() {
585
592
  CURB_DEFINE(CURLOPT_REFERER);
586
593
  CURB_DEFINE(CURLOPT_USERAGENT);
587
594
  CURB_DEFINE(CURLOPT_HTTPHEADER);
595
+ #if HAVE_CURLOPT_PROXYHEADER
596
+ CURB_DEFINE(CURLOPT_PROXYHEADER);
597
+ #endif
588
598
  #if HAVE_CURLOPT_HTTP200ALIASES
589
599
  CURB_DEFINE(CURLOPT_HTTP200ALIASES);
590
600
  #endif
@@ -1030,6 +1040,16 @@ void Init_curb_core() {
1030
1040
  CURB_DEFINE(CURLOPT_PIPEWAIT);
1031
1041
  #endif
1032
1042
 
1043
+ #if HAVE_CURLOPT_TCP_KEEPALIVE
1044
+ CURB_DEFINE(CURLOPT_TCP_KEEPALIVE);
1045
+ CURB_DEFINE(CURLOPT_TCP_KEEPIDLE);
1046
+ CURB_DEFINE(CURLOPT_TCP_KEEPINTVL);
1047
+ #endif
1048
+
1049
+ #if HAVE_CURLOPT_HAPROXYPROTOCOL
1050
+ CURB_DEFINE(CURLOPT_HAPROXYPROTOCOL);
1051
+ #endif
1052
+
1033
1053
  #if LIBCURL_VERSION_NUM >= 0x072B00 /* 7.43.0 */
1034
1054
  CURB_DEFINE(CURLPIPE_NOTHING);
1035
1055
  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.6"
24
- #define CURB_VER_NUM 906
31
+ #define CURB_VERSION "0.9.11"
32
+ #define CURB_VER_NUM 9011
25
33
  #define CURB_VER_MAJ 0
26
- #define CURB_VER_MIN 6
27
- #define CURB_VER_MIC 0
34
+ #define CURB_VER_MIN 9
35
+ #define CURB_VER_MIC 11
28
36
  #define CURB_VER_PATCH 0
29
37
 
30
38
 
@@ -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
 
@@ -223,6 +229,10 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
223
229
  curl_slist_free_all(rbce->curl_headers);
224
230
  }
225
231
 
232
+ if (rbce->curl_proxy_headers) {
233
+ curl_slist_free_all(rbce->curl_proxy_headers);
234
+ }
235
+
226
236
  if (rbce->curl_ftp_commands) {
227
237
  curl_slist_free_all(rbce->curl_ftp_commands);
228
238
  }
@@ -243,6 +253,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
243
253
  curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
244
254
  curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
245
255
  curl_easy_cleanup(rbce->curl);
256
+ rbce->curl = NULL;
246
257
  }
247
258
  }
248
259
 
@@ -258,6 +269,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
258
269
  rbce->opts = rb_hash_new();
259
270
 
260
271
  rbce->curl_headers = NULL;
272
+ rbce->curl_proxy_headers = NULL;
261
273
  rbce->curl_ftp_commands = NULL;
262
274
  rbce->curl_resolve = NULL;
263
275
 
@@ -277,6 +289,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
277
289
  rbce->ftp_response_timeout = 0;
278
290
  rbce->low_speed_limit = 0;
279
291
  rbce->low_speed_time = 0;
292
+ rbce->max_send_speed_large = 0;
293
+ rbce->max_recv_speed_large = 0;
280
294
  rbce->ssl_version = -1;
281
295
  rbce->use_ssl = -1;
282
296
  rbce->ftp_filemethod = -1;
@@ -343,7 +357,8 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
343
357
 
344
358
  rb_easy_set("url", url);
345
359
 
346
- /* set the new_curl pointer to the curl handle */
360
+
361
+ /* set the pointer to the curl handle */
347
362
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
348
363
  if (ecode != CURLE_OK) {
349
364
  raise_curl_easy_error_exception(ecode);
@@ -373,6 +388,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
373
388
  memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
374
389
  newrbce->curl = curl_easy_duphandle(rbce->curl);
375
390
  newrbce->curl_headers = NULL;
391
+ newrbce->curl_proxy_headers = NULL;
376
392
  newrbce->curl_ftp_commands = NULL;
377
393
  newrbce->curl_resolve = NULL;
378
394
 
@@ -457,6 +473,12 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
457
473
  rbce->curl_headers = NULL;
458
474
  }
459
475
 
476
+ /* Free everything up */
477
+ if (rbce->curl_proxy_headers) {
478
+ curl_slist_free_all(rbce->curl_proxy_headers);
479
+ rbce->curl_proxy_headers = NULL;
480
+ }
481
+
460
482
  return opts_dup;
461
483
  }
462
484
 
@@ -509,6 +531,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
509
531
  CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
510
532
  }
511
533
 
534
+ static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
535
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_headers);
536
+ }
537
+
512
538
  /*
513
539
  * call-seq:
514
540
  * easy.headers => Hash, Array or Str
@@ -524,6 +550,41 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
524
550
  return headers;
525
551
  }
526
552
 
553
+ /*
554
+ * call-seq:
555
+ * easy.proxy_headers = "Header: val" => "Header: val"
556
+ * easy.proxy_headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
557
+ * easy.proxy_headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
558
+ *
559
+ *
560
+ * For example to set a standard or custom header:
561
+ *
562
+ * easy.proxy_headers["MyHeader"] = "myval"
563
+ *
564
+ * To remove a standard header (this is useful when removing libcurls default
565
+ * 'Expect: 100-Continue' header when using HTTP form posts):
566
+ *
567
+ * easy.proxy_headers["Expect"] = ''
568
+ *
569
+ * Anything passed to libcurl as a header will be converted to a string during
570
+ * the perform step.
571
+ */
572
+
573
+ /*
574
+ * call-seq:
575
+ * easy.proxy_headers => Hash, Array or Str
576
+ *
577
+ * Obtain the custom HTTP proxy_headers for following requests.
578
+ */
579
+ static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
580
+ ruby_curl_easy *rbce;
581
+ VALUE proxy_headers;
582
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
583
+ proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
584
+ if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
585
+ return proxy_headers;
586
+ }
587
+
527
588
  /*
528
589
  * call-seq:
529
590
  * easy.interface => string
@@ -1139,7 +1200,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1139
1200
 
1140
1201
  /*
1141
1202
  * call-seq:
1142
- * easy.timeout = fixnum or nil => fixnum or nil
1203
+ * easy.timeout = float, fixnum or nil => numeric
1143
1204
  *
1144
1205
  * Set the maximum time in seconds that you allow the libcurl transfer
1145
1206
  * operation to take. Normally, name lookups can take a considerable time
@@ -1148,20 +1209,39 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1148
1209
  *
1149
1210
  * Set to nil (or zero) to disable timeout (it will then only timeout
1150
1211
  * on the system's internal timeouts).
1212
+ *
1213
+ * Uses timeout_ms internally instead of timeout because it allows for
1214
+ * better precision and libcurl will use the last set value when both
1215
+ * timeout and timeout_ms are set.
1216
+ *
1151
1217
  */
1152
- static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout) {
1153
- CURB_IMMED_SETTER(ruby_curl_easy, timeout, 0);
1218
+ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
1219
+ ruby_curl_easy *rbce;
1220
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1221
+
1222
+ if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
1223
+ rbce->timeout_ms = 0;
1224
+ } else {
1225
+ rbce->timeout_ms = (unsigned long)(NUM2DBL(timeout_s) * 1000);
1226
+ }
1227
+
1228
+ return DBL2NUM(rbce->timeout_ms / 1000.0);
1154
1229
  }
1155
1230
 
1156
1231
  /*
1157
1232
  * call-seq:
1158
- * easy.timeout => fixnum or nil
1233
+ * easy.timeout => numeric
1159
1234
  *
1160
1235
  * Obtain the maximum time in seconds that you allow the libcurl transfer
1161
1236
  * operation to take.
1237
+ *
1238
+ * Uses timeout_ms internally instead of timeout.
1239
+ *
1162
1240
  */
1163
- static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1164
- CURB_IMMED_GETTER(ruby_curl_easy, timeout, 0);
1241
+ static VALUE ruby_curl_easy_timeout_get(VALUE self) {
1242
+ ruby_curl_easy *rbce;
1243
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1244
+ return DBL2NUM(rbce->timeout_ms / 1000.0);
1165
1245
  }
1166
1246
 
1167
1247
  /*
@@ -1177,7 +1257,16 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1177
1257
  * on the system's internal timeouts).
1178
1258
  */
1179
1259
  static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
1180
- CURB_IMMED_SETTER(ruby_curl_easy, timeout_ms, 0);
1260
+ ruby_curl_easy *rbce;
1261
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1262
+
1263
+ if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
1264
+ rbce->timeout_ms = 0;
1265
+ } else {
1266
+ rbce->timeout_ms = NUM2ULONG(timeout_ms);
1267
+ }
1268
+
1269
+ return ULONG2NUM(rbce->timeout_ms);
1181
1270
  }
1182
1271
 
1183
1272
  /*
@@ -1187,8 +1276,10 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
1187
1276
  * Obtain the maximum time in milliseconds that you allow the libcurl transfer
1188
1277
  * operation to take.
1189
1278
  */
1190
- static VALUE ruby_curl_easy_timeout_ms_get(VALUE self, VALUE timeout_ms) {
1191
- CURB_IMMED_GETTER(ruby_curl_easy, timeout_ms, 0);
1279
+ static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
1280
+ ruby_curl_easy *rbce;
1281
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1282
+ return LONG2NUM(rbce->timeout_ms);
1192
1283
  }
1193
1284
 
1194
1285
  /*
@@ -1338,6 +1429,46 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
1338
1429
  CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
1339
1430
  }
1340
1431
 
1432
+ /*
1433
+ * call-seq:
1434
+ * easy.max_send_speed_large = fixnum or nil => fixnum or nil
1435
+ *
1436
+ * Set the maximal sending transfer speed (in bytes per second)
1437
+ */
1438
+ static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_speed_large) {
1439
+ CURB_IMMED_SETTER(ruby_curl_easy, max_send_speed_large, 0);
1440
+ }
1441
+
1442
+ /*
1443
+ * call-seq:
1444
+ * easy.max_send_speed_large = fixnum or nil => fixnum or nil
1445
+ *
1446
+ * Get the maximal sending transfer speed (in bytes per second)
1447
+ */
1448
+ static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self, VALUE max_send_speed_large) {
1449
+ CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
1450
+ }
1451
+
1452
+ /*
1453
+ * call-seq:
1454
+ * easy.max_recv_speed_large = fixnum or nil => fixnum or nil
1455
+ *
1456
+ * Set the maximal receiving transfer speed (in bytes per second)
1457
+ */
1458
+ static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_speed_large) {
1459
+ CURB_IMMED_SETTER(ruby_curl_easy, max_recv_speed_large, 0);
1460
+ }
1461
+
1462
+ /*
1463
+ * call-seq:
1464
+ * easy.max_recv_speed_large = fixnum or nil => fixnum or nil
1465
+ *
1466
+ * Get the maximal receiving transfer speed (in bytes per second)
1467
+ */
1468
+ static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self, VALUE max_recv_speed_large) {
1469
+ CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
1470
+ }
1471
+
1341
1472
  /*
1342
1473
  * call-seq:
1343
1474
  * easy.username = string => string
@@ -2012,6 +2143,38 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
2012
2143
  return header_str;
2013
2144
  }
2014
2145
 
2146
+ /***********************************************
2147
+ * This is an rb_iterate callback used to set up http proxy headers.
2148
+ */
2149
+ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
2150
+ struct curl_slist **list;
2151
+ VALUE proxy_header_str = Qnil;
2152
+
2153
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2154
+
2155
+ //rb_p(proxy_header);
2156
+
2157
+ if (rb_type(proxy_header) == T_ARRAY) {
2158
+ // we're processing a hash, proxy header is [name, val]
2159
+ VALUE name, value;
2160
+
2161
+ name = rb_obj_as_string(rb_ary_entry(proxy_header, 0));
2162
+ value = rb_obj_as_string(rb_ary_entry(proxy_header, 1));
2163
+
2164
+ // This is a bit inefficient, but we don't want to be modifying
2165
+ // the actual values in the original hash.
2166
+ proxy_header_str = rb_str_plus(name, rb_str_new2(": "));
2167
+ proxy_header_str = rb_str_plus(proxy_header_str, value);
2168
+ } else {
2169
+ proxy_header_str = rb_obj_as_string(proxy_header);
2170
+ }
2171
+
2172
+ //rb_p(header_str);
2173
+
2174
+ *list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
2175
+ return proxy_header_str;
2176
+ }
2177
+
2015
2178
  /***********************************************
2016
2179
  * This is an rb_iterate callback used to set up ftp commands.
2017
2180
  */
@@ -2051,6 +2214,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2051
2214
  CURL *curl;
2052
2215
  VALUE url, _url = rb_easy_get("url");
2053
2216
  struct curl_slist **hdrs = &(rbce->curl_headers);
2217
+ struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
2054
2218
  struct curl_slist **cmds = &(rbce->curl_ftp_commands);
2055
2219
  struct curl_slist **rslv = &(rbce->curl_resolve);
2056
2220
 
@@ -2061,7 +2225,6 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2061
2225
  }
2062
2226
 
2063
2227
  url = rb_check_string_type(_url);
2064
-
2065
2228
  curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
2066
2229
 
2067
2230
  // network stuff and auth
@@ -2174,15 +2337,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2174
2337
 
2175
2338
  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
2176
2339
 
2177
- /* timeouts override each other we cannot blindly set timeout and timeout_ms */
2178
- if (rbce->timeout && rbce->timeout > 0) {
2179
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
2180
- }
2181
- if (rbce->timeout_ms && rbce->timeout_ms > 0) {
2182
- curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
2183
- }
2340
+ #if HAVE_CURLOPT_TIMEOUT_MS
2341
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
2342
+ #endif
2343
+
2184
2344
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
2345
+ #if HAVE_CURLOPT_CONNECTTIMEOUT_MS
2185
2346
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
2347
+ #endif
2186
2348
  curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
2187
2349
 
2188
2350
  curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
@@ -2201,6 +2363,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2201
2363
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
2202
2364
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
2203
2365
 
2366
+ curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, rbce->max_recv_speed_large);
2367
+ curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, rbce->max_send_speed_large);
2368
+
2204
2369
  // Set up localport / proxy port
2205
2370
  // FIXME these won't get returned to default if they're unset Ruby
2206
2371
  if (rbce->proxy_port > 0) {
@@ -2334,6 +2499,25 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2334
2499
  }
2335
2500
  }
2336
2501
 
2502
+ #if HAVE_CURLOPT_PROXYHEADER
2503
+ /* Setup HTTP proxy headers if necessary */
2504
+ curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
2505
+
2506
+ if (!rb_easy_nil("proxy_headers")) {
2507
+ if (rb_easy_type_check("proxy_headers", T_ARRAY) || rb_easy_type_check("proxy_headers", T_HASH)) {
2508
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, phdrs);
2509
+ rb_iterate(rb_each, rb_easy_get("proxy_headers"), cb_each_http_proxy_header, wrap);
2510
+ } else {
2511
+ VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
2512
+ *phdrs = curl_slist_append(*hdrs, StringValuePtr(proxy_headers_str));
2513
+ }
2514
+
2515
+ if (*phdrs) {
2516
+ curl_easy_setopt(curl, CURLOPT_PROXYHEADER, *phdrs);
2517
+ }
2518
+ }
2519
+ #endif
2520
+
2337
2521
  /* Setup FTP commands if necessary */
2338
2522
  if (!rb_easy_nil("ftp_commands")) {
2339
2523
  if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
@@ -2346,6 +2530,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2346
2530
  }
2347
2531
  }
2348
2532
 
2533
+ #if HAVE_CURLOPT_RESOLVE
2349
2534
  /* Setup resolve list if necessary */
2350
2535
  if (!rb_easy_nil("resolve")) {
2351
2536
  if (rb_easy_type_check("resolve", T_ARRAY)) {
@@ -2357,6 +2542,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2357
2542
  curl_easy_setopt(curl, CURLOPT_RESOLVE, *rslv);
2358
2543
  }
2359
2544
  }
2545
+ #endif
2360
2546
 
2361
2547
  return Qnil;
2362
2548
  }
@@ -2364,7 +2550,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2364
2550
  *
2365
2551
  * Clean up a connection
2366
2552
  *
2367
- * Always returns Qtrue.
2553
+ * Always returns Qnil.
2368
2554
  */
2369
2555
  VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2370
2556
 
@@ -2378,6 +2564,11 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2378
2564
  rbce->curl_headers = NULL;
2379
2565
  }
2380
2566
 
2567
+ if (rbce->curl_proxy_headers) {
2568
+ curl_slist_free_all(rbce->curl_proxy_headers);
2569
+ rbce->curl_proxy_headers = NULL;
2570
+ }
2571
+
2381
2572
  ftp_commands = rbce->curl_ftp_commands;
2382
2573
  if (ftp_commands) {
2383
2574
  curl_slist_free_all(ftp_commands);
@@ -2399,6 +2590,9 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2399
2590
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
2400
2591
  }
2401
2592
 
2593
+ // set values on cleanup to nil
2594
+ rb_easy_del("multi");
2595
+
2402
2596
  return Qnil;
2403
2597
  }
2404
2598
 
@@ -3263,6 +3457,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
3263
3457
  static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3264
3458
  ruby_curl_easy *rbce;
3265
3459
  long option = NUM2LONG(opt);
3460
+ rb_io_t *open_f_ptr;
3266
3461
 
3267
3462
  Data_Get_Struct(self, ruby_curl_easy, rbce);
3268
3463
 
@@ -3383,6 +3578,34 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3383
3578
  curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
3384
3579
  } break;
3385
3580
  #endif
3581
+ #if HAVE_CURLOPT_MAXFILESIZE
3582
+ case CURLOPT_MAXFILESIZE:
3583
+ curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
3584
+ break;
3585
+ #endif
3586
+ #if HAVE_CURLOPT_TCP_KEEPALIVE
3587
+ case CURLOPT_TCP_KEEPALIVE:
3588
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
3589
+ break;
3590
+ case CURLOPT_TCP_KEEPIDLE:
3591
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
3592
+ break;
3593
+ case CURLOPT_TCP_KEEPINTVL:
3594
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
3595
+ break;
3596
+ #endif
3597
+ #if HAVE_CURLOPT_HAPROXYPROTOCOL
3598
+ case CURLOPT_HAPROXYPROTOCOL:
3599
+ curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
3600
+ break;
3601
+ #endif
3602
+ case CURLOPT_STDERR:
3603
+ // libcurl requires raw FILE pointer and this should be IO object in Ruby.
3604
+ // Tempfile or StringIO won't work.
3605
+ Check_Type(val, T_FILE);
3606
+ GetOpenFile(val, open_f_ptr);
3607
+ curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
3608
+ break;
3386
3609
  default:
3387
3610
  rb_raise(rb_eTypeError, "Curb unsupported option");
3388
3611
  }
@@ -3518,6 +3741,10 @@ void init_curb_easy() {
3518
3741
  /* Attributes for config next perform */
3519
3742
  rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
3520
3743
  rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
3744
+
3745
+ rb_define_method(cCurlEasy, "proxy_headers=", ruby_curl_easy_proxy_headers_set, 1);
3746
+ rb_define_method(cCurlEasy, "proxy_headers", ruby_curl_easy_proxy_headers_get, 0);
3747
+
3521
3748
  rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
3522
3749
  rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
3523
3750
  rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
@@ -3577,6 +3804,10 @@ void init_curb_easy() {
3577
3804
  rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
3578
3805
  rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
3579
3806
  rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
3807
+ rb_define_method(cCurlEasy, "max_send_speed_large=", ruby_curl_easy_max_send_speed_large_set, 1);
3808
+ rb_define_method(cCurlEasy, "max_send_speed_large", ruby_curl_easy_max_send_speed_large_get, 0);
3809
+ rb_define_method(cCurlEasy, "max_recv_speed_large=", ruby_curl_easy_max_recv_speed_large_set, 1);
3810
+ rb_define_method(cCurlEasy, "max_recv_speed_large", ruby_curl_easy_max_recv_speed_large_get, 0);
3580
3811
  rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
3581
3812
  rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
3582
3813
  rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);