curb 1.4.0 → 1.5.0
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 +4 -4
- data/ChangeLog.md +447 -0
- data/README.md +39 -8
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +567 -186
- data/ext/curb_easy.h +10 -0
- data/ext/curb_macros.h +16 -0
- data/ext/curb_multi.c +83 -23
- data/ext/curb_multi.h +4 -0
- data/ext/curb_postfield.c +103 -114
- data/ext/curb_postfield.h +10 -1
- data/ext/extconf.rb +1 -0
- data/lib/curl/easy.rb +24 -4
- data/lib/curl/multi.rb +31 -9
- data/lib/curl.rb +78 -15
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +1 -1
- data/tests/bug_follow_redirect_288.rb +1 -1
- data/tests/bug_poison.rb +1 -1
- data/tests/bug_raise_on_callback.rb +1 -1
- data/tests/helper.rb +9 -8
- data/tests/tc_curl_easy.rb +304 -0
- data/tests/tc_curl_easy_cookielist.rb +10 -8
- data/tests/tc_curl_maxfilesize.rb +109 -5
- data/tests/tc_curl_multi.rb +32 -0
- data/tests/tc_curl_native_coverage.rb +57 -0
- data/tests/tc_curl_network_policy.rb +133 -33
- data/tests/tc_curl_postfield.rb +137 -0
- data/tests/tc_curl_protocols.rb +19 -7
- data/tests/tc_curl_security_hardening.rb +386 -0
- data/tests/tc_curl_transfer_guard.rb +112 -0
- data/tests/tc_fiber_scheduler.rb +46 -6
- data/tests/tc_ractor.rb +52 -1
- metadata +7 -2
data/ext/curb_easy.c
CHANGED
|
@@ -650,6 +650,93 @@ static int curb_host_allowlist_prereq(void *clientp,
|
|
|
650
650
|
}
|
|
651
651
|
#endif
|
|
652
652
|
|
|
653
|
+
#if defined(CURB_HAVE_OPENSOCKET_NETWORK_POLICY) && defined(HAVE_CURLOPT_DOH_URL)
|
|
654
|
+
/* libcurl's DoH probe transfers do not inherit the socket policy callback,
|
|
655
|
+
* so under :public the DoH endpoint must be vetted before the transfer.
|
|
656
|
+
* Only public IP literals are accepted: a hostname would be resolved outside
|
|
657
|
+
* the policy, leaving a DNS-rebinding window. The host is taken from
|
|
658
|
+
* libcurl's own URL parser so it matches what libcurl will connect to. */
|
|
659
|
+
static void curb_check_public_doh_url(ruby_curl_easy *rbce, const char *doh_url) {
|
|
660
|
+
CURLU *parsed_url;
|
|
661
|
+
char *host = NULL;
|
|
662
|
+
char literal[INET6_ADDRSTRLEN + 3];
|
|
663
|
+
char *address = literal;
|
|
664
|
+
size_t len;
|
|
665
|
+
unsigned char ip[16];
|
|
666
|
+
int parsed = 0;
|
|
667
|
+
|
|
668
|
+
parsed_url = curl_url();
|
|
669
|
+
if (!parsed_url) {
|
|
670
|
+
rb_raise(rb_eNoMemError, "Failed to allocate URL parser for DoH URL check");
|
|
671
|
+
}
|
|
672
|
+
if (curl_url_set(parsed_url, CURLUPART_URL, doh_url, 0) == CURLUE_OK &&
|
|
673
|
+
curl_url_get(parsed_url, CURLUPART_HOST, &host, 0) == CURLUE_OK && host) {
|
|
674
|
+
len = strlen(host);
|
|
675
|
+
if (len < sizeof(literal)) {
|
|
676
|
+
memcpy(literal, host, len + 1);
|
|
677
|
+
parsed = 1;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (host) curl_free(host);
|
|
681
|
+
curl_url_cleanup(parsed_url);
|
|
682
|
+
|
|
683
|
+
if (!parsed) {
|
|
684
|
+
rb_raise(eCurlErrUnsafeDestination,
|
|
685
|
+
"DoH URL must use a public IP address under public network policy");
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
len = strlen(address);
|
|
689
|
+
if (len >= 2 && address[0] == '[' && address[len - 1] == ']') {
|
|
690
|
+
address[len - 1] = '\0';
|
|
691
|
+
address++;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (inet_pton(AF_INET, address, ip) == 1) {
|
|
695
|
+
if (curb_ipv4_is_unsafe_destination(ip) || !curb_cidr_rules_match(rbce, CURB_CIDR_FAMILY_IPV4, ip)) {
|
|
696
|
+
rb_raise(eCurlErrUnsafeDestination,
|
|
697
|
+
"DoH URL address %s is not allowed by public network policy", address);
|
|
698
|
+
}
|
|
699
|
+
} else if (inet_pton(AF_INET6, address, ip) == 1) {
|
|
700
|
+
if (curb_ipv6_is_unsafe_destination(ip) || !curb_cidr_rules_match(rbce, CURB_CIDR_FAMILY_IPV6, ip)) {
|
|
701
|
+
rb_raise(eCurlErrUnsafeDestination,
|
|
702
|
+
"DoH URL address %s is not allowed by public network policy", address);
|
|
703
|
+
}
|
|
704
|
+
} else {
|
|
705
|
+
rb_raise(eCurlErrUnsafeDestination,
|
|
706
|
+
"DoH URL must use a public IP address under public network policy (got host %s)", address);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
#endif
|
|
710
|
+
|
|
711
|
+
#ifdef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
712
|
+
/* file:// opens no socket, so the public policy's socket check never sees
|
|
713
|
+
* it. Without a protocol allowlist, reject it up front; libcurl's default
|
|
714
|
+
* redirect protocols already exclude file. The scheme comes from libcurl's
|
|
715
|
+
* parser when available. */
|
|
716
|
+
static void curb_check_public_url_scheme(const char *url) {
|
|
717
|
+
int is_file = 0;
|
|
718
|
+
#if LIBCURL_VERSION_NUM >= 0x073e00
|
|
719
|
+
CURLU *parsed_url = curl_url();
|
|
720
|
+
char *scheme = NULL;
|
|
721
|
+
if (!parsed_url) {
|
|
722
|
+
rb_raise(rb_eNoMemError, "Failed to allocate URL parser for scheme check");
|
|
723
|
+
}
|
|
724
|
+
if (curl_url_set(parsed_url, CURLUPART_URL, url, CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) == CURLUE_OK &&
|
|
725
|
+
curl_url_get(parsed_url, CURLUPART_SCHEME, &scheme, 0) == CURLUE_OK && scheme) {
|
|
726
|
+
is_file = STRCASECMP(scheme, "file") == 0;
|
|
727
|
+
}
|
|
728
|
+
if (scheme) curl_free(scheme);
|
|
729
|
+
curl_url_cleanup(parsed_url);
|
|
730
|
+
#else
|
|
731
|
+
while (*url == ' ' || *url == '\t') url++;
|
|
732
|
+
is_file = STRNCASECMP(url, "file:", 5) == 0;
|
|
733
|
+
#endif
|
|
734
|
+
if (is_file) {
|
|
735
|
+
rb_raise(eCurlErrUnsafeDestination, "file:// URLs are not allowed by public network policy");
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
#endif
|
|
739
|
+
|
|
653
740
|
#ifdef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
654
741
|
static curl_socket_t curb_public_network_opensocket(void *clientp, curlsocktype purpose, struct curl_sockaddr *address) {
|
|
655
742
|
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
@@ -704,6 +791,14 @@ static curl_socket_t curb_public_network_opensocket(void *clientp, curlsocktype
|
|
|
704
791
|
}
|
|
705
792
|
#endif
|
|
706
793
|
|
|
794
|
+
/* Anything other than an IP socket (e.g. a Unix domain socket configured
|
|
795
|
+
* after the policy was applied) has no address to vet. Refuse it unless
|
|
796
|
+
* Unix sockets were explicitly allowed. */
|
|
797
|
+
if (!checked_destination_address && rbce && !rbce->allow_unix_socket) {
|
|
798
|
+
curb_store_destination_error(rbce, "(non-IP socket)", "is not allowed");
|
|
799
|
+
return CURL_SOCKET_BAD;
|
|
800
|
+
}
|
|
801
|
+
|
|
707
802
|
if (!checked_destination_address && rbce && rbce->network_allowed_cidr_rule_count > 0) {
|
|
708
803
|
curb_store_destination_error(rbce, "unknown", "outside allowed CIDR ranges");
|
|
709
804
|
return CURL_SOCKET_BAD;
|
|
@@ -747,7 +842,7 @@ VALUE rb_curl_easy_take_callback_error(ruby_curl_easy *rbce) {
|
|
|
747
842
|
static VALUE ruby_curl_easy_take_callback_error(VALUE self) {
|
|
748
843
|
ruby_curl_easy *rbce = NULL;
|
|
749
844
|
|
|
750
|
-
|
|
845
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
751
846
|
return rb_curl_easy_take_callback_error(rbce);
|
|
752
847
|
}
|
|
753
848
|
|
|
@@ -879,6 +974,13 @@ static int ruby_curl_easy_body_limit_exceeded(ruby_curl_easy *rbce, size_t total
|
|
|
879
974
|
return 0;
|
|
880
975
|
}
|
|
881
976
|
|
|
977
|
+
/* Initial capacity for the default body/header buffers. rb_str_buf_cat grows
|
|
978
|
+
* them geometrically, so starting small costs a few reallocations at most,
|
|
979
|
+
* while a large fixed reservation stays attached to every returned body_str
|
|
980
|
+
* (a 2 KB response used to keep 32 KB alive). */
|
|
981
|
+
#define CURB_DEFAULT_BODY_BUFFER_CAPA 0
|
|
982
|
+
#define CURB_DEFAULT_HEADER_BUFFER_CAPA 0
|
|
983
|
+
|
|
882
984
|
/* Default body handler appends to easy.body_data buffer */
|
|
883
985
|
static size_t default_body_handler(char *stream,
|
|
884
986
|
size_t size,
|
|
@@ -893,7 +995,7 @@ static size_t default_body_handler(char *stream,
|
|
|
893
995
|
}
|
|
894
996
|
|
|
895
997
|
if (NIL_P(out)) {
|
|
896
|
-
out = rb_easy_set("body_data", rb_str_buf_new(
|
|
998
|
+
out = rb_easy_set("body_data", rb_str_buf_new(CURB_DEFAULT_BODY_BUFFER_CAPA));
|
|
897
999
|
}
|
|
898
1000
|
rb_str_buf_cat(out, stream, total);
|
|
899
1001
|
return total;
|
|
@@ -908,7 +1010,7 @@ static size_t default_header_handler(char *stream,
|
|
|
908
1010
|
size_t total = size * nmemb;
|
|
909
1011
|
VALUE out = rb_easy_get("header_data");
|
|
910
1012
|
if (NIL_P(out)) {
|
|
911
|
-
out = rb_easy_set("header_data", rb_str_buf_new(
|
|
1013
|
+
out = rb_easy_set("header_data", rb_str_buf_new(CURB_DEFAULT_HEADER_BUFFER_CAPA));
|
|
912
1014
|
}
|
|
913
1015
|
rb_str_buf_cat(out, stream, total);
|
|
914
1016
|
return total;
|
|
@@ -1303,6 +1405,49 @@ static ruby_curl_multi *ruby_curl_multi_pointer_if_compatible(VALUE multi_val) {
|
|
|
1303
1405
|
#endif
|
|
1304
1406
|
}
|
|
1305
1407
|
|
|
1408
|
+
/* Explicit lifecycle operations can update Ruby bookkeeping; the GC free
|
|
1409
|
+
* path below must remain allocation-free. */
|
|
1410
|
+
static void ruby_curl_easy_detach(VALUE self, ruby_curl_easy *rbce) {
|
|
1411
|
+
VALUE multi = rbce->multi;
|
|
1412
|
+
ruby_curl_multi *rbcm = ruby_curl_multi_pointer_if_compatible(multi);
|
|
1413
|
+
if (rbcm) {
|
|
1414
|
+
CURLMcode result = rb_curl_multi_detach_easy(rbcm, rbce);
|
|
1415
|
+
if (result != CURLM_OK) raise_curl_multi_error_exception(result);
|
|
1416
|
+
rb_curl_multi_remove_request_reference(multi, self);
|
|
1417
|
+
}
|
|
1418
|
+
rbce->multi = Qnil;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/* Release the curb-owned CURLOPT_STDERR stream. Callers must first stop
|
|
1422
|
+
* libcurl from using it (cleanup, reset, or setopt of a replacement). */
|
|
1423
|
+
static void ruby_curl_easy_close_stderr_file(ruby_curl_easy *rbce) {
|
|
1424
|
+
FILE *fp = rbce->stderr_file;
|
|
1425
|
+
if (fp) {
|
|
1426
|
+
rbce->stderr_file = NULL;
|
|
1427
|
+
fclose(fp);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
/* Open a stream curb owns on a duplicate of fd, so its lifetime is
|
|
1432
|
+
* independent of the Ruby IO it came from. */
|
|
1433
|
+
static FILE *ruby_curl_easy_dup_stderr_file(int fd) {
|
|
1434
|
+
FILE *fp;
|
|
1435
|
+
int dup_fd = rb_cloexec_dup(fd);
|
|
1436
|
+
if (dup_fd < 0) {
|
|
1437
|
+
rb_sys_fail("dup(CURLOPT_STDERR)");
|
|
1438
|
+
}
|
|
1439
|
+
rb_update_max_fd(dup_fd);
|
|
1440
|
+
/* "w" on an existing descriptor neither truncates nor changes O_APPEND. */
|
|
1441
|
+
fp = fdopen(dup_fd, "w");
|
|
1442
|
+
if (!fp) {
|
|
1443
|
+
int saved_errno = errno;
|
|
1444
|
+
close(dup_fd);
|
|
1445
|
+
errno = saved_errno;
|
|
1446
|
+
rb_sys_fail("fdopen(CURLOPT_STDERR)");
|
|
1447
|
+
}
|
|
1448
|
+
return fp;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1306
1451
|
static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
1307
1452
|
if (!rbce) {
|
|
1308
1453
|
return;
|
|
@@ -1319,10 +1464,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
|
1319
1464
|
* libcurl retaining a dangling pointer to a soon-to-be cleaned-up easy
|
|
1320
1465
|
* handle. This path runs during GC, so it must not invoke Ruby APIs that
|
|
1321
1466
|
* can allocate or raise. */
|
|
1322
|
-
|
|
1323
|
-
curl_multi_remove_handle(rbcm->handle, rbce->curl);
|
|
1324
|
-
}
|
|
1325
|
-
rb_curl_multi_forget_easy(rbcm, rbce);
|
|
1467
|
+
rb_curl_multi_detach_easy(rbcm, rbce);
|
|
1326
1468
|
}
|
|
1327
1469
|
}
|
|
1328
1470
|
|
|
@@ -1352,6 +1494,8 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
|
1352
1494
|
curl_easy_cleanup(rbce->curl);
|
|
1353
1495
|
rbce->curl = NULL;
|
|
1354
1496
|
}
|
|
1497
|
+
/* After cleanup: libcurl may log while closing connections. */
|
|
1498
|
+
ruby_curl_easy_close_stderr_file(rbce);
|
|
1355
1499
|
|
|
1356
1500
|
rbce->self = Qnil;
|
|
1357
1501
|
}
|
|
@@ -1396,6 +1540,48 @@ const rb_data_type_t ruby_curl_easy_data_type = {
|
|
|
1396
1540
|
};
|
|
1397
1541
|
|
|
1398
1542
|
|
|
1543
|
+
void ruby_curl_easy_check_access(ruby_curl_easy *rbce) {
|
|
1544
|
+
if (rbce->multipart_building) {
|
|
1545
|
+
rb_raise(rb_eRuntimeError, "Cannot access an active curl handle during multipart construction");
|
|
1546
|
+
}
|
|
1547
|
+
rb_curl_multi_check_easy_thread(rbce);
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
static void ruby_curl_easy_check_idle(ruby_curl_easy *rbce) {
|
|
1551
|
+
ruby_curl_easy_check_access(rbce);
|
|
1552
|
+
if (rb_curl_multi_easy_performing(rbce)) {
|
|
1553
|
+
rb_raise(rb_eRuntimeError, "Cannot modify an active curl handle during perform");
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
/* Public entry points must not pass an uninitialized handle to libcurl. */
|
|
1558
|
+
ruby_curl_easy *ruby_curl_easy_get_handle(VALUE self) {
|
|
1559
|
+
ruby_curl_easy *rbce;
|
|
1560
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1561
|
+
if (!rbce->curl) {
|
|
1562
|
+
rb_raise(eCurlErrFailedInit, "Curl::Easy handle is not initialized");
|
|
1563
|
+
}
|
|
1564
|
+
ruby_curl_easy_check_access(rbce);
|
|
1565
|
+
return rbce;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
/* Entry points that hand libcurl new request state (bodies, verbs, setup)
|
|
1569
|
+
* must not run while libcurl is still using the old state: replacing it
|
|
1570
|
+
* mid-transfer frees buffers libcurl is reading (use-after-free). */
|
|
1571
|
+
static ruby_curl_easy *ruby_curl_easy_get_idle_handle(VALUE self) {
|
|
1572
|
+
ruby_curl_easy *rbce = ruby_curl_easy_get_handle(self);
|
|
1573
|
+
ruby_curl_easy_check_idle(rbce);
|
|
1574
|
+
return rbce;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
/* Keep libcurl's typed getinfo arguments while checking every result. */
|
|
1578
|
+
#define CURB_GETINFO(handle, info, output) do { \
|
|
1579
|
+
CURLcode info_result = curl_easy_getinfo(handle, info, output); \
|
|
1580
|
+
if (info_result != CURLE_OK) { \
|
|
1581
|
+
raise_curl_easy_error_exception(info_result); \
|
|
1582
|
+
} \
|
|
1583
|
+
} while (0)
|
|
1584
|
+
|
|
1399
1585
|
/* ================= ALLOC METHODS ====================*/
|
|
1400
1586
|
|
|
1401
1587
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
@@ -1414,6 +1600,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
1414
1600
|
rbce->network_allowed_hosts = NULL;
|
|
1415
1601
|
rbce->network_allowed_cidr_rule_count = 0;
|
|
1416
1602
|
rbce->network_allowed_host_count = 0;
|
|
1603
|
+
/* Callers that may hold a stream close it before zeroing. */
|
|
1604
|
+
rbce->stderr_file = NULL;
|
|
1417
1605
|
|
|
1418
1606
|
/* various-typed opts */
|
|
1419
1607
|
rbce->local_port = 0;
|
|
@@ -1423,6 +1611,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
1423
1611
|
rbce->http_auth_types = 0;
|
|
1424
1612
|
rbce->proxy_auth_types = 0;
|
|
1425
1613
|
rbce->max_redirs = -1;
|
|
1614
|
+
rbce->max_redirs_set = 0;
|
|
1615
|
+
rbce->protocols_set = 0;
|
|
1426
1616
|
rbce->timeout = 0;
|
|
1427
1617
|
rbce->timeout_ms = 0;
|
|
1428
1618
|
rbce->connect_timeout = 0;
|
|
@@ -1451,6 +1641,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
1451
1641
|
rbce->unrestricted_auth = 0;
|
|
1452
1642
|
rbce->verbose = 0;
|
|
1453
1643
|
rbce->multipart_form_post = 0;
|
|
1644
|
+
rbce->multipart_form_active = 0;
|
|
1645
|
+
rbce->multipart_building = 0;
|
|
1454
1646
|
rbce->enable_cookies = 0;
|
|
1455
1647
|
rbce->cookielist_engine_enabled = 0;
|
|
1456
1648
|
rbce->ignore_content_length = 0;
|
|
@@ -1500,6 +1692,16 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
1500
1692
|
|
|
1501
1693
|
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1502
1694
|
|
|
1695
|
+
if (rbce->callback_active || rbce->native_active) {
|
|
1696
|
+
rb_raise(rb_eRuntimeError, "Cannot initialize an active curl handle");
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
ruby_curl_easy_check_idle(rbce);
|
|
1700
|
+
ruby_curl_easy_detach(self, rbce);
|
|
1701
|
+
|
|
1702
|
+
/* Detach and release any previous handle and its owned option lists. */
|
|
1703
|
+
ruby_curl_easy_free(rbce);
|
|
1704
|
+
|
|
1503
1705
|
/* handler */
|
|
1504
1706
|
rbce->curl = curl_easy_init();
|
|
1505
1707
|
if (!rbce->curl) {
|
|
@@ -1571,25 +1773,45 @@ static VALUE duplicate_upload(VALUE upload) {
|
|
|
1571
1773
|
*
|
|
1572
1774
|
* Clone this Curl::Easy instance, creating a new instance.
|
|
1573
1775
|
* This method duplicates the underlying CURL* handle.
|
|
1776
|
+
* A temporary multipart form attached during a request is not copied;
|
|
1777
|
+
* supply new PostFields to send a multipart request with the clone.
|
|
1574
1778
|
*/
|
|
1575
1779
|
static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
1576
1780
|
ruby_curl_easy *rbce, *newrbce;
|
|
1577
1781
|
|
|
1578
|
-
|
|
1782
|
+
FILE *clone_stderr_file = NULL;
|
|
1579
1783
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1784
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
1785
|
+
|
|
1786
|
+
/* Duplicate first: this can raise, and nothing needs unwinding yet. */
|
|
1787
|
+
if (rbce->stderr_file) {
|
|
1788
|
+
clone_stderr_file = ruby_curl_easy_dup_stderr_file(fileno(rbce->stderr_file));
|
|
1583
1789
|
}
|
|
1790
|
+
|
|
1791
|
+
newrbce = ALLOC(ruby_curl_easy);
|
|
1584
1792
|
/* shallow copy */
|
|
1585
1793
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
|
1586
1794
|
|
|
1587
1795
|
/* now deep copy */
|
|
1588
1796
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
|
1589
1797
|
if (!newrbce->curl) {
|
|
1590
|
-
|
|
1798
|
+
xfree(newrbce);
|
|
1799
|
+
if (clone_stderr_file) fclose(clone_stderr_file);
|
|
1591
1800
|
rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
|
|
1592
1801
|
}
|
|
1802
|
+
/* duphandle borrows HTTPPOST, whose form is freed when the original
|
|
1803
|
+
* perform unwinds. Only reset it when attached: setting HTTPPOST also
|
|
1804
|
+
* changes request options and must not affect ordinary POST/upload clones. */
|
|
1805
|
+
if (newrbce->multipart_form_active) {
|
|
1806
|
+
CURLcode ecode = curl_easy_setopt(newrbce->curl, CURLOPT_HTTPPOST, NULL);
|
|
1807
|
+
if (ecode != CURLE_OK) {
|
|
1808
|
+
curl_easy_cleanup(newrbce->curl);
|
|
1809
|
+
xfree(newrbce);
|
|
1810
|
+
if (clone_stderr_file) fclose(clone_stderr_file);
|
|
1811
|
+
raise_curl_easy_error_exception(ecode);
|
|
1812
|
+
}
|
|
1813
|
+
newrbce->multipart_form_active = 0;
|
|
1814
|
+
}
|
|
1593
1815
|
newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
|
|
1594
1816
|
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
|
1595
1817
|
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
|
@@ -1600,9 +1822,17 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
1600
1822
|
newrbce->network_allowed_hosts = NULL;
|
|
1601
1823
|
newrbce->network_allowed_host_count = 0;
|
|
1602
1824
|
|
|
1825
|
+
/* duphandle copied the original's CURLOPT_STDERR pointer; give the clone
|
|
1826
|
+
* its own stream so neither handle can outlive the other's. */
|
|
1827
|
+
newrbce->stderr_file = clone_stderr_file;
|
|
1828
|
+
if (clone_stderr_file) {
|
|
1829
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_STDERR, clone_stderr_file);
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1603
1832
|
/* A cloned easy should not retain ownership reference to the original multi. */
|
|
1604
1833
|
newrbce->multi = Qnil;
|
|
1605
1834
|
newrbce->callback_error = Qnil;
|
|
1835
|
+
newrbce->callback_active = 0;
|
|
1606
1836
|
newrbce->unsafe_destination_blocked = 0;
|
|
1607
1837
|
memset(newrbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
1608
1838
|
newrbce->native_active = 0;
|
|
@@ -1648,7 +1878,7 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
1648
1878
|
CURLcode ecode;
|
|
1649
1879
|
ruby_curl_easy *rbce;
|
|
1650
1880
|
|
|
1651
|
-
|
|
1881
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
1652
1882
|
|
|
1653
1883
|
if (rbce->callback_active) {
|
|
1654
1884
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
@@ -1658,6 +1888,9 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
1658
1888
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle during native operation");
|
|
1659
1889
|
}
|
|
1660
1890
|
|
|
1891
|
+
ruby_curl_easy_check_idle(rbce);
|
|
1892
|
+
ruby_curl_easy_detach(self, rbce);
|
|
1893
|
+
|
|
1661
1894
|
ruby_curl_easy_free(rbce);
|
|
1662
1895
|
|
|
1663
1896
|
/* reinit the handle */
|
|
@@ -1699,7 +1932,7 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
1699
1932
|
CURLcode ecode;
|
|
1700
1933
|
ruby_curl_easy *rbce;
|
|
1701
1934
|
VALUE opts_dup;
|
|
1702
|
-
|
|
1935
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
1703
1936
|
|
|
1704
1937
|
if (rbce->callback_active) {
|
|
1705
1938
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
@@ -1709,10 +1942,15 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
1709
1942
|
rb_raise(rb_eRuntimeError, "Cannot reset an active curl handle during native operation");
|
|
1710
1943
|
}
|
|
1711
1944
|
|
|
1945
|
+
ruby_curl_easy_check_idle(rbce);
|
|
1946
|
+
ruby_curl_easy_detach(self, rbce);
|
|
1947
|
+
|
|
1712
1948
|
opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
1713
1949
|
|
|
1714
1950
|
ruby_curl_easy_cleanup(self, rbce);
|
|
1715
1951
|
curl_easy_reset(rbce->curl);
|
|
1952
|
+
/* reset restored libcurl's default stderr, so ours is unused now. */
|
|
1953
|
+
ruby_curl_easy_close_stderr_file(rbce);
|
|
1716
1954
|
ruby_curl_easy_zero(rbce);
|
|
1717
1955
|
rbce->self = self;
|
|
1718
1956
|
|
|
@@ -1790,7 +2028,7 @@ static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
|
|
|
1790
2028
|
static VALUE ruby_curl_easy_headers_get(VALUE self) {
|
|
1791
2029
|
ruby_curl_easy *rbce;
|
|
1792
2030
|
VALUE headers;
|
|
1793
|
-
|
|
2031
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
1794
2032
|
headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
|
|
1795
2033
|
if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
|
|
1796
2034
|
return headers;
|
|
@@ -1825,7 +2063,7 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
|
|
|
1825
2063
|
static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
|
|
1826
2064
|
ruby_curl_easy *rbce;
|
|
1827
2065
|
VALUE proxy_headers;
|
|
1828
|
-
|
|
2066
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
1829
2067
|
proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
|
|
1830
2068
|
if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
|
|
1831
2069
|
return proxy_headers;
|
|
@@ -2075,7 +2313,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode_body(VALUE argp) {
|
|
|
2075
2313
|
char *data;
|
|
2076
2314
|
long len;
|
|
2077
2315
|
|
|
2078
|
-
|
|
2316
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
2079
2317
|
|
|
2080
2318
|
curl = rbce->curl;
|
|
2081
2319
|
|
|
@@ -2134,7 +2372,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body,
|
|
|
2134
2372
|
ruby_curl_easy *rbce;
|
|
2135
2373
|
struct post_body_set_args args = { self, post_body, force_http_get_on_nil };
|
|
2136
2374
|
|
|
2137
|
-
|
|
2375
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2138
2376
|
ruby_curl_easy_enter_native(rbce);
|
|
2139
2377
|
|
|
2140
2378
|
return rb_ensure(ruby_curl_easy_post_body_set_with_mode_body, (VALUE)&args,
|
|
@@ -2171,7 +2409,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
2171
2409
|
VALUE headers;
|
|
2172
2410
|
VALUE infile_size = Qnil;
|
|
2173
2411
|
|
|
2174
|
-
|
|
2412
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
2175
2413
|
|
|
2176
2414
|
/*
|
|
2177
2415
|
* Validate and prepare Ruby-visible state before mutating the CURL handle.
|
|
@@ -2356,7 +2594,7 @@ static VALUE ruby_curl_easy_dns_servers_get(VALUE self) {
|
|
|
2356
2594
|
static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
|
|
2357
2595
|
ruby_curl_easy *rbce;
|
|
2358
2596
|
|
|
2359
|
-
|
|
2597
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2360
2598
|
rbce->allow_unix_socket = RTEST(allow) ? 1 : 0;
|
|
2361
2599
|
|
|
2362
2600
|
return allow;
|
|
@@ -2365,7 +2603,7 @@ static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
|
|
|
2365
2603
|
static VALUE ruby_curl_easy_allow_proxy_set(VALUE self, VALUE allow) {
|
|
2366
2604
|
ruby_curl_easy *rbce;
|
|
2367
2605
|
|
|
2368
|
-
|
|
2606
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2369
2607
|
rbce->allow_proxy = RTEST(allow) ? 1 : 0;
|
|
2370
2608
|
|
|
2371
2609
|
return allow;
|
|
@@ -2384,7 +2622,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_set(VALUE self, VALUE cidrs) {
|
|
|
2384
2622
|
VALUE normalized;
|
|
2385
2623
|
VALUE stored;
|
|
2386
2624
|
|
|
2387
|
-
|
|
2625
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2388
2626
|
normalized = curb_normalize_cidr_list(cidrs);
|
|
2389
2627
|
stored = curb_dup_string_array(normalized);
|
|
2390
2628
|
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_cidrs"), stored);
|
|
@@ -2405,7 +2643,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_get(VALUE self) {
|
|
|
2405
2643
|
ruby_curl_easy *rbce;
|
|
2406
2644
|
VALUE cidrs;
|
|
2407
2645
|
|
|
2408
|
-
|
|
2646
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2409
2647
|
cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
|
|
2410
2648
|
|
|
2411
2649
|
return curb_dup_string_array(cidrs);
|
|
@@ -2424,7 +2662,7 @@ static VALUE ruby_curl_easy_allowed_hosts_set(VALUE self, VALUE hosts) {
|
|
|
2424
2662
|
VALUE normalized;
|
|
2425
2663
|
VALUE stored;
|
|
2426
2664
|
|
|
2427
|
-
|
|
2665
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2428
2666
|
normalized = curb_normalize_host_list(hosts);
|
|
2429
2667
|
stored = curb_dup_string_array(normalized);
|
|
2430
2668
|
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_hosts"), stored);
|
|
@@ -2441,7 +2679,7 @@ static VALUE ruby_curl_easy_allowed_hosts_get(VALUE self) {
|
|
|
2441
2679
|
ruby_curl_easy *rbce;
|
|
2442
2680
|
VALUE hosts;
|
|
2443
2681
|
|
|
2444
|
-
|
|
2682
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2445
2683
|
hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
|
|
2446
2684
|
|
|
2447
2685
|
return curb_dup_string_array(hosts);
|
|
@@ -2615,7 +2853,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
|
|
|
2615
2853
|
VALUE args_ary;
|
|
2616
2854
|
|
|
2617
2855
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
2618
|
-
|
|
2856
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2619
2857
|
|
|
2620
2858
|
rbce->http_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
|
|
2621
2859
|
return LONG2NUM(rbce->http_auth_types);
|
|
@@ -2646,7 +2884,7 @@ static VALUE ruby_curl_easy_proxy_auth_types_set(int argc, VALUE *argv, VALUE se
|
|
|
2646
2884
|
VALUE args_ary;
|
|
2647
2885
|
|
|
2648
2886
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
2649
|
-
|
|
2887
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2650
2888
|
|
|
2651
2889
|
rbce->proxy_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
|
|
2652
2890
|
return LONG2NUM(rbce->proxy_auth_types);
|
|
@@ -2668,14 +2906,27 @@ static VALUE ruby_curl_easy_proxy_auth_types_get(VALUE self) {
|
|
|
2668
2906
|
* easy.max_redirects = fixnum or nil => fixnum or nil
|
|
2669
2907
|
*
|
|
2670
2908
|
* Set the maximum number of redirections to follow in the following +perform+
|
|
2671
|
-
* calls. Set to
|
|
2672
|
-
*
|
|
2909
|
+
* calls. Set to -1 to allow an infinite number. When nil (the default), at
|
|
2910
|
+
* most 30 redirects are followed, matching libcurl 8.3+ on every libcurl
|
|
2911
|
+
* version. Setting this option only makes sense if +follow_location+ is also
|
|
2912
|
+
* set true.
|
|
2673
2913
|
*
|
|
2674
2914
|
* With libcurl >= 7.15.1, setting this to 0 will cause libcurl to refuse any
|
|
2675
2915
|
* redirect.
|
|
2676
2916
|
*/
|
|
2677
2917
|
static VALUE ruby_curl_easy_max_redirects_set(VALUE self, VALUE max_redirs) {
|
|
2678
|
-
|
|
2918
|
+
ruby_curl_easy *rbce;
|
|
2919
|
+
|
|
2920
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2921
|
+
ruby_curl_easy_check_access(rbce);
|
|
2922
|
+
if (NIL_P(max_redirs)) {
|
|
2923
|
+
rbce->max_redirs = -1;
|
|
2924
|
+
rbce->max_redirs_set = 0;
|
|
2925
|
+
} else {
|
|
2926
|
+
rbce->max_redirs = NUM2LONG(max_redirs);
|
|
2927
|
+
rbce->max_redirs_set = 1;
|
|
2928
|
+
}
|
|
2929
|
+
return max_redirs;
|
|
2679
2930
|
}
|
|
2680
2931
|
|
|
2681
2932
|
/*
|
|
@@ -2708,7 +2959,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
|
2708
2959
|
*/
|
|
2709
2960
|
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
|
|
2710
2961
|
ruby_curl_easy *rbce;
|
|
2711
|
-
|
|
2962
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2712
2963
|
|
|
2713
2964
|
if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
|
|
2714
2965
|
rbce->timeout_ms = 0;
|
|
@@ -2731,7 +2982,7 @@ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
|
|
|
2731
2982
|
*/
|
|
2732
2983
|
static VALUE ruby_curl_easy_timeout_get(VALUE self) {
|
|
2733
2984
|
ruby_curl_easy *rbce;
|
|
2734
|
-
|
|
2985
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2735
2986
|
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
|
2736
2987
|
}
|
|
2737
2988
|
|
|
@@ -2749,7 +3000,7 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self) {
|
|
|
2749
3000
|
*/
|
|
2750
3001
|
static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
|
2751
3002
|
ruby_curl_easy *rbce;
|
|
2752
|
-
|
|
3003
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2753
3004
|
|
|
2754
3005
|
if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
|
|
2755
3006
|
rbce->timeout_ms = 0;
|
|
@@ -2769,7 +3020,7 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
|
|
2769
3020
|
*/
|
|
2770
3021
|
static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
|
|
2771
3022
|
ruby_curl_easy *rbce;
|
|
2772
|
-
|
|
3023
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
2773
3024
|
return LONG2NUM(rbce->timeout_ms);
|
|
2774
3025
|
}
|
|
2775
3026
|
|
|
@@ -3242,7 +3493,7 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
|
|
|
3242
3493
|
*/
|
|
3243
3494
|
static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
|
|
3244
3495
|
ruby_curl_easy *rbce;
|
|
3245
|
-
|
|
3496
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
3246
3497
|
|
|
3247
3498
|
if (Qtrue == autoreferer) {
|
|
3248
3499
|
curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
|
|
@@ -3399,7 +3650,7 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
|
|
|
3399
3650
|
static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
|
|
3400
3651
|
ruby_curl_easy *rbce;
|
|
3401
3652
|
unsigned short rm;
|
|
3402
|
-
|
|
3653
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3403
3654
|
|
|
3404
3655
|
rm = rbce->resolve_mode;
|
|
3405
3656
|
|
|
@@ -3431,7 +3682,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
3431
3682
|
} else {
|
|
3432
3683
|
ruby_curl_easy *rbce;
|
|
3433
3684
|
ID resolve_mode_id;
|
|
3434
|
-
|
|
3685
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3435
3686
|
|
|
3436
3687
|
resolve_mode_id = rb_to_id(resolve_mode);
|
|
3437
3688
|
|
|
@@ -3460,7 +3711,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
3460
3711
|
*/
|
|
3461
3712
|
static VALUE ruby_curl_easy_network_policy_get(VALUE self) {
|
|
3462
3713
|
ruby_curl_easy *rbce;
|
|
3463
|
-
|
|
3714
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3464
3715
|
|
|
3465
3716
|
switch (rbce->network_policy) {
|
|
3466
3717
|
case CURB_NETWORK_POLICY_PUBLIC:
|
|
@@ -3484,7 +3735,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
|
|
|
3484
3735
|
ruby_curl_easy *rbce;
|
|
3485
3736
|
ID network_policy_id;
|
|
3486
3737
|
|
|
3487
|
-
|
|
3738
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3488
3739
|
|
|
3489
3740
|
if (NIL_P(network_policy)) {
|
|
3490
3741
|
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
@@ -3522,7 +3773,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
|
|
|
3522
3773
|
*/
|
|
3523
3774
|
static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
|
|
3524
3775
|
ruby_curl_easy *rbce;
|
|
3525
|
-
|
|
3776
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3526
3777
|
|
|
3527
3778
|
if (rbce->unsafe_destination_blocked && rbce->unsafe_destination_error[0]) {
|
|
3528
3779
|
return rb_str_new2(rbce->unsafe_destination_error);
|
|
@@ -3540,7 +3791,7 @@ static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
|
|
|
3540
3791
|
*/
|
|
3541
3792
|
static VALUE ruby_curl_easy_unix_socket_path_get(VALUE self) {
|
|
3542
3793
|
ruby_curl_easy *rbce;
|
|
3543
|
-
|
|
3794
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3544
3795
|
|
|
3545
3796
|
return rb_easy_get("unix_socket_path");
|
|
3546
3797
|
}
|
|
@@ -3559,7 +3810,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
|
|
|
3559
3810
|
ruby_curl_easy *rbce;
|
|
3560
3811
|
long http_version;
|
|
3561
3812
|
|
|
3562
|
-
|
|
3813
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3563
3814
|
|
|
3564
3815
|
if (NIL_P(version)) {
|
|
3565
3816
|
http_version = CURL_HTTP_VERSION_NONE;
|
|
@@ -3581,7 +3832,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
|
|
|
3581
3832
|
static VALUE ruby_curl_easy_http_version_get(VALUE self) {
|
|
3582
3833
|
ruby_curl_easy *rbce;
|
|
3583
3834
|
|
|
3584
|
-
|
|
3835
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
3585
3836
|
|
|
3586
3837
|
return LONG2NUM(rbce->http_version);
|
|
3587
3838
|
}
|
|
@@ -3743,6 +3994,37 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
|
3743
3994
|
|
|
3744
3995
|
/* =================== PERFORM =====================*/
|
|
3745
3996
|
|
|
3997
|
+
/* CR or LF in a header line would let the value inject extra headers or
|
|
3998
|
+
* split the request; libcurl sends header strings verbatim. NUL would
|
|
3999
|
+
* silently truncate the line. */
|
|
4000
|
+
static void curb_check_header_line_len(const char *ptr, long len, const char *what) {
|
|
4001
|
+
if (memchr(ptr, '\r', (size_t)len) || memchr(ptr, '\n', (size_t)len) || memchr(ptr, '\0', (size_t)len)) {
|
|
4002
|
+
rb_raise(rb_eArgError, "%s must not contain CR, LF, or NUL characters", what);
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
static void curb_check_header_line(VALUE str, const char *what) {
|
|
4007
|
+
curb_check_header_line_len(RSTRING_PTR(str), RSTRING_LEN(str), what);
|
|
4008
|
+
}
|
|
4009
|
+
|
|
4010
|
+
/* A String for the option stored under key, converting like rb_easy_get_str. */
|
|
4011
|
+
static VALUE curb_easy_opt_string(ruby_curl_easy *rbce, const char *key) {
|
|
4012
|
+
VALUE value = rb_hash_aref(rbce->opts, rb_easy_hkey(key));
|
|
4013
|
+
return RB_TYPE_P(value, T_STRING) ? value : rb_str_to_str(value);
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
static int curb_slist_has_header(const struct curl_slist *list, const char *name) {
|
|
4017
|
+
size_t name_len = strlen(name);
|
|
4018
|
+
for (; list; list = list->next) {
|
|
4019
|
+
const char *line = list->data;
|
|
4020
|
+
if (line && STRNCASECMP(line, name, name_len) == 0 &&
|
|
4021
|
+
(line[name_len] == ':' || line[name_len] == ';')) {
|
|
4022
|
+
return 1;
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
return 0;
|
|
4026
|
+
}
|
|
4027
|
+
|
|
3746
4028
|
/***********************************************
|
|
3747
4029
|
* This is an rb_iterate callback used to set up http headers.
|
|
3748
4030
|
*/
|
|
@@ -3774,6 +4056,8 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap, int _c, const VALUE *
|
|
|
3774
4056
|
|
|
3775
4057
|
//rb_p(header_str);
|
|
3776
4058
|
|
|
4059
|
+
StringValue(header_str);
|
|
4060
|
+
curb_check_header_line(header_str, "HTTP header");
|
|
3777
4061
|
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(header_str));
|
|
3778
4062
|
if (!new_list) {
|
|
3779
4063
|
rb_raise(rb_eNoMemError, "Failed to append to header list");
|
|
@@ -3810,6 +4094,8 @@ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap, int _c, c
|
|
|
3810
4094
|
|
|
3811
4095
|
//rb_p(header_str);
|
|
3812
4096
|
|
|
4097
|
+
StringValue(proxy_header_str);
|
|
4098
|
+
curb_check_header_line(proxy_header_str, "HTTP proxy header");
|
|
3813
4099
|
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
|
|
3814
4100
|
if (!new_list) {
|
|
3815
4101
|
rb_raise(rb_eNoMemError, "Failed to append to proxy header list");
|
|
@@ -3955,6 +4241,17 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
3955
4241
|
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, rbce->forbid_reuse_set ? rbce->forbid_reuse : 0L);
|
|
3956
4242
|
#endif
|
|
3957
4243
|
}
|
|
4244
|
+
/* With a protocol allowlist, libcurl enforces it (UnsupportedProtocolError)
|
|
4245
|
+
* and an explicit :file entry is a deliberate opt-in. */
|
|
4246
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rbce->protocols_set) {
|
|
4247
|
+
curb_check_public_url_scheme(StringValueCStr(url));
|
|
4248
|
+
}
|
|
4249
|
+
#ifdef HAVE_CURLOPT_DOH_URL
|
|
4250
|
+
/* After the CIDR rules above are prepared. */
|
|
4251
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rb_easy_nil("doh_url")) {
|
|
4252
|
+
curb_check_public_doh_url(rbce, rb_easy_get_str("doh_url"));
|
|
4253
|
+
}
|
|
4254
|
+
#endif
|
|
3958
4255
|
#endif
|
|
3959
4256
|
|
|
3960
4257
|
// network stuff and auth
|
|
@@ -4021,7 +4318,7 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4021
4318
|
/* clear out the body_data if it was set */
|
|
4022
4319
|
rb_easy_del("body_data");
|
|
4023
4320
|
} else {
|
|
4024
|
-
rb_easy_set("body_data", rb_str_buf_new(
|
|
4321
|
+
rb_easy_set("body_data", rb_str_buf_new(CURB_DEFAULT_BODY_BUFFER_CAPA));
|
|
4025
4322
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_body_handler);
|
|
4026
4323
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
|
4027
4324
|
}
|
|
@@ -4032,7 +4329,7 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4032
4329
|
/* clear out the header_data if it was set */
|
|
4033
4330
|
rb_easy_del("header_data");
|
|
4034
4331
|
} else {
|
|
4035
|
-
rb_easy_set("header_data", rb_str_buf_new(
|
|
4332
|
+
rb_easy_set("header_data", rb_str_buf_new(CURB_DEFAULT_HEADER_BUFFER_CAPA));
|
|
4036
4333
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_header_handler);
|
|
4037
4334
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
|
|
4038
4335
|
}
|
|
@@ -4076,14 +4373,20 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4076
4373
|
|
|
4077
4374
|
curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
|
|
4078
4375
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
|
|
4376
|
+
/* Unset: cap at 30, libcurl's default since 8.3.0. Passing curb's old
|
|
4377
|
+
* default of -1 made redirects unlimited on every libcurl version. */
|
|
4378
|
+
if (!rbce->max_redirs_set) {
|
|
4379
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 30L);
|
|
4380
|
+
} else {
|
|
4079
4381
|
#if LIBCURL_VERSION_NUM == 0x081000
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4382
|
+
/* Work around 8.16.0 regression that clamps -1 (infinite) to zero */
|
|
4383
|
+
if (rbce->max_redirs >= 0) {
|
|
4384
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
4385
|
+
}
|
|
4084
4386
|
#else
|
|
4085
|
-
|
|
4387
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
4086
4388
|
#endif
|
|
4389
|
+
}
|
|
4087
4390
|
|
|
4088
4391
|
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL,
|
|
4089
4392
|
public_policy_disables_proxy ? 0L : rbce->proxy_tunnel);
|
|
@@ -4199,9 +4502,7 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4199
4502
|
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
|
|
4200
4503
|
}
|
|
4201
4504
|
|
|
4202
|
-
|
|
4203
|
-
curl_easy_setopt(curl, CURLOPT_COOKIE, rb_easy_get_str("cookies"));
|
|
4204
|
-
}
|
|
4505
|
+
/* cookies= is applied after the HTTP headers below. */
|
|
4205
4506
|
|
|
4206
4507
|
/* Set up HTTPS cert handling if necessary */
|
|
4207
4508
|
if (!rb_easy_nil("cert")) {
|
|
@@ -4246,7 +4547,9 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4246
4547
|
|
|
4247
4548
|
/* Set the user-agent string if specified */
|
|
4248
4549
|
if (!rb_easy_nil("useragent")) {
|
|
4249
|
-
|
|
4550
|
+
VALUE useragent = curb_easy_opt_string(rbce, "useragent");
|
|
4551
|
+
curb_check_header_line(useragent, "useragent");
|
|
4552
|
+
curl_easy_setopt(curl, CURLOPT_USERAGENT, RSTRING_PTR(useragent));
|
|
4250
4553
|
}
|
|
4251
4554
|
|
|
4252
4555
|
/* Setup can be rerun for safety-policy changes while a handle is attached.
|
|
@@ -4263,6 +4566,7 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4263
4566
|
rb_block_call(rb_easy_get("headers"), rb_intern("each"), 0, NULL, cb_each_http_header, wrap);
|
|
4264
4567
|
} else {
|
|
4265
4568
|
VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
|
|
4569
|
+
curb_check_header_line(headers_str, "HTTP header");
|
|
4266
4570
|
struct curl_slist *new_list = curl_slist_append(*hdrs, StringValuePtr(headers_str));
|
|
4267
4571
|
if (!new_list) {
|
|
4268
4572
|
rb_raise(rb_eNoMemError, "Failed to append to headers list");
|
|
@@ -4275,6 +4579,28 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4275
4579
|
}
|
|
4276
4580
|
}
|
|
4277
4581
|
|
|
4582
|
+
/* cookies=: libcurl sends CURLOPT_COOKIE to every host a redirect reaches,
|
|
4583
|
+
* but drops a custom Cookie header on cross-host redirects (7.83+). So
|
|
4584
|
+
* send it as a header, unless the cookie engine is on: libcurl would then
|
|
4585
|
+
* emit a second Cookie line, so CURLOPT_COOKIE is kept to merge them. */
|
|
4586
|
+
curl_easy_setopt(curl, CURLOPT_COOKIE, NULL);
|
|
4587
|
+
if (!rb_easy_nil("cookies")) {
|
|
4588
|
+
VALUE cookies = curb_easy_opt_string(rbce, "cookies");
|
|
4589
|
+
curb_check_header_line(cookies, "cookies");
|
|
4590
|
+
if (rbce->enable_cookies || rbce->cookielist_engine_enabled) {
|
|
4591
|
+
curl_easy_setopt(curl, CURLOPT_COOKIE, RSTRING_PTR(cookies));
|
|
4592
|
+
} else if (RSTRING_LEN(cookies) > 0 && !curb_slist_has_header(*hdrs, "Cookie")) {
|
|
4593
|
+
/* An explicit Cookie header already wins over cookies=, as before. */
|
|
4594
|
+
VALUE cookie_header = rb_str_plus(rb_str_new_cstr("Cookie: "), cookies);
|
|
4595
|
+
struct curl_slist *new_list = curl_slist_append(*hdrs, StringValueCStr(cookie_header));
|
|
4596
|
+
if (!new_list) {
|
|
4597
|
+
rb_raise(rb_eNoMemError, "Failed to append to headers list");
|
|
4598
|
+
}
|
|
4599
|
+
*hdrs = new_list;
|
|
4600
|
+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *hdrs);
|
|
4601
|
+
}
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4278
4604
|
#ifdef HAVE_CURLOPT_PROXYHEADER
|
|
4279
4605
|
/* Setup HTTP proxy headers if necessary */
|
|
4280
4606
|
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
|
@@ -4285,6 +4611,7 @@ static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
|
4285
4611
|
rb_block_call(rb_easy_get("proxy_headers"), rb_intern("each"), 0, NULL, cb_each_http_proxy_header, wrap);
|
|
4286
4612
|
} else {
|
|
4287
4613
|
VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
|
|
4614
|
+
curb_check_header_line(proxy_headers_str, "HTTP proxy header");
|
|
4288
4615
|
struct curl_slist *new_list = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
|
|
4289
4616
|
if (!new_list) {
|
|
4290
4617
|
rb_raise(rb_eNoMemError, "Failed to append to proxy headers list");
|
|
@@ -4364,7 +4691,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
4364
4691
|
static VALUE ruby_curl_easy_setup_self(VALUE self) {
|
|
4365
4692
|
ruby_curl_easy *rbce;
|
|
4366
4693
|
|
|
4367
|
-
|
|
4694
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
4368
4695
|
ruby_curl_easy_setup(rbce);
|
|
4369
4696
|
|
|
4370
4697
|
return self;
|
|
@@ -4470,11 +4797,13 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
|
4470
4797
|
CURL *curl;
|
|
4471
4798
|
VALUE retval;
|
|
4472
4799
|
|
|
4473
|
-
|
|
4800
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
4474
4801
|
curl = rbce->curl;
|
|
4475
4802
|
|
|
4476
4803
|
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
4477
4804
|
|
|
4805
|
+
if (verb) curb_check_header_line_len(verb, (long)strlen(verb), "HTTP verb");
|
|
4806
|
+
|
|
4478
4807
|
/* Use method override and adjust related options for special verbs. */
|
|
4479
4808
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
|
4480
4809
|
|
|
@@ -4535,6 +4864,8 @@ struct easy_form_perform_args {
|
|
|
4535
4864
|
struct curl_httppost *last;
|
|
4536
4865
|
int clear_customrequest;
|
|
4537
4866
|
int form_set_on_curl;
|
|
4867
|
+
ruby_curl_form_string *strings;
|
|
4868
|
+
ruby_curl_easy *rbce;
|
|
4538
4869
|
};
|
|
4539
4870
|
|
|
4540
4871
|
struct easy_join_args {
|
|
@@ -4556,15 +4887,16 @@ static VALUE join_easy_arguments(ruby_curl_easy *rbce, VALUE args_ary) {
|
|
|
4556
4887
|
|
|
4557
4888
|
static void append_multipart_form_argument(VALUE arg,
|
|
4558
4889
|
struct curl_httppost **first,
|
|
4559
|
-
struct curl_httppost **last
|
|
4890
|
+
struct curl_httppost **last,
|
|
4891
|
+
ruby_curl_form_string **strings) {
|
|
4560
4892
|
if (rb_obj_is_instance_of(arg, cCurlPostField)) {
|
|
4561
|
-
append_to_form(arg, first, last);
|
|
4893
|
+
append_to_form(arg, first, last, strings);
|
|
4562
4894
|
} else if (rb_type(arg) == T_ARRAY) {
|
|
4563
4895
|
long j, argv_len = RARRAY_LEN(arg);
|
|
4564
4896
|
for (j = 0; j < argv_len; ++j) {
|
|
4565
4897
|
VALUE field = rb_ary_entry(arg, j);
|
|
4566
4898
|
if (rb_obj_is_instance_of(field, cCurlPostField)) {
|
|
4567
|
-
append_to_form(field, first, last);
|
|
4899
|
+
append_to_form(field, first, last, strings);
|
|
4568
4900
|
} else {
|
|
4569
4901
|
rb_raise(eCurlErrInvalidPostField,
|
|
4570
4902
|
"You must use PostFields only with multipart form posts");
|
|
@@ -4579,23 +4911,35 @@ static void append_multipart_form_argument(VALUE arg,
|
|
|
4579
4911
|
static VALUE build_and_perform_multipart_form(VALUE argp) {
|
|
4580
4912
|
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
4581
4913
|
int i;
|
|
4914
|
+
ruby_curl_easy *rbce;
|
|
4915
|
+
|
|
4916
|
+
rbce = ruby_curl_easy_get_handle(args->self);
|
|
4917
|
+
args->rbce = rbce;
|
|
4918
|
+
ruby_curl_easy_enter_native(rbce);
|
|
4919
|
+
rbce->multipart_building = 1;
|
|
4582
4920
|
|
|
4583
4921
|
for (i = 0; i < args->argc; i++) {
|
|
4584
|
-
append_multipart_form_argument(args->argv[i], &args->first, &args->last);
|
|
4922
|
+
append_multipart_form_argument(args->argv[i], &args->first, &args->last, &args->strings);
|
|
4585
4923
|
}
|
|
4586
4924
|
|
|
4587
4925
|
curl_easy_setopt(args->curl, CURLOPT_POST, 0);
|
|
4588
4926
|
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
|
|
4589
4927
|
args->form_set_on_curl = 1;
|
|
4928
|
+
rbce->multipart_form_active = 1;
|
|
4590
4929
|
|
|
4930
|
+
rbce->multipart_building = 0;
|
|
4591
4931
|
return call_easy_perform(args->self);
|
|
4592
4932
|
}
|
|
4593
4933
|
|
|
4594
4934
|
static VALUE ensure_free_form_post(VALUE argp) {
|
|
4595
4935
|
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
4936
|
+
if (args->rbce) args->rbce->multipart_building = 0;
|
|
4596
4937
|
if (args->curl) {
|
|
4597
4938
|
if (args->form_set_on_curl) {
|
|
4939
|
+
ruby_curl_easy *rbce;
|
|
4940
|
+
rbce = ruby_curl_easy_get_handle(args->self);
|
|
4598
4941
|
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
|
|
4942
|
+
rbce->multipart_form_active = 0;
|
|
4599
4943
|
}
|
|
4600
4944
|
if (args->clear_customrequest) {
|
|
4601
4945
|
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
@@ -4606,6 +4950,9 @@ static VALUE ensure_free_form_post(VALUE argp) {
|
|
|
4606
4950
|
args->first = NULL;
|
|
4607
4951
|
}
|
|
4608
4952
|
args->last = NULL;
|
|
4953
|
+
free_form_strings(args->strings);
|
|
4954
|
+
args->strings = NULL;
|
|
4955
|
+
if (args->rbce) ruby_curl_easy_leave_native((VALUE)args->rbce);
|
|
4609
4956
|
return Qnil;
|
|
4610
4957
|
}
|
|
4611
4958
|
|
|
@@ -4640,7 +4987,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
4640
4987
|
|
|
4641
4988
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
4642
4989
|
|
|
4643
|
-
|
|
4990
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
4644
4991
|
curl = rbce->curl;
|
|
4645
4992
|
|
|
4646
4993
|
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
@@ -4649,7 +4996,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
4649
4996
|
|
|
4650
4997
|
if (rbce->multipart_form_post) {
|
|
4651
4998
|
VALUE ret;
|
|
4652
|
-
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0 };
|
|
4999
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0, NULL, NULL };
|
|
4653
5000
|
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
4654
5001
|
|
|
4655
5002
|
return ret;
|
|
@@ -4699,7 +5046,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
4699
5046
|
VALUE args_ary;
|
|
4700
5047
|
|
|
4701
5048
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
4702
|
-
|
|
5049
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
4703
5050
|
curl = rbce->curl;
|
|
4704
5051
|
|
|
4705
5052
|
/* Clear the error buffer */
|
|
@@ -4710,7 +5057,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
4710
5057
|
|
|
4711
5058
|
if (rbce->multipart_form_post) {
|
|
4712
5059
|
VALUE ret;
|
|
4713
|
-
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
5060
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0, NULL, NULL };
|
|
4714
5061
|
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
4715
5062
|
return ret;
|
|
4716
5063
|
} else {
|
|
@@ -4748,7 +5095,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
4748
5095
|
VALUE args_ary;
|
|
4749
5096
|
|
|
4750
5097
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
4751
|
-
|
|
5098
|
+
rbce = ruby_curl_easy_get_idle_handle(self);
|
|
4752
5099
|
curl = rbce->curl;
|
|
4753
5100
|
|
|
4754
5101
|
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
@@ -4768,7 +5115,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
4768
5115
|
/* Otherwise, if multipart_form_post is true, use multipart logic */
|
|
4769
5116
|
else if (rbce->multipart_form_post) {
|
|
4770
5117
|
VALUE ret;
|
|
4771
|
-
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
5118
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0, NULL, NULL };
|
|
4772
5119
|
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
4773
5120
|
return ret;
|
|
4774
5121
|
}
|
|
@@ -4815,7 +5162,7 @@ static VALUE ruby_curl_easy_max_body_bytes_set(VALUE self, VALUE val) {
|
|
|
4815
5162
|
ruby_curl_easy *rbce;
|
|
4816
5163
|
long long limit;
|
|
4817
5164
|
|
|
4818
|
-
|
|
5165
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
4819
5166
|
|
|
4820
5167
|
if (NIL_P(val)) {
|
|
4821
5168
|
rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
|
|
@@ -4870,10 +5217,10 @@ static VALUE ruby_curl_easy_header_str_get(VALUE self) {
|
|
|
4870
5217
|
*/
|
|
4871
5218
|
static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
|
|
4872
5219
|
ruby_curl_easy *rbce;
|
|
4873
|
-
char* url;
|
|
5220
|
+
char* url = NULL;
|
|
4874
5221
|
|
|
4875
|
-
|
|
4876
|
-
|
|
5222
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5223
|
+
CURB_GETINFO(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
|
|
4877
5224
|
|
|
4878
5225
|
if (url && url[0]) { // curl returns empty string if none
|
|
4879
5226
|
return rb_str_new2(url);
|
|
@@ -4893,14 +5240,14 @@ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
|
|
|
4893
5240
|
*/
|
|
4894
5241
|
static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
4895
5242
|
ruby_curl_easy *rbce;
|
|
4896
|
-
long code;
|
|
5243
|
+
long code = 0;
|
|
4897
5244
|
|
|
4898
|
-
|
|
5245
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
4899
5246
|
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
|
4900
|
-
|
|
5247
|
+
CURB_GETINFO(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
|
|
4901
5248
|
#else
|
|
4902
5249
|
// old libcurl
|
|
4903
|
-
|
|
5250
|
+
CURB_GETINFO(rbce->curl, CURLINFO_HTTP_CODE, &code);
|
|
4904
5251
|
#endif
|
|
4905
5252
|
|
|
4906
5253
|
return LONG2NUM(code);
|
|
@@ -4917,10 +5264,10 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
|
4917
5264
|
*/
|
|
4918
5265
|
static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
|
|
4919
5266
|
ruby_curl_easy *rbce;
|
|
4920
|
-
char* ip;
|
|
5267
|
+
char* ip = NULL;
|
|
4921
5268
|
|
|
4922
|
-
|
|
4923
|
-
|
|
5269
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5270
|
+
CURB_GETINFO(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
|
|
4924
5271
|
|
|
4925
5272
|
if (ip && ip[0]) { // curl returns empty string if none
|
|
4926
5273
|
return rb_str_new2(ip);
|
|
@@ -4938,10 +5285,10 @@ static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
|
|
|
4938
5285
|
*/
|
|
4939
5286
|
static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
|
|
4940
5287
|
ruby_curl_easy *rbce;
|
|
4941
|
-
long code;
|
|
5288
|
+
long code = 0;
|
|
4942
5289
|
|
|
4943
|
-
|
|
4944
|
-
|
|
5290
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5291
|
+
CURB_GETINFO(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
|
|
4945
5292
|
|
|
4946
5293
|
return LONG2NUM(code);
|
|
4947
5294
|
}
|
|
@@ -4966,10 +5313,10 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
|
|
|
4966
5313
|
static VALUE ruby_curl_easy_file_time_get(VALUE self) {
|
|
4967
5314
|
#ifdef HAVE_CURLINFO_FILETIME
|
|
4968
5315
|
ruby_curl_easy *rbce;
|
|
4969
|
-
long time;
|
|
5316
|
+
long time = 0;
|
|
4970
5317
|
|
|
4971
|
-
|
|
4972
|
-
|
|
5318
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5319
|
+
CURB_GETINFO(rbce->curl, CURLINFO_FILETIME, &time);
|
|
4973
5320
|
|
|
4974
5321
|
return LONG2NUM(time);
|
|
4975
5322
|
#else
|
|
@@ -4987,10 +5334,10 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
|
|
|
4987
5334
|
*/
|
|
4988
5335
|
static VALUE ruby_curl_easy_total_time_get(VALUE self) {
|
|
4989
5336
|
ruby_curl_easy *rbce;
|
|
4990
|
-
double time;
|
|
5337
|
+
double time = 0;
|
|
4991
5338
|
|
|
4992
|
-
|
|
4993
|
-
|
|
5339
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5340
|
+
CURB_GETINFO(rbce->curl, CURLINFO_TOTAL_TIME, &time);
|
|
4994
5341
|
|
|
4995
5342
|
return rb_float_new(time);
|
|
4996
5343
|
}
|
|
@@ -5004,10 +5351,10 @@ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
|
|
|
5004
5351
|
*/
|
|
5005
5352
|
static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
|
|
5006
5353
|
ruby_curl_easy *rbce;
|
|
5007
|
-
double time;
|
|
5354
|
+
double time = 0;
|
|
5008
5355
|
|
|
5009
|
-
|
|
5010
|
-
|
|
5356
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5357
|
+
CURB_GETINFO(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
|
|
5011
5358
|
|
|
5012
5359
|
return rb_float_new(time);
|
|
5013
5360
|
}
|
|
@@ -5021,10 +5368,10 @@ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
|
|
|
5021
5368
|
*/
|
|
5022
5369
|
static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
5023
5370
|
ruby_curl_easy *rbce;
|
|
5024
|
-
double time;
|
|
5371
|
+
double time = 0;
|
|
5025
5372
|
|
|
5026
|
-
|
|
5027
|
-
|
|
5373
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5374
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONNECT_TIME, &time);
|
|
5028
5375
|
|
|
5029
5376
|
return rb_float_new(time);
|
|
5030
5377
|
}
|
|
@@ -5042,10 +5389,10 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
|
5042
5389
|
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
|
5043
5390
|
static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
|
|
5044
5391
|
ruby_curl_easy *rbce;
|
|
5045
|
-
double time;
|
|
5392
|
+
double time = 0;
|
|
5046
5393
|
|
|
5047
|
-
|
|
5048
|
-
|
|
5394
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5395
|
+
CURB_GETINFO(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
|
|
5049
5396
|
|
|
5050
5397
|
return rb_float_new(time);
|
|
5051
5398
|
}
|
|
@@ -5063,10 +5410,10 @@ static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
|
|
|
5063
5410
|
*/
|
|
5064
5411
|
static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
|
|
5065
5412
|
ruby_curl_easy *rbce;
|
|
5066
|
-
double time;
|
|
5413
|
+
double time = 0;
|
|
5067
5414
|
|
|
5068
|
-
|
|
5069
|
-
|
|
5415
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5416
|
+
CURB_GETINFO(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
|
|
5070
5417
|
|
|
5071
5418
|
return rb_float_new(time);
|
|
5072
5419
|
}
|
|
@@ -5081,10 +5428,10 @@ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
|
|
|
5081
5428
|
*/
|
|
5082
5429
|
static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
|
|
5083
5430
|
ruby_curl_easy *rbce;
|
|
5084
|
-
double time;
|
|
5431
|
+
double time = 0;
|
|
5085
5432
|
|
|
5086
|
-
|
|
5087
|
-
|
|
5433
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5434
|
+
CURB_GETINFO(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
|
|
5088
5435
|
|
|
5089
5436
|
return rb_float_new(time);
|
|
5090
5437
|
}
|
|
@@ -5103,10 +5450,10 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
|
|
|
5103
5450
|
static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
|
5104
5451
|
#ifdef HAVE_CURLINFO_REDIRECT_TIME
|
|
5105
5452
|
ruby_curl_easy *rbce;
|
|
5106
|
-
double time;
|
|
5453
|
+
double time = 0;
|
|
5107
5454
|
|
|
5108
|
-
|
|
5109
|
-
|
|
5455
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5456
|
+
CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
|
|
5110
5457
|
|
|
5111
5458
|
return rb_float_new(time);
|
|
5112
5459
|
#else
|
|
@@ -5126,10 +5473,10 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
|
|
5126
5473
|
static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
5127
5474
|
#ifdef HAVE_CURLINFO_REDIRECT_COUNT
|
|
5128
5475
|
ruby_curl_easy *rbce;
|
|
5129
|
-
long count;
|
|
5476
|
+
long count = 0;
|
|
5130
5477
|
|
|
5131
|
-
|
|
5132
|
-
|
|
5478
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5479
|
+
CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
|
|
5133
5480
|
|
|
5134
5481
|
return LONG2NUM(count);
|
|
5135
5482
|
#else
|
|
@@ -5151,10 +5498,10 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
|
5151
5498
|
static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
5152
5499
|
#ifdef HAVE_CURLINFO_REDIRECT_URL
|
|
5153
5500
|
ruby_curl_easy *rbce;
|
|
5154
|
-
char* url;
|
|
5501
|
+
char* url = NULL;
|
|
5155
5502
|
|
|
5156
|
-
|
|
5157
|
-
|
|
5503
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5504
|
+
CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_URL, &url);
|
|
5158
5505
|
|
|
5159
5506
|
if (url && url[0]) { // curl returns empty string if none
|
|
5160
5507
|
return rb_str_new2(url);
|
|
@@ -5178,15 +5525,15 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
5178
5525
|
*/
|
|
5179
5526
|
static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
5180
5527
|
ruby_curl_easy *rbce;
|
|
5181
|
-
|
|
5528
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5182
5529
|
|
|
5183
5530
|
#ifdef HAVE_CURLINFO_SIZE_UPLOAD_T
|
|
5184
|
-
curl_off_t bytes;
|
|
5185
|
-
|
|
5531
|
+
curl_off_t bytes = 0;
|
|
5532
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SIZE_UPLOAD_T, &bytes);
|
|
5186
5533
|
return LL2NUM(bytes);
|
|
5187
5534
|
#else
|
|
5188
|
-
double bytes;
|
|
5189
|
-
|
|
5535
|
+
double bytes = 0;
|
|
5536
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
|
|
5190
5537
|
return rb_float_new(bytes);
|
|
5191
5538
|
#endif
|
|
5192
5539
|
}
|
|
@@ -5200,15 +5547,15 @@ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
|
5200
5547
|
*/
|
|
5201
5548
|
static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
5202
5549
|
ruby_curl_easy *rbce;
|
|
5203
|
-
|
|
5550
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5204
5551
|
|
|
5205
5552
|
#ifdef HAVE_CURLINFO_SIZE_DOWNLOAD_T
|
|
5206
|
-
curl_off_t bytes;
|
|
5207
|
-
|
|
5553
|
+
curl_off_t bytes = 0;
|
|
5554
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SIZE_DOWNLOAD_T, &bytes);
|
|
5208
5555
|
return LL2NUM(bytes);
|
|
5209
5556
|
#else
|
|
5210
|
-
double bytes;
|
|
5211
|
-
|
|
5557
|
+
double bytes = 0;
|
|
5558
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
|
|
5212
5559
|
return rb_float_new(bytes);
|
|
5213
5560
|
#endif
|
|
5214
5561
|
}
|
|
@@ -5222,15 +5569,15 @@ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
|
5222
5569
|
*/
|
|
5223
5570
|
static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
5224
5571
|
ruby_curl_easy *rbce;
|
|
5225
|
-
|
|
5572
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5226
5573
|
|
|
5227
5574
|
#ifdef HAVE_CURLINFO_SPEED_UPLOAD_T
|
|
5228
|
-
curl_off_t bytes;
|
|
5229
|
-
|
|
5575
|
+
curl_off_t bytes = 0;
|
|
5576
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SPEED_UPLOAD_T, &bytes);
|
|
5230
5577
|
return LL2NUM(bytes);
|
|
5231
5578
|
#else
|
|
5232
|
-
double bytes;
|
|
5233
|
-
|
|
5579
|
+
double bytes = 0;
|
|
5580
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
|
|
5234
5581
|
return rb_float_new(bytes);
|
|
5235
5582
|
#endif
|
|
5236
5583
|
}
|
|
@@ -5244,15 +5591,15 @@ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
|
5244
5591
|
*/
|
|
5245
5592
|
static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
|
|
5246
5593
|
ruby_curl_easy *rbce;
|
|
5247
|
-
|
|
5594
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5248
5595
|
|
|
5249
5596
|
#ifdef HAVE_CURLINFO_SPEED_DOWNLOAD_T
|
|
5250
|
-
curl_off_t bytes;
|
|
5251
|
-
|
|
5597
|
+
curl_off_t bytes = 0;
|
|
5598
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SPEED_DOWNLOAD_T, &bytes);
|
|
5252
5599
|
return LL2NUM(bytes);
|
|
5253
5600
|
#else
|
|
5254
|
-
double bytes;
|
|
5255
|
-
|
|
5601
|
+
double bytes = 0;
|
|
5602
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
|
|
5256
5603
|
return rb_float_new(bytes);
|
|
5257
5604
|
#endif
|
|
5258
5605
|
}
|
|
@@ -5266,10 +5613,10 @@ static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
|
|
|
5266
5613
|
*/
|
|
5267
5614
|
static VALUE ruby_curl_easy_header_size_get(VALUE self) {
|
|
5268
5615
|
ruby_curl_easy *rbce;
|
|
5269
|
-
long size;
|
|
5616
|
+
long size = 0;
|
|
5270
5617
|
|
|
5271
|
-
|
|
5272
|
-
|
|
5618
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5619
|
+
CURB_GETINFO(rbce->curl, CURLINFO_HEADER_SIZE, &size);
|
|
5273
5620
|
|
|
5274
5621
|
return LONG2NUM(size);
|
|
5275
5622
|
}
|
|
@@ -5284,10 +5631,10 @@ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
|
|
|
5284
5631
|
*/
|
|
5285
5632
|
static VALUE ruby_curl_easy_request_size_get(VALUE self) {
|
|
5286
5633
|
ruby_curl_easy *rbce;
|
|
5287
|
-
long size;
|
|
5634
|
+
long size = 0;
|
|
5288
5635
|
|
|
5289
|
-
|
|
5290
|
-
|
|
5636
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5637
|
+
CURB_GETINFO(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
|
|
5291
5638
|
|
|
5292
5639
|
return LONG2NUM(size);
|
|
5293
5640
|
}
|
|
@@ -5301,10 +5648,10 @@ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
|
|
|
5301
5648
|
*/
|
|
5302
5649
|
static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
|
|
5303
5650
|
ruby_curl_easy *rbce;
|
|
5304
|
-
long result;
|
|
5651
|
+
long result = 0;
|
|
5305
5652
|
|
|
5306
|
-
|
|
5307
|
-
|
|
5653
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5654
|
+
CURB_GETINFO(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
|
|
5308
5655
|
|
|
5309
5656
|
return LONG2NUM(result);
|
|
5310
5657
|
}
|
|
@@ -5326,15 +5673,15 @@ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done
|
|
|
5326
5673
|
*/
|
|
5327
5674
|
static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
5328
5675
|
ruby_curl_easy *rbce;
|
|
5329
|
-
|
|
5676
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5330
5677
|
|
|
5331
5678
|
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
|
|
5332
|
-
curl_off_t bytes;
|
|
5333
|
-
|
|
5679
|
+
curl_off_t bytes = 0;
|
|
5680
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &bytes);
|
|
5334
5681
|
return LL2NUM(bytes);
|
|
5335
5682
|
#else
|
|
5336
|
-
double bytes;
|
|
5337
|
-
|
|
5683
|
+
double bytes = 0;
|
|
5684
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
|
|
5338
5685
|
return rb_float_new(bytes);
|
|
5339
5686
|
#endif
|
|
5340
5687
|
}
|
|
@@ -5347,15 +5694,15 @@ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
|
5347
5694
|
*/
|
|
5348
5695
|
static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
|
|
5349
5696
|
ruby_curl_easy *rbce;
|
|
5350
|
-
|
|
5697
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5351
5698
|
|
|
5352
5699
|
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_UPLOAD_T
|
|
5353
|
-
curl_off_t bytes;
|
|
5354
|
-
|
|
5700
|
+
curl_off_t bytes = 0;
|
|
5701
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &bytes);
|
|
5355
5702
|
return LL2NUM(bytes);
|
|
5356
5703
|
#else
|
|
5357
|
-
double bytes;
|
|
5358
|
-
|
|
5704
|
+
double bytes = 0;
|
|
5705
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
|
|
5359
5706
|
return rb_float_new(bytes);
|
|
5360
5707
|
#endif
|
|
5361
5708
|
}
|
|
@@ -5371,10 +5718,10 @@ static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
|
|
|
5371
5718
|
*/
|
|
5372
5719
|
static VALUE ruby_curl_easy_content_type_get(VALUE self) {
|
|
5373
5720
|
ruby_curl_easy *rbce;
|
|
5374
|
-
char* type;
|
|
5721
|
+
char* type = NULL;
|
|
5375
5722
|
|
|
5376
|
-
|
|
5377
|
-
|
|
5723
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5724
|
+
CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
|
|
5378
5725
|
|
|
5379
5726
|
if (type && type[0]) { // curl returns empty string if none
|
|
5380
5727
|
return rb_str_new2(type);
|
|
@@ -5414,10 +5761,10 @@ Pass a pointer to a long to receive a bitmask indicating the authentication meth
|
|
|
5414
5761
|
static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
|
5415
5762
|
#ifdef HAVE_CURLINFO_OS_ERRNO
|
|
5416
5763
|
ruby_curl_easy *rbce;
|
|
5417
|
-
long result;
|
|
5764
|
+
long result = 0;
|
|
5418
5765
|
|
|
5419
|
-
|
|
5420
|
-
|
|
5766
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5767
|
+
CURB_GETINFO(rbce->curl, CURLINFO_OS_ERRNO, &result);
|
|
5421
5768
|
|
|
5422
5769
|
return LONG2NUM(result);
|
|
5423
5770
|
#else
|
|
@@ -5443,10 +5790,10 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
|
|
5443
5790
|
static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
|
5444
5791
|
#ifdef HAVE_CURLINFO_NUM_CONNECTS
|
|
5445
5792
|
ruby_curl_easy *rbce;
|
|
5446
|
-
long result;
|
|
5793
|
+
long result = 0;
|
|
5447
5794
|
|
|
5448
|
-
|
|
5449
|
-
|
|
5795
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5796
|
+
CURB_GETINFO(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
|
|
5450
5797
|
|
|
5451
5798
|
return LONG2NUM(result);
|
|
5452
5799
|
#else
|
|
@@ -5478,12 +5825,12 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
|
|
5478
5825
|
static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
|
|
5479
5826
|
#ifdef HAVE_CURLINFO_COOKIELIST
|
|
5480
5827
|
ruby_curl_easy *rbce;
|
|
5481
|
-
struct curl_slist *cookies;
|
|
5828
|
+
struct curl_slist *cookies = NULL;
|
|
5482
5829
|
struct curl_slist *cookie;
|
|
5483
5830
|
VALUE rb_cookies;
|
|
5484
5831
|
|
|
5485
|
-
|
|
5486
|
-
|
|
5832
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5833
|
+
CURB_GETINFO(rbce->curl, CURLINFO_COOKIELIST, &cookies);
|
|
5487
5834
|
if (!cookies)
|
|
5488
5835
|
return Qnil;
|
|
5489
5836
|
rb_cookies = rb_ary_new();
|
|
@@ -5522,8 +5869,8 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
5522
5869
|
ruby_curl_easy *rbce;
|
|
5523
5870
|
char* path = NULL;
|
|
5524
5871
|
|
|
5525
|
-
|
|
5526
|
-
|
|
5872
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5873
|
+
CURB_GETINFO(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
|
|
5527
5874
|
|
|
5528
5875
|
if (path && path[0]) { // curl returns NULL or empty string if none
|
|
5529
5876
|
return rb_str_new2(path);
|
|
@@ -5542,7 +5889,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
5542
5889
|
*/
|
|
5543
5890
|
static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
5544
5891
|
ruby_curl_easy *rbce;
|
|
5545
|
-
|
|
5892
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5546
5893
|
return rbce->multi;
|
|
5547
5894
|
}
|
|
5548
5895
|
|
|
@@ -5555,7 +5902,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
|
5555
5902
|
VALUE old_multi;
|
|
5556
5903
|
ruby_curl_multi *old_rbcm;
|
|
5557
5904
|
CURLMcode result;
|
|
5558
|
-
|
|
5905
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5559
5906
|
|
|
5560
5907
|
if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
|
|
5561
5908
|
rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
|
|
@@ -5584,7 +5931,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
|
5584
5931
|
*/
|
|
5585
5932
|
static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
5586
5933
|
ruby_curl_easy *rbce;
|
|
5587
|
-
|
|
5934
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5588
5935
|
return LONG2NUM(rbce->last_result);
|
|
5589
5936
|
}
|
|
5590
5937
|
|
|
@@ -5594,7 +5941,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
|
5594
5941
|
*/
|
|
5595
5942
|
static VALUE ruby_curl_easy_last_error(VALUE self) {
|
|
5596
5943
|
ruby_curl_easy *rbce;
|
|
5597
|
-
|
|
5944
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5598
5945
|
|
|
5599
5946
|
if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
|
|
5600
5947
|
return rb_str_new2(rbce->err_buf);
|
|
@@ -5632,7 +5979,8 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
5632
5979
|
long option = NUM2LONG(opt);
|
|
5633
5980
|
rb_io_t *open_f_ptr;
|
|
5634
5981
|
|
|
5635
|
-
|
|
5982
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
5983
|
+
ruby_curl_easy_check_idle(rbce);
|
|
5636
5984
|
|
|
5637
5985
|
switch (option) {
|
|
5638
5986
|
/* BEHAVIOR OPTIONS */
|
|
@@ -5652,6 +6000,7 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
5652
6000
|
CURB_OBJECT_HSETTER(ruby_curl_easy, url);
|
|
5653
6001
|
} break;
|
|
5654
6002
|
case CURLOPT_CUSTOMREQUEST:
|
|
6003
|
+
if (!NIL_P(val)) curb_check_header_line(StringValue(val), "custom request method");
|
|
5655
6004
|
curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5656
6005
|
break;
|
|
5657
6006
|
case CURLOPT_HTTP_VERSION: {
|
|
@@ -5727,6 +6076,7 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
5727
6076
|
#ifdef HAVE_CURLOPT_REQUEST_TARGET
|
|
5728
6077
|
case CURLOPT_REQUEST_TARGET: {
|
|
5729
6078
|
/* Forward request-target directly to libcurl as a string. */
|
|
6079
|
+
if (!NIL_P(val)) curb_check_header_line(StringValue(val), "request target");
|
|
5730
6080
|
curl_easy_setopt(rbce->curl, CURLOPT_REQUEST_TARGET, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5731
6081
|
} break;
|
|
5732
6082
|
#endif
|
|
@@ -5883,23 +6233,36 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
5883
6233
|
curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
|
|
5884
6234
|
break;
|
|
5885
6235
|
#endif
|
|
5886
|
-
case CURLOPT_STDERR:
|
|
6236
|
+
case CURLOPT_STDERR: {
|
|
5887
6237
|
// libcurl requires raw FILE pointer and this should be IO object in Ruby.
|
|
5888
6238
|
// Tempfile or StringIO won't work.
|
|
6239
|
+
FILE *stderr_file;
|
|
5889
6240
|
Check_Type(val, T_FILE);
|
|
5890
6241
|
GetOpenFile(val, open_f_ptr);
|
|
5891
|
-
|
|
5892
|
-
/*
|
|
5893
|
-
*
|
|
6242
|
+
rb_io_check_writable(open_f_ptr);
|
|
6243
|
+
/* Hand libcurl a stream curb owns on a duplicate descriptor. Passing
|
|
6244
|
+
* the IO's own FILE* left libcurl writing through freed memory once the
|
|
6245
|
+
* caller closed the IO, including after Multi#add. */
|
|
6246
|
+
#ifdef HAVE_RB_IO_DESCRIPTOR
|
|
6247
|
+
stderr_file = ruby_curl_easy_dup_stderr_file(rb_io_descriptor(val));
|
|
6248
|
+
#else
|
|
6249
|
+
stderr_file = ruby_curl_easy_dup_stderr_file(open_f_ptr->fd);
|
|
6250
|
+
#endif
|
|
6251
|
+
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, stderr_file);
|
|
6252
|
+
ruby_curl_easy_close_stderr_file(rbce);
|
|
6253
|
+
rbce->stderr_file = stderr_file;
|
|
6254
|
+
/* Kept so completion can flush the caller's own buffered output. */
|
|
5894
6255
|
rb_easy_set("stderr_io", val);
|
|
5895
|
-
break;
|
|
6256
|
+
} break;
|
|
5896
6257
|
case CURLOPT_PROTOCOLS:
|
|
5897
6258
|
case CURLOPT_REDIR_PROTOCOLS:
|
|
5898
6259
|
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
|
6260
|
+
if (option == CURLOPT_PROTOCOLS) rbce->protocols_set = 1;
|
|
5899
6261
|
break;
|
|
5900
6262
|
#ifdef HAVE_CURLOPT_PROTOCOLS_STR
|
|
5901
6263
|
case CURLOPT_PROTOCOLS_STR:
|
|
5902
6264
|
curl_easy_setopt(rbce->curl, CURLOPT_PROTOCOLS_STR, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
6265
|
+
rbce->protocols_set = !NIL_P(val);
|
|
5903
6266
|
break;
|
|
5904
6267
|
#endif
|
|
5905
6268
|
#ifdef HAVE_CURLOPT_REDIR_PROTOCOLS_STR
|
|
@@ -6084,6 +6447,28 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
|
|
|
6084
6447
|
|
|
6085
6448
|
/* ================== ESCAPING FUNCS ==============*/
|
|
6086
6449
|
|
|
6450
|
+
struct curl_string_result {
|
|
6451
|
+
char *data;
|
|
6452
|
+
long length;
|
|
6453
|
+
};
|
|
6454
|
+
|
|
6455
|
+
static VALUE curl_string_result_body(VALUE argp) {
|
|
6456
|
+
struct curl_string_result *args = (struct curl_string_result *)argp;
|
|
6457
|
+
return rb_str_new(args->data, args->length);
|
|
6458
|
+
}
|
|
6459
|
+
|
|
6460
|
+
static VALUE curl_string_result_free(VALUE argp) {
|
|
6461
|
+
struct curl_string_result *args = (struct curl_string_result *)argp;
|
|
6462
|
+
curl_free(args->data);
|
|
6463
|
+
return Qnil;
|
|
6464
|
+
}
|
|
6465
|
+
|
|
6466
|
+
static VALUE curl_string_result_to_ruby(char *data, long length) {
|
|
6467
|
+
struct curl_string_result args = { data, length };
|
|
6468
|
+
return rb_ensure(curl_string_result_body, (VALUE)&args,
|
|
6469
|
+
curl_string_result_free, (VALUE)&args);
|
|
6470
|
+
}
|
|
6471
|
+
|
|
6087
6472
|
/*
|
|
6088
6473
|
* call-seq:
|
|
6089
6474
|
* easy.escape("some text") => "some%20text"
|
|
@@ -6096,10 +6481,9 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
|
|
|
6096
6481
|
static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
|
|
6097
6482
|
ruby_curl_easy *rbce;
|
|
6098
6483
|
char *result;
|
|
6099
|
-
VALUE rresult;
|
|
6100
6484
|
VALUE str = svalue;
|
|
6101
6485
|
|
|
6102
|
-
|
|
6486
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
6103
6487
|
|
|
6104
6488
|
/* NOTE: make sure the value is a string; rb_obj_as_string always yields a
|
|
6105
6489
|
* String, even if the object's to_s misbehaves and returns a non-String. */
|
|
@@ -6111,10 +6495,8 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
|
|
|
6111
6495
|
result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
|
|
6112
6496
|
#endif
|
|
6113
6497
|
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
return rresult;
|
|
6498
|
+
if (!result) rb_raise(eCurlErrError, "Failed to URL-encode string");
|
|
6499
|
+
return curl_string_result_to_ruby(result, (long)strlen(result));
|
|
6118
6500
|
}
|
|
6119
6501
|
|
|
6120
6502
|
/*
|
|
@@ -6129,9 +6511,8 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
6129
6511
|
ruby_curl_easy *rbce;
|
|
6130
6512
|
int rlen;
|
|
6131
6513
|
char *result;
|
|
6132
|
-
VALUE rresult;
|
|
6133
6514
|
|
|
6134
|
-
|
|
6515
|
+
rbce = ruby_curl_easy_get_handle(self);
|
|
6135
6516
|
|
|
6136
6517
|
/* Coerce as its own statement before use below - StringValuePtr and
|
|
6137
6518
|
* RSTRING_LEN are sibling args to the same call and C does not guarantee
|
|
@@ -6142,13 +6523,13 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
6142
6523
|
result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
|
|
6143
6524
|
#else
|
|
6144
6525
|
result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
|
|
6145
|
-
rlen = strlen(result);
|
|
6146
6526
|
#endif
|
|
6147
6527
|
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6528
|
+
if (!result) rb_raise(eCurlErrError, "Failed to URL-decode string");
|
|
6529
|
+
#if (LIBCURL_VERSION_NUM < 0x070f04)
|
|
6530
|
+
rlen = (int)strlen(result);
|
|
6531
|
+
#endif
|
|
6532
|
+
return curl_string_result_to_ruby(result, rlen);
|
|
6152
6533
|
}
|
|
6153
6534
|
|
|
6154
6535
|
|