curb 0.8.5 → 1.3.6
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 +7 -0
- data/README.md +579 -0
- data/Rakefile +85 -27
- data/doc.rb +48 -8
- data/ext/banned.h +32 -0
- data/ext/curb.c +563 -233
- data/ext/curb.h +19 -10
- data/ext/curb_easy.c +3229 -368
- data/ext/curb_easy.h +42 -0
- data/ext/curb_errors.c +117 -18
- data/ext/curb_errors.h +9 -5
- data/ext/curb_macros.h +33 -21
- data/ext/curb_multi.c +1904 -272
- data/ext/curb_multi.h +11 -3
- data/ext/curb_postfield.c +149 -77
- data/ext/curb_postfield.h +1 -0
- data/ext/curb_upload.c +38 -11
- data/ext/curb_upload.h +2 -0
- data/ext/extconf.rb +355 -35
- data/lib/curb.rb +1 -0
- data/lib/curl/download.rb +160 -0
- data/lib/curl/easy.rb +422 -88
- data/lib/curl/multi.rb +295 -56
- data/lib/curl.rb +676 -11
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +32 -16
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
- data/tests/bug_follow_redirect_288.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
- data/tests/bug_issue102.rb +17 -0
- data/tests/bug_issue_noproxy.rb +56 -0
- data/tests/bug_issue_post_redirect.rb +93 -0
- data/tests/bug_issue_spnego.rb +41 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_poison.rb +29 -0
- data/tests/bug_raise_on_callback.rb +30 -0
- data/tests/helper.rb +400 -44
- data/tests/leak_trace.rb +237 -0
- data/tests/mem_check.rb +3 -0
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +98 -7
- data/tests/tc_curl_easy.rb +985 -66
- data/tests/tc_curl_easy_cookielist.rb +277 -0
- data/tests/tc_curl_easy_request_target.rb +41 -0
- data/tests/tc_curl_easy_resolve.rb +48 -0
- data/tests/tc_curl_maxfilesize.rb +212 -0
- data/tests/tc_curl_multi.rb +1111 -51
- data/tests/tc_curl_native_coverage.rb +145 -0
- data/tests/tc_curl_network_policy.rb +1475 -0
- data/tests/tc_curl_postfield.rb +207 -30
- data/tests/tc_curl_protocols.rb +388 -0
- data/tests/tc_fiber_scheduler.rb +584 -0
- data/tests/tc_ftp_options.rb +39 -0
- data/tests/tc_gc_compact.rb +223 -0
- data/tests/tc_test_server_methods.rb +110 -0
- data/tests/timeout.rb +30 -6
- metadata +66 -31
- data/README +0 -194
data/ext/curb_easy.c
CHANGED
|
@@ -11,13 +11,36 @@
|
|
|
11
11
|
#include "curb_multi.h"
|
|
12
12
|
|
|
13
13
|
#include <errno.h>
|
|
14
|
+
#include <stdlib.h>
|
|
14
15
|
#include <string.h>
|
|
16
|
+
#ifndef _WIN32
|
|
17
|
+
#include <sys/types.h>
|
|
18
|
+
#include <sys/socket.h>
|
|
19
|
+
#include <netinet/in.h>
|
|
20
|
+
#include <arpa/inet.h>
|
|
21
|
+
#else
|
|
22
|
+
#include <winsock2.h>
|
|
23
|
+
#include <ws2tcpip.h>
|
|
24
|
+
#endif
|
|
25
|
+
#ifndef _WIN32
|
|
26
|
+
#include <strings.h>
|
|
27
|
+
#endif
|
|
28
|
+
|
|
29
|
+
#if defined(HAVE_CURLOPT_OPENSOCKETFUNCTION) && defined(HAVE_CURLOPT_OPENSOCKETDATA)
|
|
30
|
+
#define CURB_HAVE_OPENSOCKET_NETWORK_POLICY 1
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
#if defined(HAVE_CURLOPT_PREREQFUNCTION) && defined(HAVE_CURLOPT_PREREQDATA)
|
|
34
|
+
#define CURB_HAVE_PREREQ_HOST_POLICY 1
|
|
35
|
+
#endif
|
|
15
36
|
|
|
16
37
|
extern VALUE mCurl;
|
|
17
38
|
|
|
18
39
|
static VALUE idCall;
|
|
19
40
|
static VALUE idJoin;
|
|
20
41
|
static VALUE rbstrAmp;
|
|
42
|
+
static ID idNetworkPolicyNone;
|
|
43
|
+
static ID idNetworkPolicyPublic;
|
|
21
44
|
|
|
22
45
|
#ifdef RDOC_NEVER_DEFINED
|
|
23
46
|
mCurl = rb_define_module("Curl");
|
|
@@ -25,20 +48,859 @@ static VALUE rbstrAmp;
|
|
|
25
48
|
|
|
26
49
|
VALUE cCurlEasy;
|
|
27
50
|
|
|
51
|
+
/* Internal wrapper type for passing pointers through rb_iterate callbacks.
|
|
52
|
+
* No mark/free needed - these are temporary wrappers that don't own memory. */
|
|
53
|
+
static const rb_data_type_t curl_slist_ptr_type = {
|
|
54
|
+
"curl_slist_ptr_wrapper",
|
|
55
|
+
{ NULL, NULL, NULL },
|
|
56
|
+
NULL, NULL, 0
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// for Ruby 1.8
|
|
60
|
+
#ifndef HAVE_RB_IO_STDIO_FILE
|
|
61
|
+
static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
|
62
|
+
return fptr->f;
|
|
63
|
+
}
|
|
64
|
+
#endif
|
|
65
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list);
|
|
66
|
+
static size_t proc_data_handler(char *stream, size_t size, size_t nmemb, VALUE proc);
|
|
67
|
+
static int curb_array_includes_string(VALUE list, VALUE value);
|
|
28
68
|
|
|
29
69
|
/* ================== CURL HANDLER FUNCS ==============*/
|
|
30
70
|
|
|
31
|
-
static
|
|
71
|
+
static int curb_ipv4_is_unsafe_destination(const unsigned char *ip) {
|
|
72
|
+
if (ip[0] == 0) return 1; /* 0.0.0.0/8 */
|
|
73
|
+
if (ip[0] == 10) return 1; /* RFC1918 */
|
|
74
|
+
if (ip[0] == 100 && (ip[1] & 0xc0) == 0x40) return 1; /* 100.64.0.0/10 */
|
|
75
|
+
if (ip[0] == 100 && ip[1] == 100 && ip[2] == 100 && ip[3] == 200) return 1;
|
|
76
|
+
if (ip[0] == 127) return 1; /* loopback */
|
|
77
|
+
if (ip[0] == 169 && ip[1] == 254) return 1; /* link-local / metadata */
|
|
78
|
+
if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) return 1;/* RFC1918 */
|
|
79
|
+
if (ip[0] == 192 && ip[1] == 168) return 1; /* RFC1918 */
|
|
80
|
+
if (ip[0] == 192 && ip[1] == 0 && ip[2] == 0) return 1; /* IETF protocol assignments */
|
|
81
|
+
if (ip[0] == 192 && ip[1] == 0 && ip[2] == 2) return 1; /* TEST-NET-1 */
|
|
82
|
+
if (ip[0] == 198 && (ip[1] == 18 || ip[1] == 19)) return 1;
|
|
83
|
+
if (ip[0] == 198 && ip[1] == 51 && ip[2] == 100) return 1;
|
|
84
|
+
if (ip[0] == 203 && ip[1] == 0 && ip[2] == 113) return 1;
|
|
85
|
+
if (ip[0] >= 224) return 1; /* multicast/reserved */
|
|
86
|
+
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static int curb_ip_prefix_matches(const unsigned char *ip, const unsigned char *prefix, int bits) {
|
|
91
|
+
int full_bytes = bits / 8;
|
|
92
|
+
int remaining_bits = bits % 8;
|
|
93
|
+
int i;
|
|
94
|
+
|
|
95
|
+
for (i = 0; i < full_bytes; i++) {
|
|
96
|
+
if (ip[i] != prefix[i]) return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (remaining_bits) {
|
|
100
|
+
unsigned char mask = (unsigned char)(0xff << (8 - remaining_bits));
|
|
101
|
+
if ((ip[full_bytes] & mask) != (prefix[full_bytes] & mask)) return 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static int curb_ipv6_prefix_matches(const unsigned char *ip, const unsigned char *prefix, int bits) {
|
|
108
|
+
return curb_ip_prefix_matches(ip, prefix, bits);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static int curb_ipv6_is_all_zero(const unsigned char *ip) {
|
|
112
|
+
int i;
|
|
113
|
+
|
|
114
|
+
for (i = 0; i < 16; i++) {
|
|
115
|
+
if (ip[i] != 0) return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static int curb_ipv6_is_ipv4_mapped(const unsigned char *ip) {
|
|
122
|
+
static const unsigned char prefix[12] = {
|
|
123
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return curb_ipv6_prefix_matches(ip, prefix, 96);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static int curb_ipv6_is_ipv4_compatible(const unsigned char *ip) {
|
|
130
|
+
static const unsigned char prefix[12] = {
|
|
131
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return curb_ipv6_prefix_matches(ip, prefix, 96);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static int curb_ipv6_is_nat64_well_known(const unsigned char *ip) {
|
|
138
|
+
static const unsigned char prefix[12] = {
|
|
139
|
+
0x00, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return curb_ipv6_prefix_matches(ip, prefix, 96);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static int curb_ipv6_is_nat64_local_use(const unsigned char *ip) {
|
|
146
|
+
static const unsigned char prefix[6] = {
|
|
147
|
+
0x00, 0x64, 0xff, 0x9b, 0x00, 0x01
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return curb_ipv6_prefix_matches(ip, prefix, 48);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static int curb_ipv6_is_unsafe_destination(const unsigned char *ip) {
|
|
154
|
+
static const unsigned char documentation_prefix[4] = { 0x20, 0x01, 0x0d, 0xb8 };
|
|
155
|
+
static const unsigned char benchmarking_prefix[6] = { 0x20, 0x01, 0x00, 0x02, 0, 0 };
|
|
156
|
+
|
|
157
|
+
if (curb_ipv6_is_all_zero(ip)) return 1; /* ::/128 */
|
|
158
|
+
if (curb_ipv6_is_ipv4_mapped(ip)) return curb_ipv4_is_unsafe_destination(ip + 12);
|
|
159
|
+
if (curb_ipv6_is_nat64_well_known(ip)) return curb_ipv4_is_unsafe_destination(ip + 12);
|
|
160
|
+
if (curb_ipv6_is_nat64_local_use(ip)) return 1;
|
|
161
|
+
if (curb_ipv6_is_ipv4_compatible(ip)) return 1; /* deprecated non-public space */
|
|
162
|
+
if (ip[0] == 0 && ip[1] == 0 && ip[14] == 0 && ip[15] == 1) return 1;
|
|
163
|
+
if ((ip[0] & 0xfe) == 0xfc) return 1; /* fc00::/7 */
|
|
164
|
+
if (ip[0] == 0xfe && (ip[1] & 0xc0) == 0x80) return 1; /* fe80::/10 */
|
|
165
|
+
if (ip[0] == 0xfe && (ip[1] & 0xc0) == 0xc0) return 1; /* fec0::/10 */
|
|
166
|
+
if (ip[0] == 0xff) return 1; /* multicast */
|
|
167
|
+
if (curb_ipv6_prefix_matches(ip, documentation_prefix, 32)) return 1;
|
|
168
|
+
if (curb_ipv6_prefix_matches(ip, benchmarking_prefix, 48)) return 1;
|
|
169
|
+
if (ip[0] == 0x20 && ip[1] == 0x02) return 1; /* 2002::/16 */
|
|
170
|
+
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static void curb_clear_network_allowed_cidr_rules(ruby_curl_easy *rbce) {
|
|
175
|
+
if (!rbce || !rbce->network_allowed_cidr_rules) return;
|
|
176
|
+
|
|
177
|
+
xfree(rbce->network_allowed_cidr_rules);
|
|
178
|
+
rbce->network_allowed_cidr_rules = NULL;
|
|
179
|
+
rbce->network_allowed_cidr_rule_count = 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static void curb_raise_invalid_cidr(char *tmp, const char *cidr) {
|
|
183
|
+
if (tmp) xfree(tmp);
|
|
184
|
+
rb_raise(rb_eArgError, "invalid CIDR range: %s", cidr);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
static void curb_parse_cidr_rule(const char *cidr, curb_cidr_rule *rule) {
|
|
188
|
+
size_t len;
|
|
189
|
+
char *tmp;
|
|
190
|
+
char *address;
|
|
191
|
+
char *prefix_str = NULL;
|
|
192
|
+
char *slash;
|
|
193
|
+
long prefix = -1;
|
|
194
|
+
int max_prefix = 0;
|
|
195
|
+
unsigned char parsed[16];
|
|
196
|
+
|
|
197
|
+
if (!cidr || !rule) {
|
|
198
|
+
rb_raise(rb_eArgError, "invalid CIDR range");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
len = strlen(cidr);
|
|
202
|
+
if (len == 0) {
|
|
203
|
+
rb_raise(rb_eArgError, "invalid CIDR range: %s", cidr);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
tmp = ALLOC_N(char, len + 1);
|
|
207
|
+
memcpy(tmp, cidr, len + 1);
|
|
208
|
+
address = tmp;
|
|
209
|
+
|
|
210
|
+
if (address[0] == '[') {
|
|
211
|
+
char *closing = strchr(address, ']');
|
|
212
|
+
if (!closing) curb_raise_invalid_cidr(tmp, cidr);
|
|
213
|
+
|
|
214
|
+
*closing = '\0';
|
|
215
|
+
address++;
|
|
216
|
+
|
|
217
|
+
if (closing[1] == '/') {
|
|
218
|
+
prefix_str = closing + 2;
|
|
219
|
+
} else if (closing[1] != '\0') {
|
|
220
|
+
curb_raise_invalid_cidr(tmp, cidr);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
slash = strchr(address, '/');
|
|
224
|
+
if (slash) {
|
|
225
|
+
*slash = '\0';
|
|
226
|
+
prefix_str = slash + 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
memset(rule, 0, sizeof(curb_cidr_rule));
|
|
231
|
+
|
|
232
|
+
if (inet_pton(AF_INET, address, parsed) == 1) {
|
|
233
|
+
rule->family = CURB_CIDR_FAMILY_IPV4;
|
|
234
|
+
max_prefix = 32;
|
|
235
|
+
memcpy(rule->address, parsed, 4);
|
|
236
|
+
} else if (inet_pton(AF_INET6, address, parsed) == 1) {
|
|
237
|
+
rule->family = CURB_CIDR_FAMILY_IPV6;
|
|
238
|
+
max_prefix = 128;
|
|
239
|
+
memcpy(rule->address, parsed, 16);
|
|
240
|
+
} else {
|
|
241
|
+
curb_raise_invalid_cidr(tmp, cidr);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (prefix_str) {
|
|
245
|
+
char *endptr = NULL;
|
|
246
|
+
|
|
247
|
+
if (prefix_str[0] == '\0') curb_raise_invalid_cidr(tmp, cidr);
|
|
248
|
+
|
|
249
|
+
errno = 0;
|
|
250
|
+
prefix = strtol(prefix_str, &endptr, 10);
|
|
251
|
+
if (errno != 0 || !endptr || *endptr != '\0' || prefix < 0 || prefix > max_prefix) {
|
|
252
|
+
curb_raise_invalid_cidr(tmp, cidr);
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
prefix = max_prefix;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
rule->prefix_bits = (unsigned char)prefix;
|
|
259
|
+
xfree(tmp);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static VALUE curb_normalize_cidr_list(VALUE cidrs) {
|
|
263
|
+
VALUE list;
|
|
264
|
+
VALUE normalized;
|
|
265
|
+
long i;
|
|
266
|
+
|
|
267
|
+
if (NIL_P(cidrs)) return Qnil;
|
|
268
|
+
|
|
269
|
+
list = rb_check_array_type(cidrs);
|
|
270
|
+
if (NIL_P(list)) {
|
|
271
|
+
list = rb_ary_new_from_args(1, cidrs);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
normalized = rb_ary_new_capa(RARRAY_LEN(list));
|
|
275
|
+
for (i = 0; i < RARRAY_LEN(list); i++) {
|
|
276
|
+
VALUE item = rb_ary_entry(list, i);
|
|
277
|
+
VALUE cidr = rb_obj_as_string(item);
|
|
278
|
+
curb_cidr_rule unused_rule;
|
|
279
|
+
|
|
280
|
+
curb_parse_cidr_rule(StringValueCStr(cidr), &unused_rule);
|
|
281
|
+
if (!curb_array_includes_string(normalized, cidr)) {
|
|
282
|
+
rb_ary_push(normalized, rb_str_dup(cidr));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return normalized;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
static VALUE curb_dup_string_array(VALUE list) {
|
|
290
|
+
VALUE copy;
|
|
291
|
+
long i;
|
|
292
|
+
|
|
293
|
+
if (NIL_P(list)) return Qnil;
|
|
294
|
+
|
|
295
|
+
copy = rb_ary_new_capa(RARRAY_LEN(list));
|
|
296
|
+
for (i = 0; i < RARRAY_LEN(list); i++) {
|
|
297
|
+
rb_ary_push(copy, rb_str_dup(rb_ary_entry(list, i)));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return copy;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
static int curb_array_includes_string(VALUE list, VALUE value) {
|
|
304
|
+
long i;
|
|
305
|
+
|
|
306
|
+
for (i = 0; i < RARRAY_LEN(list); i++) {
|
|
307
|
+
if (rb_str_cmp(rb_ary_entry(list, i), value) == 0) return 1;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return 0;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
static char curb_ascii_downcase(char c) {
|
|
314
|
+
if (c >= 'A' && c <= 'Z') return (char)(c - 'A' + 'a');
|
|
315
|
+
return c;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
static char *curb_normalized_host_from_range(const char *start, const char *end, int raise_errors) {
|
|
319
|
+
char *host;
|
|
320
|
+
size_t len;
|
|
321
|
+
size_t i;
|
|
322
|
+
|
|
323
|
+
while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) start++;
|
|
324
|
+
while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) end--;
|
|
325
|
+
while (end > start && end[-1] == '.') end--;
|
|
326
|
+
|
|
327
|
+
if (end <= start) {
|
|
328
|
+
if (!raise_errors) return NULL;
|
|
329
|
+
rb_raise(rb_eArgError, "allowed_hosts cannot include blank entries");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
len = (size_t)(end - start);
|
|
333
|
+
host = ALLOC_N(char, len + 1);
|
|
334
|
+
for (i = 0; i < len; i++) {
|
|
335
|
+
host[i] = curb_ascii_downcase(start[i]);
|
|
336
|
+
}
|
|
337
|
+
host[len] = '\0';
|
|
338
|
+
|
|
339
|
+
return host;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
static char *curb_normalize_host_value_impl(const char *value, int raise_errors) {
|
|
343
|
+
const char *start;
|
|
344
|
+
const char *end;
|
|
345
|
+
const char *scheme;
|
|
346
|
+
const char *authority_end;
|
|
347
|
+
const char *scan;
|
|
348
|
+
const char *last_at = NULL;
|
|
349
|
+
int colon_count = 0;
|
|
350
|
+
|
|
351
|
+
if (!value) {
|
|
352
|
+
if (!raise_errors) return NULL;
|
|
353
|
+
rb_raise(rb_eArgError, "allowed_hosts cannot include blank entries");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
start = value;
|
|
357
|
+
end = value + strlen(value);
|
|
358
|
+
while (start < end && (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')) start++;
|
|
359
|
+
while (end > start && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) end--;
|
|
360
|
+
if (end <= start) {
|
|
361
|
+
if (!raise_errors) return NULL;
|
|
362
|
+
rb_raise(rb_eArgError, "allowed_hosts cannot include blank entries");
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
scheme = strstr(start, "://");
|
|
366
|
+
if (scheme && scheme < end) {
|
|
367
|
+
start = scheme + 3;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
authority_end = end;
|
|
371
|
+
for (scan = start; scan < end; scan++) {
|
|
372
|
+
if (*scan == '/' || *scan == '?' || *scan == '#') {
|
|
373
|
+
authority_end = scan;
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
for (scan = start; scan < authority_end; scan++) {
|
|
379
|
+
if (*scan == '@') last_at = scan;
|
|
380
|
+
}
|
|
381
|
+
if (last_at) start = last_at + 1;
|
|
382
|
+
|
|
383
|
+
if (start < authority_end && *start == '[') {
|
|
384
|
+
const char *closing = start + 1;
|
|
385
|
+
while (closing < authority_end && *closing != ']') closing++;
|
|
386
|
+
if (closing >= authority_end) {
|
|
387
|
+
if (!raise_errors) return NULL;
|
|
388
|
+
rb_raise(rb_eArgError, "invalid allowed host: %s", value);
|
|
389
|
+
}
|
|
390
|
+
return curb_normalized_host_from_range(start + 1, closing, raise_errors);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
for (scan = start; scan < authority_end; scan++) {
|
|
394
|
+
if (*scan == ':') colon_count++;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (colon_count <= 1) {
|
|
398
|
+
for (scan = start; scan < authority_end; scan++) {
|
|
399
|
+
if (*scan == ':') {
|
|
400
|
+
authority_end = scan;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return curb_normalized_host_from_range(start, authority_end, raise_errors);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
static char *curb_normalize_host_value(const char *value) {
|
|
410
|
+
return curb_normalize_host_value_impl(value, 1);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
static char *curb_try_normalize_host_value(const char *value) {
|
|
414
|
+
return curb_normalize_host_value_impl(value, 0);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
static VALUE curb_normalize_host_list(VALUE hosts) {
|
|
418
|
+
VALUE list;
|
|
419
|
+
VALUE normalized;
|
|
420
|
+
long i;
|
|
421
|
+
|
|
422
|
+
if (NIL_P(hosts)) return Qnil;
|
|
423
|
+
|
|
424
|
+
list = rb_check_array_type(hosts);
|
|
425
|
+
if (NIL_P(list)) {
|
|
426
|
+
list = rb_ary_new_from_args(1, hosts);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
normalized = rb_ary_new_capa(RARRAY_LEN(list));
|
|
430
|
+
for (i = 0; i < RARRAY_LEN(list); i++) {
|
|
431
|
+
VALUE item = rb_ary_entry(list, i);
|
|
432
|
+
VALUE host_value = rb_obj_as_string(item);
|
|
433
|
+
char *host = curb_normalize_host_value(StringValueCStr(host_value));
|
|
434
|
+
VALUE normalized_host = rb_str_new_cstr(host);
|
|
435
|
+
|
|
436
|
+
if (!curb_array_includes_string(normalized, normalized_host)) {
|
|
437
|
+
rb_ary_push(normalized, normalized_host);
|
|
438
|
+
}
|
|
439
|
+
xfree(host);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return normalized;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
static void curb_clear_network_allowed_hosts(ruby_curl_easy *rbce) {
|
|
446
|
+
size_t i;
|
|
447
|
+
|
|
448
|
+
if (!rbce || !rbce->network_allowed_hosts) return;
|
|
449
|
+
|
|
450
|
+
for (i = 0; i < rbce->network_allowed_host_count; i++) {
|
|
451
|
+
if (rbce->network_allowed_hosts[i]) xfree(rbce->network_allowed_hosts[i]);
|
|
452
|
+
}
|
|
453
|
+
xfree(rbce->network_allowed_hosts);
|
|
454
|
+
rbce->network_allowed_hosts = NULL;
|
|
455
|
+
rbce->network_allowed_host_count = 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
static char *curb_strdup_cstr(const char *value) {
|
|
459
|
+
size_t len = strlen(value);
|
|
460
|
+
char *copy = ALLOC_N(char, len + 1);
|
|
461
|
+
memcpy(copy, value, len + 1);
|
|
462
|
+
return copy;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
static void curb_prepare_network_allowed_hosts(ruby_curl_easy *rbce) {
|
|
466
|
+
VALUE hosts;
|
|
467
|
+
long count;
|
|
468
|
+
long i;
|
|
469
|
+
char **rules;
|
|
470
|
+
|
|
471
|
+
if (!rbce) return;
|
|
472
|
+
|
|
473
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
474
|
+
|
|
475
|
+
hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
|
|
476
|
+
if (NIL_P(hosts)) return;
|
|
477
|
+
|
|
478
|
+
count = RARRAY_LEN(hosts);
|
|
479
|
+
if (count <= 0) return;
|
|
480
|
+
|
|
481
|
+
rules = ALLOC_N(char *, count);
|
|
482
|
+
for (i = 0; i < count; i++) {
|
|
483
|
+
VALUE host = rb_ary_entry(hosts, i);
|
|
484
|
+
rules[i] = curb_strdup_cstr(StringValueCStr(host));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
rbce->network_allowed_hosts = rules;
|
|
488
|
+
rbce->network_allowed_host_count = (size_t)count;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static int curb_host_rules_match(const ruby_curl_easy *rbce, const char *host) {
|
|
492
|
+
size_t i;
|
|
493
|
+
|
|
494
|
+
if (!rbce || rbce->network_allowed_host_count == 0) return 1;
|
|
495
|
+
|
|
496
|
+
for (i = 0; i < rbce->network_allowed_host_count; i++) {
|
|
497
|
+
if (strcmp(host, rbce->network_allowed_hosts[i]) == 0) return 1;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return 0;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
static void curb_prepare_network_allowed_cidr_rules(ruby_curl_easy *rbce) {
|
|
504
|
+
VALUE cidrs;
|
|
505
|
+
long count;
|
|
506
|
+
long i;
|
|
507
|
+
curb_cidr_rule *rules;
|
|
508
|
+
|
|
509
|
+
if (!rbce) return;
|
|
510
|
+
|
|
511
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
512
|
+
|
|
513
|
+
cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
|
|
514
|
+
if (NIL_P(cidrs)) return;
|
|
515
|
+
|
|
516
|
+
count = RARRAY_LEN(cidrs);
|
|
517
|
+
if (count <= 0) return;
|
|
518
|
+
|
|
519
|
+
rules = ALLOC_N(curb_cidr_rule, count);
|
|
520
|
+
for (i = 0; i < count; i++) {
|
|
521
|
+
VALUE cidr = rb_ary_entry(cidrs, i);
|
|
522
|
+
curb_parse_cidr_rule(StringValueCStr(cidr), &rules[i]);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
rbce->network_allowed_cidr_rules = rules;
|
|
526
|
+
rbce->network_allowed_cidr_rule_count = (size_t)count;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
static int curb_cidr_rules_match(const ruby_curl_easy *rbce, unsigned char family, const unsigned char *ip) {
|
|
530
|
+
size_t i;
|
|
531
|
+
|
|
532
|
+
if (!rbce || rbce->network_allowed_cidr_rule_count == 0) return 1;
|
|
533
|
+
|
|
534
|
+
for (i = 0; i < rbce->network_allowed_cidr_rule_count; i++) {
|
|
535
|
+
const curb_cidr_rule *rule = &rbce->network_allowed_cidr_rules[i];
|
|
536
|
+
if (rule->family != family) continue;
|
|
537
|
+
if (curb_ip_prefix_matches(ip, rule->address, rule->prefix_bits)) return 1;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return 0;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
static void curb_format_ipv4(char *buf, size_t len, const unsigned char *ip) {
|
|
544
|
+
snprintf(buf, len, "%u.%u.%u.%u",
|
|
545
|
+
(unsigned int)ip[0], (unsigned int)ip[1],
|
|
546
|
+
(unsigned int)ip[2], (unsigned int)ip[3]);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
static void curb_format_ipv6(char *buf, size_t len, const unsigned char *ip) {
|
|
550
|
+
#ifdef AF_INET6
|
|
551
|
+
#ifdef _WIN32
|
|
552
|
+
if (inet_ntop(AF_INET6, (void *)ip, buf, len)) return;
|
|
553
|
+
#else
|
|
554
|
+
if (inet_ntop(AF_INET6, (const void *)ip, buf, (socklen_t)len)) return;
|
|
555
|
+
#endif
|
|
556
|
+
#endif
|
|
557
|
+
|
|
558
|
+
snprintf(buf, len,
|
|
559
|
+
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
|
560
|
+
(unsigned int)ip[0], (unsigned int)ip[1],
|
|
561
|
+
(unsigned int)ip[2], (unsigned int)ip[3],
|
|
562
|
+
(unsigned int)ip[4], (unsigned int)ip[5],
|
|
563
|
+
(unsigned int)ip[6], (unsigned int)ip[7],
|
|
564
|
+
(unsigned int)ip[8], (unsigned int)ip[9],
|
|
565
|
+
(unsigned int)ip[10], (unsigned int)ip[11],
|
|
566
|
+
(unsigned int)ip[12], (unsigned int)ip[13],
|
|
567
|
+
(unsigned int)ip[14], (unsigned int)ip[15]);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
static void curb_store_destination_error(ruby_curl_easy *rbce, const char *address, const char *reason) {
|
|
571
|
+
if (!rbce) return;
|
|
572
|
+
|
|
573
|
+
rbce->unsafe_destination_blocked = 1;
|
|
574
|
+
|
|
575
|
+
if (reason && reason[0]) {
|
|
576
|
+
snprintf(rbce->unsafe_destination_error, CURL_ERROR_SIZE,
|
|
577
|
+
"blocked destination address %s %s by public network policy", address, reason);
|
|
578
|
+
} else {
|
|
579
|
+
snprintf(rbce->unsafe_destination_error, CURL_ERROR_SIZE,
|
|
580
|
+
"blocked unsafe destination address %s by public network policy", address);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
snprintf(rbce->err_buf, CURL_ERROR_SIZE, "%s", rbce->unsafe_destination_error);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
static void curb_store_unsafe_destination_error(ruby_curl_easy *rbce, const char *address) {
|
|
587
|
+
curb_store_destination_error(rbce, address, NULL);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
static void curb_store_host_allowlist_error(ruby_curl_easy *rbce, const char *host) {
|
|
591
|
+
if (!rbce) return;
|
|
592
|
+
|
|
593
|
+
rbce->unsafe_destination_blocked = 1;
|
|
594
|
+
snprintf(rbce->unsafe_destination_error, CURL_ERROR_SIZE,
|
|
595
|
+
"blocked URL host %s by safe mode host allowlist", host ? host : "unknown");
|
|
596
|
+
snprintf(rbce->err_buf, CURL_ERROR_SIZE, "%s", rbce->unsafe_destination_error);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
#ifdef CURB_HAVE_PREREQ_HOST_POLICY
|
|
600
|
+
static int curb_host_allowlist_prereq(void *clientp,
|
|
601
|
+
char *conn_primary_ip,
|
|
602
|
+
char *conn_local_ip,
|
|
603
|
+
int conn_primary_port,
|
|
604
|
+
int conn_local_port) {
|
|
605
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
606
|
+
char *effective_url = NULL;
|
|
607
|
+
char *host = NULL;
|
|
608
|
+
CURLcode rc;
|
|
609
|
+
|
|
610
|
+
(void)conn_primary_ip;
|
|
611
|
+
(void)conn_local_ip;
|
|
612
|
+
(void)conn_primary_port;
|
|
613
|
+
(void)conn_local_port;
|
|
614
|
+
|
|
615
|
+
if (!rbce || rbce->network_allowed_host_count == 0) {
|
|
616
|
+
return CURL_PREREQFUNC_OK;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
rc = curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &effective_url);
|
|
620
|
+
if (rc != CURLE_OK || !effective_url) {
|
|
621
|
+
curb_store_host_allowlist_error(rbce, "unknown");
|
|
622
|
+
return CURL_PREREQFUNC_ABORT;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
host = curb_try_normalize_host_value(effective_url);
|
|
626
|
+
if (!host) {
|
|
627
|
+
curb_store_host_allowlist_error(rbce, "unknown");
|
|
628
|
+
return CURL_PREREQFUNC_ABORT;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (!curb_host_rules_match(rbce, host)) {
|
|
632
|
+
curb_store_host_allowlist_error(rbce, host);
|
|
633
|
+
xfree(host);
|
|
634
|
+
return CURL_PREREQFUNC_ABORT;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
xfree(host);
|
|
638
|
+
return CURL_PREREQFUNC_OK;
|
|
639
|
+
}
|
|
640
|
+
#endif
|
|
641
|
+
|
|
642
|
+
#ifdef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
643
|
+
static curl_socket_t curb_public_network_opensocket(void *clientp, curlsocktype purpose, struct curl_sockaddr *address) {
|
|
644
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
645
|
+
curl_socket_t sockfd;
|
|
646
|
+
char address_string[80];
|
|
647
|
+
int checked_destination_address = 0;
|
|
648
|
+
|
|
649
|
+
(void)purpose;
|
|
650
|
+
|
|
651
|
+
if (!address) {
|
|
652
|
+
curb_store_unsafe_destination_error(rbce, "unknown");
|
|
653
|
+
return CURL_SOCKET_BAD;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
#ifdef AF_INET
|
|
657
|
+
if (address->family == AF_INET && address->addrlen >= sizeof(struct sockaddr_in)) {
|
|
658
|
+
const struct sockaddr_in *sin = (const struct sockaddr_in *)&address->addr;
|
|
659
|
+
const unsigned char *ip = (const unsigned char *)&sin->sin_addr;
|
|
660
|
+
checked_destination_address = 1;
|
|
661
|
+
|
|
662
|
+
if (curb_ipv4_is_unsafe_destination(ip)) {
|
|
663
|
+
curb_format_ipv4(address_string, sizeof(address_string), ip);
|
|
664
|
+
curb_store_unsafe_destination_error(rbce, address_string);
|
|
665
|
+
return CURL_SOCKET_BAD;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (!curb_cidr_rules_match(rbce, CURB_CIDR_FAMILY_IPV4, ip)) {
|
|
669
|
+
curb_format_ipv4(address_string, sizeof(address_string), ip);
|
|
670
|
+
curb_store_destination_error(rbce, address_string, "outside allowed CIDR ranges");
|
|
671
|
+
return CURL_SOCKET_BAD;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
#endif
|
|
675
|
+
|
|
676
|
+
#ifdef AF_INET6
|
|
677
|
+
if (address->family == AF_INET6 && address->addrlen >= sizeof(struct sockaddr_in6)) {
|
|
678
|
+
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)&address->addr;
|
|
679
|
+
const unsigned char *ip = (const unsigned char *)&sin6->sin6_addr;
|
|
680
|
+
checked_destination_address = 1;
|
|
681
|
+
|
|
682
|
+
if (curb_ipv6_is_unsafe_destination(ip)) {
|
|
683
|
+
curb_format_ipv6(address_string, sizeof(address_string), ip);
|
|
684
|
+
curb_store_unsafe_destination_error(rbce, address_string);
|
|
685
|
+
return CURL_SOCKET_BAD;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (!curb_cidr_rules_match(rbce, CURB_CIDR_FAMILY_IPV6, ip)) {
|
|
689
|
+
curb_format_ipv6(address_string, sizeof(address_string), ip);
|
|
690
|
+
curb_store_destination_error(rbce, address_string, "outside allowed CIDR ranges");
|
|
691
|
+
return CURL_SOCKET_BAD;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
#endif
|
|
695
|
+
|
|
696
|
+
if (!checked_destination_address && rbce && rbce->network_allowed_cidr_rule_count > 0) {
|
|
697
|
+
curb_store_destination_error(rbce, "unknown", "outside allowed CIDR ranges");
|
|
698
|
+
return CURL_SOCKET_BAD;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
sockfd = socket(address->family, address->socktype, address->protocol);
|
|
702
|
+
if (sockfd == CURL_SOCKET_BAD) {
|
|
703
|
+
return CURL_SOCKET_BAD;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return sockfd;
|
|
707
|
+
}
|
|
708
|
+
#endif
|
|
709
|
+
|
|
710
|
+
static VALUE callback_exception(VALUE unused, VALUE exception) {
|
|
32
711
|
return Qfalse;
|
|
33
|
-
}
|
|
712
|
+
}
|
|
34
713
|
|
|
35
|
-
|
|
36
|
-
|
|
714
|
+
static VALUE callback_exception_store_on_easy(VALUE arg, VALUE exception) {
|
|
715
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
716
|
+
|
|
717
|
+
if (rbce && NIL_P(rbce->callback_error)) {
|
|
718
|
+
rbce->callback_error = exception;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
return Qfalse;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
VALUE rb_curl_easy_take_callback_error(ruby_curl_easy *rbce) {
|
|
725
|
+
VALUE exception = Qnil;
|
|
726
|
+
|
|
727
|
+
if (!rbce) {
|
|
728
|
+
return Qnil;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
exception = rbce->callback_error;
|
|
732
|
+
rbce->callback_error = Qnil;
|
|
733
|
+
return exception;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
static VALUE ruby_curl_easy_take_callback_error(VALUE self) {
|
|
737
|
+
ruby_curl_easy *rbce = NULL;
|
|
738
|
+
|
|
739
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
740
|
+
return rb_curl_easy_take_callback_error(rbce);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
static VALUE ensure_clear_easy_callback_active(VALUE arg) {
|
|
744
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
745
|
+
if (rbce) {
|
|
746
|
+
rbce->callback_active = 0;
|
|
747
|
+
}
|
|
748
|
+
return Qnil;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
static VALUE with_easy_callback_active(ruby_curl_easy *rbce, VALUE (*func)(VALUE), VALUE arg) {
|
|
752
|
+
rbce->callback_active = 1;
|
|
753
|
+
return rb_ensure(func, arg, ensure_clear_easy_callback_active, (VALUE)rbce);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
static void ruby_curl_easy_enter_native(ruby_curl_easy *rbce) {
|
|
757
|
+
if (rbce) {
|
|
758
|
+
rbce->native_active++;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
static VALUE ruby_curl_easy_leave_native(VALUE arg) {
|
|
763
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
764
|
+
if (rbce && rbce->native_active > 0) {
|
|
765
|
+
rbce->native_active--;
|
|
766
|
+
}
|
|
767
|
+
return Qnil;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
struct stream_read_call_args {
|
|
771
|
+
VALUE stream;
|
|
772
|
+
size_t read_bytes;
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
static VALUE call_stream_read(VALUE argp) {
|
|
776
|
+
struct stream_read_call_args *args = (struct stream_read_call_args *)argp;
|
|
777
|
+
return rb_funcall(args->stream, rb_intern("read"), 1, ULONG2NUM((unsigned long)args->read_bytes));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
static VALUE call_stream_to_s(VALUE stream) {
|
|
781
|
+
return rb_funcall(stream, rb_intern("to_s"), 0);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static VALUE call_string_value(VALUE str) {
|
|
785
|
+
StringValue(str);
|
|
786
|
+
return str;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
struct stream_seek_call_args {
|
|
790
|
+
VALUE stream;
|
|
791
|
+
curl_off_t offset;
|
|
792
|
+
int origin;
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
static VALUE call_stream_seek(VALUE argp) {
|
|
796
|
+
struct stream_seek_call_args *args = (struct stream_seek_call_args *)argp;
|
|
797
|
+
return rb_funcall(args->stream, rb_intern("seek"), 2, LL2NUM(args->offset), INT2NUM(args->origin));
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
struct proc_data_call_args {
|
|
801
|
+
char *stream;
|
|
802
|
+
size_t size;
|
|
803
|
+
size_t nmemb;
|
|
804
|
+
VALUE proc;
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
static VALUE call_proc_data_handler_wrapped(VALUE argp) {
|
|
808
|
+
struct proc_data_call_args *args = (struct proc_data_call_args *)argp;
|
|
809
|
+
return ULONG2NUM((unsigned long)proc_data_handler(args->stream, args->size, args->nmemb, args->proc));
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
struct easy_callback_dispatch_args {
|
|
813
|
+
ruby_curl_easy *rbce;
|
|
814
|
+
VALUE (*func)(VALUE);
|
|
815
|
+
VALUE arg;
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
static VALUE call_with_easy_callback_active(VALUE argp) {
|
|
819
|
+
struct easy_callback_dispatch_args *args = (struct easy_callback_dispatch_args *)argp;
|
|
820
|
+
return with_easy_callback_active(args->rbce, args->func, args->arg);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static VALUE rescue_easy_callback(ruby_curl_easy *rbce, VALUE (*func)(VALUE), VALUE arg) {
|
|
824
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
825
|
+
dispatch_args.rbce = rbce;
|
|
826
|
+
dispatch_args.func = func;
|
|
827
|
+
dispatch_args.arg = arg;
|
|
828
|
+
return rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
static size_t curl_read_abort_result(void) {
|
|
832
|
+
#ifdef CURL_READFUNC_ABORT
|
|
833
|
+
return CURL_READFUNC_ABORT;
|
|
834
|
+
#else
|
|
835
|
+
return 0;
|
|
836
|
+
#endif
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
static int curl_seek_fail_result(void) {
|
|
840
|
+
#ifdef CURL_SEEKFUNC_FAIL
|
|
841
|
+
return CURL_SEEKFUNC_FAIL;
|
|
842
|
+
#else
|
|
843
|
+
return 1;
|
|
844
|
+
#endif
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
static int ruby_curl_easy_body_limit_exceeded(ruby_curl_easy *rbce, size_t total) {
|
|
848
|
+
VALUE max_body_bytes = rb_easy_get("max_body_bytes");
|
|
849
|
+
curl_off_t limit;
|
|
850
|
+
|
|
851
|
+
if (NIL_P(max_body_bytes)) {
|
|
852
|
+
return 0;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
limit = (curl_off_t)NUM2LL(max_body_bytes);
|
|
856
|
+
if (limit <= 0) {
|
|
857
|
+
return 0;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if ((curl_off_t)total > limit - rbce->downloaded_body_bytes) {
|
|
861
|
+
if (NIL_P(rbce->callback_error)) {
|
|
862
|
+
rbce->callback_error = rb_exc_new_cstr(eCurlErrFileSizeExceeded, "Maximum body size exceeded");
|
|
863
|
+
}
|
|
864
|
+
return 1;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
rbce->downloaded_body_bytes += (curl_off_t)total;
|
|
868
|
+
return 0;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/* Default body handler appends to easy.body_data buffer */
|
|
872
|
+
static size_t default_body_handler(char *stream,
|
|
37
873
|
size_t size,
|
|
38
874
|
size_t nmemb,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
875
|
+
void *userdata) {
|
|
876
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)userdata;
|
|
877
|
+
size_t total = size * nmemb;
|
|
878
|
+
VALUE out = rb_easy_get("body_data");
|
|
879
|
+
|
|
880
|
+
if (ruby_curl_easy_body_limit_exceeded(rbce, total)) {
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (NIL_P(out)) {
|
|
885
|
+
out = rb_easy_set("body_data", rb_str_buf_new(32768));
|
|
886
|
+
}
|
|
887
|
+
rb_str_buf_cat(out, stream, total);
|
|
888
|
+
return total;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/* Default header handler appends to easy.header_data buffer */
|
|
892
|
+
static size_t default_header_handler(char *stream,
|
|
893
|
+
size_t size,
|
|
894
|
+
size_t nmemb,
|
|
895
|
+
void *userdata) {
|
|
896
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)userdata;
|
|
897
|
+
size_t total = size * nmemb;
|
|
898
|
+
VALUE out = rb_easy_get("header_data");
|
|
899
|
+
if (NIL_P(out)) {
|
|
900
|
+
out = rb_easy_set("header_data", rb_str_buf_new(16384));
|
|
901
|
+
}
|
|
902
|
+
rb_str_buf_cat(out, stream, total);
|
|
903
|
+
return total;
|
|
42
904
|
}
|
|
43
905
|
|
|
44
906
|
// size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
|
|
@@ -48,14 +910,36 @@ static size_t read_data_handler(void *ptr,
|
|
|
48
910
|
ruby_curl_easy *rbce) {
|
|
49
911
|
VALUE upload = rb_easy_get("upload");
|
|
50
912
|
size_t read_bytes = (size*nmemb);
|
|
51
|
-
VALUE stream
|
|
913
|
+
VALUE stream;
|
|
914
|
+
|
|
915
|
+
if (NIL_P(upload)) {
|
|
916
|
+
return curl_read_abort_result();
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
stream = ruby_curl_upload_stream_get(upload);
|
|
52
920
|
|
|
53
921
|
if (rb_respond_to(stream, rb_intern("read"))) {//if (rb_respond_to(stream, rb_intern("to_s"))) {
|
|
54
922
|
/* copy read_bytes from stream into ptr */
|
|
55
|
-
|
|
923
|
+
struct stream_read_call_args args;
|
|
924
|
+
args.stream = stream;
|
|
925
|
+
args.read_bytes = read_bytes;
|
|
926
|
+
VALUE str = rescue_easy_callback(rbce, call_stream_read, (VALUE)&args);
|
|
56
927
|
if( str != Qnil ) {
|
|
57
|
-
|
|
58
|
-
|
|
928
|
+
size_t str_len;
|
|
929
|
+
|
|
930
|
+
str = rescue_easy_callback(rbce, call_string_value, str);
|
|
931
|
+
if (str == Qfalse || str == Qnil) {
|
|
932
|
+
return curl_read_abort_result();
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
str_len = (size_t)RSTRING_LEN(str);
|
|
936
|
+
if (str_len > read_bytes) {
|
|
937
|
+
snprintf(rbce->err_buf, CURL_ERROR_SIZE, "read callback returned more data than requested");
|
|
938
|
+
return curl_read_abort_result();
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
memcpy(ptr, RSTRING_PTR(str), str_len);
|
|
942
|
+
return str_len;
|
|
59
943
|
}
|
|
60
944
|
else {
|
|
61
945
|
return 0;
|
|
@@ -67,13 +951,22 @@ static size_t read_data_handler(void *ptr,
|
|
|
67
951
|
size_t len;
|
|
68
952
|
size_t remaining;
|
|
69
953
|
char *str_ptr;
|
|
70
|
-
|
|
71
|
-
str =
|
|
954
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
955
|
+
str = rescue_easy_callback(rbce, call_stream_to_s, stream);
|
|
956
|
+
str = rescue_easy_callback(rbce, call_string_value, str);
|
|
957
|
+
if (str == Qfalse || str == Qnil) {
|
|
958
|
+
return curl_read_abort_result();
|
|
959
|
+
}
|
|
960
|
+
|
|
72
961
|
len = RSTRING_LEN(str);
|
|
962
|
+
if (rbcu->offset >= len) {
|
|
963
|
+
return 0;
|
|
964
|
+
}
|
|
965
|
+
|
|
73
966
|
remaining = len - rbcu->offset;
|
|
74
967
|
str_ptr = RSTRING_PTR(str);
|
|
75
968
|
|
|
76
|
-
if( remaining
|
|
969
|
+
if( remaining <= read_bytes ) {
|
|
77
970
|
if( remaining > 0 ) {
|
|
78
971
|
memcpy(ptr, str_ptr+rbcu->offset, remaining);
|
|
79
972
|
read_bytes = remaining;
|
|
@@ -81,14 +974,10 @@ static size_t read_data_handler(void *ptr,
|
|
|
81
974
|
}
|
|
82
975
|
return remaining;
|
|
83
976
|
}
|
|
84
|
-
else
|
|
977
|
+
else { // read_bytes < remaining - send what we can fit in the buffer(ptr)
|
|
85
978
|
memcpy(ptr, str_ptr+rbcu->offset, read_bytes);
|
|
86
979
|
rbcu->offset += read_bytes;
|
|
87
980
|
}
|
|
88
|
-
else { // they're equal
|
|
89
|
-
memcpy(ptr, str_ptr+rbcu->offset, --read_bytes);
|
|
90
|
-
rbcu->offset += read_bytes;
|
|
91
|
-
}
|
|
92
981
|
return read_bytes;
|
|
93
982
|
}
|
|
94
983
|
else {
|
|
@@ -96,6 +985,38 @@ static size_t read_data_handler(void *ptr,
|
|
|
96
985
|
}
|
|
97
986
|
}
|
|
98
987
|
|
|
988
|
+
int seek_data_handler(ruby_curl_easy *rbce,
|
|
989
|
+
curl_off_t offset,
|
|
990
|
+
int origin) {
|
|
991
|
+
|
|
992
|
+
VALUE upload = rb_easy_get("upload");
|
|
993
|
+
VALUE stream;
|
|
994
|
+
|
|
995
|
+
if (NIL_P(upload)) {
|
|
996
|
+
return curl_seek_fail_result();
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
stream = ruby_curl_upload_stream_get(upload);
|
|
1000
|
+
|
|
1001
|
+
if (rb_respond_to(stream, rb_intern("seek"))) {
|
|
1002
|
+
struct stream_seek_call_args args;
|
|
1003
|
+
args.stream = stream;
|
|
1004
|
+
args.offset = offset;
|
|
1005
|
+
args.origin = origin;
|
|
1006
|
+
rescue_easy_callback(rbce, call_stream_seek, (VALUE)&args);
|
|
1007
|
+
if (!NIL_P(rbce->callback_error)) {
|
|
1008
|
+
return curl_seek_fail_result();
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
ruby_curl_upload *rbcu;
|
|
1012
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
1013
|
+
// This OK because curl only uses SEEK_SET as per the documentation
|
|
1014
|
+
rbcu->offset = offset;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
return 0;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
99
1020
|
static size_t proc_data_handler(char *stream,
|
|
100
1021
|
size_t size,
|
|
101
1022
|
size_t nmemb,
|
|
@@ -120,22 +1041,44 @@ static size_t proc_data_handler_body(char *stream,
|
|
|
120
1041
|
size_t nmemb,
|
|
121
1042
|
ruby_curl_easy *rbce)
|
|
122
1043
|
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
1044
|
+
struct proc_data_call_args args;
|
|
1045
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
1046
|
+
VALUE procret;
|
|
1047
|
+
args.stream = stream;
|
|
1048
|
+
args.size = size;
|
|
1049
|
+
args.nmemb = nmemb;
|
|
1050
|
+
args.proc = rb_easy_get("body_proc");
|
|
1051
|
+
|
|
1052
|
+
if (ruby_curl_easy_body_limit_exceeded(rbce, size * nmemb)) {
|
|
1053
|
+
return 0;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
dispatch_args.rbce = rbce;
|
|
1057
|
+
dispatch_args.func = call_proc_data_handler_wrapped;
|
|
1058
|
+
dispatch_args.arg = (VALUE)&args;
|
|
1059
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
1060
|
+
|
|
1061
|
+
return ((procret == Qfalse) || (procret == Qnil)) ? 0 : NUM2ULONG(procret);
|
|
128
1062
|
}
|
|
129
1063
|
static size_t proc_data_handler_header(char *stream,
|
|
130
1064
|
size_t size,
|
|
131
1065
|
size_t nmemb,
|
|
132
1066
|
ruby_curl_easy *rbce)
|
|
133
1067
|
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
1068
|
+
struct proc_data_call_args args;
|
|
1069
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
1070
|
+
VALUE procret;
|
|
1071
|
+
args.stream = stream;
|
|
1072
|
+
args.size = size;
|
|
1073
|
+
args.nmemb = nmemb;
|
|
1074
|
+
args.proc = rb_easy_get("header_proc");
|
|
1075
|
+
|
|
1076
|
+
dispatch_args.rbce = rbce;
|
|
1077
|
+
dispatch_args.func = call_proc_data_handler_wrapped;
|
|
1078
|
+
dispatch_args.arg = (VALUE)&args;
|
|
1079
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
1080
|
+
|
|
1081
|
+
return ((procret == Qfalse) || (procret == Qnil)) ? 0 : NUM2ULONG(procret);
|
|
139
1082
|
}
|
|
140
1083
|
|
|
141
1084
|
|
|
@@ -147,11 +1090,18 @@ static VALUE call_progress_handler(VALUE ary) {
|
|
|
147
1090
|
rb_ary_entry(ary, 4)); // rb_float_new(ulnow));
|
|
148
1091
|
}
|
|
149
1092
|
|
|
150
|
-
|
|
1093
|
+
/* CURLOPT_PROGRESSFUNCTION callback (deprecated since 7.32.0) */
|
|
1094
|
+
#ifndef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
1095
|
+
static int proc_progress_handler(void *clientp,
|
|
151
1096
|
double dltotal,
|
|
152
1097
|
double dlnow,
|
|
153
1098
|
double ultotal,
|
|
154
1099
|
double ulnow) {
|
|
1100
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
1101
|
+
VALUE proc = rb_easy_get("progress_proc");
|
|
1102
|
+
if (proc == Qnil) {
|
|
1103
|
+
return 0;
|
|
1104
|
+
}
|
|
155
1105
|
VALUE procret;
|
|
156
1106
|
VALUE callargs = rb_ary_new2(5);
|
|
157
1107
|
|
|
@@ -161,71 +1111,297 @@ static int proc_progress_handler(VALUE proc,
|
|
|
161
1111
|
rb_ary_store(callargs, 3, rb_float_new(ultotal));
|
|
162
1112
|
rb_ary_store(callargs, 4, rb_float_new(ulnow));
|
|
163
1113
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
1114
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
1115
|
+
dispatch_args.rbce = rbce;
|
|
1116
|
+
dispatch_args.func = call_progress_handler;
|
|
1117
|
+
dispatch_args.arg = callargs;
|
|
1118
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
1119
|
+
|
|
1120
|
+
return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
|
|
1121
|
+
}
|
|
1122
|
+
#endif
|
|
1123
|
+
|
|
1124
|
+
/* CURLOPT_XFERINFOFUNCTION callback (since 7.32.0, replaces PROGRESSFUNCTION) */
|
|
1125
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
1126
|
+
static int proc_xferinfo_handler(void *clientp,
|
|
1127
|
+
curl_off_t dltotal,
|
|
1128
|
+
curl_off_t dlnow,
|
|
1129
|
+
curl_off_t ultotal,
|
|
1130
|
+
curl_off_t ulnow) {
|
|
1131
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
1132
|
+
VALUE proc = rb_easy_get("progress_proc");
|
|
1133
|
+
if (proc == Qnil) {
|
|
1134
|
+
return 0;
|
|
1135
|
+
}
|
|
1136
|
+
VALUE procret;
|
|
1137
|
+
VALUE callargs = rb_ary_new2(5);
|
|
1138
|
+
|
|
1139
|
+
rb_ary_store(callargs, 0, proc);
|
|
1140
|
+
rb_ary_store(callargs, 1, LL2NUM(dltotal));
|
|
1141
|
+
rb_ary_store(callargs, 2, LL2NUM(dlnow));
|
|
1142
|
+
rb_ary_store(callargs, 3, LL2NUM(ultotal));
|
|
1143
|
+
rb_ary_store(callargs, 4, LL2NUM(ulnow));
|
|
1144
|
+
|
|
1145
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
1146
|
+
dispatch_args.rbce = rbce;
|
|
1147
|
+
dispatch_args.func = call_progress_handler;
|
|
1148
|
+
dispatch_args.arg = callargs;
|
|
1149
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
170
1150
|
|
|
171
1151
|
return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
|
|
172
1152
|
}
|
|
1153
|
+
#endif
|
|
173
1154
|
|
|
174
1155
|
static VALUE call_debug_handler(VALUE ary) {
|
|
175
1156
|
return rb_funcall(rb_ary_entry(ary, 0), idCall, 2,
|
|
176
|
-
rb_ary_entry(ary, 1), //
|
|
1157
|
+
rb_ary_entry(ary, 1), // INT2NUM(type),
|
|
177
1158
|
rb_ary_entry(ary, 2)); // rb_str_new(data, data_len)
|
|
178
1159
|
}
|
|
179
1160
|
static int proc_debug_handler(CURL *curl,
|
|
180
1161
|
curl_infotype type,
|
|
181
1162
|
char *data,
|
|
182
1163
|
size_t data_len,
|
|
183
|
-
|
|
1164
|
+
void *clientp) {
|
|
1165
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
1166
|
+
VALUE proc = rb_easy_get("debug_proc");
|
|
1167
|
+
if (proc == Qnil) {
|
|
1168
|
+
return 0;
|
|
1169
|
+
}
|
|
184
1170
|
VALUE callargs = rb_ary_new2(3);
|
|
185
1171
|
rb_ary_store(callargs, 0, proc);
|
|
186
|
-
rb_ary_store(callargs, 1,
|
|
1172
|
+
rb_ary_store(callargs, 1, INT2NUM(type));
|
|
187
1173
|
rb_ary_store(callargs, 2, rb_str_new(data, data_len));
|
|
188
|
-
|
|
1174
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
1175
|
+
dispatch_args.rbce = rbce;
|
|
1176
|
+
dispatch_args.func = call_debug_handler;
|
|
1177
|
+
dispatch_args.arg = callargs;
|
|
1178
|
+
rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
189
1179
|
/* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
|
|
190
1180
|
* this means exceptions will be swallowed
|
|
191
1181
|
*/
|
|
192
|
-
//rb_funcall(proc, idCall, 2,
|
|
1182
|
+
//rb_funcall(proc, idCall, 2, INT2NUM(type), rb_str_new(data, data_len));
|
|
193
1183
|
return 0;
|
|
194
1184
|
}
|
|
195
1185
|
|
|
196
|
-
/* ================== MARK/FREE
|
|
197
|
-
void curl_easy_mark(
|
|
198
|
-
|
|
199
|
-
if (
|
|
1186
|
+
/* ================== MARK/FREE/SIZE FUNCS ==================*/
|
|
1187
|
+
static void curl_easy_mark(void *ptr) {
|
|
1188
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
|
|
1189
|
+
if (rbce) {
|
|
1190
|
+
if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
|
|
1191
|
+
if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
|
|
1192
|
+
if (!NIL_P(rbce->callback_error)) { rb_gc_mark(rbce->callback_error); }
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
static void ruby_curl_easy_clear_headers_list(ruby_curl_easy *rbce) {
|
|
1197
|
+
if (!rbce || !rbce->curl_headers) {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (rbce->curl) {
|
|
1201
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HTTPHEADER, NULL);
|
|
1202
|
+
}
|
|
1203
|
+
curl_slist_free_all(rbce->curl_headers);
|
|
1204
|
+
rbce->curl_headers = NULL;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
static void ruby_curl_easy_clear_proxy_headers_list(ruby_curl_easy *rbce) {
|
|
1208
|
+
if (!rbce || !rbce->curl_proxy_headers) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
#ifdef HAVE_CURLOPT_PROXYHEADER
|
|
1212
|
+
if (rbce->curl) {
|
|
1213
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROXYHEADER, NULL);
|
|
1214
|
+
}
|
|
1215
|
+
#endif
|
|
1216
|
+
curl_slist_free_all(rbce->curl_proxy_headers);
|
|
1217
|
+
rbce->curl_proxy_headers = NULL;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
static void ruby_curl_easy_clear_ftp_commands_list(ruby_curl_easy *rbce) {
|
|
1221
|
+
if (!rbce || !rbce->curl_ftp_commands) {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
if (rbce->curl) {
|
|
1225
|
+
curl_easy_setopt(rbce->curl, CURLOPT_QUOTE, NULL);
|
|
1226
|
+
}
|
|
1227
|
+
curl_slist_free_all(rbce->curl_ftp_commands);
|
|
1228
|
+
rbce->curl_ftp_commands = NULL;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
static void ruby_curl_easy_clear_resolve_list(ruby_curl_easy *rbce) {
|
|
1232
|
+
if (!rbce || !rbce->curl_resolve) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
1236
|
+
if (rbce->curl) {
|
|
1237
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, NULL);
|
|
1238
|
+
}
|
|
1239
|
+
#endif
|
|
1240
|
+
curl_slist_free_all(rbce->curl_resolve);
|
|
1241
|
+
rbce->curl_resolve = NULL;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
static void ruby_curl_easy_clear_connect_to_list(ruby_curl_easy *rbce) {
|
|
1245
|
+
if (!rbce || !rbce->curl_connect_to) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
1249
|
+
if (rbce->curl) {
|
|
1250
|
+
curl_easy_setopt(rbce->curl, CURLOPT_CONNECT_TO, NULL);
|
|
1251
|
+
}
|
|
1252
|
+
#endif
|
|
1253
|
+
curl_slist_free_all(rbce->curl_connect_to);
|
|
1254
|
+
rbce->curl_connect_to = NULL;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
static void ruby_curl_easy_clear_setup_lists(ruby_curl_easy *rbce) {
|
|
1258
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
1259
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
1260
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
1261
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
1262
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/* Legacy wrapper for external callers */
|
|
1266
|
+
void ruby_curl_easy_mark(ruby_curl_easy *rbce) {
|
|
1267
|
+
curl_easy_mark((void *)rbce);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
static ruby_curl_multi *ruby_curl_multi_pointer_if_compatible(VALUE multi_val) {
|
|
1271
|
+
if (NIL_P(multi_val) || !RB_TYPE_P(multi_val, T_DATA)) {
|
|
1272
|
+
return NULL;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
#if defined(RTYPEDDATA_P) && defined(RTYPEDDATA_TYPE) && defined(RTYPEDDATA_DATA)
|
|
1276
|
+
if (!RTYPEDDATA_P(multi_val)) {
|
|
1277
|
+
return NULL;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
if (RTYPEDDATA_TYPE(multi_val) != &ruby_curl_multi_data_type) {
|
|
1281
|
+
return NULL;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
return (ruby_curl_multi *)RTYPEDDATA_DATA(multi_val);
|
|
1285
|
+
#else
|
|
1286
|
+
if (!rb_typeddata_is_kind_of(multi_val, &ruby_curl_multi_data_type)) {
|
|
1287
|
+
return NULL;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return DATA_PTR(multi_val);
|
|
1291
|
+
#endif
|
|
200
1292
|
}
|
|
201
1293
|
|
|
202
1294
|
static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
203
|
-
if (rbce
|
|
204
|
-
|
|
1295
|
+
if (!rbce) {
|
|
1296
|
+
return;
|
|
205
1297
|
}
|
|
206
1298
|
|
|
207
|
-
if (rbce->
|
|
208
|
-
|
|
1299
|
+
if (!NIL_P(rbce->multi)) {
|
|
1300
|
+
VALUE multi_val = rbce->multi;
|
|
1301
|
+
ruby_curl_multi *rbcm = ruby_curl_multi_pointer_if_compatible(multi_val);
|
|
1302
|
+
|
|
1303
|
+
rbce->multi = Qnil;
|
|
1304
|
+
|
|
1305
|
+
if (rbcm) {
|
|
1306
|
+
/* Best-effort: ensure the handle is detached from the multi to avoid
|
|
1307
|
+
* libcurl retaining a dangling pointer to a soon-to-be cleaned-up easy
|
|
1308
|
+
* handle. This path runs during GC, so it must not invoke Ruby APIs that
|
|
1309
|
+
* can allocate or raise. */
|
|
1310
|
+
if (rbcm->handle && rbce->curl) {
|
|
1311
|
+
curl_multi_remove_handle(rbcm->handle, rbce->curl);
|
|
1312
|
+
}
|
|
1313
|
+
rb_curl_multi_forget_easy(rbcm, rbce);
|
|
1314
|
+
}
|
|
209
1315
|
}
|
|
210
1316
|
|
|
1317
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
1318
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
1319
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
1320
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
1321
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
1322
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
1323
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
1324
|
+
|
|
211
1325
|
if (rbce->curl) {
|
|
1326
|
+
/* disable any progress or debug events */
|
|
1327
|
+
curl_easy_setopt(rbce->curl, CURLOPT_WRITEFUNCTION, NULL);
|
|
1328
|
+
curl_easy_setopt(rbce->curl, CURLOPT_WRITEDATA, NULL);
|
|
1329
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HEADERFUNCTION, NULL);
|
|
1330
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HEADERDATA, NULL);
|
|
1331
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DEBUGFUNCTION, NULL);
|
|
1332
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DEBUGDATA, NULL);
|
|
1333
|
+
curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 0);
|
|
1334
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
1335
|
+
curl_easy_setopt(rbce->curl, CURLOPT_XFERINFOFUNCTION, NULL);
|
|
1336
|
+
#else
|
|
1337
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
|
|
1338
|
+
#endif
|
|
1339
|
+
curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
|
|
212
1340
|
curl_easy_cleanup(rbce->curl);
|
|
1341
|
+
rbce->curl = NULL;
|
|
213
1342
|
}
|
|
1343
|
+
|
|
1344
|
+
rbce->self = Qnil;
|
|
214
1345
|
}
|
|
215
1346
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
1347
|
+
/* TypedData-compatible free function */
|
|
1348
|
+
static void curl_easy_free(void *ptr) {
|
|
1349
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
|
|
1350
|
+
if (rbce) {
|
|
1351
|
+
ruby_curl_easy_free(rbce);
|
|
1352
|
+
free(rbce);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/* Legacy wrapper for external callers (e.g., curb_multi) */
|
|
1357
|
+
void ruby_curl_easy_free_wrapper(ruby_curl_easy *rbce) {
|
|
1358
|
+
curl_easy_free((void *)rbce);
|
|
219
1359
|
}
|
|
220
1360
|
|
|
1361
|
+
static size_t curl_easy_memsize(const void *ptr) {
|
|
1362
|
+
const ruby_curl_easy *rbce = (const ruby_curl_easy *)ptr;
|
|
1363
|
+
size_t size = sizeof(ruby_curl_easy);
|
|
1364
|
+
/* Note: We don't count curl_slist or CURL handle memory as they're
|
|
1365
|
+
* managed by libcurl and would require complex introspection */
|
|
1366
|
+
(void)rbce; /* silence unused warning */
|
|
1367
|
+
return size;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
const rb_data_type_t ruby_curl_easy_data_type = {
|
|
1371
|
+
"Curl::Easy",
|
|
1372
|
+
{
|
|
1373
|
+
curl_easy_mark,
|
|
1374
|
+
curl_easy_free,
|
|
1375
|
+
curl_easy_memsize,
|
|
1376
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
1377
|
+
NULL, /* compact - not needed */
|
|
1378
|
+
#endif
|
|
1379
|
+
},
|
|
1380
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
1381
|
+
NULL, NULL, /* parent, data */
|
|
1382
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
1383
|
+
#endif
|
|
1384
|
+
};
|
|
1385
|
+
|
|
221
1386
|
|
|
222
1387
|
/* ================= ALLOC METHODS ====================*/
|
|
223
1388
|
|
|
224
1389
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
225
1390
|
rbce->opts = rb_hash_new();
|
|
226
1391
|
|
|
1392
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
1393
|
+
memset(rbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
1394
|
+
|
|
1395
|
+
rbce->self = Qnil;
|
|
227
1396
|
rbce->curl_headers = NULL;
|
|
1397
|
+
rbce->curl_proxy_headers = NULL;
|
|
228
1398
|
rbce->curl_ftp_commands = NULL;
|
|
1399
|
+
rbce->curl_resolve = NULL;
|
|
1400
|
+
rbce->curl_connect_to = NULL;
|
|
1401
|
+
rbce->network_allowed_cidr_rules = NULL;
|
|
1402
|
+
rbce->network_allowed_hosts = NULL;
|
|
1403
|
+
rbce->network_allowed_cidr_rule_count = 0;
|
|
1404
|
+
rbce->network_allowed_host_count = 0;
|
|
229
1405
|
|
|
230
1406
|
/* various-typed opts */
|
|
231
1407
|
rbce->local_port = 0;
|
|
@@ -236,15 +1412,21 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
236
1412
|
rbce->proxy_auth_types = 0;
|
|
237
1413
|
rbce->max_redirs = -1;
|
|
238
1414
|
rbce->timeout = 0;
|
|
1415
|
+
rbce->timeout_ms = 0;
|
|
239
1416
|
rbce->connect_timeout = 0;
|
|
1417
|
+
rbce->connect_timeout_ms = 0;
|
|
240
1418
|
rbce->dns_cache_timeout = 60;
|
|
241
1419
|
rbce->ftp_response_timeout = 0;
|
|
242
1420
|
rbce->low_speed_limit = 0;
|
|
243
1421
|
rbce->low_speed_time = 0;
|
|
1422
|
+
rbce->max_send_speed_large = 0;
|
|
1423
|
+
rbce->max_recv_speed_large = 0;
|
|
244
1424
|
rbce->ssl_version = -1;
|
|
245
1425
|
rbce->use_ssl = -1;
|
|
246
1426
|
rbce->ftp_filemethod = -1;
|
|
1427
|
+
rbce->http_version = CURL_HTTP_VERSION_NONE;
|
|
247
1428
|
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
1429
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
248
1430
|
|
|
249
1431
|
/* bool opts */
|
|
250
1432
|
rbce->proxy_tunnel = 0;
|
|
@@ -258,29 +1440,53 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
258
1440
|
rbce->verbose = 0;
|
|
259
1441
|
rbce->multipart_form_post = 0;
|
|
260
1442
|
rbce->enable_cookies = 0;
|
|
1443
|
+
rbce->cookielist_engine_enabled = 0;
|
|
261
1444
|
rbce->ignore_content_length = 0;
|
|
262
1445
|
rbce->callback_active = 0;
|
|
1446
|
+
rbce->unsafe_destination_blocked = 0;
|
|
1447
|
+
rbce->allow_proxy = 0;
|
|
1448
|
+
rbce->allow_unix_socket = 0;
|
|
1449
|
+
rbce->forbid_reuse_set = 0;
|
|
1450
|
+
rbce->native_active = 0;
|
|
1451
|
+
rbce->forbid_reuse = 0;
|
|
1452
|
+
rbce->callback_error = Qnil;
|
|
1453
|
+
rbce->last_result = 0;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/*
|
|
1457
|
+
* Allocate space for a Curl::Easy instance.
|
|
1458
|
+
*/
|
|
1459
|
+
static VALUE ruby_curl_easy_allocate(VALUE klass) {
|
|
1460
|
+
ruby_curl_easy *rbce;
|
|
1461
|
+
rbce = ALLOC(ruby_curl_easy);
|
|
1462
|
+
if (!rbce) {
|
|
1463
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy");
|
|
1464
|
+
}
|
|
1465
|
+
rbce->curl = NULL;
|
|
1466
|
+
rbce->opts = Qnil;
|
|
1467
|
+
rbce->multi = Qnil;
|
|
1468
|
+
ruby_curl_easy_zero(rbce);
|
|
1469
|
+
return TypedData_Wrap_Struct(klass, &ruby_curl_easy_data_type, rbce);
|
|
263
1470
|
}
|
|
264
1471
|
|
|
265
1472
|
/*
|
|
266
1473
|
* call-seq:
|
|
267
|
-
* Curl::Easy.new =>
|
|
268
|
-
* Curl::Easy.new(url = nil) =>
|
|
269
|
-
* Curl::Easy.new(url = nil) { |self| ... } =>
|
|
1474
|
+
* Curl::Easy.new => #<Curl::Easy...>
|
|
1475
|
+
* Curl::Easy.new(url = nil) => #<Curl::Easy...>
|
|
1476
|
+
* Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
|
|
270
1477
|
*
|
|
271
|
-
*
|
|
1478
|
+
* Initialize a new Curl::Easy instance, optionally supplying the URL.
|
|
272
1479
|
* The block form allows further configuration to be supplied before
|
|
273
1480
|
* the instance is returned.
|
|
274
1481
|
*/
|
|
275
|
-
static VALUE
|
|
1482
|
+
static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
276
1483
|
CURLcode ecode;
|
|
277
1484
|
VALUE url, blk;
|
|
278
|
-
VALUE new_curl;
|
|
279
1485
|
ruby_curl_easy *rbce;
|
|
280
1486
|
|
|
281
1487
|
rb_scan_args(argc, argv, "01&", &url, &blk);
|
|
282
1488
|
|
|
283
|
-
|
|
1489
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
284
1490
|
|
|
285
1491
|
/* handler */
|
|
286
1492
|
rbce->curl = curl_easy_init();
|
|
@@ -288,32 +1494,67 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
|
288
1494
|
rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
|
|
289
1495
|
}
|
|
290
1496
|
|
|
291
|
-
new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
|
|
292
|
-
|
|
293
1497
|
rbce->multi = Qnil;
|
|
294
1498
|
rbce->opts = Qnil;
|
|
295
1499
|
|
|
296
1500
|
ruby_curl_easy_zero(rbce);
|
|
1501
|
+
rbce->self = self;
|
|
1502
|
+
|
|
1503
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
|
297
1504
|
|
|
298
1505
|
rb_easy_set("url", url);
|
|
299
1506
|
|
|
300
|
-
/* set the
|
|
301
|
-
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)
|
|
1507
|
+
/* set the pointer to the curl handle */
|
|
1508
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
302
1509
|
if (ecode != CURLE_OK) {
|
|
303
1510
|
raise_curl_easy_error_exception(ecode);
|
|
304
1511
|
}
|
|
305
1512
|
|
|
306
1513
|
if (blk != Qnil) {
|
|
307
|
-
rb_funcall(blk, idCall, 1,
|
|
1514
|
+
rb_funcall(blk, idCall, 1, self);
|
|
308
1515
|
}
|
|
309
1516
|
|
|
310
|
-
return
|
|
1517
|
+
return self;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
/* Helper to duplicate a curl_slist */
|
|
1521
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list) {
|
|
1522
|
+
struct curl_slist *dup = NULL;
|
|
1523
|
+
struct curl_slist *tmp;
|
|
1524
|
+
struct curl_slist *new_list;
|
|
1525
|
+
for (tmp = list; tmp; tmp = tmp->next) {
|
|
1526
|
+
new_list = curl_slist_append(dup, tmp->data);
|
|
1527
|
+
if (!new_list) {
|
|
1528
|
+
if (dup) { curl_slist_free_all(dup); }
|
|
1529
|
+
rb_raise(rb_eNoMemError, "Failed to duplicate curl_slist");
|
|
1530
|
+
}
|
|
1531
|
+
dup = new_list;
|
|
1532
|
+
}
|
|
1533
|
+
return dup;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
static VALUE duplicate_upload(VALUE upload) {
|
|
1537
|
+
ruby_curl_upload *rbcu, *newrbcu;
|
|
1538
|
+
VALUE new_upload;
|
|
1539
|
+
|
|
1540
|
+
if (NIL_P(upload)) {
|
|
1541
|
+
return Qnil;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
1545
|
+
|
|
1546
|
+
new_upload = ruby_curl_upload_new(cCurlUpload);
|
|
1547
|
+
TypedData_Get_Struct(new_upload, ruby_curl_upload, &ruby_curl_upload_data_type, newrbcu);
|
|
1548
|
+
newrbcu->stream = rbcu->stream;
|
|
1549
|
+
newrbcu->offset = rbcu->offset;
|
|
1550
|
+
|
|
1551
|
+
return new_upload;
|
|
311
1552
|
}
|
|
312
1553
|
|
|
313
1554
|
/*
|
|
314
1555
|
* call-seq:
|
|
315
|
-
* easy.clone =>
|
|
316
|
-
* easy.dup =>
|
|
1556
|
+
* easy.clone => <easy clone>
|
|
1557
|
+
* easy.dup => <easy clone>
|
|
317
1558
|
*
|
|
318
1559
|
* Clone this Curl::Easy instance, creating a new instance.
|
|
319
1560
|
* This method duplicates the underlying CURL* handle.
|
|
@@ -321,15 +1562,65 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
|
321
1562
|
static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
322
1563
|
ruby_curl_easy *rbce, *newrbce;
|
|
323
1564
|
|
|
324
|
-
|
|
1565
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
325
1566
|
|
|
326
1567
|
newrbce = ALLOC(ruby_curl_easy);
|
|
1568
|
+
if (!newrbce) {
|
|
1569
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy clone");
|
|
1570
|
+
}
|
|
1571
|
+
/* shallow copy */
|
|
327
1572
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
|
1573
|
+
|
|
1574
|
+
/* now deep copy */
|
|
328
1575
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
|
329
|
-
newrbce->
|
|
330
|
-
|
|
1576
|
+
if (!newrbce->curl) {
|
|
1577
|
+
free(newrbce);
|
|
1578
|
+
rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
|
|
1579
|
+
}
|
|
1580
|
+
newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
|
|
1581
|
+
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
|
1582
|
+
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
|
1583
|
+
newrbce->curl_resolve = (rbce->curl_resolve) ? duplicate_curl_slist(rbce->curl_resolve) : NULL;
|
|
1584
|
+
newrbce->curl_connect_to = (rbce->curl_connect_to) ? duplicate_curl_slist(rbce->curl_connect_to) : NULL;
|
|
1585
|
+
newrbce->network_allowed_cidr_rules = NULL;
|
|
1586
|
+
newrbce->network_allowed_cidr_rule_count = 0;
|
|
1587
|
+
newrbce->network_allowed_hosts = NULL;
|
|
1588
|
+
newrbce->network_allowed_host_count = 0;
|
|
1589
|
+
|
|
1590
|
+
/* A cloned easy should not retain ownership reference to the original multi. */
|
|
1591
|
+
newrbce->multi = Qnil;
|
|
1592
|
+
newrbce->callback_error = Qnil;
|
|
1593
|
+
newrbce->unsafe_destination_blocked = 0;
|
|
1594
|
+
memset(newrbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
1595
|
+
newrbce->native_active = 0;
|
|
1596
|
+
|
|
1597
|
+
if (rbce->opts != Qnil) {
|
|
1598
|
+
newrbce->opts = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
1599
|
+
}
|
|
331
1600
|
|
|
332
|
-
|
|
1601
|
+
/* Set the error buffer on the new curl handle using the new err_buf */
|
|
1602
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_ERRORBUFFER, newrbce->err_buf);
|
|
1603
|
+
|
|
1604
|
+
if (newrbce->opts != Qnil) {
|
|
1605
|
+
VALUE upload = rb_hash_aref(newrbce->opts, rb_easy_hkey("upload"));
|
|
1606
|
+
if (!NIL_P(upload)) {
|
|
1607
|
+
rb_hash_aset(newrbce->opts, rb_easy_hkey("upload"), duplicate_upload(upload));
|
|
1608
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
1609
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READDATA, newrbce);
|
|
1610
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
1611
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
1612
|
+
#endif
|
|
1613
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
1614
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKDATA, newrbce);
|
|
1615
|
+
#endif
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
VALUE clone = TypedData_Wrap_Struct(cCurlEasy, &ruby_curl_easy_data_type, newrbce);
|
|
1620
|
+
newrbce->self = clone;
|
|
1621
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_PRIVATE, (void*)newrbce);
|
|
1622
|
+
|
|
1623
|
+
return clone;
|
|
333
1624
|
}
|
|
334
1625
|
|
|
335
1626
|
/*
|
|
@@ -337,19 +1628,23 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
337
1628
|
* easy.close => nil
|
|
338
1629
|
*
|
|
339
1630
|
* Close the Curl::Easy instance. Any open connections are closed
|
|
340
|
-
* The easy handle is reinitialized. If a previous multi handle was
|
|
1631
|
+
* The easy handle is reinitialized. If a previous multi handle was
|
|
341
1632
|
* open it is set to nil and will be cleared after a GC.
|
|
342
1633
|
*/
|
|
343
1634
|
static VALUE ruby_curl_easy_close(VALUE self) {
|
|
344
1635
|
CURLcode ecode;
|
|
345
1636
|
ruby_curl_easy *rbce;
|
|
346
1637
|
|
|
347
|
-
|
|
1638
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
348
1639
|
|
|
349
1640
|
if (rbce->callback_active) {
|
|
350
1641
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
351
1642
|
}
|
|
352
1643
|
|
|
1644
|
+
if (rbce->native_active) {
|
|
1645
|
+
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle during native operation");
|
|
1646
|
+
}
|
|
1647
|
+
|
|
353
1648
|
ruby_curl_easy_free(rbce);
|
|
354
1649
|
|
|
355
1650
|
/* reinit the handle */
|
|
@@ -361,9 +1656,12 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
361
1656
|
rbce->multi = Qnil;
|
|
362
1657
|
|
|
363
1658
|
ruby_curl_easy_zero(rbce);
|
|
1659
|
+
rbce->self = self;
|
|
1660
|
+
|
|
1661
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, rbce->err_buf);
|
|
364
1662
|
|
|
365
1663
|
/* give the new curl handle a reference back to the ruby object */
|
|
366
|
-
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)
|
|
1664
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
367
1665
|
if (ecode != CURLE_OK) {
|
|
368
1666
|
raise_curl_easy_error_exception(ecode);
|
|
369
1667
|
}
|
|
@@ -387,29 +1685,31 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
387
1685
|
CURLcode ecode;
|
|
388
1686
|
ruby_curl_easy *rbce;
|
|
389
1687
|
VALUE opts_dup;
|
|
390
|
-
|
|
1688
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
391
1689
|
|
|
392
1690
|
if (rbce->callback_active) {
|
|
393
1691
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
394
1692
|
}
|
|
395
1693
|
|
|
1694
|
+
if (rbce->native_active) {
|
|
1695
|
+
rb_raise(rb_eRuntimeError, "Cannot reset an active curl handle during native operation");
|
|
1696
|
+
}
|
|
1697
|
+
|
|
396
1698
|
opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
397
1699
|
|
|
1700
|
+
ruby_curl_easy_cleanup(self, rbce);
|
|
398
1701
|
curl_easy_reset(rbce->curl);
|
|
399
1702
|
ruby_curl_easy_zero(rbce);
|
|
1703
|
+
rbce->self = self;
|
|
400
1704
|
|
|
401
|
-
|
|
402
|
-
|
|
1705
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
|
1706
|
+
|
|
1707
|
+
/* reset clobbers the private setting, so reset it to self */
|
|
1708
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
403
1709
|
if (ecode != CURLE_OK) {
|
|
404
1710
|
raise_curl_easy_error_exception(ecode);
|
|
405
1711
|
}
|
|
406
1712
|
|
|
407
|
-
/* Free everything up */
|
|
408
|
-
if (rbce->curl_headers) {
|
|
409
|
-
curl_slist_free_all(rbce->curl_headers);
|
|
410
|
-
rbce->curl_headers = NULL;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
1713
|
return opts_dup;
|
|
414
1714
|
}
|
|
415
1715
|
|
|
@@ -462,6 +1762,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
|
|
|
462
1762
|
CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
|
|
463
1763
|
}
|
|
464
1764
|
|
|
1765
|
+
static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
|
|
1766
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_headers);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
465
1769
|
/*
|
|
466
1770
|
* call-seq:
|
|
467
1771
|
* easy.headers => Hash, Array or Str
|
|
@@ -471,12 +1775,47 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
|
|
|
471
1775
|
static VALUE ruby_curl_easy_headers_get(VALUE self) {
|
|
472
1776
|
ruby_curl_easy *rbce;
|
|
473
1777
|
VALUE headers;
|
|
474
|
-
|
|
475
|
-
headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
|
|
1778
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1779
|
+
headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
|
|
476
1780
|
if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
|
|
477
1781
|
return headers;
|
|
478
1782
|
}
|
|
479
1783
|
|
|
1784
|
+
/*
|
|
1785
|
+
* call-seq:
|
|
1786
|
+
* easy.proxy_headers = "Header: val" => "Header: val"
|
|
1787
|
+
* easy.proxy_headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
|
|
1788
|
+
* easy.proxy_headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
|
|
1789
|
+
*
|
|
1790
|
+
*
|
|
1791
|
+
* For example to set a standard or custom header:
|
|
1792
|
+
*
|
|
1793
|
+
* easy.proxy_headers["MyHeader"] = "myval"
|
|
1794
|
+
*
|
|
1795
|
+
* To remove a standard header (this is useful when removing libcurls default
|
|
1796
|
+
* 'Expect: 100-Continue' header when using HTTP form posts):
|
|
1797
|
+
*
|
|
1798
|
+
* easy.proxy_headers["Expect"] = ''
|
|
1799
|
+
*
|
|
1800
|
+
* Anything passed to libcurl as a header will be converted to a string during
|
|
1801
|
+
* the perform step.
|
|
1802
|
+
*/
|
|
1803
|
+
|
|
1804
|
+
/*
|
|
1805
|
+
* call-seq:
|
|
1806
|
+
* easy.proxy_headers => Hash, Array or Str
|
|
1807
|
+
*
|
|
1808
|
+
* Obtain the custom HTTP proxy_headers for following requests.
|
|
1809
|
+
*/
|
|
1810
|
+
static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
|
|
1811
|
+
ruby_curl_easy *rbce;
|
|
1812
|
+
VALUE proxy_headers;
|
|
1813
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1814
|
+
proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
|
|
1815
|
+
if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
|
|
1816
|
+
return proxy_headers;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
480
1819
|
/*
|
|
481
1820
|
* call-seq:
|
|
482
1821
|
* easy.interface => string
|
|
@@ -515,7 +1854,16 @@ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
|
|
|
515
1854
|
* call-seq:
|
|
516
1855
|
* easy.cookies => "name1=content1; name2=content2;"
|
|
517
1856
|
*
|
|
518
|
-
* Obtain the
|
|
1857
|
+
* Obtain the manually set Cookie header string for this Curl::Easy instance.
|
|
1858
|
+
*
|
|
1859
|
+
* Notes:
|
|
1860
|
+
* - This corresponds to libcurl's CURLOPT_COOKIE and only affects the outgoing
|
|
1861
|
+
* Cookie request header. It does NOT modify the internal libcurl cookie engine
|
|
1862
|
+
* that stores cookies received via Set-Cookie.
|
|
1863
|
+
* - To inspect or modify cookies stored in the cookie engine, use
|
|
1864
|
+
* +easy.cookielist+ (getter) and +easy.cookielist=+ or +easy.set(:cookielist, ...)+ (setter).
|
|
1865
|
+
* - To clear a previously set manual Cookie header, assign an empty string.
|
|
1866
|
+
* Assigning +nil+ currently has no effect.
|
|
519
1867
|
*/
|
|
520
1868
|
static VALUE ruby_curl_easy_cookies_get(VALUE self) {
|
|
521
1869
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookies);
|
|
@@ -525,7 +1873,8 @@ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
|
|
|
525
1873
|
* call-seq:
|
|
526
1874
|
* easy.cookiefile => string
|
|
527
1875
|
*
|
|
528
|
-
* Obtain the cookiefile
|
|
1876
|
+
* Obtain the cookiefile path for this Curl::Easy instance (used to load cookies when the
|
|
1877
|
+
* cookie engine is enabled).
|
|
529
1878
|
*/
|
|
530
1879
|
static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
|
|
531
1880
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookiefile);
|
|
@@ -535,7 +1884,8 @@ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
|
|
|
535
1884
|
* call-seq:
|
|
536
1885
|
* easy.cookiejar => string
|
|
537
1886
|
*
|
|
538
|
-
* Obtain the cookiejar
|
|
1887
|
+
* Obtain the cookiejar path for this Curl::Easy instance (used to persist cookies when the
|
|
1888
|
+
* cookie engine is enabled).
|
|
539
1889
|
*/
|
|
540
1890
|
static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
|
|
541
1891
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookiejar);
|
|
@@ -684,57 +2034,102 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
|
|
|
684
2034
|
/*
|
|
685
2035
|
* call-seq:
|
|
686
2036
|
* easy.post_body = "some=form%20data&to=send" => string or nil
|
|
687
|
-
*
|
|
2037
|
+
*
|
|
688
2038
|
* Sets the POST body of this Curl::Easy instance. This is expected to be
|
|
689
2039
|
* URL encoded; no additional processing or encoding is done on the string.
|
|
690
2040
|
* The content-type header will be set to application/x-www-form-urlencoded.
|
|
691
|
-
*
|
|
2041
|
+
*
|
|
692
2042
|
* This is handy if you want to perform a POST against a Curl::Multi instance.
|
|
693
2043
|
*/
|
|
694
|
-
|
|
2044
|
+
struct post_body_set_args {
|
|
2045
|
+
VALUE self;
|
|
2046
|
+
VALUE post_body;
|
|
2047
|
+
int force_http_get_on_nil;
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
static VALUE ruby_curl_easy_post_body_set_with_mode_body(VALUE argp) {
|
|
2051
|
+
struct post_body_set_args *args = (struct post_body_set_args *)argp;
|
|
2052
|
+
VALUE self = args->self;
|
|
2053
|
+
VALUE post_body = args->post_body;
|
|
2054
|
+
int force_http_get_on_nil = args->force_http_get_on_nil;
|
|
695
2055
|
ruby_curl_easy *rbce;
|
|
696
2056
|
CURL *curl;
|
|
697
|
-
|
|
2057
|
+
|
|
2058
|
+
VALUE body_str;
|
|
2059
|
+
VALUE retained_body_str;
|
|
698
2060
|
char *data;
|
|
699
2061
|
long len;
|
|
700
2062
|
|
|
701
|
-
|
|
702
|
-
|
|
2063
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2064
|
+
|
|
703
2065
|
curl = rbce->curl;
|
|
704
|
-
|
|
2066
|
+
|
|
705
2067
|
if ( post_body == Qnil ) {
|
|
706
2068
|
rb_easy_del("postdata_buffer");
|
|
707
|
-
curl_easy_setopt(curl,
|
|
708
|
-
|
|
709
|
-
|
|
2069
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
|
2070
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
|
|
2071
|
+
if (force_http_get_on_nil) {
|
|
2072
|
+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
|
2073
|
+
}
|
|
2074
|
+
|
|
2075
|
+
} else {
|
|
710
2076
|
if (rb_type(post_body) == T_STRING) {
|
|
711
|
-
|
|
712
|
-
len = RSTRING_LEN(post_body);
|
|
2077
|
+
body_str = post_body;
|
|
713
2078
|
}
|
|
714
2079
|
else if (rb_respond_to(post_body, rb_intern("to_s"))) {
|
|
715
|
-
|
|
716
|
-
data = StringValuePtr(str_body);
|
|
717
|
-
len = RSTRING_LEN(post_body);
|
|
2080
|
+
body_str = rb_funcall(post_body, rb_intern("to_s"), 0);
|
|
718
2081
|
}
|
|
719
2082
|
else {
|
|
720
2083
|
rb_raise(rb_eRuntimeError, "post data must respond_to .to_s");
|
|
721
2084
|
}
|
|
722
|
-
|
|
723
|
-
|
|
2085
|
+
|
|
2086
|
+
StringValue(body_str);
|
|
2087
|
+
|
|
2088
|
+
// Store the string, since it has to hang around for the duration of the
|
|
724
2089
|
// request. See CURLOPT_POSTFIELDS in the libcurl docs.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
2090
|
+
#ifdef HAVE_CURLOPT_COPYPOSTFIELDS
|
|
2091
|
+
/*
|
|
2092
|
+
* libcurl copies the bytes immediately for COPYPOSTFIELDS, so retain a
|
|
2093
|
+
* matching Ruby snapshot for post_body instead of the caller's mutable
|
|
2094
|
+
* source string.
|
|
2095
|
+
*/
|
|
2096
|
+
retained_body_str = rb_str_dup(body_str);
|
|
2097
|
+
#else
|
|
2098
|
+
retained_body_str = body_str;
|
|
2099
|
+
#endif
|
|
2100
|
+
data = StringValuePtr(retained_body_str);
|
|
2101
|
+
len = RSTRING_LEN(retained_body_str);
|
|
2102
|
+
rb_easy_set("postdata_buffer", retained_body_str);
|
|
2103
|
+
|
|
728
2104
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
|
729
|
-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
|
730
2105
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
|
|
731
|
-
|
|
2106
|
+
#ifdef HAVE_CURLOPT_COPYPOSTFIELDS
|
|
2107
|
+
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, data);
|
|
2108
|
+
#else
|
|
2109
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
|
2110
|
+
#endif
|
|
2111
|
+
|
|
732
2112
|
return post_body;
|
|
733
2113
|
}
|
|
734
|
-
|
|
2114
|
+
|
|
735
2115
|
return Qnil;
|
|
736
2116
|
}
|
|
737
2117
|
|
|
2118
|
+
static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body, int force_http_get_on_nil) {
|
|
2119
|
+
ruby_curl_easy *rbce;
|
|
2120
|
+
struct post_body_set_args args = { self, post_body, force_http_get_on_nil };
|
|
2121
|
+
|
|
2122
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2123
|
+
ruby_curl_easy_enter_native(rbce);
|
|
2124
|
+
|
|
2125
|
+
return rb_ensure(ruby_curl_easy_post_body_set_with_mode_body, (VALUE)&args,
|
|
2126
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
|
|
2130
|
+
return ruby_curl_easy_post_body_set_with_mode(self, post_body, 1);
|
|
2131
|
+
}
|
|
2132
|
+
|
|
738
2133
|
/*
|
|
739
2134
|
* call-seq:
|
|
740
2135
|
* easy.post_body => string or nil
|
|
@@ -748,7 +2143,7 @@ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
|
|
|
748
2143
|
/*
|
|
749
2144
|
* call-seq:
|
|
750
2145
|
* easy.put_data = data => ""
|
|
751
|
-
*
|
|
2146
|
+
*
|
|
752
2147
|
* Points this Curl::Easy instance to data to be uploaded via PUT. This
|
|
753
2148
|
* sets the request to a PUT type request - useful if you want to PUT via
|
|
754
2149
|
* a multi handle.
|
|
@@ -757,26 +2152,15 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
757
2152
|
ruby_curl_easy *rbce;
|
|
758
2153
|
CURL *curl;
|
|
759
2154
|
VALUE upload;
|
|
2155
|
+
VALUE upload_stream = data;
|
|
760
2156
|
VALUE headers;
|
|
2157
|
+
VALUE infile_size = Qnil;
|
|
761
2158
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
upload = ruby_curl_upload_new(cCurlUpload);
|
|
765
|
-
ruby_curl_upload_stream_set(upload,data);
|
|
766
|
-
|
|
767
|
-
curl = rbce->curl;
|
|
768
|
-
rb_easy_set("upload", upload); /* keep the upload object alive as long as
|
|
769
|
-
the easy handle is active or until the upload
|
|
770
|
-
is complete or terminated... */
|
|
771
|
-
|
|
772
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
|
773
|
-
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
|
774
|
-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
775
|
-
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
|
2159
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
776
2160
|
|
|
777
|
-
/*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
2161
|
+
/*
|
|
2162
|
+
* Validate and prepare Ruby-visible state before mutating the CURL handle.
|
|
2163
|
+
* Several branches below can raise (header type, stat, size, to_s).
|
|
780
2164
|
*/
|
|
781
2165
|
if (!rb_easy_nil("headers")) {
|
|
782
2166
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_STRING)) {
|
|
@@ -784,43 +2168,80 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
784
2168
|
}
|
|
785
2169
|
}
|
|
786
2170
|
|
|
787
|
-
|
|
788
|
-
|
|
2171
|
+
if (!NIL_P(data) && !rb_respond_to(data, rb_intern("read"))) {
|
|
2172
|
+
if (rb_respond_to(data, rb_intern("to_s"))) {
|
|
2173
|
+
upload_stream = rb_obj_as_string(data);
|
|
2174
|
+
} else {
|
|
2175
|
+
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
789
2178
|
|
|
790
2179
|
headers = rb_easy_get("headers");
|
|
791
|
-
if( headers == Qnil ) {
|
|
2180
|
+
if( headers == Qnil ) {
|
|
792
2181
|
headers = rb_hash_new();
|
|
793
2182
|
}
|
|
794
2183
|
|
|
795
|
-
if (rb_respond_to(data, rb_intern("read"))) {
|
|
796
|
-
VALUE stat =
|
|
797
|
-
if
|
|
2184
|
+
if (!NIL_P(data) && rb_respond_to(data, rb_intern("read"))) {
|
|
2185
|
+
VALUE stat = Qnil;
|
|
2186
|
+
if (rb_respond_to(data, rb_intern("stat"))) {
|
|
2187
|
+
stat = rb_funcall(data, rb_intern("stat"), 0);
|
|
2188
|
+
}
|
|
2189
|
+
if(!NIL_P(stat) && stat != Qfalse && rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil) {
|
|
798
2190
|
VALUE size;
|
|
799
2191
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
800
2192
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
801
2193
|
}
|
|
802
2194
|
size = rb_funcall(stat, rb_intern("size"), 0);
|
|
803
|
-
|
|
2195
|
+
infile_size = size;
|
|
804
2196
|
}
|
|
805
2197
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
|
806
2198
|
rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
|
807
2199
|
}
|
|
808
2200
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
|
|
809
2201
|
VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
|
|
810
|
-
|
|
2202
|
+
infile_size = size;
|
|
811
2203
|
}
|
|
812
2204
|
}
|
|
813
|
-
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
|
814
|
-
|
|
2205
|
+
else if (!NIL_P(data) && rb_respond_to(data, rb_intern("to_s"))) {
|
|
2206
|
+
infile_size = LONG2NUM(RSTRING_LEN(upload_stream));
|
|
815
2207
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
816
2208
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
817
2209
|
}
|
|
818
2210
|
}
|
|
2211
|
+
else if (NIL_P(data)) {
|
|
2212
|
+
/* Preserve legacy nil handling: configure an upload with no payload. */
|
|
2213
|
+
}
|
|
819
2214
|
else {
|
|
820
2215
|
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
|
821
2216
|
}
|
|
822
2217
|
rb_easy_set("headers",headers);
|
|
823
2218
|
|
|
2219
|
+
upload = ruby_curl_upload_new(cCurlUpload);
|
|
2220
|
+
ruby_curl_upload_stream_set(upload, upload_stream);
|
|
2221
|
+
|
|
2222
|
+
curl = rbce->curl;
|
|
2223
|
+
rb_easy_set("upload", upload); /* keep the upload object alive as long as
|
|
2224
|
+
the easy handle is active or until the upload
|
|
2225
|
+
is complete or terminated... */
|
|
2226
|
+
|
|
2227
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
|
2228
|
+
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
2229
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
|
2230
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
|
|
2231
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
|
2232
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
2233
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
2234
|
+
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
2235
|
+
#endif
|
|
2236
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
|
2237
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
2238
|
+
curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
|
|
2239
|
+
#endif
|
|
2240
|
+
|
|
2241
|
+
if (!NIL_P(infile_size)) {
|
|
2242
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, NUM2LONG(infile_size));
|
|
2243
|
+
}
|
|
2244
|
+
|
|
824
2245
|
// if we made it this far, all should be well.
|
|
825
2246
|
return data;
|
|
826
2247
|
}
|
|
@@ -829,20 +2250,188 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
829
2250
|
* call-seq:
|
|
830
2251
|
* easy.ftp_commands = ["CWD /", "MKD directory"] => ["CWD /", ...]
|
|
831
2252
|
*
|
|
832
|
-
* Explicitly sets the list of commands to execute on the FTP server when calling perform
|
|
2253
|
+
* Explicitly sets the list of commands to execute on the FTP server when calling perform.
|
|
2254
|
+
*
|
|
2255
|
+
* NOTE:
|
|
2256
|
+
* - This maps to libcurl CURLOPT_QUOTE; it sends commands on the control connection.
|
|
2257
|
+
* - Do not include data-transfer commands like LIST/NLST/RETR/STOR here. libcurl does not
|
|
2258
|
+
* parse PASV/EPSV replies from QUOTE commands and will not establish the required data
|
|
2259
|
+
* connection. For directory listings, set CURLOPT_DIRLISTONLY (via `easy.set(:dirlistonly, true)`)
|
|
2260
|
+
* and request an FTP directory URL (e.g. "ftp://host/path/") so libcurl manages PASV/EPSV
|
|
2261
|
+
* and the data connection for you.
|
|
833
2262
|
*/
|
|
834
2263
|
static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
|
|
835
2264
|
CURB_OBJECT_HSETTER(ruby_curl_easy, ftp_commands);
|
|
836
2265
|
}
|
|
837
2266
|
|
|
838
2267
|
/*
|
|
839
|
-
* call-seq
|
|
2268
|
+
* call-seq:
|
|
840
2269
|
* easy.ftp_commands => array or nil
|
|
841
2270
|
*/
|
|
842
2271
|
static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
|
|
843
2272
|
CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_commands);
|
|
844
2273
|
}
|
|
845
2274
|
|
|
2275
|
+
/*
|
|
2276
|
+
* call-seq:
|
|
2277
|
+
* easy.resolve = [ "example.com:80:127.0.0.1" ] => [ "example.com:80:127.0.0.1" ]
|
|
2278
|
+
*
|
|
2279
|
+
* Set the resolve list to statically resolve hostnames to IP addresses,
|
|
2280
|
+
* bypassing DNS for matching hostname/port combinations.
|
|
2281
|
+
*/
|
|
2282
|
+
static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
|
|
2283
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, resolve);
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2286
|
+
/*
|
|
2287
|
+
* call-seq:
|
|
2288
|
+
* easy.resolve => array or nil
|
|
2289
|
+
*/
|
|
2290
|
+
static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
|
2291
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, resolve);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
/*
|
|
2295
|
+
* call-seq:
|
|
2296
|
+
* easy.connect_to = [ "example.com:80:127.0.0.1:80" ] => [ "example.com:80:127.0.0.1:80" ]
|
|
2297
|
+
*
|
|
2298
|
+
* Set the connect-to list to redirect matching request host/port pairs to
|
|
2299
|
+
* alternate connection host/port pairs.
|
|
2300
|
+
*/
|
|
2301
|
+
static VALUE ruby_curl_easy_connect_to_set(VALUE self, VALUE connect_to) {
|
|
2302
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, connect_to);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
/*
|
|
2306
|
+
* call-seq:
|
|
2307
|
+
* easy.connect_to => array or nil
|
|
2308
|
+
*/
|
|
2309
|
+
static VALUE ruby_curl_easy_connect_to_get(VALUE self) {
|
|
2310
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, connect_to);
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
/*
|
|
2314
|
+
* call-seq:
|
|
2315
|
+
* easy.doh_url = "https://dns.example/dns-query" => "https://dns.example/dns-query"
|
|
2316
|
+
*
|
|
2317
|
+
* Set the DNS-over-HTTPS URL to use for resolving hostnames.
|
|
2318
|
+
*/
|
|
2319
|
+
static VALUE ruby_curl_easy_doh_url_set(VALUE self, VALUE doh_url) {
|
|
2320
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, doh_url);
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
/*
|
|
2324
|
+
* call-seq:
|
|
2325
|
+
* easy.doh_url => string or nil
|
|
2326
|
+
*/
|
|
2327
|
+
static VALUE ruby_curl_easy_doh_url_get(VALUE self) {
|
|
2328
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, doh_url);
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
2332
|
+
/*
|
|
2333
|
+
* call-seq:
|
|
2334
|
+
* easy.dns_servers => string or nil
|
|
2335
|
+
*/
|
|
2336
|
+
static VALUE ruby_curl_easy_dns_servers_get(VALUE self) {
|
|
2337
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, dns_servers);
|
|
2338
|
+
}
|
|
2339
|
+
#endif
|
|
2340
|
+
|
|
2341
|
+
static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
|
|
2342
|
+
ruby_curl_easy *rbce;
|
|
2343
|
+
|
|
2344
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2345
|
+
rbce->allow_unix_socket = RTEST(allow) ? 1 : 0;
|
|
2346
|
+
|
|
2347
|
+
return allow;
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
static VALUE ruby_curl_easy_allow_proxy_set(VALUE self, VALUE allow) {
|
|
2351
|
+
ruby_curl_easy *rbce;
|
|
2352
|
+
|
|
2353
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2354
|
+
rbce->allow_proxy = RTEST(allow) ? 1 : 0;
|
|
2355
|
+
|
|
2356
|
+
return allow;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
/*
|
|
2360
|
+
* call-seq:
|
|
2361
|
+
* easy.allowed_cidrs = ["203.0.113.0/24"] => ["203.0.113.0/24"]
|
|
2362
|
+
*
|
|
2363
|
+
* Set resolved-peer CIDR ranges that are allowed when network_policy is :public.
|
|
2364
|
+
* Private/local unsafe ranges are still blocked before this allowlist is
|
|
2365
|
+
* evaluated.
|
|
2366
|
+
*/
|
|
2367
|
+
static VALUE ruby_curl_easy_allowed_cidrs_set(VALUE self, VALUE cidrs) {
|
|
2368
|
+
ruby_curl_easy *rbce;
|
|
2369
|
+
VALUE normalized;
|
|
2370
|
+
VALUE stored;
|
|
2371
|
+
|
|
2372
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2373
|
+
normalized = curb_normalize_cidr_list(cidrs);
|
|
2374
|
+
stored = curb_dup_string_array(normalized);
|
|
2375
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_cidrs"), stored);
|
|
2376
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC) {
|
|
2377
|
+
curb_prepare_network_allowed_cidr_rules(rbce);
|
|
2378
|
+
} else {
|
|
2379
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
return curb_dup_string_array(stored);
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
/*
|
|
2386
|
+
* call-seq:
|
|
2387
|
+
* easy.allowed_cidrs => array or nil
|
|
2388
|
+
*/
|
|
2389
|
+
static VALUE ruby_curl_easy_allowed_cidrs_get(VALUE self) {
|
|
2390
|
+
ruby_curl_easy *rbce;
|
|
2391
|
+
VALUE cidrs;
|
|
2392
|
+
|
|
2393
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2394
|
+
cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
|
|
2395
|
+
|
|
2396
|
+
return curb_dup_string_array(cidrs);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
/*
|
|
2400
|
+
* call-seq:
|
|
2401
|
+
* easy.allowed_hosts = ["api.example.com"] => ["api.example.com"]
|
|
2402
|
+
*
|
|
2403
|
+
* Set URL hosts allowed for this handle. When libcurl supports
|
|
2404
|
+
* CURLOPT_PREREQFUNCTION, this is checked before each request, including
|
|
2405
|
+
* followed redirects.
|
|
2406
|
+
*/
|
|
2407
|
+
static VALUE ruby_curl_easy_allowed_hosts_set(VALUE self, VALUE hosts) {
|
|
2408
|
+
ruby_curl_easy *rbce;
|
|
2409
|
+
VALUE normalized;
|
|
2410
|
+
VALUE stored;
|
|
2411
|
+
|
|
2412
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2413
|
+
normalized = curb_normalize_host_list(hosts);
|
|
2414
|
+
stored = curb_dup_string_array(normalized);
|
|
2415
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_hosts"), stored);
|
|
2416
|
+
curb_prepare_network_allowed_hosts(rbce);
|
|
2417
|
+
|
|
2418
|
+
return curb_dup_string_array(stored);
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/*
|
|
2422
|
+
* call-seq:
|
|
2423
|
+
* easy.allowed_hosts => array or nil
|
|
2424
|
+
*/
|
|
2425
|
+
static VALUE ruby_curl_easy_allowed_hosts_get(VALUE self) {
|
|
2426
|
+
ruby_curl_easy *rbce;
|
|
2427
|
+
VALUE hosts;
|
|
2428
|
+
|
|
2429
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2430
|
+
hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
|
|
2431
|
+
|
|
2432
|
+
return curb_dup_string_array(hosts);
|
|
2433
|
+
}
|
|
2434
|
+
|
|
846
2435
|
/* ================== IMMED ATTRS ==================*/
|
|
847
2436
|
|
|
848
2437
|
/*
|
|
@@ -951,16 +2540,16 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
|
|
|
951
2540
|
(!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
|
|
952
2541
|
(!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
|
|
953
2542
|
(!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
|
|
954
|
-
(!strncmp("
|
|
955
|
-
(!strncmp("
|
|
956
|
-
#else
|
|
2543
|
+
(!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
|
|
2544
|
+
(!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
|
|
2545
|
+
#else
|
|
957
2546
|
#define CURL_HTTPAUTH_STR_TO_NUM(node) \
|
|
958
2547
|
(!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
|
|
959
2548
|
(!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
|
|
960
2549
|
(!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
|
|
961
2550
|
(!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
|
|
962
|
-
(!strncmp("
|
|
963
|
-
(!strncmp("
|
|
2551
|
+
(!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
|
|
2552
|
+
(!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
|
|
964
2553
|
#endif
|
|
965
2554
|
/*
|
|
966
2555
|
* call-seq:
|
|
@@ -974,21 +2563,22 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
|
|
|
974
2563
|
static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
|
|
975
2564
|
ruby_curl_easy *rbce;
|
|
976
2565
|
VALUE args_ary;
|
|
977
|
-
|
|
2566
|
+
long i, len;
|
|
978
2567
|
char* node = NULL;
|
|
979
|
-
long mask =
|
|
2568
|
+
long mask = 0;
|
|
980
2569
|
|
|
981
2570
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
982
|
-
|
|
2571
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
983
2572
|
|
|
984
|
-
len =
|
|
2573
|
+
len = RARRAY_LEN(args_ary);
|
|
985
2574
|
|
|
986
|
-
if (len == 1 && (
|
|
987
|
-
|
|
2575
|
+
if (len == 1 && (rb_ary_entry(args_ary,0) == Qnil || TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM ||
|
|
2576
|
+
TYPE(rb_ary_entry(args_ary,0)) == T_BIGNUM)) {
|
|
2577
|
+
if (rb_ary_entry(args_ary,0) == Qnil) {
|
|
988
2578
|
rbce->http_auth_types = 0;
|
|
989
2579
|
}
|
|
990
2580
|
else {
|
|
991
|
-
rbce->http_auth_types =
|
|
2581
|
+
rbce->http_auth_types = NUM2LONG(rb_ary_entry(args_ary,0));
|
|
992
2582
|
}
|
|
993
2583
|
}
|
|
994
2584
|
else {
|
|
@@ -1001,7 +2591,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
|
|
|
1001
2591
|
}
|
|
1002
2592
|
rbce->http_auth_types = mask;
|
|
1003
2593
|
}
|
|
1004
|
-
return
|
|
2594
|
+
return LONG2NUM(rbce->http_auth_types);
|
|
1005
2595
|
}
|
|
1006
2596
|
|
|
1007
2597
|
/*
|
|
@@ -1066,7 +2656,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
|
1066
2656
|
|
|
1067
2657
|
/*
|
|
1068
2658
|
* call-seq:
|
|
1069
|
-
* easy.timeout = fixnum or nil
|
|
2659
|
+
* easy.timeout = float, fixnum or nil => numeric
|
|
1070
2660
|
*
|
|
1071
2661
|
* Set the maximum time in seconds that you allow the libcurl transfer
|
|
1072
2662
|
* operation to take. Normally, name lookups can take a considerable time
|
|
@@ -1075,20 +2665,77 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
|
1075
2665
|
*
|
|
1076
2666
|
* Set to nil (or zero) to disable timeout (it will then only timeout
|
|
1077
2667
|
* on the system's internal timeouts).
|
|
2668
|
+
*
|
|
2669
|
+
* Uses timeout_ms internally instead of timeout because it allows for
|
|
2670
|
+
* better precision and libcurl will use the last set value when both
|
|
2671
|
+
* timeout and timeout_ms are set.
|
|
2672
|
+
*
|
|
1078
2673
|
*/
|
|
1079
|
-
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE
|
|
1080
|
-
|
|
2674
|
+
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
|
|
2675
|
+
ruby_curl_easy *rbce;
|
|
2676
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2677
|
+
|
|
2678
|
+
if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
|
|
2679
|
+
rbce->timeout_ms = 0;
|
|
2680
|
+
} else {
|
|
2681
|
+
rbce->timeout_ms = (unsigned long)(NUM2DBL(timeout_s) * 1000);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
|
1081
2685
|
}
|
|
1082
2686
|
|
|
1083
2687
|
/*
|
|
1084
2688
|
* call-seq:
|
|
1085
|
-
* easy.timeout =>
|
|
2689
|
+
* easy.timeout => numeric
|
|
1086
2690
|
*
|
|
1087
2691
|
* Obtain the maximum time in seconds that you allow the libcurl transfer
|
|
1088
2692
|
* operation to take.
|
|
2693
|
+
*
|
|
2694
|
+
* Uses timeout_ms internally instead of timeout.
|
|
2695
|
+
*
|
|
2696
|
+
*/
|
|
2697
|
+
static VALUE ruby_curl_easy_timeout_get(VALUE self) {
|
|
2698
|
+
ruby_curl_easy *rbce;
|
|
2699
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2700
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
/*
|
|
2704
|
+
* call-seq:
|
|
2705
|
+
* easy.timeout_ms = fixnum or nil => fixnum or nil
|
|
2706
|
+
*
|
|
2707
|
+
* Set the maximum time in milliseconds that you allow the libcurl transfer
|
|
2708
|
+
* operation to take. Normally, name lookups can take a considerable time
|
|
2709
|
+
* and limiting operations to less than a few minutes risk aborting
|
|
2710
|
+
* perfectly normal operations.
|
|
2711
|
+
*
|
|
2712
|
+
* Set to nil (or zero) to disable timeout (it will then only timeout
|
|
2713
|
+
* on the system's internal timeouts).
|
|
2714
|
+
*/
|
|
2715
|
+
static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
|
2716
|
+
ruby_curl_easy *rbce;
|
|
2717
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2718
|
+
|
|
2719
|
+
if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
|
|
2720
|
+
rbce->timeout_ms = 0;
|
|
2721
|
+
} else {
|
|
2722
|
+
rbce->timeout_ms = NUM2ULONG(timeout_ms);
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
return ULONG2NUM(rbce->timeout_ms);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
/*
|
|
2729
|
+
* call-seq:
|
|
2730
|
+
* easy.timeout_ms => fixnum or nil
|
|
2731
|
+
*
|
|
2732
|
+
* Obtain the maximum time in milliseconds that you allow the libcurl transfer
|
|
2733
|
+
* operation to take.
|
|
1089
2734
|
*/
|
|
1090
|
-
static VALUE
|
|
1091
|
-
|
|
2735
|
+
static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
|
|
2736
|
+
ruby_curl_easy *rbce;
|
|
2737
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2738
|
+
return LONG2NUM(rbce->timeout_ms);
|
|
1092
2739
|
}
|
|
1093
2740
|
|
|
1094
2741
|
/*
|
|
@@ -1113,10 +2760,36 @@ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeou
|
|
|
1113
2760
|
* Obtain the maximum time in seconds that you allow the connection to the
|
|
1114
2761
|
* server to take.
|
|
1115
2762
|
*/
|
|
1116
|
-
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self
|
|
2763
|
+
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self) {
|
|
1117
2764
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
|
|
1118
2765
|
}
|
|
1119
2766
|
|
|
2767
|
+
/*
|
|
2768
|
+
* call-seq:
|
|
2769
|
+
* easy.connect_timeout_ms = fixnum or nil => fixnum or nil
|
|
2770
|
+
*
|
|
2771
|
+
* Set the maximum time in milliseconds that you allow the connection to the
|
|
2772
|
+
* server to take. This only limits the connection phase, once it has
|
|
2773
|
+
* connected, this option is of no more use.
|
|
2774
|
+
*
|
|
2775
|
+
* Set to nil (or zero) to disable connection timeout (it will then only
|
|
2776
|
+
* timeout on the system's internal timeouts).
|
|
2777
|
+
*/
|
|
2778
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_set(VALUE self, VALUE connect_timeout_ms) {
|
|
2779
|
+
CURB_IMMED_SETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
/*
|
|
2783
|
+
* call-seq:
|
|
2784
|
+
* easy.connect_timeout_ms => fixnum or nil
|
|
2785
|
+
*
|
|
2786
|
+
* Obtain the maximum time in milliseconds that you allow the connection to the
|
|
2787
|
+
* server to take.
|
|
2788
|
+
*/
|
|
2789
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self) {
|
|
2790
|
+
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
|
2791
|
+
}
|
|
2792
|
+
|
|
1120
2793
|
/*
|
|
1121
2794
|
* call-seq:
|
|
1122
2795
|
* easy.dns_cache_timeout = fixnum or nil => fixnum or nil
|
|
@@ -1136,7 +2809,7 @@ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_ti
|
|
|
1136
2809
|
*
|
|
1137
2810
|
* Obtain the dns cache timeout in seconds.
|
|
1138
2811
|
*/
|
|
1139
|
-
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self
|
|
2812
|
+
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self) {
|
|
1140
2813
|
CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
|
|
1141
2814
|
}
|
|
1142
2815
|
|
|
@@ -1163,7 +2836,7 @@ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_respo
|
|
|
1163
2836
|
*
|
|
1164
2837
|
* Obtain the maximum time that libcurl will wait for FTP command responses.
|
|
1165
2838
|
*/
|
|
1166
|
-
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self
|
|
2839
|
+
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self) {
|
|
1167
2840
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
|
|
1168
2841
|
}
|
|
1169
2842
|
|
|
@@ -1186,7 +2859,7 @@ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limi
|
|
|
1186
2859
|
* Obtain the minimum transfer speed over +low_speed+time+ below which the
|
|
1187
2860
|
* transfer will be aborted.
|
|
1188
2861
|
*/
|
|
1189
|
-
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self
|
|
2862
|
+
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self) {
|
|
1190
2863
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
|
|
1191
2864
|
}
|
|
1192
2865
|
|
|
@@ -1208,10 +2881,50 @@ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time)
|
|
|
1208
2881
|
* Obtain the time that the transfer should be below +low_speed_limit+ for
|
|
1209
2882
|
* the library to abort it.
|
|
1210
2883
|
*/
|
|
1211
|
-
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self
|
|
2884
|
+
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self) {
|
|
1212
2885
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
|
|
1213
2886
|
}
|
|
1214
2887
|
|
|
2888
|
+
/*
|
|
2889
|
+
* call-seq:
|
|
2890
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
|
2891
|
+
*
|
|
2892
|
+
* Set the maximal sending transfer speed (in bytes per second)
|
|
2893
|
+
*/
|
|
2894
|
+
static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_speed_large) {
|
|
2895
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_send_speed_large, 0);
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
/*
|
|
2899
|
+
* call-seq:
|
|
2900
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
|
2901
|
+
*
|
|
2902
|
+
* Get the maximal sending transfer speed (in bytes per second)
|
|
2903
|
+
*/
|
|
2904
|
+
static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self) {
|
|
2905
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
/*
|
|
2909
|
+
* call-seq:
|
|
2910
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
|
2911
|
+
*
|
|
2912
|
+
* Set the maximal receiving transfer speed (in bytes per second)
|
|
2913
|
+
*/
|
|
2914
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_speed_large) {
|
|
2915
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
/*
|
|
2919
|
+
* call-seq:
|
|
2920
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
|
2921
|
+
*
|
|
2922
|
+
* Get the maximal receiving transfer speed (in bytes per second)
|
|
2923
|
+
*/
|
|
2924
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self) {
|
|
2925
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
|
2926
|
+
}
|
|
2927
|
+
|
|
1215
2928
|
/*
|
|
1216
2929
|
* call-seq:
|
|
1217
2930
|
* easy.username = string => string
|
|
@@ -1219,7 +2932,7 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
|
|
|
1219
2932
|
* Set the HTTP Authentication username.
|
|
1220
2933
|
*/
|
|
1221
2934
|
static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
1222
|
-
#
|
|
2935
|
+
#ifdef HAVE_CURLOPT_USERNAME
|
|
1223
2936
|
CURB_OBJECT_HSETTER(ruby_curl_easy, username);
|
|
1224
2937
|
#else
|
|
1225
2938
|
return Qnil;
|
|
@@ -1229,11 +2942,11 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
|
1229
2942
|
/*
|
|
1230
2943
|
* call-seq:
|
|
1231
2944
|
* easy.username => string
|
|
1232
|
-
*
|
|
2945
|
+
*
|
|
1233
2946
|
* Get the current username
|
|
1234
2947
|
*/
|
|
1235
|
-
static VALUE ruby_curl_easy_username_get(VALUE self
|
|
1236
|
-
#
|
|
2948
|
+
static VALUE ruby_curl_easy_username_get(VALUE self) {
|
|
2949
|
+
#ifdef HAVE_CURLOPT_USERNAME
|
|
1237
2950
|
CURB_OBJECT_HGETTER(ruby_curl_easy, username);
|
|
1238
2951
|
#else
|
|
1239
2952
|
return Qnil;
|
|
@@ -1247,7 +2960,7 @@ static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
|
|
|
1247
2960
|
* Set the HTTP Authentication password.
|
|
1248
2961
|
*/
|
|
1249
2962
|
static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
1250
|
-
#
|
|
2963
|
+
#ifdef HAVE_CURLOPT_PASSWORD
|
|
1251
2964
|
CURB_OBJECT_HSETTER(ruby_curl_easy, password);
|
|
1252
2965
|
#else
|
|
1253
2966
|
return Qnil;
|
|
@@ -1257,11 +2970,11 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
|
1257
2970
|
/*
|
|
1258
2971
|
* call-seq:
|
|
1259
2972
|
* easy.password => string
|
|
1260
|
-
*
|
|
2973
|
+
*
|
|
1261
2974
|
* Get the current password
|
|
1262
2975
|
*/
|
|
1263
|
-
static VALUE ruby_curl_easy_password_get(VALUE self
|
|
1264
|
-
#
|
|
2976
|
+
static VALUE ruby_curl_easy_password_get(VALUE self) {
|
|
2977
|
+
#ifdef HAVE_CURLOPT_PASSWORD
|
|
1265
2978
|
CURB_OBJECT_HGETTER(ruby_curl_easy, password);
|
|
1266
2979
|
#else
|
|
1267
2980
|
return Qnil;
|
|
@@ -1273,8 +2986,16 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
|
|
|
1273
2986
|
* easy.ssl_version = value => fixnum or nil
|
|
1274
2987
|
*
|
|
1275
2988
|
* Sets the version of SSL/TLS that libcurl will attempt to use. Valid
|
|
1276
|
-
* options are
|
|
1277
|
-
*
|
|
2989
|
+
* options are:
|
|
2990
|
+
*
|
|
2991
|
+
* Curl::CURL_SSLVERSION_DEFAULT
|
|
2992
|
+
* Curl::CURL_SSLVERSION_TLSv1 (TLS 1.x)
|
|
2993
|
+
* Curl::CURL_SSLVERSION_SSLv2
|
|
2994
|
+
* Curl::CURL_SSLVERSION_SSLv3
|
|
2995
|
+
* Curl::CURL_SSLVERSION_TLSv1_0
|
|
2996
|
+
* Curl::CURL_SSLVERSION_TLSv1_1
|
|
2997
|
+
* Curl::CURL_SSLVERSION_TLSv1_2
|
|
2998
|
+
* Curl::CURL_SSLVERSION_TLSv1_3
|
|
1278
2999
|
*/
|
|
1279
3000
|
static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
1280
3001
|
CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
|
|
@@ -1286,14 +3007,14 @@ static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
|
1286
3007
|
*
|
|
1287
3008
|
* Get the version of SSL/TLS that libcurl will attempt to use.
|
|
1288
3009
|
*/
|
|
1289
|
-
static VALUE ruby_curl_easy_ssl_version_get(VALUE self
|
|
3010
|
+
static VALUE ruby_curl_easy_ssl_version_get(VALUE self) {
|
|
1290
3011
|
CURB_IMMED_GETTER(ruby_curl_easy, ssl_version, -1);
|
|
1291
3012
|
}
|
|
1292
3013
|
|
|
1293
3014
|
/*
|
|
1294
3015
|
* call-seq:
|
|
1295
3016
|
* easy.use_ssl = value => fixnum or nil
|
|
1296
|
-
*
|
|
3017
|
+
*
|
|
1297
3018
|
* Ensure libcurl uses SSL for FTP connections. Valid options are Curl::CURL_USESSL_NONE,
|
|
1298
3019
|
* Curl::CURL_USESSL_TRY, Curl::CURL_USESSL_CONTROL, and Curl::CURL_USESSL_ALL.
|
|
1299
3020
|
*/
|
|
@@ -1307,7 +3028,7 @@ static VALUE ruby_curl_easy_use_ssl_set(VALUE self, VALUE use_ssl) {
|
|
|
1307
3028
|
*
|
|
1308
3029
|
* Get the desired level for using SSL on FTP connections.
|
|
1309
3030
|
*/
|
|
1310
|
-
static VALUE ruby_curl_easy_use_ssl_get(VALUE self
|
|
3031
|
+
static VALUE ruby_curl_easy_use_ssl_get(VALUE self) {
|
|
1311
3032
|
CURB_IMMED_GETTER(ruby_curl_easy, use_ssl, -1);
|
|
1312
3033
|
}
|
|
1313
3034
|
|
|
@@ -1323,12 +3044,12 @@ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod)
|
|
|
1323
3044
|
}
|
|
1324
3045
|
|
|
1325
3046
|
/*
|
|
1326
|
-
* call-seq
|
|
3047
|
+
* call-seq:
|
|
1327
3048
|
* easy.ftp_filemethod => fixnum
|
|
1328
3049
|
*
|
|
1329
3050
|
* Get the configuration for how libcurl will reach files on the server.
|
|
1330
3051
|
*/
|
|
1331
|
-
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self
|
|
3052
|
+
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self) {
|
|
1332
3053
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_filemethod, -1);
|
|
1333
3054
|
}
|
|
1334
3055
|
|
|
@@ -1486,7 +3207,7 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
|
|
|
1486
3207
|
*/
|
|
1487
3208
|
static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
|
|
1488
3209
|
ruby_curl_easy *rbce;
|
|
1489
|
-
|
|
3210
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1490
3211
|
|
|
1491
3212
|
if (Qtrue == autoreferer) {
|
|
1492
3213
|
curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
|
|
@@ -1587,7 +3308,12 @@ static VALUE ruby_curl_easy_multipart_form_post_q(VALUE self) {
|
|
|
1587
3308
|
* easy.enable_cookies = boolean => boolean
|
|
1588
3309
|
*
|
|
1589
3310
|
* Configure whether the libcurl cookie engine is enabled for this Curl::Easy
|
|
1590
|
-
* instance.
|
|
3311
|
+
* instance. When enabled, cookies received via Set-Cookie are stored by libcurl
|
|
3312
|
+
* and automatically sent on subsequent matching requests. Use +easy.cookiefile+
|
|
3313
|
+
* to load cookies and +easy.cookiejar+ to persist them.
|
|
3314
|
+
*
|
|
3315
|
+
* This setting is independent from the manual Cookie header set via +easy.cookies+.
|
|
3316
|
+
* The manual header is additive and can be cleared by assigning an empty string.
|
|
1591
3317
|
*/
|
|
1592
3318
|
static VALUE ruby_curl_easy_enable_cookies_set(VALUE self, VALUE enable_cookies)
|
|
1593
3319
|
{
|
|
@@ -1637,9 +3363,10 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
|
|
|
1637
3363
|
*/
|
|
1638
3364
|
static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
|
|
1639
3365
|
ruby_curl_easy *rbce;
|
|
1640
|
-
|
|
3366
|
+
unsigned short rm;
|
|
3367
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1641
3368
|
|
|
1642
|
-
|
|
3369
|
+
rm = rbce->resolve_mode;
|
|
1643
3370
|
|
|
1644
3371
|
switch(rm) {
|
|
1645
3372
|
case CURL_IPRESOLVE_V4:
|
|
@@ -1668,9 +3395,10 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
1668
3395
|
return Qnil;
|
|
1669
3396
|
} else {
|
|
1670
3397
|
ruby_curl_easy *rbce;
|
|
1671
|
-
|
|
3398
|
+
ID resolve_mode_id;
|
|
3399
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1672
3400
|
|
|
1673
|
-
|
|
3401
|
+
resolve_mode_id = rb_to_id(resolve_mode);
|
|
1674
3402
|
|
|
1675
3403
|
if (resolve_mode_id == rb_intern("auto")) {
|
|
1676
3404
|
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
@@ -1688,12 +3416,147 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
1688
3416
|
}
|
|
1689
3417
|
}
|
|
1690
3418
|
|
|
3419
|
+
/*
|
|
3420
|
+
* call-seq:
|
|
3421
|
+
* easy.network_policy => symbol
|
|
3422
|
+
*
|
|
3423
|
+
* Determine which native network policy will be enforced when libcurl opens
|
|
3424
|
+
* sockets for this handle.
|
|
3425
|
+
*/
|
|
3426
|
+
static VALUE ruby_curl_easy_network_policy_get(VALUE self) {
|
|
3427
|
+
ruby_curl_easy *rbce;
|
|
3428
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3429
|
+
|
|
3430
|
+
switch (rbce->network_policy) {
|
|
3431
|
+
case CURB_NETWORK_POLICY_PUBLIC:
|
|
3432
|
+
return ID2SYM(idNetworkPolicyPublic);
|
|
3433
|
+
case CURB_NETWORK_POLICY_NONE:
|
|
3434
|
+
default:
|
|
3435
|
+
return ID2SYM(idNetworkPolicyNone);
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
/*
|
|
3440
|
+
* call-seq:
|
|
3441
|
+
* easy.network_policy = symbol => symbol
|
|
3442
|
+
*
|
|
3443
|
+
* Supported values:
|
|
3444
|
+
* [:none] disables native destination checks.
|
|
3445
|
+
* [:public] blocks loopback, private, link-local, multicast,
|
|
3446
|
+
* unspecified, metadata, and other non-public addresses.
|
|
3447
|
+
*/
|
|
3448
|
+
static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy) {
|
|
3449
|
+
ruby_curl_easy *rbce;
|
|
3450
|
+
ID network_policy_id;
|
|
3451
|
+
|
|
3452
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3453
|
+
|
|
3454
|
+
if (NIL_P(network_policy)) {
|
|
3455
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
3456
|
+
return ID2SYM(idNetworkPolicyNone);
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
if (TYPE(network_policy) != T_SYMBOL) {
|
|
3460
|
+
rb_raise(rb_eTypeError, "network_policy must be a Symbol");
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
network_policy_id = rb_to_id(network_policy);
|
|
3464
|
+
|
|
3465
|
+
if (network_policy_id == idNetworkPolicyNone) {
|
|
3466
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
3467
|
+
rbce->allow_proxy = 0;
|
|
3468
|
+
return network_policy;
|
|
3469
|
+
} else if (network_policy_id == idNetworkPolicyPublic) {
|
|
3470
|
+
#ifndef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
3471
|
+
rb_raise(rb_eNotImpError, "network_policy=:public requires CURLOPT_OPENSOCKETFUNCTION support");
|
|
3472
|
+
#else
|
|
3473
|
+
rbce->network_policy = CURB_NETWORK_POLICY_PUBLIC;
|
|
3474
|
+
rbce->allow_proxy = 0;
|
|
3475
|
+
return network_policy;
|
|
3476
|
+
#endif
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
rb_raise(rb_eArgError, "network_policy must be one of :none, :public");
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
/*
|
|
3483
|
+
* call-seq:
|
|
3484
|
+
* easy.unsafe_destination_error => string or nil
|
|
3485
|
+
*
|
|
3486
|
+
* Return the native network policy block reason from the most recent transfer.
|
|
3487
|
+
*/
|
|
3488
|
+
static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
|
|
3489
|
+
ruby_curl_easy *rbce;
|
|
3490
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3491
|
+
|
|
3492
|
+
if (rbce->unsafe_destination_blocked && rbce->unsafe_destination_error[0]) {
|
|
3493
|
+
return rb_str_new2(rbce->unsafe_destination_error);
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
return Qnil;
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
3500
|
+
/*
|
|
3501
|
+
* call-seq:
|
|
3502
|
+
* easy.unix_socket_path => string or nil
|
|
3503
|
+
*
|
|
3504
|
+
* Return the configured Unix socket path, if set through CURLOPT_UNIX_SOCKET_PATH.
|
|
3505
|
+
*/
|
|
3506
|
+
static VALUE ruby_curl_easy_unix_socket_path_get(VALUE self) {
|
|
3507
|
+
ruby_curl_easy *rbce;
|
|
3508
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3509
|
+
|
|
3510
|
+
return rb_easy_get("unix_socket_path");
|
|
3511
|
+
}
|
|
3512
|
+
#endif
|
|
3513
|
+
|
|
3514
|
+
/*
|
|
3515
|
+
* call-seq:
|
|
3516
|
+
* easy.http_version = Curl::HTTP_1_1 => Curl::HTTP_1_1
|
|
3517
|
+
*
|
|
3518
|
+
* Force libcurl to use a specific HTTP protocol version. By default libcurl
|
|
3519
|
+
* negotiates the highest version supported by both peers. Supported constants
|
|
3520
|
+
* include Curl::HTTP_NONE, Curl::HTTP_1_0, Curl::HTTP_1_1, Curl::HTTP_2_0,
|
|
3521
|
+
* Curl::HTTP_2TLS, and Curl::HTTP_2_PRIOR_KNOWLEDGE (when provided by libcurl).
|
|
3522
|
+
*/
|
|
3523
|
+
static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
|
|
3524
|
+
ruby_curl_easy *rbce;
|
|
3525
|
+
long http_version;
|
|
3526
|
+
|
|
3527
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3528
|
+
|
|
3529
|
+
if (NIL_P(version)) {
|
|
3530
|
+
http_version = CURL_HTTP_VERSION_NONE;
|
|
3531
|
+
} else {
|
|
3532
|
+
http_version = NUM2LONG(version);
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
rbce->http_version = http_version;
|
|
3536
|
+
|
|
3537
|
+
return version;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
/*
|
|
3541
|
+
* call-seq:
|
|
3542
|
+
* easy.http_version => integer
|
|
3543
|
+
*
|
|
3544
|
+
* Returns the HTTP protocol version currently configured.
|
|
3545
|
+
*/
|
|
3546
|
+
static VALUE ruby_curl_easy_http_version_get(VALUE self) {
|
|
3547
|
+
ruby_curl_easy *rbce;
|
|
3548
|
+
|
|
3549
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3550
|
+
|
|
3551
|
+
return LONG2NUM(rbce->http_version);
|
|
3552
|
+
}
|
|
3553
|
+
|
|
1691
3554
|
|
|
1692
3555
|
/* ================= EVENT PROCS ================== */
|
|
1693
3556
|
|
|
1694
3557
|
/*
|
|
1695
3558
|
* call-seq:
|
|
1696
|
-
* easy.on_body { |body_data| ... } =>
|
|
3559
|
+
* easy.on_body { |body_data| ... } => <old handler>
|
|
1697
3560
|
*
|
|
1698
3561
|
* Assign or remove the +on_body+ handler for this Curl::Easy instance.
|
|
1699
3562
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1712,7 +3575,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1712
3575
|
|
|
1713
3576
|
/*
|
|
1714
3577
|
* call-seq:
|
|
1715
|
-
* easy.on_success { |easy| ... } =>
|
|
3578
|
+
* easy.on_success { |easy| ... } => <old handler>
|
|
1716
3579
|
*
|
|
1717
3580
|
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
|
1718
3581
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1727,7 +3590,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1727
3590
|
|
|
1728
3591
|
/*
|
|
1729
3592
|
* call-seq:
|
|
1730
|
-
* easy.on_failure {|easy,code| ... } =>
|
|
3593
|
+
* easy.on_failure {|easy,code| ... } => <old handler>
|
|
1731
3594
|
*
|
|
1732
3595
|
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
|
1733
3596
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1742,13 +3605,13 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1742
3605
|
|
|
1743
3606
|
/*
|
|
1744
3607
|
* call-seq:
|
|
1745
|
-
* easy.on_missing {|easy,code| ... } =>
|
|
3608
|
+
* easy.on_missing {|easy,code| ... } => <old handler;>
|
|
1746
3609
|
*
|
|
1747
3610
|
* Assign or remove the on_missing handler for this Curl::Easy instance.
|
|
1748
3611
|
* To remove a previously-supplied handler, call this method with no attached
|
|
1749
3612
|
* block.
|
|
1750
3613
|
*
|
|
1751
|
-
* The +on_missing+ handler is called when request is finished with a
|
|
3614
|
+
* The +on_missing+ handler is called when request is finished with a
|
|
1752
3615
|
* status of 40x
|
|
1753
3616
|
*/
|
|
1754
3617
|
static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1757,13 +3620,13 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1757
3620
|
|
|
1758
3621
|
/*
|
|
1759
3622
|
* call-seq:
|
|
1760
|
-
* easy.on_redirect {|easy,code| ... } =>
|
|
3623
|
+
* easy.on_redirect {|easy,code| ... } => <old handler;>
|
|
1761
3624
|
*
|
|
1762
3625
|
* Assign or remove the on_redirect handler for this Curl::Easy instance.
|
|
1763
3626
|
* To remove a previously-supplied handler, call this method with no attached
|
|
1764
3627
|
* block.
|
|
1765
3628
|
*
|
|
1766
|
-
* The +on_redirect+ handler is called when request is finished with a
|
|
3629
|
+
* The +on_redirect+ handler is called when request is finished with a
|
|
1767
3630
|
* status of 30x
|
|
1768
3631
|
*/
|
|
1769
3632
|
static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1772,7 +3635,7 @@ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1772
3635
|
|
|
1773
3636
|
/*
|
|
1774
3637
|
* call-seq:
|
|
1775
|
-
* easy.on_complete {|easy| ... } =>
|
|
3638
|
+
* easy.on_complete {|easy| ... } => <old handler>
|
|
1776
3639
|
*
|
|
1777
3640
|
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
|
1778
3641
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1786,7 +3649,7 @@ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1786
3649
|
|
|
1787
3650
|
/*
|
|
1788
3651
|
* call-seq:
|
|
1789
|
-
* easy.on_header { |header_data| ... } =>
|
|
3652
|
+
* easy.on_header { |header_data| ... } => <old handler>
|
|
1790
3653
|
*
|
|
1791
3654
|
* Assign or remove the +on_header+ handler for this Curl::Easy instance.
|
|
1792
3655
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1802,7 +3665,7 @@ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1802
3665
|
|
|
1803
3666
|
/*
|
|
1804
3667
|
* call-seq:
|
|
1805
|
-
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } =>
|
|
3668
|
+
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => <old handler>
|
|
1806
3669
|
*
|
|
1807
3670
|
* Assign or remove the +on_progress+ handler for this Curl::Easy instance.
|
|
1808
3671
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1823,7 +3686,7 @@ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1823
3686
|
|
|
1824
3687
|
/*
|
|
1825
3688
|
* call-seq:
|
|
1826
|
-
* easy.on_debug { |type, data| ... } =>
|
|
3689
|
+
* easy.on_debug { |type, data| ... } => <old handler>
|
|
1827
3690
|
*
|
|
1828
3691
|
* Assign or remove the +on_debug+ handler for this Curl::Easy instance.
|
|
1829
3692
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1848,12 +3711,12 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1848
3711
|
/***********************************************
|
|
1849
3712
|
* This is an rb_iterate callback used to set up http headers.
|
|
1850
3713
|
*/
|
|
1851
|
-
static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
3714
|
+
static VALUE cb_each_http_header(VALUE header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
1852
3715
|
struct curl_slist **list;
|
|
1853
|
-
Data_Get_Struct(wrap, struct curl_slist *, list);
|
|
1854
|
-
|
|
1855
3716
|
VALUE header_str = Qnil;
|
|
1856
3717
|
|
|
3718
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
3719
|
+
|
|
1857
3720
|
//rb_p(header);
|
|
1858
3721
|
|
|
1859
3722
|
if (rb_type(header) == T_ARRAY) {
|
|
@@ -1862,57 +3725,203 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
|
1862
3725
|
|
|
1863
3726
|
name = rb_obj_as_string(rb_ary_entry(header, 0));
|
|
1864
3727
|
value = rb_obj_as_string(rb_ary_entry(header, 1));
|
|
3728
|
+
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
|
|
3729
|
+
header_str = rb_str_plus(name, rb_str_new2(":"));
|
|
3730
|
+
} else {
|
|
3731
|
+
// This is a bit inefficient, but we don't want to be modifying
|
|
3732
|
+
// the actual values in the original hash.
|
|
3733
|
+
header_str = rb_str_plus(name, rb_str_new2(": "));
|
|
3734
|
+
header_str = rb_str_plus(header_str, value);
|
|
3735
|
+
}
|
|
3736
|
+
} else {
|
|
3737
|
+
header_str = rb_obj_as_string(header);
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
//rb_p(header_str);
|
|
3741
|
+
|
|
3742
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(header_str));
|
|
3743
|
+
if (!new_list) {
|
|
3744
|
+
rb_raise(rb_eNoMemError, "Failed to append to header list");
|
|
3745
|
+
}
|
|
3746
|
+
*list = new_list;
|
|
3747
|
+
return header_str;
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
/***********************************************
|
|
3751
|
+
* This is an rb_iterate callback used to set up http proxy headers.
|
|
3752
|
+
*/
|
|
3753
|
+
static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
3754
|
+
struct curl_slist **list;
|
|
3755
|
+
VALUE proxy_header_str = Qnil;
|
|
3756
|
+
|
|
3757
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
3758
|
+
|
|
3759
|
+
//rb_p(proxy_header);
|
|
3760
|
+
|
|
3761
|
+
if (rb_type(proxy_header) == T_ARRAY) {
|
|
3762
|
+
// we're processing a hash, proxy header is [name, val]
|
|
3763
|
+
VALUE name, value;
|
|
3764
|
+
|
|
3765
|
+
name = rb_obj_as_string(rb_ary_entry(proxy_header, 0));
|
|
3766
|
+
value = rb_obj_as_string(rb_ary_entry(proxy_header, 1));
|
|
1865
3767
|
|
|
1866
3768
|
// This is a bit inefficient, but we don't want to be modifying
|
|
1867
3769
|
// the actual values in the original hash.
|
|
1868
|
-
|
|
1869
|
-
|
|
3770
|
+
proxy_header_str = rb_str_plus(name, rb_str_new2(": "));
|
|
3771
|
+
proxy_header_str = rb_str_plus(proxy_header_str, value);
|
|
1870
3772
|
} else {
|
|
1871
|
-
|
|
3773
|
+
proxy_header_str = rb_obj_as_string(proxy_header);
|
|
1872
3774
|
}
|
|
1873
3775
|
|
|
1874
3776
|
//rb_p(header_str);
|
|
1875
3777
|
|
|
1876
|
-
*
|
|
1877
|
-
|
|
3778
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
|
|
3779
|
+
if (!new_list) {
|
|
3780
|
+
rb_raise(rb_eNoMemError, "Failed to append to proxy header list");
|
|
3781
|
+
}
|
|
3782
|
+
*list = new_list;
|
|
3783
|
+
return proxy_header_str;
|
|
1878
3784
|
}
|
|
1879
3785
|
|
|
1880
3786
|
/***********************************************
|
|
1881
3787
|
* This is an rb_iterate callback used to set up ftp commands.
|
|
1882
3788
|
*/
|
|
1883
|
-
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
|
3789
|
+
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
1884
3790
|
struct curl_slist **list;
|
|
1885
|
-
|
|
3791
|
+
VALUE ftp_command_string;
|
|
3792
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
1886
3793
|
|
|
1887
|
-
|
|
1888
|
-
*
|
|
3794
|
+
ftp_command_string = rb_obj_as_string(ftp_command);
|
|
3795
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(ftp_command_string));
|
|
3796
|
+
if (!new_list) {
|
|
3797
|
+
rb_raise(rb_eNoMemError, "Failed to append to FTP command list");
|
|
3798
|
+
}
|
|
3799
|
+
*list = new_list;
|
|
1889
3800
|
|
|
1890
3801
|
return ftp_command_string;
|
|
1891
3802
|
}
|
|
1892
3803
|
|
|
3804
|
+
/***********************************************
|
|
3805
|
+
* This is an rb_iterate callback used to set up the resolve list.
|
|
3806
|
+
*/
|
|
3807
|
+
static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
3808
|
+
struct curl_slist **list;
|
|
3809
|
+
VALUE resolve_string;
|
|
3810
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
3811
|
+
|
|
3812
|
+
resolve_string = rb_obj_as_string(resolve);
|
|
3813
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(resolve_string));
|
|
3814
|
+
if (!new_list) {
|
|
3815
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
3816
|
+
}
|
|
3817
|
+
*list = new_list;
|
|
3818
|
+
|
|
3819
|
+
return resolve_string;
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
/***********************************************
|
|
3823
|
+
* This is an rb_iterate callback used to set up the connect-to list.
|
|
3824
|
+
*/
|
|
3825
|
+
static VALUE cb_each_connect_to(VALUE connect_to, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
3826
|
+
struct curl_slist **list;
|
|
3827
|
+
VALUE connect_to_string;
|
|
3828
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
3829
|
+
|
|
3830
|
+
connect_to_string = rb_obj_as_string(connect_to);
|
|
3831
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(connect_to_string));
|
|
3832
|
+
if (!new_list) {
|
|
3833
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
3834
|
+
}
|
|
3835
|
+
*list = new_list;
|
|
3836
|
+
|
|
3837
|
+
return connect_to_string;
|
|
3838
|
+
}
|
|
3839
|
+
|
|
1893
3840
|
/***********************************************
|
|
1894
3841
|
*
|
|
1895
3842
|
* Setup a connection
|
|
1896
3843
|
*
|
|
1897
3844
|
* Always returns Qtrue, rb_raise on error.
|
|
1898
3845
|
*/
|
|
1899
|
-
VALUE
|
|
3846
|
+
static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
3847
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
1900
3848
|
// TODO this could do with a bit of refactoring...
|
|
1901
3849
|
CURL *curl;
|
|
1902
3850
|
VALUE url, _url = rb_easy_get("url");
|
|
1903
3851
|
struct curl_slist **hdrs = &(rbce->curl_headers);
|
|
3852
|
+
struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
|
|
1904
3853
|
struct curl_slist **cmds = &(rbce->curl_ftp_commands);
|
|
3854
|
+
struct curl_slist **rslv = &(rbce->curl_resolve);
|
|
3855
|
+
struct curl_slist **cnto = &(rbce->curl_connect_to);
|
|
3856
|
+
int public_policy_disables_proxy;
|
|
1905
3857
|
|
|
1906
3858
|
curl = rbce->curl;
|
|
3859
|
+
public_policy_disables_proxy = rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rbce->allow_proxy;
|
|
3860
|
+
rbce->callback_error = Qnil;
|
|
3861
|
+
rbce->unsafe_destination_blocked = 0;
|
|
3862
|
+
memset(rbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
1907
3863
|
|
|
1908
3864
|
if (_url == Qnil) {
|
|
1909
3865
|
rb_raise(eCurlErrError, "No URL supplied");
|
|
1910
3866
|
}
|
|
1911
3867
|
|
|
1912
3868
|
url = rb_check_string_type(_url);
|
|
1913
|
-
|
|
1914
3869
|
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
|
1915
3870
|
|
|
3871
|
+
#ifdef HAVE_CURLOPT_DOH_URL
|
|
3872
|
+
curl_easy_setopt(curl, CURLOPT_DOH_URL, rb_easy_nil("doh_url") ? NULL : rb_easy_get_str("doh_url"));
|
|
3873
|
+
#endif
|
|
3874
|
+
|
|
3875
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
3876
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rb_easy_nil("dns_servers")) {
|
|
3877
|
+
rb_raise(eCurlErrUnsafeDestination, "DNS server overrides are disabled by public network policy");
|
|
3878
|
+
}
|
|
3879
|
+
curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, rb_easy_nil("dns_servers") ? NULL : rb_easy_get_str("dns_servers"));
|
|
3880
|
+
#endif
|
|
3881
|
+
|
|
3882
|
+
#ifdef CURB_HAVE_PREREQ_HOST_POLICY
|
|
3883
|
+
if (!rb_easy_nil("allowed_hosts")) {
|
|
3884
|
+
curb_prepare_network_allowed_hosts(rbce);
|
|
3885
|
+
curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, curb_host_allowlist_prereq);
|
|
3886
|
+
curl_easy_setopt(curl, CURLOPT_PREREQDATA, rbce);
|
|
3887
|
+
} else {
|
|
3888
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
3889
|
+
curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, NULL);
|
|
3890
|
+
curl_easy_setopt(curl, CURLOPT_PREREQDATA, NULL);
|
|
3891
|
+
}
|
|
3892
|
+
#else
|
|
3893
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
3894
|
+
#endif
|
|
3895
|
+
|
|
3896
|
+
#ifdef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
3897
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC) {
|
|
3898
|
+
curb_prepare_network_allowed_cidr_rules(rbce);
|
|
3899
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, curb_public_network_opensocket);
|
|
3900
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, rbce);
|
|
3901
|
+
#ifdef HAVE_CURLOPT_FRESH_CONNECT
|
|
3902
|
+
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
|
|
3903
|
+
#endif
|
|
3904
|
+
#ifdef HAVE_CURLOPT_FORBID_REUSE
|
|
3905
|
+
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
|
|
3906
|
+
#endif
|
|
3907
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
3908
|
+
if (!rbce->allow_unix_socket) {
|
|
3909
|
+
curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, NULL);
|
|
3910
|
+
}
|
|
3911
|
+
#endif
|
|
3912
|
+
} else {
|
|
3913
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
3914
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, NULL);
|
|
3915
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, NULL);
|
|
3916
|
+
#ifdef HAVE_CURLOPT_FRESH_CONNECT
|
|
3917
|
+
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 0L);
|
|
3918
|
+
#endif
|
|
3919
|
+
#ifdef HAVE_CURLOPT_FORBID_REUSE
|
|
3920
|
+
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, rbce->forbid_reuse_set ? rbce->forbid_reuse : 0L);
|
|
3921
|
+
#endif
|
|
3922
|
+
}
|
|
3923
|
+
#endif
|
|
3924
|
+
|
|
1916
3925
|
// network stuff and auth
|
|
1917
3926
|
if (!rb_easy_nil("interface_hm")) {
|
|
1918
3927
|
curl_easy_setopt(curl, CURLOPT_INTERFACE, rb_easy_get_str("interface_hm"));
|
|
@@ -1920,7 +3929,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1920
3929
|
curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
|
|
1921
3930
|
}
|
|
1922
3931
|
|
|
1923
|
-
#if HAVE_CURLOPT_USERNAME
|
|
3932
|
+
#if defined(HAVE_CURLOPT_USERNAME) && defined(HAVE_CURLOPT_PASSWORD)
|
|
1924
3933
|
if (!rb_easy_nil("username")) {
|
|
1925
3934
|
curl_easy_setopt(curl, CURLOPT_USERNAME, rb_easy_get_str("username"));
|
|
1926
3935
|
} else {
|
|
@@ -1936,7 +3945,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1936
3945
|
|
|
1937
3946
|
if (!rb_easy_nil("userpwd")) {
|
|
1938
3947
|
curl_easy_setopt(curl, CURLOPT_USERPWD, rb_easy_get_str("userpwd"));
|
|
1939
|
-
#if HAVE_CURLOPT_USERNAME
|
|
3948
|
+
#if defined(HAVE_CURLOPT_USERNAME) && defined(HAVE_CURLOPT_PASSWORD)
|
|
1940
3949
|
} else if (rb_easy_nil("username") && rb_easy_nil("password")) { /* don't set this even to NULL if we have set username and password */
|
|
1941
3950
|
#else
|
|
1942
3951
|
} else {
|
|
@@ -1944,28 +3953,42 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1944
3953
|
curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
|
|
1945
3954
|
}
|
|
1946
3955
|
|
|
1947
|
-
if (
|
|
3956
|
+
if (public_policy_disables_proxy) {
|
|
3957
|
+
curl_easy_setopt(curl, CURLOPT_PROXY, "");
|
|
3958
|
+
} else if (rb_easy_nil("proxy_url")) {
|
|
1948
3959
|
curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
|
|
1949
3960
|
} else {
|
|
1950
3961
|
curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
|
|
1951
3962
|
}
|
|
1952
3963
|
|
|
1953
|
-
if (
|
|
3964
|
+
if (public_policy_disables_proxy) {
|
|
3965
|
+
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
|
3966
|
+
} else if (rb_easy_nil("proxypwd")) {
|
|
1954
3967
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
|
1955
3968
|
} else {
|
|
1956
3969
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
|
|
1957
3970
|
}
|
|
1958
3971
|
|
|
3972
|
+
#ifdef HAVE_CURLOPT_NOPROXY
|
|
3973
|
+
if (rb_easy_nil("noproxy")) {
|
|
3974
|
+
curl_easy_setopt(curl, CURLOPT_NOPROXY, NULL);
|
|
3975
|
+
} else {
|
|
3976
|
+
curl_easy_setopt(curl, CURLOPT_NOPROXY, rb_easy_get_str("noproxy"));
|
|
3977
|
+
}
|
|
3978
|
+
#endif
|
|
3979
|
+
|
|
1959
3980
|
// body/header procs
|
|
3981
|
+
rbce->downloaded_body_bytes = 0;
|
|
3982
|
+
|
|
1960
3983
|
if (!rb_easy_nil("body_proc")) {
|
|
1961
3984
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
|
|
1962
3985
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
|
1963
3986
|
/* clear out the body_data if it was set */
|
|
1964
3987
|
rb_easy_del("body_data");
|
|
1965
3988
|
} else {
|
|
1966
|
-
|
|
1967
|
-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&
|
|
1968
|
-
curl_easy_setopt(curl, CURLOPT_WRITEDATA,
|
|
3989
|
+
rb_easy_set("body_data", rb_str_buf_new(32768));
|
|
3990
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_body_handler);
|
|
3991
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
|
1969
3992
|
}
|
|
1970
3993
|
|
|
1971
3994
|
if (!rb_easy_nil("header_proc")) {
|
|
@@ -1974,9 +3997,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1974
3997
|
/* clear out the header_data if it was set */
|
|
1975
3998
|
rb_easy_del("header_data");
|
|
1976
3999
|
} else {
|
|
1977
|
-
|
|
1978
|
-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&
|
|
1979
|
-
curl_easy_setopt(curl, CURLOPT_HEADERDATA,
|
|
4000
|
+
rb_easy_set("header_data", rb_str_buf_new(16384));
|
|
4001
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_header_handler);
|
|
4002
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
|
|
1980
4003
|
}
|
|
1981
4004
|
|
|
1982
4005
|
/* encoding */
|
|
@@ -1986,21 +4009,31 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1986
4009
|
|
|
1987
4010
|
// progress and debug procs
|
|
1988
4011
|
if (!rb_easy_nil("progress_proc")) {
|
|
4012
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
4013
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &proc_xferinfo_handler);
|
|
4014
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, rbce);
|
|
4015
|
+
#else
|
|
1989
4016
|
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&proc_progress_handler);
|
|
1990
|
-
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
|
|
4017
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce);
|
|
4018
|
+
#endif
|
|
1991
4019
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
|
1992
4020
|
} else {
|
|
1993
4021
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
|
4022
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
4023
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, rbce);
|
|
4024
|
+
#else
|
|
4025
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce);
|
|
4026
|
+
#endif
|
|
1994
4027
|
}
|
|
1995
4028
|
|
|
1996
4029
|
if (!rb_easy_nil("debug_proc")) {
|
|
1997
4030
|
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, (curl_debug_callback)&proc_debug_handler);
|
|
1998
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA,
|
|
4031
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce);
|
|
1999
4032
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
|
2000
4033
|
} else {
|
|
2001
4034
|
// have to remove handler to re-enable standard verbosity
|
|
2002
4035
|
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
|
|
2003
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA,
|
|
4036
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce);
|
|
2004
4037
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
|
|
2005
4038
|
}
|
|
2006
4039
|
|
|
@@ -2008,9 +4041,17 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2008
4041
|
|
|
2009
4042
|
curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
|
|
2010
4043
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
|
|
4044
|
+
#if LIBCURL_VERSION_NUM == 0x081000
|
|
4045
|
+
/* Work around 8.16.0 regression that clamps -1 (infinite) to zero */
|
|
4046
|
+
if (rbce->max_redirs >= 0) {
|
|
4047
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
4048
|
+
}
|
|
4049
|
+
#else
|
|
2011
4050
|
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
4051
|
+
#endif
|
|
2012
4052
|
|
|
2013
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL,
|
|
4053
|
+
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL,
|
|
4054
|
+
public_policy_disables_proxy ? 0L : rbce->proxy_tunnel);
|
|
2014
4055
|
curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
|
|
2015
4056
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
|
|
2016
4057
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
|
|
@@ -2023,13 +4064,22 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2023
4064
|
|
|
2024
4065
|
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
|
|
2025
4066
|
|
|
2026
|
-
|
|
4067
|
+
#ifdef HAVE_CURLOPT_TIMEOUT_MS
|
|
4068
|
+
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
|
|
4069
|
+
#endif
|
|
4070
|
+
|
|
2027
4071
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
|
|
4072
|
+
#ifdef HAVE_CURLOPT_CONNECTTIMEOUT_MS
|
|
4073
|
+
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
|
|
4074
|
+
#endif
|
|
2028
4075
|
curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
|
|
2029
4076
|
|
|
2030
4077
|
curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
|
|
2031
4078
|
|
|
2032
4079
|
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, rbce->resolve_mode);
|
|
4080
|
+
#if HAVE_CURLOPT_HTTP_VERSION
|
|
4081
|
+
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, rbce->http_version);
|
|
4082
|
+
#endif
|
|
2033
4083
|
|
|
2034
4084
|
|
|
2035
4085
|
#if LIBCURL_VERSION_NUM >= 0x070a08
|
|
@@ -2043,6 +4093,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2043
4093
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
|
|
2044
4094
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
|
|
2045
4095
|
|
|
4096
|
+
curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, rbce->max_recv_speed_large);
|
|
4097
|
+
curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, rbce->max_send_speed_large);
|
|
4098
|
+
|
|
2046
4099
|
// Set up localport / proxy port
|
|
2047
4100
|
// FIXME these won't get returned to default if they're unset Ruby
|
|
2048
4101
|
if (rbce->proxy_port > 0) {
|
|
@@ -2075,29 +4128,27 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2075
4128
|
#endif
|
|
2076
4129
|
}
|
|
2077
4130
|
|
|
2078
|
-
|
|
4131
|
+
/*
|
|
4132
|
+
* NOTE: we used to set CURLAUTH_ANY but see: http://curl.haxx.se/mail/lib-2015-06/0033.html
|
|
4133
|
+
*/
|
|
4134
|
+
if (rbce->http_auth_types != 0) {
|
|
2079
4135
|
#if LIBCURL_VERSION_NUM >= 0x070a06
|
|
2080
4136
|
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
|
|
2081
|
-
} else {
|
|
2082
|
-
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
|
2083
4137
|
#else
|
|
2084
4138
|
rb_warn("Installed libcurl is too old to support http_auth_types");
|
|
2085
4139
|
#endif
|
|
2086
4140
|
}
|
|
2087
4141
|
|
|
2088
|
-
if (rbce->proxy_auth_types
|
|
4142
|
+
if (rbce->proxy_auth_types != 0) {
|
|
2089
4143
|
#if LIBCURL_VERSION_NUM >= 0x070a07
|
|
2090
4144
|
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
|
|
2091
|
-
} else {
|
|
2092
|
-
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
|
2093
4145
|
#else
|
|
2094
4146
|
rb_warn("Installed libcurl is too old to support proxy_auth_types");
|
|
2095
4147
|
#endif
|
|
2096
4148
|
}
|
|
2097
4149
|
|
|
2098
|
-
/* Set up HTTP cookie handling if necessary
|
|
2099
|
-
|
|
2100
|
-
*/
|
|
4150
|
+
/* Set up HTTP cookie handling if necessary */
|
|
4151
|
+
/* Enable/attach cookie engine if requested, or implicitly via COOKIELIST usage */
|
|
2101
4152
|
if (rbce->enable_cookies) {
|
|
2102
4153
|
if (!rb_easy_nil("cookiejar")) {
|
|
2103
4154
|
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, rb_easy_get_str("cookiejar"));
|
|
@@ -2108,6 +4159,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2108
4159
|
} else {
|
|
2109
4160
|
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
|
|
2110
4161
|
}
|
|
4162
|
+
} else if (rbce->cookielist_engine_enabled) {
|
|
4163
|
+
/* Ensure cookie engine is enabled even if enable_cookies? is false. */
|
|
4164
|
+
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
|
|
2111
4165
|
}
|
|
2112
4166
|
|
|
2113
4167
|
if (!rb_easy_nil("cookies")) {
|
|
@@ -2150,7 +4204,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2150
4204
|
rb_warn("libcurl is not configured with SSL support");
|
|
2151
4205
|
}
|
|
2152
4206
|
#endif
|
|
2153
|
-
|
|
4207
|
+
|
|
2154
4208
|
if (rbce->ftp_filemethod > 0) {
|
|
2155
4209
|
curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
|
|
2156
4210
|
}
|
|
@@ -2160,16 +4214,25 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2160
4214
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, rb_easy_get_str("useragent"));
|
|
2161
4215
|
}
|
|
2162
4216
|
|
|
4217
|
+
/* Setup can be rerun for safety-policy changes while a handle is attached.
|
|
4218
|
+
* Rebuild slist-backed options from Ruby opts instead of appending to stale
|
|
4219
|
+
* native lists. */
|
|
4220
|
+
ruby_curl_easy_clear_setup_lists(rbce);
|
|
4221
|
+
|
|
2163
4222
|
/* Setup HTTP headers if necessary */
|
|
2164
4223
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
|
2165
4224
|
|
|
2166
4225
|
if (!rb_easy_nil("headers")) {
|
|
2167
4226
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
|
|
2168
|
-
VALUE wrap =
|
|
2169
|
-
|
|
4227
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, hdrs);
|
|
4228
|
+
rb_block_call(rb_easy_get("headers"), rb_intern("each"), 0, NULL, cb_each_http_header, wrap);
|
|
2170
4229
|
} else {
|
|
2171
4230
|
VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
|
|
2172
|
-
*
|
|
4231
|
+
struct curl_slist *new_list = curl_slist_append(*hdrs, StringValuePtr(headers_str));
|
|
4232
|
+
if (!new_list) {
|
|
4233
|
+
rb_raise(rb_eNoMemError, "Failed to append to headers list");
|
|
4234
|
+
}
|
|
4235
|
+
*hdrs = new_list;
|
|
2173
4236
|
}
|
|
2174
4237
|
|
|
2175
4238
|
if (*hdrs) {
|
|
@@ -2177,11 +4240,34 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2177
4240
|
}
|
|
2178
4241
|
}
|
|
2179
4242
|
|
|
4243
|
+
#ifdef HAVE_CURLOPT_PROXYHEADER
|
|
4244
|
+
/* Setup HTTP proxy headers if necessary */
|
|
4245
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
|
4246
|
+
|
|
4247
|
+
if (!rb_easy_nil("proxy_headers")) {
|
|
4248
|
+
if (rb_easy_type_check("proxy_headers", T_ARRAY) || rb_easy_type_check("proxy_headers", T_HASH)) {
|
|
4249
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, phdrs);
|
|
4250
|
+
rb_block_call(rb_easy_get("proxy_headers"), rb_intern("each"), 0, NULL, cb_each_http_proxy_header, wrap);
|
|
4251
|
+
} else {
|
|
4252
|
+
VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
|
|
4253
|
+
struct curl_slist *new_list = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
|
|
4254
|
+
if (!new_list) {
|
|
4255
|
+
rb_raise(rb_eNoMemError, "Failed to append to proxy headers list");
|
|
4256
|
+
}
|
|
4257
|
+
*phdrs = new_list;
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
if (*phdrs) {
|
|
4261
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, *phdrs);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
#endif
|
|
4265
|
+
|
|
2180
4266
|
/* Setup FTP commands if necessary */
|
|
2181
4267
|
if (!rb_easy_nil("ftp_commands")) {
|
|
2182
4268
|
if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
|
|
2183
|
-
VALUE wrap =
|
|
2184
|
-
|
|
4269
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, cmds);
|
|
4270
|
+
rb_block_call(rb_easy_get("ftp_commands"), rb_intern("each"), 0, NULL, cb_each_ftp_command, wrap);
|
|
2185
4271
|
}
|
|
2186
4272
|
|
|
2187
4273
|
if (*cmds) {
|
|
@@ -2189,40 +4275,155 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2189
4275
|
}
|
|
2190
4276
|
}
|
|
2191
4277
|
|
|
4278
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
4279
|
+
/* Setup resolve list if necessary */
|
|
4280
|
+
if (!rb_easy_nil("resolve")) {
|
|
4281
|
+
if (rb_easy_type_check("resolve", T_ARRAY)) {
|
|
4282
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, rslv);
|
|
4283
|
+
rb_block_call(rb_easy_get("resolve"), rb_intern("each"), 0, NULL, cb_each_resolve, wrap);
|
|
4284
|
+
} else {
|
|
4285
|
+
VALUE resolve_str = rb_obj_as_string(rb_easy_get("resolve"));
|
|
4286
|
+
struct curl_slist *new_list = curl_slist_append(*rslv, StringValuePtr(resolve_str));
|
|
4287
|
+
if (!new_list) {
|
|
4288
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
4289
|
+
}
|
|
4290
|
+
*rslv = new_list;
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
if (*rslv) {
|
|
4294
|
+
curl_easy_setopt(curl, CURLOPT_RESOLVE, *rslv);
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
#endif
|
|
4298
|
+
|
|
4299
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
4300
|
+
/* Setup connect-to list if necessary */
|
|
4301
|
+
if (!rb_easy_nil("connect_to")) {
|
|
4302
|
+
if (rb_easy_type_check("connect_to", T_ARRAY)) {
|
|
4303
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, cnto);
|
|
4304
|
+
rb_block_call(rb_easy_get("connect_to"), rb_intern("each"), 0, NULL, cb_each_connect_to, wrap);
|
|
4305
|
+
} else {
|
|
4306
|
+
VALUE connect_to_str = rb_obj_as_string(rb_easy_get("connect_to"));
|
|
4307
|
+
struct curl_slist *new_list = curl_slist_append(*cnto, StringValuePtr(connect_to_str));
|
|
4308
|
+
if (!new_list) {
|
|
4309
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
4310
|
+
}
|
|
4311
|
+
*cnto = new_list;
|
|
4312
|
+
}
|
|
4313
|
+
|
|
4314
|
+
if (*cnto) {
|
|
4315
|
+
curl_easy_setopt(curl, CURLOPT_CONNECT_TO, *cnto);
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
#endif
|
|
4319
|
+
|
|
2192
4320
|
return Qnil;
|
|
2193
4321
|
}
|
|
4322
|
+
|
|
4323
|
+
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
4324
|
+
ruby_curl_easy_enter_native(rbce);
|
|
4325
|
+
return rb_ensure(ruby_curl_easy_setup_body, (VALUE)rbce,
|
|
4326
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
static VALUE ruby_curl_easy_setup_self(VALUE self) {
|
|
4330
|
+
ruby_curl_easy *rbce;
|
|
4331
|
+
|
|
4332
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4333
|
+
ruby_curl_easy_setup(rbce);
|
|
4334
|
+
|
|
4335
|
+
return self;
|
|
4336
|
+
}
|
|
2194
4337
|
/***********************************************
|
|
2195
4338
|
*
|
|
2196
4339
|
* Clean up a connection
|
|
2197
4340
|
*
|
|
2198
|
-
* Always returns
|
|
4341
|
+
* Always returns Qnil.
|
|
2199
4342
|
*/
|
|
2200
4343
|
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2201
4344
|
|
|
2202
4345
|
CURL *curl = rbce->curl;
|
|
2203
4346
|
struct curl_slist *ftp_commands;
|
|
4347
|
+
struct curl_slist *resolve;
|
|
4348
|
+
struct curl_slist *connect_to;
|
|
2204
4349
|
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
curl_slist_free_all(rbce->curl_headers);
|
|
2208
|
-
rbce->curl_headers = NULL;
|
|
2209
|
-
}
|
|
4350
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
4351
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
2210
4352
|
|
|
2211
4353
|
ftp_commands = rbce->curl_ftp_commands;
|
|
2212
4354
|
if (ftp_commands) {
|
|
2213
|
-
|
|
2214
|
-
rbce->curl_ftp_commands = NULL;
|
|
4355
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
2215
4356
|
}
|
|
2216
4357
|
|
|
4358
|
+
resolve = rbce->curl_resolve;
|
|
4359
|
+
if (resolve) {
|
|
4360
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
4361
|
+
}
|
|
4362
|
+
|
|
4363
|
+
connect_to = rbce->curl_connect_to;
|
|
4364
|
+
if (connect_to) {
|
|
4365
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
4366
|
+
}
|
|
4367
|
+
|
|
4368
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
4369
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
4370
|
+
|
|
2217
4371
|
/* clean up a PUT request's curl options. */
|
|
2218
4372
|
if (!rb_easy_nil("upload")) {
|
|
2219
4373
|
rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
|
|
2220
4374
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
|
2221
4375
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
|
2222
4376
|
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
|
4377
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
4378
|
+
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, NULL);
|
|
4379
|
+
#endif
|
|
4380
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
4381
|
+
curl_easy_setopt(curl, CURLOPT_SEEKDATA, NULL);
|
|
4382
|
+
#endif
|
|
2223
4383
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
|
2224
4384
|
}
|
|
2225
4385
|
|
|
4386
|
+
// set values on cleanup to nil
|
|
4387
|
+
//rb_easy_del("multi");
|
|
4388
|
+
|
|
4389
|
+
return Qnil;
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4392
|
+
struct easy_perform_request_restore_args {
|
|
4393
|
+
VALUE self;
|
|
4394
|
+
CURL *curl;
|
|
4395
|
+
ruby_curl_easy *rbce;
|
|
4396
|
+
int clear_customrequest;
|
|
4397
|
+
int clear_nobody;
|
|
4398
|
+
int clear_postfields;
|
|
4399
|
+
};
|
|
4400
|
+
|
|
4401
|
+
static VALUE perform_with_request_restore_body(VALUE argp) {
|
|
4402
|
+
struct easy_perform_request_restore_args *args = (struct easy_perform_request_restore_args *)argp;
|
|
4403
|
+
return rb_funcall(args->self, rb_intern("perform"), 0);
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
static VALUE perform_with_request_restore_ensure(VALUE argp) {
|
|
4407
|
+
struct easy_perform_request_restore_args *args = (struct easy_perform_request_restore_args *)argp;
|
|
4408
|
+
|
|
4409
|
+
if (args->curl) {
|
|
4410
|
+
if (args->clear_nobody) {
|
|
4411
|
+
curl_easy_setopt(args->curl, CURLOPT_NOBODY, 0L);
|
|
4412
|
+
}
|
|
4413
|
+
if (args->clear_customrequest) {
|
|
4414
|
+
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
4415
|
+
}
|
|
4416
|
+
if (args->clear_postfields) {
|
|
4417
|
+
curl_easy_setopt(args->curl, CURLOPT_POST, 0L);
|
|
4418
|
+
curl_easy_setopt(args->curl, CURLOPT_POSTFIELDS, NULL);
|
|
4419
|
+
curl_easy_setopt(args->curl, CURLOPT_POSTFIELDSIZE, 0L);
|
|
4420
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPGET, 1L);
|
|
4421
|
+
if (args->rbce && !NIL_P(args->rbce->opts)) {
|
|
4422
|
+
rb_hash_delete(args->rbce->opts, rb_easy_hkey("postdata_buffer"));
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
|
|
2226
4427
|
return Qnil;
|
|
2227
4428
|
}
|
|
2228
4429
|
|
|
@@ -2234,14 +4435,33 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
|
2234
4435
|
CURL *curl;
|
|
2235
4436
|
VALUE retval;
|
|
2236
4437
|
|
|
2237
|
-
|
|
4438
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2238
4439
|
curl = rbce->curl;
|
|
2239
4440
|
|
|
4441
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
4442
|
+
|
|
4443
|
+
/* Use method override and adjust related options for special verbs. */
|
|
2240
4444
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
|
2241
4445
|
|
|
2242
|
-
|
|
4446
|
+
/* For HEAD, ensure no body is requested/downloaded, as some servers
|
|
4447
|
+
* include a Content-Length header which should not cause libcurl to
|
|
4448
|
+
* wait for a body that will never arrive. */
|
|
4449
|
+
int is_head = (verb && (
|
|
4450
|
+
#ifdef _WIN32
|
|
4451
|
+
_stricmp(verb, "HEAD") == 0
|
|
4452
|
+
#else
|
|
4453
|
+
strcasecmp(verb, "HEAD") == 0
|
|
4454
|
+
#endif
|
|
4455
|
+
));
|
|
4456
|
+
if (is_head) {
|
|
4457
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
|
4458
|
+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
|
|
4459
|
+
curl_easy_setopt(curl, CURLOPT_POST, 0L);
|
|
4460
|
+
}
|
|
2243
4461
|
|
|
2244
|
-
|
|
4462
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, is_head, 0 };
|
|
4463
|
+
retval = rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
4464
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2245
4465
|
|
|
2246
4466
|
return retval;
|
|
2247
4467
|
}
|
|
@@ -2262,9 +4482,96 @@ static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
|
|
|
2262
4482
|
str_verb = rb_funcall(verb, rb_intern("to_s"), 0);
|
|
2263
4483
|
return ruby_curl_easy_perform_verb_str(self, StringValueCStr(str_verb));
|
|
2264
4484
|
}
|
|
2265
|
-
else {
|
|
2266
|
-
rb_raise(rb_eRuntimeError, "Invalid HTTP VERB, must response to 'to_s'");
|
|
4485
|
+
else {
|
|
4486
|
+
rb_raise(rb_eRuntimeError, "Invalid HTTP VERB, must response to 'to_s'");
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
static VALUE call_easy_perform(VALUE self) {
|
|
4491
|
+
return rb_funcall(self, rb_intern("perform"), 0);
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
struct easy_form_perform_args {
|
|
4495
|
+
VALUE self;
|
|
4496
|
+
CURL *curl;
|
|
4497
|
+
int argc;
|
|
4498
|
+
VALUE *argv;
|
|
4499
|
+
struct curl_httppost *first;
|
|
4500
|
+
struct curl_httppost *last;
|
|
4501
|
+
int clear_customrequest;
|
|
4502
|
+
int form_set_on_curl;
|
|
4503
|
+
};
|
|
4504
|
+
|
|
4505
|
+
struct easy_join_args {
|
|
4506
|
+
VALUE args_ary;
|
|
4507
|
+
};
|
|
4508
|
+
|
|
4509
|
+
static VALUE join_easy_arguments_body(VALUE argp) {
|
|
4510
|
+
struct easy_join_args *args = (struct easy_join_args *)argp;
|
|
4511
|
+
return rb_funcall(args->args_ary, idJoin, 1, rbstrAmp);
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
static VALUE join_easy_arguments(ruby_curl_easy *rbce, VALUE args_ary) {
|
|
4515
|
+
struct easy_join_args args = { args_ary };
|
|
4516
|
+
|
|
4517
|
+
ruby_curl_easy_enter_native(rbce);
|
|
4518
|
+
return rb_ensure(join_easy_arguments_body, (VALUE)&args,
|
|
4519
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
4520
|
+
}
|
|
4521
|
+
|
|
4522
|
+
static void append_multipart_form_argument(VALUE arg,
|
|
4523
|
+
struct curl_httppost **first,
|
|
4524
|
+
struct curl_httppost **last) {
|
|
4525
|
+
if (rb_obj_is_instance_of(arg, cCurlPostField)) {
|
|
4526
|
+
append_to_form(arg, first, last);
|
|
4527
|
+
} else if (rb_type(arg) == T_ARRAY) {
|
|
4528
|
+
long j, argv_len = RARRAY_LEN(arg);
|
|
4529
|
+
for (j = 0; j < argv_len; ++j) {
|
|
4530
|
+
VALUE field = rb_ary_entry(arg, j);
|
|
4531
|
+
if (rb_obj_is_instance_of(field, cCurlPostField)) {
|
|
4532
|
+
append_to_form(field, first, last);
|
|
4533
|
+
} else {
|
|
4534
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
4535
|
+
"You must use PostFields only with multipart form posts");
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
} else {
|
|
4539
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
4540
|
+
"You must use PostFields only with multipart form posts");
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
|
|
4544
|
+
static VALUE build_and_perform_multipart_form(VALUE argp) {
|
|
4545
|
+
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
4546
|
+
int i;
|
|
4547
|
+
|
|
4548
|
+
for (i = 0; i < args->argc; i++) {
|
|
4549
|
+
append_multipart_form_argument(args->argv[i], &args->first, &args->last);
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4552
|
+
curl_easy_setopt(args->curl, CURLOPT_POST, 0);
|
|
4553
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
|
|
4554
|
+
args->form_set_on_curl = 1;
|
|
4555
|
+
|
|
4556
|
+
return call_easy_perform(args->self);
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4559
|
+
static VALUE ensure_free_form_post(VALUE argp) {
|
|
4560
|
+
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
4561
|
+
if (args->curl) {
|
|
4562
|
+
if (args->form_set_on_curl) {
|
|
4563
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
|
|
4564
|
+
}
|
|
4565
|
+
if (args->clear_customrequest) {
|
|
4566
|
+
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
if (args->first) {
|
|
4570
|
+
curl_formfree(args->first);
|
|
4571
|
+
args->first = NULL;
|
|
2267
4572
|
}
|
|
4573
|
+
args->last = NULL;
|
|
4574
|
+
return Qnil;
|
|
2268
4575
|
}
|
|
2269
4576
|
|
|
2270
4577
|
/*
|
|
@@ -2294,51 +4601,27 @@ static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
|
|
|
2294
4601
|
static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2295
4602
|
ruby_curl_easy *rbce;
|
|
2296
4603
|
CURL *curl;
|
|
2297
|
-
int i;
|
|
2298
4604
|
VALUE args_ary;
|
|
2299
4605
|
|
|
2300
4606
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
2301
4607
|
|
|
2302
|
-
|
|
4608
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2303
4609
|
curl = rbce->curl;
|
|
2304
4610
|
|
|
4611
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
4612
|
+
|
|
2305
4613
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
2306
4614
|
|
|
2307
4615
|
if (rbce->multipart_form_post) {
|
|
2308
4616
|
VALUE ret;
|
|
2309
|
-
struct
|
|
2310
|
-
|
|
2311
|
-
// Make the multipart form
|
|
2312
|
-
for (i = 0; i < argc; i++) {
|
|
2313
|
-
if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
|
|
2314
|
-
append_to_form(argv[i], &first, &last);
|
|
2315
|
-
} else if (rb_type(argv[i]) == T_ARRAY) {
|
|
2316
|
-
// see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
|
|
2317
|
-
int c = 0, argv_len = (int)RARRAY_LEN(argv[i]);
|
|
2318
|
-
for (; c < argv_len; ++c) {
|
|
2319
|
-
if (rb_obj_is_instance_of(rb_ary_entry(argv[i],c), cCurlPostField)) {
|
|
2320
|
-
append_to_form(rb_ary_entry(argv[i],c), &first, &last);
|
|
2321
|
-
} else {
|
|
2322
|
-
rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
|
|
2323
|
-
return Qnil;
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
} else {
|
|
2327
|
-
rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
|
|
2328
|
-
return Qnil;
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
|
|
2332
|
-
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
2333
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
|
|
2334
|
-
ret = rb_funcall(self, rb_intern("perform"), 0);
|
|
2335
|
-
curl_formfree(first);
|
|
4617
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0 };
|
|
4618
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
2336
4619
|
|
|
2337
4620
|
return ret;
|
|
2338
4621
|
} else {
|
|
2339
4622
|
VALUE post_body = Qnil;
|
|
2340
4623
|
/* TODO: check for PostField.file and raise error before to_s fails */
|
|
2341
|
-
if ((post_body =
|
|
4624
|
+
if ((post_body = join_easy_arguments(rbce, args_ary)) == Qnil) {
|
|
2342
4625
|
rb_raise(eCurlErrError, "Failed to join arguments");
|
|
2343
4626
|
return Qnil;
|
|
2344
4627
|
} else {
|
|
@@ -2353,7 +4636,65 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
2353
4636
|
ruby_curl_easy_post_body_set(self, post_body);
|
|
2354
4637
|
}
|
|
2355
4638
|
|
|
2356
|
-
|
|
4639
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 0 };
|
|
4640
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
4641
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4646
|
+
/*
|
|
4647
|
+
* call-seq:
|
|
4648
|
+
* easy.http_patch("url=encoded%20form%20data;and=so%20on") => true
|
|
4649
|
+
* easy.http_patch("url=encoded%20form%20data", "and=so%20on", ...) => true
|
|
4650
|
+
* easy.http_patch("url=encoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
|
|
4651
|
+
* easy.http_patch(Curl::PostField, Curl::PostField ..., Curl::PostField) => true
|
|
4652
|
+
*
|
|
4653
|
+
* PATCH the specified formdata to the currently configured URL using
|
|
4654
|
+
* the current options set for this Curl::Easy instance. This method
|
|
4655
|
+
* always returns true, or raises an exception (defined under
|
|
4656
|
+
* Curl::Err) on error.
|
|
4657
|
+
*
|
|
4658
|
+
* When multipart_form_post is true the multipart logic is used; otherwise,
|
|
4659
|
+
* the arguments are joined into a raw PATCH body.
|
|
4660
|
+
*/
|
|
4661
|
+
static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
4662
|
+
ruby_curl_easy *rbce;
|
|
4663
|
+
CURL *curl;
|
|
4664
|
+
VALUE args_ary;
|
|
4665
|
+
|
|
4666
|
+
rb_scan_args(argc, argv, "*", &args_ary);
|
|
4667
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4668
|
+
curl = rbce->curl;
|
|
4669
|
+
|
|
4670
|
+
/* Clear the error buffer */
|
|
4671
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
4672
|
+
|
|
4673
|
+
/* Set the custom HTTP method to PATCH */
|
|
4674
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
|
|
4675
|
+
|
|
4676
|
+
if (rbce->multipart_form_post) {
|
|
4677
|
+
VALUE ret;
|
|
4678
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
4679
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
4680
|
+
return ret;
|
|
4681
|
+
} else {
|
|
4682
|
+
/* Join arguments into a raw PATCH body */
|
|
4683
|
+
VALUE patch_body = join_easy_arguments(rbce, args_ary);
|
|
4684
|
+
if (patch_body == Qnil) {
|
|
4685
|
+
rb_raise(eCurlErrError, "Failed to join arguments");
|
|
4686
|
+
return Qnil;
|
|
4687
|
+
} else {
|
|
4688
|
+
if (rb_type(patch_body) == T_STRING && RSTRING_LEN(patch_body) > 0) {
|
|
4689
|
+
ruby_curl_easy_post_body_set(self, patch_body);
|
|
4690
|
+
}
|
|
4691
|
+
/* If postdata_buffer is still nil, set it so that the PATCH header is enabled */
|
|
4692
|
+
if (rb_easy_nil("postdata_buffer")) {
|
|
4693
|
+
ruby_curl_easy_post_body_set(self, patch_body);
|
|
4694
|
+
}
|
|
4695
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 1 };
|
|
4696
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
4697
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2357
4698
|
}
|
|
2358
4699
|
}
|
|
2359
4700
|
}
|
|
@@ -2366,17 +4707,47 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
2366
4707
|
* current options set for this Curl::Easy instance. This method always
|
|
2367
4708
|
* returns true, or raises an exception (defined under Curl::Err) on error.
|
|
2368
4709
|
*/
|
|
2369
|
-
static VALUE ruby_curl_easy_perform_put(VALUE
|
|
4710
|
+
static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
2370
4711
|
ruby_curl_easy *rbce;
|
|
2371
4712
|
CURL *curl;
|
|
4713
|
+
VALUE args_ary;
|
|
2372
4714
|
|
|
2373
|
-
|
|
4715
|
+
rb_scan_args(argc, argv, "*", &args_ary);
|
|
4716
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2374
4717
|
curl = rbce->curl;
|
|
2375
4718
|
|
|
2376
|
-
|
|
2377
|
-
|
|
4719
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
4720
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
|
2378
4721
|
|
|
2379
|
-
|
|
4722
|
+
/* New: if no arguments were provided, treat as an empty PUT */
|
|
4723
|
+
if (RARRAY_LEN(args_ary) == 0) {
|
|
4724
|
+
/* Option 1: explicitly set an empty body */
|
|
4725
|
+
ruby_curl_easy_put_data_set(self, rb_str_new2(""));
|
|
4726
|
+
}
|
|
4727
|
+
/* If a single argument is given and it is a String or responds to read, use legacy behavior */
|
|
4728
|
+
else if (RARRAY_LEN(args_ary) == 1 &&
|
|
4729
|
+
(rb_type(rb_ary_entry(args_ary, 0)) == T_STRING ||
|
|
4730
|
+
rb_respond_to(rb_ary_entry(args_ary, 0), rb_intern("read")))) {
|
|
4731
|
+
ruby_curl_easy_put_data_set(self, rb_ary_entry(args_ary, 0));
|
|
4732
|
+
}
|
|
4733
|
+
/* Otherwise, if multipart_form_post is true, use multipart logic */
|
|
4734
|
+
else if (rbce->multipart_form_post) {
|
|
4735
|
+
VALUE ret;
|
|
4736
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
4737
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
4738
|
+
return ret;
|
|
4739
|
+
}
|
|
4740
|
+
/* Fallback: join all arguments */
|
|
4741
|
+
else {
|
|
4742
|
+
VALUE post_body = join_easy_arguments(rbce, args_ary);
|
|
4743
|
+
if (post_body != Qnil && rb_type(post_body) == T_STRING &&
|
|
4744
|
+
RSTRING_LEN(post_body) > 0) {
|
|
4745
|
+
ruby_curl_easy_put_data_set(self, post_body);
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 0 };
|
|
4749
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
4750
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2380
4751
|
}
|
|
2381
4752
|
|
|
2382
4753
|
|
|
@@ -2391,9 +4762,54 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
|
2391
4762
|
* your own body handler, this string will be empty.
|
|
2392
4763
|
*/
|
|
2393
4764
|
static VALUE ruby_curl_easy_body_str_get(VALUE self) {
|
|
4765
|
+
/*
|
|
4766
|
+
TODO: can we force_encoding on the return here if we see charset=utf-8 in the content-type header?
|
|
4767
|
+
Content-Type: application/json; charset=utf-8
|
|
4768
|
+
*/
|
|
2394
4769
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
|
2395
4770
|
}
|
|
2396
4771
|
|
|
4772
|
+
/*
|
|
4773
|
+
* call-seq:
|
|
4774
|
+
* easy.max_body_bytes = bytes_or_nil => bytes_or_nil
|
|
4775
|
+
*
|
|
4776
|
+
* Set an application-level cap for bytes accepted by the body write callback.
|
|
4777
|
+
* +nil+ or 0 clears the cap.
|
|
4778
|
+
*/
|
|
4779
|
+
static VALUE ruby_curl_easy_max_body_bytes_set(VALUE self, VALUE val) {
|
|
4780
|
+
ruby_curl_easy *rbce;
|
|
4781
|
+
long long limit;
|
|
4782
|
+
|
|
4783
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4784
|
+
|
|
4785
|
+
if (NIL_P(val)) {
|
|
4786
|
+
rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
|
|
4787
|
+
return Qnil;
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
limit = NUM2LL(val);
|
|
4791
|
+
if (limit < 0) {
|
|
4792
|
+
rb_raise(rb_eArgError, "max_body_bytes must be greater than or equal to zero");
|
|
4793
|
+
}
|
|
4794
|
+
|
|
4795
|
+
if (limit == 0) {
|
|
4796
|
+
rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
|
|
4797
|
+
} else {
|
|
4798
|
+
val = LL2NUM(limit);
|
|
4799
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("max_body_bytes"), val);
|
|
4800
|
+
}
|
|
4801
|
+
|
|
4802
|
+
return val;
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4805
|
+
/*
|
|
4806
|
+
* call-seq:
|
|
4807
|
+
* easy.max_body_bytes => bytes_or_nil
|
|
4808
|
+
*/
|
|
4809
|
+
static VALUE ruby_curl_easy_max_body_bytes_get(VALUE self) {
|
|
4810
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, max_body_bytes);
|
|
4811
|
+
}
|
|
4812
|
+
|
|
2397
4813
|
/*
|
|
2398
4814
|
* call-seq:
|
|
2399
4815
|
* easy.header_str => "response header"
|
|
@@ -2421,7 +4837,7 @@ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
|
|
|
2421
4837
|
ruby_curl_easy *rbce;
|
|
2422
4838
|
char* url;
|
|
2423
4839
|
|
|
2424
|
-
|
|
4840
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2425
4841
|
curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
|
|
2426
4842
|
|
|
2427
4843
|
if (url && url[0]) { // curl returns empty string if none
|
|
@@ -2444,7 +4860,7 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
|
2444
4860
|
ruby_curl_easy *rbce;
|
|
2445
4861
|
long code;
|
|
2446
4862
|
|
|
2447
|
-
|
|
4863
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2448
4864
|
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
|
2449
4865
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
|
|
2450
4866
|
#else
|
|
@@ -2467,8 +4883,8 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
|
2467
4883
|
static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
|
|
2468
4884
|
ruby_curl_easy *rbce;
|
|
2469
4885
|
char* ip;
|
|
2470
|
-
|
|
2471
|
-
|
|
4886
|
+
|
|
4887
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2472
4888
|
curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
|
|
2473
4889
|
|
|
2474
4890
|
if (ip && ip[0]) { // curl returns empty string if none
|
|
@@ -2489,7 +4905,7 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
|
|
|
2489
4905
|
ruby_curl_easy *rbce;
|
|
2490
4906
|
long code;
|
|
2491
4907
|
|
|
2492
|
-
|
|
4908
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2493
4909
|
curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
|
|
2494
4910
|
|
|
2495
4911
|
return LONG2NUM(code);
|
|
@@ -2517,13 +4933,13 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
|
|
|
2517
4933
|
ruby_curl_easy *rbce;
|
|
2518
4934
|
long time;
|
|
2519
4935
|
|
|
2520
|
-
|
|
4936
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2521
4937
|
curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
|
|
2522
4938
|
|
|
2523
4939
|
return LONG2NUM(time);
|
|
2524
4940
|
#else
|
|
2525
4941
|
rb_warn("Installed libcurl is too old to support file_time");
|
|
2526
|
-
return
|
|
4942
|
+
return LONG2NUM(0);
|
|
2527
4943
|
#endif
|
|
2528
4944
|
}
|
|
2529
4945
|
|
|
@@ -2538,7 +4954,7 @@ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
|
|
|
2538
4954
|
ruby_curl_easy *rbce;
|
|
2539
4955
|
double time;
|
|
2540
4956
|
|
|
2541
|
-
|
|
4957
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2542
4958
|
curl_easy_getinfo(rbce->curl, CURLINFO_TOTAL_TIME, &time);
|
|
2543
4959
|
|
|
2544
4960
|
return rb_float_new(time);
|
|
@@ -2555,7 +4971,7 @@ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
|
|
|
2555
4971
|
ruby_curl_easy *rbce;
|
|
2556
4972
|
double time;
|
|
2557
4973
|
|
|
2558
|
-
|
|
4974
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2559
4975
|
curl_easy_getinfo(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
|
|
2560
4976
|
|
|
2561
4977
|
return rb_float_new(time);
|
|
@@ -2572,7 +4988,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
|
2572
4988
|
ruby_curl_easy *rbce;
|
|
2573
4989
|
double time;
|
|
2574
4990
|
|
|
2575
|
-
|
|
4991
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2576
4992
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONNECT_TIME, &time);
|
|
2577
4993
|
|
|
2578
4994
|
return rb_float_new(time);
|
|
@@ -2585,7 +5001,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
|
2585
5001
|
* Retrieve the time, in seconds, it took from the start until the SSL/SSH
|
|
2586
5002
|
* connect/handshake to the remote host was completed. This time is most often
|
|
2587
5003
|
* very near to the pre transfer time, except for cases such as HTTP
|
|
2588
|
-
*
|
|
5004
|
+
* pipelining where the pretransfer time can be delayed due to waits in line
|
|
2589
5005
|
* for the pipeline and more.
|
|
2590
5006
|
*/
|
|
2591
5007
|
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
|
@@ -2593,7 +5009,7 @@ static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
|
|
|
2593
5009
|
ruby_curl_easy *rbce;
|
|
2594
5010
|
double time;
|
|
2595
5011
|
|
|
2596
|
-
|
|
5012
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2597
5013
|
curl_easy_getinfo(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
|
|
2598
5014
|
|
|
2599
5015
|
return rb_float_new(time);
|
|
@@ -2614,7 +5030,7 @@ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
|
|
|
2614
5030
|
ruby_curl_easy *rbce;
|
|
2615
5031
|
double time;
|
|
2616
5032
|
|
|
2617
|
-
|
|
5033
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2618
5034
|
curl_easy_getinfo(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
|
|
2619
5035
|
|
|
2620
5036
|
return rb_float_new(time);
|
|
@@ -2632,7 +5048,7 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
|
|
|
2632
5048
|
ruby_curl_easy *rbce;
|
|
2633
5049
|
double time;
|
|
2634
5050
|
|
|
2635
|
-
|
|
5051
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2636
5052
|
curl_easy_getinfo(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
|
|
2637
5053
|
|
|
2638
5054
|
return rb_float_new(time);
|
|
@@ -2654,7 +5070,7 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
|
|
2654
5070
|
ruby_curl_easy *rbce;
|
|
2655
5071
|
double time;
|
|
2656
5072
|
|
|
2657
|
-
|
|
5073
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2658
5074
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
|
|
2659
5075
|
|
|
2660
5076
|
return rb_float_new(time);
|
|
@@ -2677,13 +5093,13 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
|
2677
5093
|
ruby_curl_easy *rbce;
|
|
2678
5094
|
long count;
|
|
2679
5095
|
|
|
2680
|
-
|
|
5096
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2681
5097
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
|
|
2682
5098
|
|
|
2683
5099
|
return LONG2NUM(count);
|
|
2684
5100
|
#else
|
|
2685
5101
|
rb_warn("Installed libcurl is too old to support redirect_count");
|
|
2686
|
-
return
|
|
5102
|
+
return LONG2NUM(-1);
|
|
2687
5103
|
#endif
|
|
2688
5104
|
|
|
2689
5105
|
}
|
|
@@ -2692,7 +5108,7 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
|
2692
5108
|
* call-seq:
|
|
2693
5109
|
* easy.redirect_url => "http://some.url" or nil
|
|
2694
5110
|
*
|
|
2695
|
-
* Retrieve the URL a redirect would take you to if you
|
|
5111
|
+
* Retrieve the URL a redirect would take you to if you
|
|
2696
5112
|
* would enable CURLOPT_FOLLOWLOCATION.
|
|
2697
5113
|
*
|
|
2698
5114
|
* Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
|
|
@@ -2702,7 +5118,7 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2702
5118
|
ruby_curl_easy *rbce;
|
|
2703
5119
|
char* url;
|
|
2704
5120
|
|
|
2705
|
-
|
|
5121
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2706
5122
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
|
|
2707
5123
|
|
|
2708
5124
|
if (url && url[0]) { // curl returns empty string if none
|
|
@@ -2712,7 +5128,7 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2712
5128
|
}
|
|
2713
5129
|
#else
|
|
2714
5130
|
rb_warn("Installed libcurl is too old to support redirect_url");
|
|
2715
|
-
return
|
|
5131
|
+
return LONG2NUM(-1);
|
|
2716
5132
|
#endif
|
|
2717
5133
|
}
|
|
2718
5134
|
|
|
@@ -2727,12 +5143,17 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2727
5143
|
*/
|
|
2728
5144
|
static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
2729
5145
|
ruby_curl_easy *rbce;
|
|
2730
|
-
|
|
5146
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2731
5147
|
|
|
2732
|
-
|
|
5148
|
+
#ifdef HAVE_CURLINFO_SIZE_UPLOAD_T
|
|
5149
|
+
curl_off_t bytes;
|
|
5150
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD_T, &bytes);
|
|
5151
|
+
return LL2NUM(bytes);
|
|
5152
|
+
#else
|
|
5153
|
+
double bytes;
|
|
2733
5154
|
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
|
|
2734
|
-
|
|
2735
5155
|
return rb_float_new(bytes);
|
|
5156
|
+
#endif
|
|
2736
5157
|
}
|
|
2737
5158
|
|
|
2738
5159
|
/*
|
|
@@ -2744,12 +5165,17 @@ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
|
2744
5165
|
*/
|
|
2745
5166
|
static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
2746
5167
|
ruby_curl_easy *rbce;
|
|
2747
|
-
|
|
5168
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2748
5169
|
|
|
2749
|
-
|
|
5170
|
+
#ifdef HAVE_CURLINFO_SIZE_DOWNLOAD_T
|
|
5171
|
+
curl_off_t bytes;
|
|
5172
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD_T, &bytes);
|
|
5173
|
+
return LL2NUM(bytes);
|
|
5174
|
+
#else
|
|
5175
|
+
double bytes;
|
|
2750
5176
|
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
|
|
2751
|
-
|
|
2752
5177
|
return rb_float_new(bytes);
|
|
5178
|
+
#endif
|
|
2753
5179
|
}
|
|
2754
5180
|
|
|
2755
5181
|
/*
|
|
@@ -2761,12 +5187,17 @@ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
|
2761
5187
|
*/
|
|
2762
5188
|
static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
2763
5189
|
ruby_curl_easy *rbce;
|
|
2764
|
-
|
|
5190
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2765
5191
|
|
|
2766
|
-
|
|
5192
|
+
#ifdef HAVE_CURLINFO_SPEED_UPLOAD_T
|
|
5193
|
+
curl_off_t bytes;
|
|
5194
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD_T, &bytes);
|
|
5195
|
+
return LL2NUM(bytes);
|
|
5196
|
+
#else
|
|
5197
|
+
double bytes;
|
|
2767
5198
|
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
|
|
2768
|
-
|
|
2769
5199
|
return rb_float_new(bytes);
|
|
5200
|
+
#endif
|
|
2770
5201
|
}
|
|
2771
5202
|
|
|
2772
5203
|
/*
|
|
@@ -2778,12 +5209,17 @@ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
|
2778
5209
|
*/
|
|
2779
5210
|
static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
|
|
2780
5211
|
ruby_curl_easy *rbce;
|
|
2781
|
-
|
|
5212
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2782
5213
|
|
|
2783
|
-
|
|
5214
|
+
#ifdef HAVE_CURLINFO_SPEED_DOWNLOAD_T
|
|
5215
|
+
curl_off_t bytes;
|
|
5216
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD_T, &bytes);
|
|
5217
|
+
return LL2NUM(bytes);
|
|
5218
|
+
#else
|
|
5219
|
+
double bytes;
|
|
2784
5220
|
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
|
|
2785
|
-
|
|
2786
5221
|
return rb_float_new(bytes);
|
|
5222
|
+
#endif
|
|
2787
5223
|
}
|
|
2788
5224
|
|
|
2789
5225
|
/*
|
|
@@ -2797,7 +5233,7 @@ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
|
|
|
2797
5233
|
ruby_curl_easy *rbce;
|
|
2798
5234
|
long size;
|
|
2799
5235
|
|
|
2800
|
-
|
|
5236
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2801
5237
|
curl_easy_getinfo(rbce->curl, CURLINFO_HEADER_SIZE, &size);
|
|
2802
5238
|
|
|
2803
5239
|
return LONG2NUM(size);
|
|
@@ -2815,7 +5251,7 @@ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
|
|
|
2815
5251
|
ruby_curl_easy *rbce;
|
|
2816
5252
|
long size;
|
|
2817
5253
|
|
|
2818
|
-
|
|
5254
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2819
5255
|
curl_easy_getinfo(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
|
|
2820
5256
|
|
|
2821
5257
|
return LONG2NUM(size);
|
|
@@ -2832,7 +5268,7 @@ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
|
|
|
2832
5268
|
ruby_curl_easy *rbce;
|
|
2833
5269
|
long result;
|
|
2834
5270
|
|
|
2835
|
-
|
|
5271
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2836
5272
|
curl_easy_getinfo(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
|
|
2837
5273
|
|
|
2838
5274
|
return LONG2NUM(result);
|
|
@@ -2855,12 +5291,17 @@ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done
|
|
|
2855
5291
|
*/
|
|
2856
5292
|
static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
2857
5293
|
ruby_curl_easy *rbce;
|
|
2858
|
-
|
|
5294
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2859
5295
|
|
|
2860
|
-
|
|
5296
|
+
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
|
|
5297
|
+
curl_off_t bytes;
|
|
5298
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &bytes);
|
|
5299
|
+
return LL2NUM(bytes);
|
|
5300
|
+
#else
|
|
5301
|
+
double bytes;
|
|
2861
5302
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
|
|
2862
|
-
|
|
2863
5303
|
return rb_float_new(bytes);
|
|
5304
|
+
#endif
|
|
2864
5305
|
}
|
|
2865
5306
|
|
|
2866
5307
|
/*
|
|
@@ -2871,12 +5312,17 @@ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
|
2871
5312
|
*/
|
|
2872
5313
|
static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
|
|
2873
5314
|
ruby_curl_easy *rbce;
|
|
2874
|
-
|
|
5315
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2875
5316
|
|
|
2876
|
-
|
|
5317
|
+
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_UPLOAD_T
|
|
5318
|
+
curl_off_t bytes;
|
|
5319
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &bytes);
|
|
5320
|
+
return LL2NUM(bytes);
|
|
5321
|
+
#else
|
|
5322
|
+
double bytes;
|
|
2877
5323
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
|
|
2878
|
-
|
|
2879
5324
|
return rb_float_new(bytes);
|
|
5325
|
+
#endif
|
|
2880
5326
|
}
|
|
2881
5327
|
|
|
2882
5328
|
/*
|
|
@@ -2892,7 +5338,7 @@ static VALUE ruby_curl_easy_content_type_get(VALUE self) {
|
|
|
2892
5338
|
ruby_curl_easy *rbce;
|
|
2893
5339
|
char* type;
|
|
2894
5340
|
|
|
2895
|
-
|
|
5341
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2896
5342
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
|
|
2897
5343
|
|
|
2898
5344
|
if (type && type[0]) { // curl returns empty string if none
|
|
@@ -2935,13 +5381,13 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
|
|
2935
5381
|
ruby_curl_easy *rbce;
|
|
2936
5382
|
long result;
|
|
2937
5383
|
|
|
2938
|
-
|
|
5384
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2939
5385
|
curl_easy_getinfo(rbce->curl, CURLINFO_OS_ERRNO, &result);
|
|
2940
5386
|
|
|
2941
5387
|
return LONG2NUM(result);
|
|
2942
5388
|
#else
|
|
2943
5389
|
rb_warn("Installed libcurl is too old to support os_errno");
|
|
2944
|
-
return
|
|
5390
|
+
return LONG2NUM(0);
|
|
2945
5391
|
#endif
|
|
2946
5392
|
}
|
|
2947
5393
|
|
|
@@ -2964,23 +5410,59 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
|
|
2964
5410
|
ruby_curl_easy *rbce;
|
|
2965
5411
|
long result;
|
|
2966
5412
|
|
|
2967
|
-
|
|
5413
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2968
5414
|
curl_easy_getinfo(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
|
|
2969
5415
|
|
|
2970
5416
|
return LONG2NUM(result);
|
|
2971
5417
|
#else
|
|
2972
5418
|
rb_warn("Installed libcurl is too old to support num_connects");
|
|
2973
|
-
return
|
|
5419
|
+
return LONG2NUM(-1);
|
|
2974
5420
|
#endif
|
|
2975
5421
|
}
|
|
2976
5422
|
|
|
2977
5423
|
|
|
2978
|
-
/*
|
|
5424
|
+
/*
|
|
5425
|
+
* call-seq:
|
|
5426
|
+
* easy.cookielist => cookielist
|
|
5427
|
+
*
|
|
5428
|
+
* Retrieves the cookies curl knows in an array of strings.
|
|
5429
|
+
* Returned strings are in Netscape cookiejar format or in Set-Cookie format.
|
|
5430
|
+
* Since 7.43.0 cookies in the Set-Cookie format without a domain name are not exported.
|
|
5431
|
+
*
|
|
5432
|
+
* To modify the cookie engine (add/replace/remove), use +easy.cookielist= string+
|
|
5433
|
+
* or +easy.set(:cookielist, string)+ with one of the following accepted inputs:
|
|
5434
|
+
* - A Set-Cookie style header string: "Set-Cookie: name=value; Domain=example.com; Path=/; Expires=..."
|
|
5435
|
+
* - One or more lines in Netscape cookie file format (tab-separated fields)
|
|
5436
|
+
* - Special commands: "ALL" (clear all), "SESS" (remove session cookies), "FLUSH" (write to jar), "RELOAD" (reload from file)
|
|
5437
|
+
*
|
|
5438
|
+
* @see https://curl.se/libcurl/c/CURLINFO_COOKIELIST.html option <code>CURLINFO_COOKIELIST</code> of
|
|
5439
|
+
* <code>curl_easy_getopt(3)</code> to see how libcurl behaves.
|
|
5440
|
+
* @note requires libcurl 7.14.1 or higher, otherwise +-1+ is always returned
|
|
5441
|
+
* @return [Array<String>, nil, -1] array of strings, or +nil+ if there are no cookies, or +-1+ if the libcurl version is too old
|
|
5442
|
+
*/
|
|
5443
|
+
static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
|
|
5444
|
+
#ifdef HAVE_CURLINFO_COOKIELIST
|
|
5445
|
+
ruby_curl_easy *rbce;
|
|
5446
|
+
struct curl_slist *cookies;
|
|
5447
|
+
struct curl_slist *cookie;
|
|
5448
|
+
VALUE rb_cookies;
|
|
5449
|
+
|
|
5450
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
5451
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
|
|
5452
|
+
if (!cookies)
|
|
5453
|
+
return Qnil;
|
|
5454
|
+
rb_cookies = rb_ary_new();
|
|
5455
|
+
for (cookie = cookies; cookie; cookie = cookie->next)
|
|
5456
|
+
rb_ary_push(rb_cookies, rb_str_new2(cookie->data));
|
|
5457
|
+
curl_slist_free_all(cookies);
|
|
5458
|
+
return rb_cookies;
|
|
2979
5459
|
|
|
2980
|
-
|
|
5460
|
+
#else
|
|
5461
|
+
rb_warn("Installed libcurl is too old to support cookielist");
|
|
5462
|
+
return INT2FIX(-1);
|
|
5463
|
+
#endif
|
|
5464
|
+
}
|
|
2981
5465
|
|
|
2982
|
-
Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all cookies cURL knows (expired ones, too). Don't forget to curl_slist_free_all(3) the list after it has been used. If there are no cookies (cookies for the handle have not been enabled or simply none have been received) 'struct curl_slist *' will be set to point to NULL. (Added in 7.14.1)
|
|
2983
|
-
*/
|
|
2984
5466
|
|
|
2985
5467
|
/* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
|
|
2986
5468
|
* return an open Socket or something.
|
|
@@ -3005,7 +5487,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
3005
5487
|
ruby_curl_easy *rbce;
|
|
3006
5488
|
char* path = NULL;
|
|
3007
5489
|
|
|
3008
|
-
|
|
5490
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3009
5491
|
curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
|
|
3010
5492
|
|
|
3011
5493
|
if (path && path[0]) { // curl returns NULL or empty string if none
|
|
@@ -3014,7 +5496,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
3014
5496
|
return Qnil;
|
|
3015
5497
|
}
|
|
3016
5498
|
#else
|
|
3017
|
-
rb_warn("Installed libcurl is too old to support
|
|
5499
|
+
rb_warn("Installed libcurl is too old to support ftp_entry_path");
|
|
3018
5500
|
return Qnil;
|
|
3019
5501
|
#endif
|
|
3020
5502
|
}
|
|
@@ -3025,7 +5507,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
3025
5507
|
*/
|
|
3026
5508
|
static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
3027
5509
|
ruby_curl_easy *rbce;
|
|
3028
|
-
|
|
5510
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3029
5511
|
return rbce->multi;
|
|
3030
5512
|
}
|
|
3031
5513
|
|
|
@@ -3035,7 +5517,28 @@ static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
|
3035
5517
|
*/
|
|
3036
5518
|
static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
3037
5519
|
ruby_curl_easy *rbce;
|
|
3038
|
-
|
|
5520
|
+
VALUE old_multi;
|
|
5521
|
+
ruby_curl_multi *old_rbcm;
|
|
5522
|
+
CURLMcode result;
|
|
5523
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
5524
|
+
|
|
5525
|
+
if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
|
|
5526
|
+
rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
|
|
5527
|
+
}
|
|
5528
|
+
|
|
5529
|
+
old_multi = rbce->multi;
|
|
5530
|
+
if (old_multi == multi) {
|
|
5531
|
+
return rbce->multi;
|
|
5532
|
+
}
|
|
5533
|
+
|
|
5534
|
+
old_rbcm = ruby_curl_multi_pointer_if_compatible(old_multi);
|
|
5535
|
+
if (old_rbcm) {
|
|
5536
|
+
result = rb_curl_multi_detach_easy(old_rbcm, rbce);
|
|
5537
|
+
if (result != CURLM_OK) {
|
|
5538
|
+
raise_curl_multi_error_exception(result);
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
|
|
3039
5542
|
rbce->multi = multi;
|
|
3040
5543
|
return rbce->multi;
|
|
3041
5544
|
}
|
|
@@ -3046,21 +5549,44 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
|
3046
5549
|
*/
|
|
3047
5550
|
static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3048
5551
|
ruby_curl_easy *rbce;
|
|
3049
|
-
|
|
3050
|
-
return
|
|
5552
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
5553
|
+
return LONG2NUM(rbce->last_result);
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
/*
|
|
5557
|
+
* call-seq:
|
|
5558
|
+
* easy.last_error => "Error details" or nil
|
|
5559
|
+
*/
|
|
5560
|
+
static VALUE ruby_curl_easy_last_error(VALUE self) {
|
|
5561
|
+
ruby_curl_easy *rbce;
|
|
5562
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
5563
|
+
|
|
5564
|
+
if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
|
|
5565
|
+
return rb_str_new2(rbce->err_buf);
|
|
5566
|
+
} else {
|
|
5567
|
+
return Qnil;
|
|
5568
|
+
}
|
|
3051
5569
|
}
|
|
3052
5570
|
|
|
3053
5571
|
/*
|
|
3054
5572
|
* call-seq:
|
|
3055
|
-
* easy.setopt
|
|
5573
|
+
* easy.setopt(opt, val) => val
|
|
5574
|
+
*
|
|
5575
|
+
* Initial access to libcurl curl_easy_setopt
|
|
3056
5576
|
*
|
|
3057
|
-
*
|
|
5577
|
+
* @param [Fixnum] opt The option to set, see +Curl::CURLOPT_*+ constants
|
|
5578
|
+
* @param [Object] val
|
|
5579
|
+
* @return [Object] val
|
|
5580
|
+
* @raise [TypeError] if the option is not supported
|
|
5581
|
+
* @note Some options - like url or cookie - aren't set directly throught +curl_easy_setopt+, but stored in the Ruby object state.
|
|
5582
|
+
* @note When +curl_easy_setopt+ is called, return value is not checked here.
|
|
3058
5583
|
*/
|
|
3059
5584
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3060
5585
|
ruby_curl_easy *rbce;
|
|
3061
|
-
long option =
|
|
5586
|
+
long option = NUM2LONG(opt);
|
|
5587
|
+
rb_io_t *open_f_ptr;
|
|
3062
5588
|
|
|
3063
|
-
|
|
5589
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3064
5590
|
|
|
3065
5591
|
switch (option) {
|
|
3066
5592
|
/* BEHAVIOR OPTIONS */
|
|
@@ -3082,9 +5608,11 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3082
5608
|
case CURLOPT_CUSTOMREQUEST:
|
|
3083
5609
|
curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
3084
5610
|
break;
|
|
3085
|
-
case CURLOPT_HTTP_VERSION:
|
|
3086
|
-
|
|
3087
|
-
|
|
5611
|
+
case CURLOPT_HTTP_VERSION: {
|
|
5612
|
+
long http_version = NIL_P(val) ? CURL_HTTP_VERSION_NONE : NUM2LONG(val);
|
|
5613
|
+
rbce->http_version = http_version;
|
|
5614
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, http_version);
|
|
5615
|
+
} break;
|
|
3088
5616
|
case CURLOPT_PROXY: {
|
|
3089
5617
|
VALUE proxy_url = val;
|
|
3090
5618
|
CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
|
|
@@ -3096,6 +5624,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3096
5624
|
case CURLOPT_HEADER:
|
|
3097
5625
|
case CURLOPT_NOPROGRESS:
|
|
3098
5626
|
case CURLOPT_NOSIGNAL:
|
|
5627
|
+
#ifdef HAVE_CURLOPT_PATH_AS_IS
|
|
5628
|
+
case CURLOPT_PATH_AS_IS:
|
|
5629
|
+
#endif
|
|
5630
|
+
#ifdef HAVE_CURLOPT_PIPEWAIT
|
|
5631
|
+
case CURLOPT_PIPEWAIT:
|
|
5632
|
+
#endif
|
|
3099
5633
|
case CURLOPT_HTTPGET:
|
|
3100
5634
|
case CURLOPT_NOBODY: {
|
|
3101
5635
|
int type = rb_type(val);
|
|
@@ -3107,8 +5641,17 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3107
5641
|
} else {
|
|
3108
5642
|
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
3109
5643
|
}
|
|
3110
|
-
curl_easy_setopt(rbce->curl, option,
|
|
5644
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(value));
|
|
3111
5645
|
} break;
|
|
5646
|
+
case CURLOPT_POST: {
|
|
5647
|
+
curl_easy_setopt(rbce->curl, CURLOPT_POST, rb_type(val) == T_TRUE);
|
|
5648
|
+
} break;
|
|
5649
|
+
case CURLOPT_MAXCONNECTS: {
|
|
5650
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXCONNECTS, NUM2LONG(val));
|
|
5651
|
+
} break;
|
|
5652
|
+
case CURLOPT_POSTFIELDS: {
|
|
5653
|
+
ruby_curl_easy_post_body_set_with_mode(self, val, 0);
|
|
5654
|
+
} break;
|
|
3112
5655
|
case CURLOPT_USERPWD: {
|
|
3113
5656
|
VALUE userpwd = val;
|
|
3114
5657
|
CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
|
|
@@ -3117,6 +5660,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3117
5660
|
VALUE proxypwd = val;
|
|
3118
5661
|
CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
|
|
3119
5662
|
} break;
|
|
5663
|
+
#ifdef HAVE_CURLOPT_NOPROXY
|
|
5664
|
+
case CURLOPT_NOPROXY: {
|
|
5665
|
+
VALUE noproxy = val;
|
|
5666
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, noproxy);
|
|
5667
|
+
} break;
|
|
5668
|
+
#endif
|
|
3120
5669
|
case CURLOPT_COOKIE: {
|
|
3121
5670
|
VALUE cookies = val;
|
|
3122
5671
|
CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
|
|
@@ -3129,19 +5678,278 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3129
5678
|
VALUE cookiejar = val;
|
|
3130
5679
|
CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
|
|
3131
5680
|
} break;
|
|
5681
|
+
#ifdef HAVE_CURLOPT_REQUEST_TARGET
|
|
5682
|
+
case CURLOPT_REQUEST_TARGET: {
|
|
5683
|
+
/* Forward request-target directly to libcurl as a string. */
|
|
5684
|
+
curl_easy_setopt(rbce->curl, CURLOPT_REQUEST_TARGET, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5685
|
+
} break;
|
|
5686
|
+
#endif
|
|
5687
|
+
#ifdef HAVE_CURLOPT_DOH_URL
|
|
5688
|
+
case CURLOPT_DOH_URL: {
|
|
5689
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("doh_url"), val);
|
|
5690
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_URL, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5691
|
+
} break;
|
|
5692
|
+
#endif
|
|
5693
|
+
case CURLOPT_TCP_NODELAY: {
|
|
5694
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
|
5695
|
+
} break;
|
|
5696
|
+
/* FTP-specific toggles */
|
|
5697
|
+
#ifdef HAVE_CURLOPT_DIRLISTONLY
|
|
5698
|
+
case CURLOPT_DIRLISTONLY: {
|
|
5699
|
+
int type = rb_type(val);
|
|
5700
|
+
VALUE value;
|
|
5701
|
+
if (type == T_TRUE) {
|
|
5702
|
+
value = rb_int_new(1);
|
|
5703
|
+
} else if (type == T_FALSE) {
|
|
5704
|
+
value = rb_int_new(0);
|
|
5705
|
+
} else {
|
|
5706
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
5707
|
+
}
|
|
5708
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DIRLISTONLY, NUM2LONG(value));
|
|
5709
|
+
} break;
|
|
5710
|
+
#endif
|
|
5711
|
+
#ifdef HAVE_CURLOPT_FTP_USE_EPSV
|
|
5712
|
+
case CURLOPT_FTP_USE_EPSV: {
|
|
5713
|
+
int type = rb_type(val);
|
|
5714
|
+
VALUE value;
|
|
5715
|
+
if (type == T_TRUE) {
|
|
5716
|
+
value = rb_int_new(1);
|
|
5717
|
+
} else if (type == T_FALSE) {
|
|
5718
|
+
value = rb_int_new(0);
|
|
5719
|
+
} else {
|
|
5720
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
5721
|
+
}
|
|
5722
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPSV, NUM2LONG(value));
|
|
5723
|
+
} break;
|
|
5724
|
+
#endif
|
|
5725
|
+
#ifdef HAVE_CURLOPT_FTP_USE_EPRT
|
|
5726
|
+
case CURLOPT_FTP_USE_EPRT: {
|
|
5727
|
+
int type = rb_type(val);
|
|
5728
|
+
VALUE value;
|
|
5729
|
+
if (type == T_TRUE) {
|
|
5730
|
+
value = rb_int_new(1);
|
|
5731
|
+
} else if (type == T_FALSE) {
|
|
5732
|
+
value = rb_int_new(0);
|
|
5733
|
+
} else {
|
|
5734
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
5735
|
+
}
|
|
5736
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPRT, NUM2LONG(value));
|
|
5737
|
+
} break;
|
|
5738
|
+
#endif
|
|
5739
|
+
#ifdef HAVE_CURLOPT_FTP_SKIP_PASV_IP
|
|
5740
|
+
case CURLOPT_FTP_SKIP_PASV_IP: {
|
|
5741
|
+
int type = rb_type(val);
|
|
5742
|
+
VALUE value;
|
|
5743
|
+
if (type == T_TRUE) {
|
|
5744
|
+
value = rb_int_new(1);
|
|
5745
|
+
} else if (type == T_FALSE) {
|
|
5746
|
+
value = rb_int_new(0);
|
|
5747
|
+
} else {
|
|
5748
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
5749
|
+
}
|
|
5750
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_SKIP_PASV_IP, NUM2LONG(value));
|
|
5751
|
+
} break;
|
|
5752
|
+
#endif
|
|
5753
|
+
case CURLOPT_RANGE: {
|
|
5754
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
|
5755
|
+
} break;
|
|
3132
5756
|
case CURLOPT_RESUME_FROM: {
|
|
3133
|
-
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM,
|
|
5757
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
|
|
3134
5758
|
} break;
|
|
3135
5759
|
case CURLOPT_FAILONERROR: {
|
|
3136
|
-
curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR,
|
|
5760
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, NUM2LONG(val));
|
|
3137
5761
|
} break;
|
|
3138
|
-
|
|
5762
|
+
case CURLOPT_SSL_CIPHER_LIST: {
|
|
5763
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_CIPHER_LIST, StringValueCStr(val));
|
|
5764
|
+
} break;
|
|
5765
|
+
case CURLOPT_FORBID_REUSE: {
|
|
5766
|
+
rbce->forbid_reuse = NUM2LONG(val);
|
|
5767
|
+
rbce->forbid_reuse_set = 1;
|
|
5768
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FORBID_REUSE, rbce->forbid_reuse);
|
|
5769
|
+
} break;
|
|
5770
|
+
#ifdef HAVE_CURLOPT_GSSAPI_DELEGATION
|
|
3139
5771
|
case CURLOPT_GSSAPI_DELEGATION: {
|
|
3140
|
-
curl_easy_setopt(rbce->curl, CURLOPT_GSSAPI_DELEGATION,
|
|
5772
|
+
curl_easy_setopt(rbce->curl, CURLOPT_GSSAPI_DELEGATION, NUM2LONG(val));
|
|
3141
5773
|
} break;
|
|
3142
5774
|
#endif
|
|
3143
|
-
|
|
5775
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
5776
|
+
case CURLOPT_UNIX_SOCKET_PATH: {
|
|
5777
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("unix_socket_path"), val);
|
|
5778
|
+
curl_easy_setopt(rbce->curl, CURLOPT_UNIX_SOCKET_PATH, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5779
|
+
} break;
|
|
5780
|
+
#endif
|
|
5781
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
5782
|
+
case CURLOPT_DNS_SERVERS: {
|
|
5783
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("dns_servers"), val);
|
|
5784
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DNS_SERVERS, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5785
|
+
} break;
|
|
5786
|
+
#endif
|
|
5787
|
+
#ifdef HAVE_CURLOPT_MAX_SEND_SPEED_LARGE
|
|
5788
|
+
case CURLOPT_MAX_SEND_SPEED_LARGE: {
|
|
5789
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) NUM2LL(val));
|
|
5790
|
+
} break;
|
|
5791
|
+
#endif
|
|
5792
|
+
#ifdef HAVE_CURLOPT_MAX_RECV_SPEED_LARGE
|
|
5793
|
+
case CURLOPT_MAX_RECV_SPEED_LARGE: {
|
|
5794
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
|
|
5795
|
+
} break;
|
|
5796
|
+
#endif
|
|
5797
|
+
#ifdef HAVE_CURLOPT_MAXFILESIZE
|
|
5798
|
+
case CURLOPT_MAXFILESIZE:
|
|
5799
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
|
|
5800
|
+
break;
|
|
5801
|
+
#endif
|
|
5802
|
+
#ifdef HAVE_CURLOPT_MAXFILESIZE_LARGE
|
|
5803
|
+
case CURLOPT_MAXFILESIZE_LARGE:
|
|
5804
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE_LARGE, (curl_off_t)NUM2LL(val));
|
|
5805
|
+
break;
|
|
5806
|
+
#endif
|
|
5807
|
+
#ifdef HAVE_CURLOPT_TCP_KEEPALIVE
|
|
5808
|
+
case CURLOPT_TCP_KEEPALIVE:
|
|
5809
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
|
|
5810
|
+
break;
|
|
5811
|
+
case CURLOPT_TCP_KEEPIDLE:
|
|
5812
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
|
|
5813
|
+
break;
|
|
5814
|
+
case CURLOPT_TCP_KEEPINTVL:
|
|
5815
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
|
|
5816
|
+
break;
|
|
5817
|
+
#endif
|
|
5818
|
+
#ifdef HAVE_CURLOPT_HAPROXYPROTOCOL
|
|
5819
|
+
case CURLOPT_HAPROXYPROTOCOL:
|
|
5820
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
|
|
5821
|
+
break;
|
|
5822
|
+
#endif
|
|
5823
|
+
case CURLOPT_STDERR:
|
|
5824
|
+
// libcurl requires raw FILE pointer and this should be IO object in Ruby.
|
|
5825
|
+
// Tempfile or StringIO won't work.
|
|
5826
|
+
Check_Type(val, T_FILE);
|
|
5827
|
+
GetOpenFile(val, open_f_ptr);
|
|
5828
|
+
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
|
|
5829
|
+
/* Retain a Ruby reference to the IO to prevent GC/finalization
|
|
5830
|
+
* while libcurl still holds and writes to the underlying FILE*. */
|
|
5831
|
+
rb_easy_set("stderr_io", val);
|
|
5832
|
+
break;
|
|
5833
|
+
case CURLOPT_PROTOCOLS:
|
|
5834
|
+
case CURLOPT_REDIR_PROTOCOLS:
|
|
5835
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
|
5836
|
+
break;
|
|
5837
|
+
#ifdef HAVE_CURLOPT_PROTOCOLS_STR
|
|
5838
|
+
case CURLOPT_PROTOCOLS_STR:
|
|
5839
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROTOCOLS_STR, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5840
|
+
break;
|
|
5841
|
+
#endif
|
|
5842
|
+
#ifdef HAVE_CURLOPT_REDIR_PROTOCOLS_STR
|
|
5843
|
+
case CURLOPT_REDIR_PROTOCOLS_STR:
|
|
5844
|
+
curl_easy_setopt(rbce->curl, CURLOPT_REDIR_PROTOCOLS_STR, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5845
|
+
break;
|
|
5846
|
+
#endif
|
|
5847
|
+
#ifdef HAVE_CURLOPT_SSL_SESSIONID_CACHE
|
|
5848
|
+
case CURLOPT_SSL_SESSIONID_CACHE:
|
|
5849
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
|
5850
|
+
break;
|
|
5851
|
+
#endif
|
|
5852
|
+
#ifdef HAVE_CURLOPT_COOKIELIST
|
|
5853
|
+
case CURLOPT_COOKIELIST: {
|
|
5854
|
+
/* Forward to libcurl */
|
|
5855
|
+
curl_easy_setopt(rbce->curl, CURLOPT_COOKIELIST, StringValueCStr(val));
|
|
5856
|
+
/* Track whether the cookie engine should be enabled for requests.
|
|
5857
|
+
* According to libcurl docs, CURLOPT_COOKIELIST also enables the cookie engine
|
|
5858
|
+
* when provided with a non-command string. Some environments may still require
|
|
5859
|
+
* an explicit "enable" via CURLOPT_COOKIEFILE="" to send cookies on requests.
|
|
5860
|
+
* We do that in the perform setup when this flag is set.
|
|
5861
|
+
*/
|
|
5862
|
+
if (RB_TYPE_P(val, T_STRING)) {
|
|
5863
|
+
const char *s = StringValueCStr(val);
|
|
5864
|
+
if (!(strcmp(s, "ALL") == 0 || strcmp(s, "SESS") == 0 || strcmp(s, "FLUSH") == 0 || strcmp(s, "RELOAD") == 0)) {
|
|
5865
|
+
rbce->cookielist_engine_enabled = 1;
|
|
5866
|
+
}
|
|
5867
|
+
} else {
|
|
5868
|
+
/* Non-string values are unexpected; be conservative and do not enable. */
|
|
5869
|
+
}
|
|
5870
|
+
} break;
|
|
5871
|
+
#endif
|
|
5872
|
+
#ifdef HAVE_CURLOPT_PROXY_SSL_VERIFYHOST
|
|
5873
|
+
case CURLOPT_PROXY_SSL_VERIFYHOST:
|
|
5874
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROXY_SSL_VERIFYHOST, NUM2LONG(val));
|
|
5875
|
+
break;
|
|
5876
|
+
#endif
|
|
5877
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYPEER
|
|
5878
|
+
case CURLOPT_DOH_SSL_VERIFYPEER:
|
|
5879
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYPEER, NUM2LONG(val));
|
|
3144
5880
|
break;
|
|
5881
|
+
#endif
|
|
5882
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYHOST
|
|
5883
|
+
case CURLOPT_DOH_SSL_VERIFYHOST:
|
|
5884
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYHOST, NUM2LONG(val));
|
|
5885
|
+
break;
|
|
5886
|
+
#endif
|
|
5887
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYSTATUS
|
|
5888
|
+
case CURLOPT_DOH_SSL_VERIFYSTATUS:
|
|
5889
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYSTATUS, NUM2LONG(val));
|
|
5890
|
+
break;
|
|
5891
|
+
#endif
|
|
5892
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
5893
|
+
case CURLOPT_RESOLVE: {
|
|
5894
|
+
struct curl_slist *list = NULL;
|
|
5895
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
5896
|
+
if (NIL_P(val)) {
|
|
5897
|
+
/* When nil is passed, we clear any previous resolve list */
|
|
5898
|
+
list = NULL;
|
|
5899
|
+
} else if (TYPE(val) == T_ARRAY) {
|
|
5900
|
+
long i, len = RARRAY_LEN(val);
|
|
5901
|
+
for (i = 0; i < len; i++) {
|
|
5902
|
+
VALUE item = rb_ary_entry(val, i);
|
|
5903
|
+
struct curl_slist *new_list = curl_slist_append(list, StringValueCStr(item));
|
|
5904
|
+
if (!new_list) {
|
|
5905
|
+
curl_slist_free_all(list);
|
|
5906
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
5907
|
+
}
|
|
5908
|
+
list = new_list;
|
|
5909
|
+
}
|
|
5910
|
+
} else {
|
|
5911
|
+
/* If a single string is passed, use it directly */
|
|
5912
|
+
list = curl_slist_append(NULL, StringValueCStr(val));
|
|
5913
|
+
if (!list) {
|
|
5914
|
+
rb_raise(rb_eNoMemError, "Failed to create resolve list");
|
|
5915
|
+
}
|
|
5916
|
+
}
|
|
5917
|
+
/* Save the list pointer in the ruby_curl_easy structure for cleanup later */
|
|
5918
|
+
rbce->curl_resolve = list;
|
|
5919
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("resolve"), val);
|
|
5920
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, list);
|
|
5921
|
+
} break;
|
|
5922
|
+
#endif
|
|
5923
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
5924
|
+
case CURLOPT_CONNECT_TO: {
|
|
5925
|
+
struct curl_slist *list = NULL;
|
|
5926
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
5927
|
+
if (NIL_P(val)) {
|
|
5928
|
+
list = NULL;
|
|
5929
|
+
} else if (TYPE(val) == T_ARRAY) {
|
|
5930
|
+
long i, len = RARRAY_LEN(val);
|
|
5931
|
+
for (i = 0; i < len; i++) {
|
|
5932
|
+
VALUE item = rb_ary_entry(val, i);
|
|
5933
|
+
struct curl_slist *new_list = curl_slist_append(list, StringValueCStr(item));
|
|
5934
|
+
if (!new_list) {
|
|
5935
|
+
curl_slist_free_all(list);
|
|
5936
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
5937
|
+
}
|
|
5938
|
+
list = new_list;
|
|
5939
|
+
}
|
|
5940
|
+
} else {
|
|
5941
|
+
list = curl_slist_append(NULL, StringValueCStr(val));
|
|
5942
|
+
if (!list) {
|
|
5943
|
+
rb_raise(rb_eNoMemError, "Failed to create connect-to list");
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
rbce->curl_connect_to = list;
|
|
5947
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("connect_to"), val);
|
|
5948
|
+
curl_easy_setopt(rbce->curl, CURLOPT_CONNECT_TO, list);
|
|
5949
|
+
} break;
|
|
5950
|
+
#endif
|
|
5951
|
+
default:
|
|
5952
|
+
rb_raise(rb_eTypeError, "Curb unsupported option");
|
|
3145
5953
|
}
|
|
3146
5954
|
|
|
3147
5955
|
return val;
|
|
@@ -3149,9 +5957,13 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3149
5957
|
|
|
3150
5958
|
/*
|
|
3151
5959
|
* call-seq:
|
|
3152
|
-
* easy.getinfo
|
|
5960
|
+
* easy.getinfo(opt) => nil
|
|
3153
5961
|
*
|
|
3154
5962
|
* Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
|
|
5963
|
+
*
|
|
5964
|
+
* @note This method is not implemented yet.
|
|
5965
|
+
* @param [Fixnum] code Constant +CURLINFO_*+ from libcurl
|
|
5966
|
+
* @return [nil]
|
|
3155
5967
|
*/
|
|
3156
5968
|
static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
|
|
3157
5969
|
return Qnil;
|
|
@@ -3164,7 +5976,7 @@ static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
|
|
|
3164
5976
|
static VALUE ruby_curl_easy_inspect(VALUE self) {
|
|
3165
5977
|
char buf[64];
|
|
3166
5978
|
ruby_curl_easy *rbce;
|
|
3167
|
-
|
|
5979
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3168
5980
|
/* if we don't have a url set... we'll crash... */
|
|
3169
5981
|
if( !rb_easy_nil("url") && rb_easy_type_check("url", T_STRING)) {
|
|
3170
5982
|
VALUE url = rb_easy_get("url");
|
|
@@ -3196,7 +6008,7 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
|
|
|
3196
6008
|
VALUE rresult;
|
|
3197
6009
|
VALUE str = svalue;
|
|
3198
6010
|
|
|
3199
|
-
|
|
6011
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3200
6012
|
|
|
3201
6013
|
/* NOTE: make sure the value is a string, if not call to_s */
|
|
3202
6014
|
if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
|
|
@@ -3227,12 +6039,12 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
3227
6039
|
char *result;
|
|
3228
6040
|
VALUE rresult;
|
|
3229
6041
|
|
|
3230
|
-
|
|
6042
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3231
6043
|
|
|
3232
6044
|
#if (LIBCURL_VERSION_NUM >= 0x070f04)
|
|
3233
6045
|
result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
|
|
3234
6046
|
#else
|
|
3235
|
-
result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
|
|
6047
|
+
result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
|
|
3236
6048
|
rlen = strlen(result);
|
|
3237
6049
|
#endif
|
|
3238
6050
|
|
|
@@ -3247,18 +6059,21 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
3247
6059
|
|
|
3248
6060
|
/*
|
|
3249
6061
|
* call-seq:
|
|
3250
|
-
* Curl::Easy.error(code) => String
|
|
6062
|
+
* Curl::Easy.error(code) => [ErrCode, String]
|
|
3251
6063
|
*
|
|
3252
6064
|
* translate an internal libcurl error to ruby error class
|
|
3253
6065
|
*/
|
|
3254
6066
|
static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
|
|
3255
|
-
return rb_curl_easy_error(
|
|
6067
|
+
return rb_curl_easy_error(NUM2INT(code));
|
|
3256
6068
|
}
|
|
3257
6069
|
|
|
3258
6070
|
/* =================== INIT LIB =====================*/
|
|
6071
|
+
// TODO: https://bugs.ruby-lang.org/issues/18007
|
|
3259
6072
|
void init_curb_easy() {
|
|
3260
6073
|
idCall = rb_intern("call");
|
|
3261
6074
|
idJoin = rb_intern("join");
|
|
6075
|
+
idNetworkPolicyNone = rb_intern("none");
|
|
6076
|
+
idNetworkPolicyPublic = rb_intern("public");
|
|
3262
6077
|
|
|
3263
6078
|
rbstrAmp = rb_str_new2("&");
|
|
3264
6079
|
rb_global_variable(&rbstrAmp);
|
|
@@ -3266,12 +6081,21 @@ void init_curb_easy() {
|
|
|
3266
6081
|
cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
|
|
3267
6082
|
|
|
3268
6083
|
/* Class methods */
|
|
3269
|
-
|
|
6084
|
+
rb_define_alloc_func(cCurlEasy, ruby_curl_easy_allocate);
|
|
3270
6085
|
rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
|
|
3271
6086
|
|
|
6087
|
+
/* Initialize method */
|
|
6088
|
+
rb_define_method(cCurlEasy, "initialize", ruby_curl_easy_initialize, -1);
|
|
6089
|
+
|
|
3272
6090
|
/* Attributes for config next perform */
|
|
3273
6091
|
rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
|
|
3274
6092
|
rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
|
|
6093
|
+
rb_define_method(cCurlEasy, "http_version=", ruby_curl_easy_http_version_set, 1);
|
|
6094
|
+
rb_define_method(cCurlEasy, "http_version", ruby_curl_easy_http_version_get, 0);
|
|
6095
|
+
|
|
6096
|
+
rb_define_method(cCurlEasy, "proxy_headers=", ruby_curl_easy_proxy_headers_set, 1);
|
|
6097
|
+
rb_define_method(cCurlEasy, "proxy_headers", ruby_curl_easy_proxy_headers_get, 0);
|
|
6098
|
+
|
|
3275
6099
|
rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
|
|
3276
6100
|
rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
|
|
3277
6101
|
rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
|
|
@@ -3298,6 +6122,19 @@ void init_curb_easy() {
|
|
|
3298
6122
|
rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
|
|
3299
6123
|
rb_define_method(cCurlEasy, "ftp_commands=", ruby_curl_easy_ftp_commands_set, 1);
|
|
3300
6124
|
rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
|
|
6125
|
+
rb_define_method(cCurlEasy, "resolve=", ruby_curl_easy_resolve_set, 1);
|
|
6126
|
+
rb_define_method(cCurlEasy, "resolve", ruby_curl_easy_resolve_get, 0);
|
|
6127
|
+
rb_define_method(cCurlEasy, "connect_to=", ruby_curl_easy_connect_to_set, 1);
|
|
6128
|
+
rb_define_method(cCurlEasy, "connect_to", ruby_curl_easy_connect_to_get, 0);
|
|
6129
|
+
rb_define_method(cCurlEasy, "doh_url=", ruby_curl_easy_doh_url_set, 1);
|
|
6130
|
+
rb_define_method(cCurlEasy, "doh_url", ruby_curl_easy_doh_url_get, 0);
|
|
6131
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
6132
|
+
rb_define_method(cCurlEasy, "dns_servers", ruby_curl_easy_dns_servers_get, 0);
|
|
6133
|
+
#endif
|
|
6134
|
+
rb_define_method(cCurlEasy, "allowed_cidrs=", ruby_curl_easy_allowed_cidrs_set, 1);
|
|
6135
|
+
rb_define_method(cCurlEasy, "allowed_cidrs", ruby_curl_easy_allowed_cidrs_get, 0);
|
|
6136
|
+
rb_define_method(cCurlEasy, "allowed_hosts=", ruby_curl_easy_allowed_hosts_set, 1);
|
|
6137
|
+
rb_define_method(cCurlEasy, "allowed_hosts", ruby_curl_easy_allowed_hosts_get, 0);
|
|
3301
6138
|
|
|
3302
6139
|
rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
|
|
3303
6140
|
rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
|
|
@@ -3315,8 +6152,12 @@ void init_curb_easy() {
|
|
|
3315
6152
|
rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);
|
|
3316
6153
|
rb_define_method(cCurlEasy, "timeout=", ruby_curl_easy_timeout_set, 1);
|
|
3317
6154
|
rb_define_method(cCurlEasy, "timeout", ruby_curl_easy_timeout_get, 0);
|
|
6155
|
+
rb_define_method(cCurlEasy, "timeout_ms=", ruby_curl_easy_timeout_ms_set, 1);
|
|
6156
|
+
rb_define_method(cCurlEasy, "timeout_ms", ruby_curl_easy_timeout_ms_get, 0);
|
|
3318
6157
|
rb_define_method(cCurlEasy, "connect_timeout=", ruby_curl_easy_connect_timeout_set, 1);
|
|
3319
6158
|
rb_define_method(cCurlEasy, "connect_timeout", ruby_curl_easy_connect_timeout_get, 0);
|
|
6159
|
+
rb_define_method(cCurlEasy, "connect_timeout_ms=", ruby_curl_easy_connect_timeout_ms_set, 1);
|
|
6160
|
+
rb_define_method(cCurlEasy, "connect_timeout_ms", ruby_curl_easy_connect_timeout_ms_get, 0);
|
|
3320
6161
|
rb_define_method(cCurlEasy, "dns_cache_timeout=", ruby_curl_easy_dns_cache_timeout_set, 1);
|
|
3321
6162
|
rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
|
|
3322
6163
|
rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
|
|
@@ -3325,6 +6166,10 @@ void init_curb_easy() {
|
|
|
3325
6166
|
rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
|
|
3326
6167
|
rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
|
|
3327
6168
|
rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
|
|
6169
|
+
rb_define_method(cCurlEasy, "max_send_speed_large=", ruby_curl_easy_max_send_speed_large_set, 1);
|
|
6170
|
+
rb_define_method(cCurlEasy, "max_send_speed_large", ruby_curl_easy_max_send_speed_large_get, 0);
|
|
6171
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large=", ruby_curl_easy_max_recv_speed_large_set, 1);
|
|
6172
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large", ruby_curl_easy_max_recv_speed_large_get, 0);
|
|
3328
6173
|
rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
|
|
3329
6174
|
rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
|
|
3330
6175
|
rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
|
|
@@ -3363,6 +6208,8 @@ void init_curb_easy() {
|
|
|
3363
6208
|
rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
|
|
3364
6209
|
rb_define_method(cCurlEasy, "resolve_mode", ruby_curl_easy_resolve_mode, 0);
|
|
3365
6210
|
rb_define_method(cCurlEasy, "resolve_mode=", ruby_curl_easy_resolve_mode_set, 1);
|
|
6211
|
+
rb_define_method(cCurlEasy, "network_policy", ruby_curl_easy_network_policy_get, 0);
|
|
6212
|
+
rb_define_method(cCurlEasy, "network_policy=", ruby_curl_easy_network_policy_set, 1);
|
|
3366
6213
|
|
|
3367
6214
|
rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
|
|
3368
6215
|
rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
|
|
@@ -3376,14 +6223,18 @@ void init_curb_easy() {
|
|
|
3376
6223
|
|
|
3377
6224
|
rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
|
|
3378
6225
|
rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
|
|
3379
|
-
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
|
|
6226
|
+
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, -1);
|
|
6227
|
+
rb_define_method(cCurlEasy, "http_patch", ruby_curl_easy_perform_patch, -1);
|
|
3380
6228
|
|
|
3381
6229
|
/* Post-perform info methods */
|
|
3382
6230
|
rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
|
|
6231
|
+
rb_define_method(cCurlEasy, "max_body_bytes=", ruby_curl_easy_max_body_bytes_set, 1);
|
|
6232
|
+
rb_define_method(cCurlEasy, "max_body_bytes", ruby_curl_easy_max_body_bytes_get, 0);
|
|
3383
6233
|
rb_define_method(cCurlEasy, "header_str", ruby_curl_easy_header_str_get, 0);
|
|
3384
6234
|
|
|
3385
6235
|
rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
|
|
3386
6236
|
rb_define_method(cCurlEasy, "response_code", ruby_curl_easy_response_code_get, 0);
|
|
6237
|
+
rb_define_method(cCurlEasy, "code", ruby_curl_easy_response_code_get, 0);
|
|
3387
6238
|
#if defined(HAVE_CURLINFO_PRIMARY_IP)
|
|
3388
6239
|
rb_define_method(cCurlEasy, "primary_ip", ruby_curl_easy_primary_ip_get, 0);
|
|
3389
6240
|
#endif
|
|
@@ -3412,6 +6263,7 @@ void init_curb_easy() {
|
|
|
3412
6263
|
rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
|
|
3413
6264
|
rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
|
|
3414
6265
|
rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
|
|
6266
|
+
rb_define_method(cCurlEasy, "cookielist", ruby_curl_easy_cookielist_get, 0);
|
|
3415
6267
|
rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
|
|
3416
6268
|
|
|
3417
6269
|
rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);
|
|
@@ -3428,7 +6280,16 @@ void init_curb_easy() {
|
|
|
3428
6280
|
|
|
3429
6281
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
|
3430
6282
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
|
6283
|
+
rb_define_private_method(cCurlEasy, "__curb_native_setup!", ruby_curl_easy_setup_self, 0);
|
|
6284
|
+
rb_define_private_method(cCurlEasy, "__curb_allow_proxy=", ruby_curl_easy_allow_proxy_set, 1);
|
|
6285
|
+
rb_define_private_method(cCurlEasy, "__curb_allow_unix_socket=", ruby_curl_easy_allow_unix_socket_set, 1);
|
|
6286
|
+
rb_define_private_method(cCurlEasy, "_take_callback_error", ruby_curl_easy_take_callback_error, 0);
|
|
3431
6287
|
rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
|
|
6288
|
+
rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
|
|
6289
|
+
rb_define_method(cCurlEasy, "unsafe_destination_error", ruby_curl_easy_unsafe_destination_error_get, 0);
|
|
6290
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
6291
|
+
rb_define_method(cCurlEasy, "unix_socket_path", ruby_curl_easy_unix_socket_path_get, 0);
|
|
6292
|
+
#endif
|
|
3432
6293
|
|
|
3433
6294
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
|
3434
6295
|
rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
|