curb 0.9.7 → 1.0.1
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 +5 -5
- data/README.markdown +54 -5
- data/Rakefile +33 -20
- data/ext/banned.h +32 -0
- data/ext/curb.c +170 -8
- data/ext/curb.h +18 -5
- data/ext/curb_easy.c +321 -43
- data/ext/curb_easy.h +6 -0
- data/ext/curb_multi.c +136 -171
- data/ext/curb_multi.h +0 -1
- data/ext/curb_postfield.c +7 -7
- data/ext/extconf.rb +45 -0
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +14 -7
- data/lib/curl/multi.rb +42 -3
- data/lib/curl.rb +12 -3
- data/tests/bug_issue277.rb +32 -0
- data/tests/helper.rb +79 -1
- data/tests/tc_curl_easy.rb +118 -16
- data/tests/tc_curl_maxfilesize.rb +12 -0
- data/tests/tc_curl_multi.rb +109 -5
- data/tests/tc_curl_postfield.rb +29 -29
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/timeout.rb +21 -5
- metadata +14 -8
data/ext/curb_easy.c
CHANGED
@@ -25,6 +25,12 @@ static VALUE rbstrAmp;
|
|
25
25
|
|
26
26
|
VALUE cCurlEasy;
|
27
27
|
|
28
|
+
// for Ruby 1.8
|
29
|
+
#ifndef HAVE_RB_IO_STDIO_FILE
|
30
|
+
static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
31
|
+
return fptr->f;
|
32
|
+
}
|
33
|
+
#endif
|
28
34
|
|
29
35
|
/* ================== CURL HANDLER FUNCS ==============*/
|
30
36
|
|
@@ -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
|
|
@@ -257,7 +268,10 @@ void curl_easy_free(ruby_curl_easy *rbce) {
|
|
257
268
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
258
269
|
rbce->opts = rb_hash_new();
|
259
270
|
|
271
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
272
|
+
|
260
273
|
rbce->curl_headers = NULL;
|
274
|
+
rbce->curl_proxy_headers = NULL;
|
261
275
|
rbce->curl_ftp_commands = NULL;
|
262
276
|
rbce->curl_resolve = NULL;
|
263
277
|
|
@@ -277,6 +291,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
277
291
|
rbce->ftp_response_timeout = 0;
|
278
292
|
rbce->low_speed_limit = 0;
|
279
293
|
rbce->low_speed_time = 0;
|
294
|
+
rbce->max_send_speed_large = 0;
|
295
|
+
rbce->max_recv_speed_large = 0;
|
280
296
|
rbce->ssl_version = -1;
|
281
297
|
rbce->use_ssl = -1;
|
282
298
|
rbce->ftp_filemethod = -1;
|
@@ -313,9 +329,9 @@ static VALUE ruby_curl_easy_allocate(VALUE klass) {
|
|
313
329
|
|
314
330
|
/*
|
315
331
|
* call-seq:
|
316
|
-
* Curl::Easy.new =>
|
317
|
-
* Curl::Easy.new(url = nil) =>
|
318
|
-
* Curl::Easy.new(url = nil) { |self| ... } =>
|
332
|
+
* Curl::Easy.new => #<Curl::Easy...>
|
333
|
+
* Curl::Easy.new(url = nil) => #<Curl::Easy...>
|
334
|
+
* Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
|
319
335
|
*
|
320
336
|
* Initialize a new Curl::Easy instance, optionally supplying the URL.
|
321
337
|
* The block form allows further configuration to be supplied before
|
@@ -341,9 +357,11 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
341
357
|
|
342
358
|
ruby_curl_easy_zero(rbce);
|
343
359
|
|
360
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
361
|
+
|
344
362
|
rb_easy_set("url", url);
|
345
363
|
|
346
|
-
/* set the
|
364
|
+
/* set the pointer to the curl handle */
|
347
365
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
348
366
|
if (ecode != CURLE_OK) {
|
349
367
|
raise_curl_easy_error_exception(ecode);
|
@@ -358,8 +376,8 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
358
376
|
|
359
377
|
/*
|
360
378
|
* call-seq:
|
361
|
-
* easy.clone =>
|
362
|
-
* easy.dup =>
|
379
|
+
* easy.clone => <easy clone>
|
380
|
+
* easy.dup => <easy clone>
|
363
381
|
*
|
364
382
|
* Clone this Curl::Easy instance, creating a new instance.
|
365
383
|
* This method duplicates the underlying CURL* handle.
|
@@ -373,9 +391,12 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
373
391
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
374
392
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
375
393
|
newrbce->curl_headers = NULL;
|
394
|
+
newrbce->curl_proxy_headers = NULL;
|
376
395
|
newrbce->curl_ftp_commands = NULL;
|
377
396
|
newrbce->curl_resolve = NULL;
|
378
397
|
|
398
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
399
|
+
|
379
400
|
return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
|
380
401
|
}
|
381
402
|
|
@@ -445,7 +466,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
445
466
|
curl_easy_reset(rbce->curl);
|
446
467
|
ruby_curl_easy_zero(rbce);
|
447
468
|
|
448
|
-
|
469
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
470
|
+
|
471
|
+
/* reset clobbers the private setting, so reset it to self */
|
449
472
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
450
473
|
if (ecode != CURLE_OK) {
|
451
474
|
raise_curl_easy_error_exception(ecode);
|
@@ -457,6 +480,12 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
457
480
|
rbce->curl_headers = NULL;
|
458
481
|
}
|
459
482
|
|
483
|
+
/* Free everything up */
|
484
|
+
if (rbce->curl_proxy_headers) {
|
485
|
+
curl_slist_free_all(rbce->curl_proxy_headers);
|
486
|
+
rbce->curl_proxy_headers = NULL;
|
487
|
+
}
|
488
|
+
|
460
489
|
return opts_dup;
|
461
490
|
}
|
462
491
|
|
@@ -509,6 +538,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
|
|
509
538
|
CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
|
510
539
|
}
|
511
540
|
|
541
|
+
static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
|
542
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_headers);
|
543
|
+
}
|
544
|
+
|
512
545
|
/*
|
513
546
|
* call-seq:
|
514
547
|
* easy.headers => Hash, Array or Str
|
@@ -524,6 +557,41 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
|
|
524
557
|
return headers;
|
525
558
|
}
|
526
559
|
|
560
|
+
/*
|
561
|
+
* call-seq:
|
562
|
+
* easy.proxy_headers = "Header: val" => "Header: val"
|
563
|
+
* easy.proxy_headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
|
564
|
+
* easy.proxy_headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
|
565
|
+
*
|
566
|
+
*
|
567
|
+
* For example to set a standard or custom header:
|
568
|
+
*
|
569
|
+
* easy.proxy_headers["MyHeader"] = "myval"
|
570
|
+
*
|
571
|
+
* To remove a standard header (this is useful when removing libcurls default
|
572
|
+
* 'Expect: 100-Continue' header when using HTTP form posts):
|
573
|
+
*
|
574
|
+
* easy.proxy_headers["Expect"] = ''
|
575
|
+
*
|
576
|
+
* Anything passed to libcurl as a header will be converted to a string during
|
577
|
+
* the perform step.
|
578
|
+
*/
|
579
|
+
|
580
|
+
/*
|
581
|
+
* call-seq:
|
582
|
+
* easy.proxy_headers => Hash, Array or Str
|
583
|
+
*
|
584
|
+
* Obtain the custom HTTP proxy_headers for following requests.
|
585
|
+
*/
|
586
|
+
static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
|
587
|
+
ruby_curl_easy *rbce;
|
588
|
+
VALUE proxy_headers;
|
589
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
590
|
+
proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
|
591
|
+
if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
|
592
|
+
return proxy_headers;
|
593
|
+
}
|
594
|
+
|
527
595
|
/*
|
528
596
|
* call-seq:
|
529
597
|
* easy.interface => string
|
@@ -889,7 +957,7 @@ static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
|
|
889
957
|
}
|
890
958
|
|
891
959
|
/*
|
892
|
-
* call-seq
|
960
|
+
* call-seq:
|
893
961
|
* easy.ftp_commands => array or nil
|
894
962
|
*/
|
895
963
|
static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
|
@@ -908,7 +976,7 @@ static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
|
|
908
976
|
}
|
909
977
|
|
910
978
|
/*
|
911
|
-
* call-seq
|
979
|
+
* call-seq:
|
912
980
|
* easy.resolve => array or nil
|
913
981
|
*/
|
914
982
|
static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
@@ -1139,7 +1207,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
1139
1207
|
|
1140
1208
|
/*
|
1141
1209
|
* call-seq:
|
1142
|
-
* easy.timeout = fixnum or nil
|
1210
|
+
* easy.timeout = float, fixnum or nil => numeric
|
1143
1211
|
*
|
1144
1212
|
* Set the maximum time in seconds that you allow the libcurl transfer
|
1145
1213
|
* operation to take. Normally, name lookups can take a considerable time
|
@@ -1148,20 +1216,39 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
1148
1216
|
*
|
1149
1217
|
* Set to nil (or zero) to disable timeout (it will then only timeout
|
1150
1218
|
* on the system's internal timeouts).
|
1219
|
+
*
|
1220
|
+
* Uses timeout_ms internally instead of timeout because it allows for
|
1221
|
+
* better precision and libcurl will use the last set value when both
|
1222
|
+
* timeout and timeout_ms are set.
|
1223
|
+
*
|
1151
1224
|
*/
|
1152
|
-
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE
|
1153
|
-
|
1225
|
+
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
|
1226
|
+
ruby_curl_easy *rbce;
|
1227
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1228
|
+
|
1229
|
+
if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
|
1230
|
+
rbce->timeout_ms = 0;
|
1231
|
+
} else {
|
1232
|
+
rbce->timeout_ms = (unsigned long)(NUM2DBL(timeout_s) * 1000);
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
1154
1236
|
}
|
1155
1237
|
|
1156
1238
|
/*
|
1157
1239
|
* call-seq:
|
1158
|
-
* easy.timeout =>
|
1240
|
+
* easy.timeout => numeric
|
1159
1241
|
*
|
1160
1242
|
* Obtain the maximum time in seconds that you allow the libcurl transfer
|
1161
1243
|
* operation to take.
|
1244
|
+
*
|
1245
|
+
* Uses timeout_ms internally instead of timeout.
|
1246
|
+
*
|
1162
1247
|
*/
|
1163
|
-
static VALUE ruby_curl_easy_timeout_get(VALUE self
|
1164
|
-
|
1248
|
+
static VALUE ruby_curl_easy_timeout_get(VALUE self) {
|
1249
|
+
ruby_curl_easy *rbce;
|
1250
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1251
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
1165
1252
|
}
|
1166
1253
|
|
1167
1254
|
/*
|
@@ -1177,7 +1264,16 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
|
|
1177
1264
|
* on the system's internal timeouts).
|
1178
1265
|
*/
|
1179
1266
|
static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
1180
|
-
|
1267
|
+
ruby_curl_easy *rbce;
|
1268
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1269
|
+
|
1270
|
+
if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
|
1271
|
+
rbce->timeout_ms = 0;
|
1272
|
+
} else {
|
1273
|
+
rbce->timeout_ms = NUM2ULONG(timeout_ms);
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
return ULONG2NUM(rbce->timeout_ms);
|
1181
1277
|
}
|
1182
1278
|
|
1183
1279
|
/*
|
@@ -1187,8 +1283,10 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
|
1187
1283
|
* Obtain the maximum time in milliseconds that you allow the libcurl transfer
|
1188
1284
|
* operation to take.
|
1189
1285
|
*/
|
1190
|
-
static VALUE ruby_curl_easy_timeout_ms_get(VALUE self
|
1191
|
-
|
1286
|
+
static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
|
1287
|
+
ruby_curl_easy *rbce;
|
1288
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
1289
|
+
return LONG2NUM(rbce->timeout_ms);
|
1192
1290
|
}
|
1193
1291
|
|
1194
1292
|
/*
|
@@ -1338,6 +1436,46 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
|
|
1338
1436
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
|
1339
1437
|
}
|
1340
1438
|
|
1439
|
+
/*
|
1440
|
+
* call-seq:
|
1441
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
1442
|
+
*
|
1443
|
+
* Set the maximal sending transfer speed (in bytes per second)
|
1444
|
+
*/
|
1445
|
+
static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_speed_large) {
|
1446
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_send_speed_large, 0);
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
/*
|
1450
|
+
* call-seq:
|
1451
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
1452
|
+
*
|
1453
|
+
* Get the maximal sending transfer speed (in bytes per second)
|
1454
|
+
*/
|
1455
|
+
static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self, VALUE max_send_speed_large) {
|
1456
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
/*
|
1460
|
+
* call-seq:
|
1461
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
1462
|
+
*
|
1463
|
+
* Set the maximal receiving transfer speed (in bytes per second)
|
1464
|
+
*/
|
1465
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_speed_large) {
|
1466
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
/*
|
1470
|
+
* call-seq:
|
1471
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
1472
|
+
*
|
1473
|
+
* Get the maximal receiving transfer speed (in bytes per second)
|
1474
|
+
*/
|
1475
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self, VALUE max_recv_speed_large) {
|
1476
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
1477
|
+
}
|
1478
|
+
|
1341
1479
|
/*
|
1342
1480
|
* call-seq:
|
1343
1481
|
* easy.username = string => string
|
@@ -1408,6 +1546,7 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
|
|
1408
1546
|
* Curl::CURL_SSLVERSION_TLSv1_0
|
1409
1547
|
* Curl::CURL_SSLVERSION_TLSv1_1
|
1410
1548
|
* Curl::CURL_SSLVERSION_TLSv1_2
|
1549
|
+
* Curl::CURL_SSLVERSION_TLSv1_3
|
1411
1550
|
*/
|
1412
1551
|
static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
1413
1552
|
CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
|
@@ -1456,7 +1595,7 @@ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod)
|
|
1456
1595
|
}
|
1457
1596
|
|
1458
1597
|
/*
|
1459
|
-
* call-seq
|
1598
|
+
* call-seq:
|
1460
1599
|
* easy.ftp_filemethod => fixnum
|
1461
1600
|
*
|
1462
1601
|
* Get the configuration for how libcurl will reach files on the server.
|
@@ -1828,7 +1967,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
1828
1967
|
|
1829
1968
|
/*
|
1830
1969
|
* call-seq:
|
1831
|
-
* easy.on_body { |body_data| ... } =>
|
1970
|
+
* easy.on_body { |body_data| ... } => <old handler>
|
1832
1971
|
*
|
1833
1972
|
* Assign or remove the +on_body+ handler for this Curl::Easy instance.
|
1834
1973
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1847,7 +1986,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
1847
1986
|
|
1848
1987
|
/*
|
1849
1988
|
* call-seq:
|
1850
|
-
* easy.on_success { |easy| ... } =>
|
1989
|
+
* easy.on_success { |easy| ... } => <old handler>
|
1851
1990
|
*
|
1852
1991
|
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
1853
1992
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1862,7 +2001,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
|
1862
2001
|
|
1863
2002
|
/*
|
1864
2003
|
* call-seq:
|
1865
|
-
* easy.on_failure {|easy,code| ... } =>
|
2004
|
+
* easy.on_failure {|easy,code| ... } => <old handler>
|
1866
2005
|
*
|
1867
2006
|
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
1868
2007
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1877,7 +2016,7 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
|
1877
2016
|
|
1878
2017
|
/*
|
1879
2018
|
* call-seq:
|
1880
|
-
* easy.on_missing {|easy,code| ... } =>
|
2019
|
+
* easy.on_missing {|easy,code| ... } => <old handler;>
|
1881
2020
|
*
|
1882
2021
|
* Assign or remove the on_missing handler for this Curl::Easy instance.
|
1883
2022
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -1892,7 +2031,7 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
1892
2031
|
|
1893
2032
|
/*
|
1894
2033
|
* call-seq:
|
1895
|
-
* easy.on_redirect {|easy,code| ... } =>
|
2034
|
+
* easy.on_redirect {|easy,code| ... } => <old handler;>
|
1896
2035
|
*
|
1897
2036
|
* Assign or remove the on_redirect handler for this Curl::Easy instance.
|
1898
2037
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -1907,7 +2046,7 @@ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
1907
2046
|
|
1908
2047
|
/*
|
1909
2048
|
* call-seq:
|
1910
|
-
* easy.on_complete {|easy| ... } =>
|
2049
|
+
* easy.on_complete {|easy| ... } => <old handler>
|
1911
2050
|
*
|
1912
2051
|
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
1913
2052
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1921,7 +2060,7 @@ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
|
1921
2060
|
|
1922
2061
|
/*
|
1923
2062
|
* call-seq:
|
1924
|
-
* easy.on_header { |header_data| ... } =>
|
2063
|
+
* easy.on_header { |header_data| ... } => <old handler>
|
1925
2064
|
*
|
1926
2065
|
* Assign or remove the +on_header+ handler for this Curl::Easy instance.
|
1927
2066
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1937,7 +2076,7 @@ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
|
|
1937
2076
|
|
1938
2077
|
/*
|
1939
2078
|
* call-seq:
|
1940
|
-
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } =>
|
2079
|
+
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => <old handler>
|
1941
2080
|
*
|
1942
2081
|
* Assign or remove the +on_progress+ handler for this Curl::Easy instance.
|
1943
2082
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1958,7 +2097,7 @@ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
|
|
1958
2097
|
|
1959
2098
|
/*
|
1960
2099
|
* call-seq:
|
1961
|
-
* easy.on_debug { |type, data| ... } =>
|
2100
|
+
* easy.on_debug { |type, data| ... } => <old handler>
|
1962
2101
|
*
|
1963
2102
|
* Assign or remove the +on_debug+ handler for this Curl::Easy instance.
|
1964
2103
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1997,11 +2136,14 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
1997
2136
|
|
1998
2137
|
name = rb_obj_as_string(rb_ary_entry(header, 0));
|
1999
2138
|
value = rb_obj_as_string(rb_ary_entry(header, 1));
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2139
|
+
if (rb_str_strlen(value) == 0) { // removing the header e.g. Accept: with nothing trailing should remove it see: https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html
|
2140
|
+
header_str = rb_str_plus(name, rb_str_new2(":"));
|
2141
|
+
} else {
|
2142
|
+
// This is a bit inefficient, but we don't want to be modifying
|
2143
|
+
// the actual values in the original hash.
|
2144
|
+
header_str = rb_str_plus(name, rb_str_new2(": "));
|
2145
|
+
header_str = rb_str_plus(header_str, value);
|
2146
|
+
}
|
2005
2147
|
} else {
|
2006
2148
|
header_str = rb_obj_as_string(header);
|
2007
2149
|
}
|
@@ -2012,6 +2154,38 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2012
2154
|
return header_str;
|
2013
2155
|
}
|
2014
2156
|
|
2157
|
+
/***********************************************
|
2158
|
+
* This is an rb_iterate callback used to set up http proxy headers.
|
2159
|
+
*/
|
2160
|
+
static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
|
2161
|
+
struct curl_slist **list;
|
2162
|
+
VALUE proxy_header_str = Qnil;
|
2163
|
+
|
2164
|
+
Data_Get_Struct(wrap, struct curl_slist *, list);
|
2165
|
+
|
2166
|
+
//rb_p(proxy_header);
|
2167
|
+
|
2168
|
+
if (rb_type(proxy_header) == T_ARRAY) {
|
2169
|
+
// we're processing a hash, proxy header is [name, val]
|
2170
|
+
VALUE name, value;
|
2171
|
+
|
2172
|
+
name = rb_obj_as_string(rb_ary_entry(proxy_header, 0));
|
2173
|
+
value = rb_obj_as_string(rb_ary_entry(proxy_header, 1));
|
2174
|
+
|
2175
|
+
// This is a bit inefficient, but we don't want to be modifying
|
2176
|
+
// the actual values in the original hash.
|
2177
|
+
proxy_header_str = rb_str_plus(name, rb_str_new2(": "));
|
2178
|
+
proxy_header_str = rb_str_plus(proxy_header_str, value);
|
2179
|
+
} else {
|
2180
|
+
proxy_header_str = rb_obj_as_string(proxy_header);
|
2181
|
+
}
|
2182
|
+
|
2183
|
+
//rb_p(header_str);
|
2184
|
+
|
2185
|
+
*list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
|
2186
|
+
return proxy_header_str;
|
2187
|
+
}
|
2188
|
+
|
2015
2189
|
/***********************************************
|
2016
2190
|
* This is an rb_iterate callback used to set up ftp commands.
|
2017
2191
|
*/
|
@@ -2051,6 +2225,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2051
2225
|
CURL *curl;
|
2052
2226
|
VALUE url, _url = rb_easy_get("url");
|
2053
2227
|
struct curl_slist **hdrs = &(rbce->curl_headers);
|
2228
|
+
struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
|
2054
2229
|
struct curl_slist **cmds = &(rbce->curl_ftp_commands);
|
2055
2230
|
struct curl_slist **rslv = &(rbce->curl_resolve);
|
2056
2231
|
|
@@ -2061,7 +2236,6 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2061
2236
|
}
|
2062
2237
|
|
2063
2238
|
url = rb_check_string_type(_url);
|
2064
|
-
|
2065
2239
|
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
2066
2240
|
|
2067
2241
|
// network stuff and auth
|
@@ -2174,15 +2348,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2174
2348
|
|
2175
2349
|
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
|
2176
2350
|
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
if (rbce->timeout_ms && rbce->timeout_ms > 0) {
|
2182
|
-
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
|
2183
|
-
}
|
2351
|
+
#if HAVE_CURLOPT_TIMEOUT_MS
|
2352
|
+
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
|
2353
|
+
#endif
|
2354
|
+
|
2184
2355
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
|
2356
|
+
#if HAVE_CURLOPT_CONNECTTIMEOUT_MS
|
2185
2357
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
|
2358
|
+
#endif
|
2186
2359
|
curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
|
2187
2360
|
|
2188
2361
|
curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
|
@@ -2201,6 +2374,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2201
2374
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
|
2202
2375
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
|
2203
2376
|
|
2377
|
+
curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, rbce->max_recv_speed_large);
|
2378
|
+
curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, rbce->max_send_speed_large);
|
2379
|
+
|
2204
2380
|
// Set up localport / proxy port
|
2205
2381
|
// FIXME these won't get returned to default if they're unset Ruby
|
2206
2382
|
if (rbce->proxy_port > 0) {
|
@@ -2334,6 +2510,25 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2334
2510
|
}
|
2335
2511
|
}
|
2336
2512
|
|
2513
|
+
#if HAVE_CURLOPT_PROXYHEADER
|
2514
|
+
/* Setup HTTP proxy headers if necessary */
|
2515
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
2516
|
+
|
2517
|
+
if (!rb_easy_nil("proxy_headers")) {
|
2518
|
+
if (rb_easy_type_check("proxy_headers", T_ARRAY) || rb_easy_type_check("proxy_headers", T_HASH)) {
|
2519
|
+
VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, phdrs);
|
2520
|
+
rb_iterate(rb_each, rb_easy_get("proxy_headers"), cb_each_http_proxy_header, wrap);
|
2521
|
+
} else {
|
2522
|
+
VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
|
2523
|
+
*phdrs = curl_slist_append(*hdrs, StringValuePtr(proxy_headers_str));
|
2524
|
+
}
|
2525
|
+
|
2526
|
+
if (*phdrs) {
|
2527
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, *phdrs);
|
2528
|
+
}
|
2529
|
+
}
|
2530
|
+
#endif
|
2531
|
+
|
2337
2532
|
/* Setup FTP commands if necessary */
|
2338
2533
|
if (!rb_easy_nil("ftp_commands")) {
|
2339
2534
|
if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
|
@@ -2366,7 +2561,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2366
2561
|
*
|
2367
2562
|
* Clean up a connection
|
2368
2563
|
*
|
2369
|
-
* Always returns
|
2564
|
+
* Always returns Qnil.
|
2370
2565
|
*/
|
2371
2566
|
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
2372
2567
|
|
@@ -2380,6 +2575,11 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2380
2575
|
rbce->curl_headers = NULL;
|
2381
2576
|
}
|
2382
2577
|
|
2578
|
+
if (rbce->curl_proxy_headers) {
|
2579
|
+
curl_slist_free_all(rbce->curl_proxy_headers);
|
2580
|
+
rbce->curl_proxy_headers = NULL;
|
2581
|
+
}
|
2582
|
+
|
2383
2583
|
ftp_commands = rbce->curl_ftp_commands;
|
2384
2584
|
if (ftp_commands) {
|
2385
2585
|
curl_slist_free_all(ftp_commands);
|
@@ -2401,6 +2601,9 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2401
2601
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
2402
2602
|
}
|
2403
2603
|
|
2604
|
+
// set values on cleanup to nil
|
2605
|
+
rb_easy_del("multi");
|
2606
|
+
|
2404
2607
|
return Qnil;
|
2405
2608
|
}
|
2406
2609
|
|
@@ -2415,6 +2618,8 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
2415
2618
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2416
2619
|
curl = rbce->curl;
|
2417
2620
|
|
2621
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2622
|
+
|
2418
2623
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
2419
2624
|
|
2420
2625
|
retval = rb_funcall(self, rb_intern("perform"), 0);
|
@@ -2480,6 +2685,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2480
2685
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2481
2686
|
curl = rbce->curl;
|
2482
2687
|
|
2688
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2689
|
+
|
2483
2690
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2484
2691
|
|
2485
2692
|
if (rbce->multipart_form_post) {
|
@@ -2551,6 +2758,8 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2551
2758
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2552
2759
|
curl = rbce->curl;
|
2553
2760
|
|
2761
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2762
|
+
|
2554
2763
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2555
2764
|
ruby_curl_easy_put_data_set(self, data);
|
2556
2765
|
|
@@ -2569,6 +2778,10 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2569
2778
|
* your own body handler, this string will be empty.
|
2570
2779
|
*/
|
2571
2780
|
static VALUE ruby_curl_easy_body_str_get(VALUE self) {
|
2781
|
+
/*
|
2782
|
+
TODO: can we force_encoding on the return here if we see charset=utf-8 in the content-type header?
|
2783
|
+
Content-Type: application/json; charset=utf-8
|
2784
|
+
*/
|
2572
2785
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
2573
2786
|
}
|
2574
2787
|
|
@@ -2763,7 +2976,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
2763
2976
|
* Retrieve the time, in seconds, it took from the start until the SSL/SSH
|
2764
2977
|
* connect/handshake to the remote host was completed. This time is most often
|
2765
2978
|
* very near to the pre transfer time, except for cases such as HTTP
|
2766
|
-
*
|
2979
|
+
* pipelining where the pretransfer time can be delayed due to waits in line
|
2767
2980
|
* for the pipeline and more.
|
2768
2981
|
*/
|
2769
2982
|
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
@@ -3256,6 +3469,21 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3256
3469
|
return LONG2NUM(rbce->last_result);
|
3257
3470
|
}
|
3258
3471
|
|
3472
|
+
/*
|
3473
|
+
* call-seq:
|
3474
|
+
* easy.last_error => "Error details" or nil
|
3475
|
+
*/
|
3476
|
+
static VALUE ruby_curl_easy_last_error(VALUE self) {
|
3477
|
+
ruby_curl_easy *rbce;
|
3478
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
3479
|
+
|
3480
|
+
if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
|
3481
|
+
return rb_str_new2(rbce->err_buf);
|
3482
|
+
} else {
|
3483
|
+
return Qnil;
|
3484
|
+
}
|
3485
|
+
}
|
3486
|
+
|
3259
3487
|
/*
|
3260
3488
|
* call-seq:
|
3261
3489
|
* easy.setopt Fixnum, value => value
|
@@ -3265,6 +3493,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3265
3493
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
3266
3494
|
ruby_curl_easy *rbce;
|
3267
3495
|
long option = NUM2LONG(opt);
|
3496
|
+
rb_io_t *open_f_ptr;
|
3268
3497
|
|
3269
3498
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
3270
3499
|
|
@@ -3353,6 +3582,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3353
3582
|
case CURLOPT_TCP_NODELAY: {
|
3354
3583
|
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
3355
3584
|
} break;
|
3585
|
+
case CURLOPT_RANGE: {
|
3586
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
3587
|
+
} break;
|
3356
3588
|
case CURLOPT_RESUME_FROM: {
|
3357
3589
|
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
|
3358
3590
|
} break;
|
@@ -3384,6 +3616,43 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3384
3616
|
case CURLOPT_MAX_RECV_SPEED_LARGE: {
|
3385
3617
|
curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
|
3386
3618
|
} break;
|
3619
|
+
#endif
|
3620
|
+
#if HAVE_CURLOPT_MAXFILESIZE
|
3621
|
+
case CURLOPT_MAXFILESIZE:
|
3622
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
|
3623
|
+
break;
|
3624
|
+
#endif
|
3625
|
+
#if HAVE_CURLOPT_TCP_KEEPALIVE
|
3626
|
+
case CURLOPT_TCP_KEEPALIVE:
|
3627
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
|
3628
|
+
break;
|
3629
|
+
case CURLOPT_TCP_KEEPIDLE:
|
3630
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
|
3631
|
+
break;
|
3632
|
+
case CURLOPT_TCP_KEEPINTVL:
|
3633
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
|
3634
|
+
break;
|
3635
|
+
#endif
|
3636
|
+
#if HAVE_CURLOPT_HAPROXYPROTOCOL
|
3637
|
+
case CURLOPT_HAPROXYPROTOCOL:
|
3638
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
|
3639
|
+
break;
|
3640
|
+
#endif
|
3641
|
+
case CURLOPT_STDERR:
|
3642
|
+
// libcurl requires raw FILE pointer and this should be IO object in Ruby.
|
3643
|
+
// Tempfile or StringIO won't work.
|
3644
|
+
Check_Type(val, T_FILE);
|
3645
|
+
GetOpenFile(val, open_f_ptr);
|
3646
|
+
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
|
3647
|
+
break;
|
3648
|
+
case CURLOPT_PROTOCOLS:
|
3649
|
+
case CURLOPT_REDIR_PROTOCOLS:
|
3650
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
3651
|
+
break;
|
3652
|
+
#if HAVE_CURLOPT_SSL_SESSIONID_CACHE
|
3653
|
+
case CURLOPT_SSL_SESSIONID_CACHE:
|
3654
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
3655
|
+
break;
|
3387
3656
|
#endif
|
3388
3657
|
default:
|
3389
3658
|
rb_raise(rb_eTypeError, "Curb unsupported option");
|
@@ -3520,6 +3789,10 @@ void init_curb_easy() {
|
|
3520
3789
|
/* Attributes for config next perform */
|
3521
3790
|
rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
|
3522
3791
|
rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
|
3792
|
+
|
3793
|
+
rb_define_method(cCurlEasy, "proxy_headers=", ruby_curl_easy_proxy_headers_set, 1);
|
3794
|
+
rb_define_method(cCurlEasy, "proxy_headers", ruby_curl_easy_proxy_headers_get, 0);
|
3795
|
+
|
3523
3796
|
rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
|
3524
3797
|
rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
|
3525
3798
|
rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
|
@@ -3579,6 +3852,10 @@ void init_curb_easy() {
|
|
3579
3852
|
rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
|
3580
3853
|
rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
|
3581
3854
|
rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
|
3855
|
+
rb_define_method(cCurlEasy, "max_send_speed_large=", ruby_curl_easy_max_send_speed_large_set, 1);
|
3856
|
+
rb_define_method(cCurlEasy, "max_send_speed_large", ruby_curl_easy_max_send_speed_large_get, 0);
|
3857
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large=", ruby_curl_easy_max_recv_speed_large_set, 1);
|
3858
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large", ruby_curl_easy_max_recv_speed_large_get, 0);
|
3582
3859
|
rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
|
3583
3860
|
rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
|
3584
3861
|
rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
|
@@ -3684,6 +3961,7 @@ void init_curb_easy() {
|
|
3684
3961
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
3685
3962
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
3686
3963
|
rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
|
3964
|
+
rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
|
3687
3965
|
|
3688
3966
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
3689
3967
|
rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
|