curb 0.9.7 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|