curb 0.9.2 → 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.
data/ext/curb_easy.c CHANGED
@@ -25,12 +25,18 @@ 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
 
31
37
  static VALUE callback_exception(VALUE unused) {
32
38
  return Qfalse;
33
- }
39
+ }
34
40
 
35
41
  /* These handle both body and header data */
36
42
  static size_t default_data_handler(char *stream,
@@ -223,12 +229,31 @@ 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
  }
229
239
 
240
+ if (rbce->curl_resolve) {
241
+ curl_slist_free_all(rbce->curl_resolve);
242
+ }
243
+
230
244
  if (rbce->curl) {
245
+ /* disable any progress or debug events */
246
+ curl_easy_setopt(rbce->curl, CURLOPT_WRITEFUNCTION, NULL);
247
+ curl_easy_setopt(rbce->curl, CURLOPT_WRITEDATA, NULL);
248
+ curl_easy_setopt(rbce->curl, CURLOPT_HEADERFUNCTION, NULL);
249
+ curl_easy_setopt(rbce->curl, CURLOPT_HEADERDATA, NULL);
250
+ curl_easy_setopt(rbce->curl, CURLOPT_DEBUGFUNCTION, NULL);
251
+ curl_easy_setopt(rbce->curl, CURLOPT_DEBUGDATA, NULL);
252
+ curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 0);
253
+ curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
254
+ curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
231
255
  curl_easy_cleanup(rbce->curl);
256
+ rbce->curl = NULL;
232
257
  }
233
258
  }
234
259
 
@@ -244,7 +269,9 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
244
269
  rbce->opts = rb_hash_new();
245
270
 
246
271
  rbce->curl_headers = NULL;
272
+ rbce->curl_proxy_headers = NULL;
247
273
  rbce->curl_ftp_commands = NULL;
274
+ rbce->curl_resolve = NULL;
248
275
 
249
276
  /* various-typed opts */
250
277
  rbce->local_port = 0;
@@ -262,6 +289,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
262
289
  rbce->ftp_response_timeout = 0;
263
290
  rbce->low_speed_limit = 0;
264
291
  rbce->low_speed_time = 0;
292
+ rbce->max_send_speed_large = 0;
293
+ rbce->max_recv_speed_large = 0;
265
294
  rbce->ssl_version = -1;
266
295
  rbce->use_ssl = -1;
267
296
  rbce->ftp_filemethod = -1;
@@ -283,25 +312,37 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
283
312
  rbce->callback_active = 0;
284
313
  }
285
314
 
315
+ /*
316
+ * Allocate space for a Curl::Easy instance.
317
+ */
318
+ static VALUE ruby_curl_easy_allocate(VALUE klass) {
319
+ ruby_curl_easy *rbce;
320
+ rbce = ALLOC(ruby_curl_easy);
321
+ rbce->curl = NULL;
322
+ rbce->opts = Qnil;
323
+ rbce->multi = Qnil;
324
+ ruby_curl_easy_zero(rbce);
325
+ return Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
326
+ }
327
+
286
328
  /*
287
329
  * call-seq:
288
330
  * Curl::Easy.new => #<Curl::Easy...>
289
331
  * Curl::Easy.new(url = nil) => #<Curl::Easy...>
290
332
  * Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
291
333
  *
292
- * Create a new Curl::Easy instance, optionally supplying the URL.
334
+ * Initialize a new Curl::Easy instance, optionally supplying the URL.
293
335
  * The block form allows further configuration to be supplied before
294
336
  * the instance is returned.
295
337
  */
296
- static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
338
+ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
297
339
  CURLcode ecode;
298
340
  VALUE url, blk;
299
- VALUE new_curl;
300
341
  ruby_curl_easy *rbce;
301
342
 
302
343
  rb_scan_args(argc, argv, "01&", &url, &blk);
303
344
 
304
- rbce = ALLOC(ruby_curl_easy);
345
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
305
346
 
306
347
  /* handler */
307
348
  rbce->curl = curl_easy_init();
@@ -309,8 +350,6 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
309
350
  rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
310
351
  }
311
352
 
312
- new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
313
-
314
353
  rbce->multi = Qnil;
315
354
  rbce->opts = Qnil;
316
355
 
@@ -318,17 +357,18 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
318
357
 
319
358
  rb_easy_set("url", url);
320
359
 
321
- /* set the new_curl pointer to the curl handle */
322
- ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)new_curl);
360
+
361
+ /* set the pointer to the curl handle */
362
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
323
363
  if (ecode != CURLE_OK) {
324
364
  raise_curl_easy_error_exception(ecode);
325
365
  }
326
366
 
327
367
  if (blk != Qnil) {
328
- rb_funcall(blk, idCall, 1, new_curl);
368
+ rb_funcall(blk, idCall, 1, self);
329
369
  }
330
370
 
331
- return new_curl;
371
+ return self;
332
372
  }
333
373
 
334
374
  /*
@@ -348,7 +388,9 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
348
388
  memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
349
389
  newrbce->curl = curl_easy_duphandle(rbce->curl);
350
390
  newrbce->curl_headers = NULL;
391
+ newrbce->curl_proxy_headers = NULL;
351
392
  newrbce->curl_ftp_commands = NULL;
393
+ newrbce->curl_resolve = NULL;
352
394
 
353
395
  return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
354
396
  }
@@ -358,7 +400,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
358
400
  * easy.close => nil
359
401
  *
360
402
  * Close the Curl::Easy instance. Any open connections are closed
361
- * The easy handle is reinitialized. If a previous multi handle was
403
+ * The easy handle is reinitialized. If a previous multi handle was
362
404
  * open it is set to nil and will be cleared after a GC.
363
405
  */
364
406
  static VALUE ruby_curl_easy_close(VALUE self) {
@@ -431,6 +473,12 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
431
473
  rbce->curl_headers = NULL;
432
474
  }
433
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
+
434
482
  return opts_dup;
435
483
  }
436
484
 
@@ -483,6 +531,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
483
531
  CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
484
532
  }
485
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
+
486
538
  /*
487
539
  * call-seq:
488
540
  * easy.headers => Hash, Array or Str
@@ -493,11 +545,46 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
493
545
  ruby_curl_easy *rbce;
494
546
  VALUE headers;
495
547
  Data_Get_Struct(self, ruby_curl_easy, rbce);
496
- headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
548
+ headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
497
549
  if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
498
550
  return headers;
499
551
  }
500
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
+
501
588
  /*
502
589
  * call-seq:
503
590
  * easy.interface => string
@@ -705,29 +792,29 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
705
792
  /*
706
793
  * call-seq:
707
794
  * easy.post_body = "some=form%20data&to=send" => string or nil
708
- *
795
+ *
709
796
  * Sets the POST body of this Curl::Easy instance. This is expected to be
710
797
  * URL encoded; no additional processing or encoding is done on the string.
711
798
  * The content-type header will be set to application/x-www-form-urlencoded.
712
- *
799
+ *
713
800
  * This is handy if you want to perform a POST against a Curl::Multi instance.
714
801
  */
715
802
  static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
716
803
  ruby_curl_easy *rbce;
717
804
  CURL *curl;
718
-
805
+
719
806
  char *data;
720
807
  long len;
721
808
 
722
809
  Data_Get_Struct(self, ruby_curl_easy, rbce);
723
-
810
+
724
811
  curl = rbce->curl;
725
-
812
+
726
813
  if ( post_body == Qnil ) {
727
814
  rb_easy_del("postdata_buffer");
728
815
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
729
-
730
- } else {
816
+
817
+ } else {
731
818
  if (rb_type(post_body) == T_STRING) {
732
819
  data = StringValuePtr(post_body);
733
820
  len = RSTRING_LEN(post_body);
@@ -740,19 +827,19 @@ static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
740
827
  else {
741
828
  rb_raise(rb_eRuntimeError, "post data must respond_to .to_s");
742
829
  }
743
-
744
- // Store the string, since it has to hang around for the duration of the
830
+
831
+ // Store the string, since it has to hang around for the duration of the
745
832
  // request. See CURLOPT_POSTFIELDS in the libcurl docs.
746
833
  //rbce->postdata_buffer = post_body;
747
834
  rb_easy_set("postdata_buffer", post_body);
748
-
835
+
749
836
  curl_easy_setopt(curl, CURLOPT_POST, 1);
750
837
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
751
838
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
752
-
839
+
753
840
  return post_body;
754
841
  }
755
-
842
+
756
843
  return Qnil;
757
844
  }
758
845
 
@@ -769,7 +856,7 @@ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
769
856
  /*
770
857
  * call-seq:
771
858
  * easy.put_data = data => ""
772
- *
859
+ *
773
860
  * Points this Curl::Easy instance to data to be uploaded via PUT. This
774
861
  * sets the request to a PUT type request - useful if you want to PUT via
775
862
  * a multi handle.
@@ -801,7 +888,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
801
888
  curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
802
889
  #endif
803
890
 
804
- /*
891
+ /*
805
892
  * we need to set specific headers for the PUT to work... so
806
893
  * convert the internal headers structure to a HASH if one is set
807
894
  */
@@ -815,7 +902,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
815
902
  if (NIL_P(data)) { return data; }
816
903
 
817
904
  headers = rb_easy_get("headers");
818
- if( headers == Qnil ) {
905
+ if( headers == Qnil ) {
819
906
  headers = rb_hash_new();
820
907
  }
821
908
 
@@ -870,6 +957,25 @@ static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
870
957
  CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_commands);
871
958
  }
872
959
 
960
+ /*
961
+ * call-seq:
962
+ * easy.resolve = [ "example.com:80:127.0.0.1" ] => [ "example.com:80:127.0.0.1" ]
963
+ *
964
+ * Set the resolve list to statically resolve hostnames to IP addresses,
965
+ * bypassing DNS for matching hostname/port combinations.
966
+ */
967
+ static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
968
+ CURB_OBJECT_HSETTER(ruby_curl_easy, resolve);
969
+ }
970
+
971
+ /*
972
+ * call-seq
973
+ * easy.resolve => array or nil
974
+ */
975
+ static VALUE ruby_curl_easy_resolve_get(VALUE self) {
976
+ CURB_OBJECT_HGETTER(ruby_curl_easy, resolve);
977
+ }
978
+
873
979
  /* ================== IMMED ATTRS ==================*/
874
980
 
875
981
  /*
@@ -980,7 +1086,7 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
980
1086
  (!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
981
1087
  (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
982
1088
  (!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
983
- #else
1089
+ #else
984
1090
  #define CURL_HTTPAUTH_STR_TO_NUM(node) \
985
1091
  (!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
986
1092
  (!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
@@ -1012,7 +1118,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
1012
1118
 
1013
1119
  if (len == 1 && (rb_ary_entry(args_ary,0) == Qnil || TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM ||
1014
1120
  TYPE(rb_ary_entry(args_ary,0)) == T_BIGNUM)) {
1015
- if (rb_ary_entry(args_ary,0) == Qnil) {
1121
+ if (rb_ary_entry(args_ary,0) == Qnil) {
1016
1122
  rbce->http_auth_types = 0;
1017
1123
  }
1018
1124
  else {
@@ -1094,7 +1200,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1094
1200
 
1095
1201
  /*
1096
1202
  * call-seq:
1097
- * easy.timeout = fixnum or nil => fixnum or nil
1203
+ * easy.timeout = float, fixnum or nil => numeric
1098
1204
  *
1099
1205
  * Set the maximum time in seconds that you allow the libcurl transfer
1100
1206
  * operation to take. Normally, name lookups can take a considerable time
@@ -1103,20 +1209,39 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1103
1209
  *
1104
1210
  * Set to nil (or zero) to disable timeout (it will then only timeout
1105
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
+ *
1106
1217
  */
1107
- static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout) {
1108
- 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);
1109
1229
  }
1110
1230
 
1111
1231
  /*
1112
1232
  * call-seq:
1113
- * easy.timeout => fixnum or nil
1233
+ * easy.timeout => numeric
1114
1234
  *
1115
1235
  * Obtain the maximum time in seconds that you allow the libcurl transfer
1116
1236
  * operation to take.
1237
+ *
1238
+ * Uses timeout_ms internally instead of timeout.
1239
+ *
1117
1240
  */
1118
- static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1119
- 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);
1120
1245
  }
1121
1246
 
1122
1247
  /*
@@ -1132,7 +1257,16 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1132
1257
  * on the system's internal timeouts).
1133
1258
  */
1134
1259
  static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
1135
- 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);
1136
1270
  }
1137
1271
 
1138
1272
  /*
@@ -1142,8 +1276,10 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
1142
1276
  * Obtain the maximum time in milliseconds that you allow the libcurl transfer
1143
1277
  * operation to take.
1144
1278
  */
1145
- static VALUE ruby_curl_easy_timeout_ms_get(VALUE self, VALUE timeout_ms) {
1146
- 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);
1147
1283
  }
1148
1284
 
1149
1285
  /*
@@ -1293,6 +1429,46 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
1293
1429
  CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
1294
1430
  }
1295
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
+
1296
1472
  /*
1297
1473
  * call-seq:
1298
1474
  * easy.username = string => string
@@ -1310,7 +1486,7 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
1310
1486
  /*
1311
1487
  * call-seq:
1312
1488
  * easy.username => string
1313
- *
1489
+ *
1314
1490
  * Get the current username
1315
1491
  */
1316
1492
  static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
@@ -1338,7 +1514,7 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
1338
1514
  /*
1339
1515
  * call-seq:
1340
1516
  * easy.password => string
1341
- *
1517
+ *
1342
1518
  * Get the current password
1343
1519
  */
1344
1520
  static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
@@ -1381,7 +1557,7 @@ static VALUE ruby_curl_easy_ssl_version_get(VALUE self, VALUE ssl_version) {
1381
1557
  /*
1382
1558
  * call-seq:
1383
1559
  * easy.use_ssl = value => fixnum or nil
1384
- *
1560
+ *
1385
1561
  * Ensure libcurl uses SSL for FTP connections. Valid options are Curl::CURL_USESSL_NONE,
1386
1562
  * Curl::CURL_USESSL_TRY, Curl::CURL_USESSL_CONTROL, and Curl::CURL_USESSL_ALL.
1387
1563
  */
@@ -1838,7 +2014,7 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1838
2014
  * To remove a previously-supplied handler, call this method with no attached
1839
2015
  * block.
1840
2016
  *
1841
- * The +on_missing+ handler is called when request is finished with a
2017
+ * The +on_missing+ handler is called when request is finished with a
1842
2018
  * status of 40x
1843
2019
  */
1844
2020
  static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
@@ -1853,7 +2029,7 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
1853
2029
  * To remove a previously-supplied handler, call this method with no attached
1854
2030
  * block.
1855
2031
  *
1856
- * The +on_redirect+ handler is called when request is finished with a
2032
+ * The +on_redirect+ handler is called when request is finished with a
1857
2033
  * status of 30x
1858
2034
  */
1859
2035
  static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
@@ -1967,6 +2143,38 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
1967
2143
  return header_str;
1968
2144
  }
1969
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
+
1970
2178
  /***********************************************
1971
2179
  * This is an rb_iterate callback used to set up ftp commands.
1972
2180
  */
@@ -1981,6 +2189,20 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
1981
2189
  return ftp_command_string;
1982
2190
  }
1983
2191
 
2192
+ /***********************************************
2193
+ * This is an rb_iterate callback used to set up the resolve list.
2194
+ */
2195
+ static VALUE cb_each_resolve(VALUE resolve, VALUE wrap) {
2196
+ struct curl_slist **list;
2197
+ VALUE resolve_string;
2198
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2199
+
2200
+ resolve_string = rb_obj_as_string(resolve);
2201
+ *list = curl_slist_append(*list, StringValuePtr(resolve));
2202
+
2203
+ return resolve_string;
2204
+ }
2205
+
1984
2206
  /***********************************************
1985
2207
  *
1986
2208
  * Setup a connection
@@ -1992,7 +2214,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
1992
2214
  CURL *curl;
1993
2215
  VALUE url, _url = rb_easy_get("url");
1994
2216
  struct curl_slist **hdrs = &(rbce->curl_headers);
2217
+ struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
1995
2218
  struct curl_slist **cmds = &(rbce->curl_ftp_commands);
2219
+ struct curl_slist **rslv = &(rbce->curl_resolve);
1996
2220
 
1997
2221
  curl = rbce->curl;
1998
2222
 
@@ -2001,7 +2225,6 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2001
2225
  }
2002
2226
 
2003
2227
  url = rb_check_string_type(_url);
2004
-
2005
2228
  curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
2006
2229
 
2007
2230
  // network stuff and auth
@@ -2114,15 +2337,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2114
2337
 
2115
2338
  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
2116
2339
 
2117
- /* timeouts override each other we cannot blindly set timeout and timeout_ms */
2118
- if (rbce->timeout && rbce->timeout > 0) {
2119
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
2120
- }
2121
- if (rbce->timeout_ms && rbce->timeout_ms > 0) {
2122
- curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
2123
- }
2340
+ #if HAVE_CURLOPT_TIMEOUT_MS
2341
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
2342
+ #endif
2343
+
2124
2344
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
2345
+ #if HAVE_CURLOPT_CONNECTTIMEOUT_MS
2125
2346
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
2347
+ #endif
2126
2348
  curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
2127
2349
 
2128
2350
  curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
@@ -2141,6 +2363,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2141
2363
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
2142
2364
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
2143
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
+
2144
2369
  // Set up localport / proxy port
2145
2370
  // FIXME these won't get returned to default if they're unset Ruby
2146
2371
  if (rbce->proxy_port > 0) {
@@ -2247,7 +2472,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2247
2472
  rb_warn("libcurl is not configured with SSL support");
2248
2473
  }
2249
2474
  #endif
2250
-
2475
+
2251
2476
  if (rbce->ftp_filemethod > 0) {
2252
2477
  curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
2253
2478
  }
@@ -2274,6 +2499,25 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2274
2499
  }
2275
2500
  }
2276
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
+
2277
2521
  /* Setup FTP commands if necessary */
2278
2522
  if (!rb_easy_nil("ftp_commands")) {
2279
2523
  if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
@@ -2286,18 +2530,33 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2286
2530
  }
2287
2531
  }
2288
2532
 
2533
+ #if HAVE_CURLOPT_RESOLVE
2534
+ /* Setup resolve list if necessary */
2535
+ if (!rb_easy_nil("resolve")) {
2536
+ if (rb_easy_type_check("resolve", T_ARRAY)) {
2537
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, rslv);
2538
+ rb_iterate(rb_each, rb_easy_get("resolve"), cb_each_resolve, wrap);
2539
+ }
2540
+
2541
+ if (*rslv) {
2542
+ curl_easy_setopt(curl, CURLOPT_RESOLVE, *rslv);
2543
+ }
2544
+ }
2545
+ #endif
2546
+
2289
2547
  return Qnil;
2290
2548
  }
2291
2549
  /***********************************************
2292
2550
  *
2293
2551
  * Clean up a connection
2294
2552
  *
2295
- * Always returns Qtrue.
2553
+ * Always returns Qnil.
2296
2554
  */
2297
2555
  VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2298
2556
 
2299
2557
  CURL *curl = rbce->curl;
2300
2558
  struct curl_slist *ftp_commands;
2559
+ struct curl_slist *resolve;
2301
2560
 
2302
2561
  /* Free everything up */
2303
2562
  if (rbce->curl_headers) {
@@ -2305,12 +2564,23 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2305
2564
  rbce->curl_headers = NULL;
2306
2565
  }
2307
2566
 
2567
+ if (rbce->curl_proxy_headers) {
2568
+ curl_slist_free_all(rbce->curl_proxy_headers);
2569
+ rbce->curl_proxy_headers = NULL;
2570
+ }
2571
+
2308
2572
  ftp_commands = rbce->curl_ftp_commands;
2309
2573
  if (ftp_commands) {
2310
2574
  curl_slist_free_all(ftp_commands);
2311
2575
  rbce->curl_ftp_commands = NULL;
2312
2576
  }
2313
2577
 
2578
+ resolve = rbce->curl_resolve;
2579
+ if (resolve) {
2580
+ curl_slist_free_all(resolve);
2581
+ rbce->curl_resolve = NULL;
2582
+ }
2583
+
2314
2584
  /* clean up a PUT request's curl options. */
2315
2585
  if (!rb_easy_nil("upload")) {
2316
2586
  rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
@@ -2320,6 +2590,9 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2320
2590
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
2321
2591
  }
2322
2592
 
2593
+ // set values on cleanup to nil
2594
+ rb_easy_del("multi");
2595
+
2323
2596
  return Qnil;
2324
2597
  }
2325
2598
 
@@ -2564,7 +2837,7 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
2564
2837
  static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
2565
2838
  ruby_curl_easy *rbce;
2566
2839
  char* ip;
2567
-
2840
+
2568
2841
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2569
2842
  curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
2570
2843
 
@@ -2789,7 +3062,7 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
2789
3062
  * call-seq:
2790
3063
  * easy.redirect_url => "http://some.url" or nil
2791
3064
  *
2792
- * Retrieve the URL a redirect would take you to if you
3065
+ * Retrieve the URL a redirect would take you to if you
2793
3066
  * would enable CURLOPT_FOLLOWLOCATION.
2794
3067
  *
2795
3068
  * Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
@@ -3072,12 +3345,40 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
3072
3345
  }
3073
3346
 
3074
3347
 
3075
- /* TODO this needs to be implemented.
3348
+ /*
3349
+ * call-seq:
3350
+ * easy.cookielist => array
3351
+ *
3352
+ * Retrieves the cookies curl knows in an array of strings.
3353
+ * Returned strings are in Netscape cookiejar format or in Set-Cookie format.
3354
+ *
3355
+ * See also option CURLINFO_COOKIELIST of curl_easy_getopt(3) to see how libcurl behaves.
3356
+ *
3357
+ * (requires libcurl 7.14.1 or higher, otherwise -1 is always returned).
3358
+ */
3359
+ static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
3360
+ #ifdef HAVE_CURLINFO_COOKIELIST
3361
+ ruby_curl_easy *rbce;
3362
+ struct curl_slist *cookies;
3363
+ struct curl_slist *cookie;
3364
+ VALUE rb_cookies;
3365
+
3366
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3367
+ curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
3368
+ if (!cookies)
3369
+ return Qnil;
3370
+ rb_cookies = rb_ary_new();
3371
+ for (cookie = cookies; cookie; cookie = cookie->next)
3372
+ rb_ary_push(rb_cookies, rb_str_new2(cookie->data));
3373
+ curl_slist_free_all(cookies);
3374
+ return rb_cookies;
3076
3375
 
3077
- CURLINFO_COOKIELIST
3376
+ #else
3377
+ rb_warn("Installed libcurl is too old to support cookielist");
3378
+ return INT2FIX(-1);
3379
+ #endif
3380
+ }
3078
3381
 
3079
- Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all cookies cURL knows (expired ones, too). Don't forget to curl_slist_free_all(3) the list after it has been used. If there are no cookies (cookies for the handle have not been enabled or simply none have been received) 'struct curl_slist *' will be set to point to NULL. (Added in 7.14.1)
3080
- */
3081
3382
 
3082
3383
  /* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
3083
3384
  * return an open Socket or something.
@@ -3156,6 +3457,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
3156
3457
  static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3157
3458
  ruby_curl_easy *rbce;
3158
3459
  long option = NUM2LONG(opt);
3460
+ rb_io_t *open_f_ptr;
3159
3461
 
3160
3462
  Data_Get_Struct(self, ruby_curl_easy, rbce);
3161
3463
 
@@ -3193,6 +3495,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3193
3495
  case CURLOPT_HEADER:
3194
3496
  case CURLOPT_NOPROGRESS:
3195
3497
  case CURLOPT_NOSIGNAL:
3498
+ #if HAVE_CURLOPT_PATH_AS_IS
3499
+ case CURLOPT_PATH_AS_IS:
3500
+ #endif
3501
+ #if HAVE_CURLOPT_PIPEWAIT
3502
+ case CURLOPT_PIPEWAIT:
3503
+ #endif
3196
3504
  case CURLOPT_HTTPGET:
3197
3505
  case CURLOPT_NOBODY: {
3198
3506
  int type = rb_type(val);
@@ -3260,6 +3568,44 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3260
3568
  curl_easy_setopt(rbce->curl, CURLOPT_UNIX_SOCKET_PATH, StringValueCStr(val));
3261
3569
  } break;
3262
3570
  #endif
3571
+ #if HAVE_CURLOPT_MAX_SEND_SPEED_LARGE
3572
+ case CURLOPT_MAX_SEND_SPEED_LARGE: {
3573
+ curl_easy_setopt(rbce->curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) NUM2LL(val));
3574
+ } break;
3575
+ #endif
3576
+ #if HAVE_CURLOPT_MAX_RECV_SPEED_LARGE
3577
+ case CURLOPT_MAX_RECV_SPEED_LARGE: {
3578
+ curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
3579
+ } break;
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;
3263
3609
  default:
3264
3610
  rb_raise(rb_eTypeError, "Curb unsupported option");
3265
3611
  }
@@ -3386,12 +3732,19 @@ void init_curb_easy() {
3386
3732
  cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
3387
3733
 
3388
3734
  /* Class methods */
3389
- rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
3735
+ rb_define_alloc_func(cCurlEasy, ruby_curl_easy_allocate);
3390
3736
  rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
3391
3737
 
3738
+ /* Initialize method */
3739
+ rb_define_method(cCurlEasy, "initialize", ruby_curl_easy_initialize, -1);
3740
+
3392
3741
  /* Attributes for config next perform */
3393
3742
  rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
3394
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
+
3395
3748
  rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
3396
3749
  rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
3397
3750
  rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
@@ -3418,6 +3771,8 @@ void init_curb_easy() {
3418
3771
  rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
3419
3772
  rb_define_method(cCurlEasy, "ftp_commands=", ruby_curl_easy_ftp_commands_set, 1);
3420
3773
  rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
3774
+ rb_define_method(cCurlEasy, "resolve=", ruby_curl_easy_resolve_set, 1);
3775
+ rb_define_method(cCurlEasy, "resolve", ruby_curl_easy_resolve_get, 0);
3421
3776
 
3422
3777
  rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
3423
3778
  rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
@@ -3449,6 +3804,10 @@ void init_curb_easy() {
3449
3804
  rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
3450
3805
  rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
3451
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);
3452
3811
  rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
3453
3812
  rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
3454
3813
  rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
@@ -3536,6 +3895,7 @@ void init_curb_easy() {
3536
3895
  rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
3537
3896
  rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
3538
3897
  rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
3898
+ rb_define_method(cCurlEasy, "cookielist", ruby_curl_easy_cookielist_get, 0);
3539
3899
  rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
3540
3900
 
3541
3901
  rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);