curb 0.9.6 → 0.9.11

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
- 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);